diff options
Diffstat (limited to 'fs/locks.c')
-rw-r--r-- | fs/locks.c | 106 |
1 files changed, 60 insertions, 46 deletions
diff --git a/fs/locks.c b/fs/locks.c index 909eab8fb1d0..56f996e98bbc 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
@@ -139,10 +139,7 @@ int lease_break_time = 45; | |||
139 | #define for_each_lock(inode, lockp) \ | 139 | #define for_each_lock(inode, lockp) \ |
140 | for (lockp = &inode->i_flock; *lockp != NULL; lockp = &(*lockp)->fl_next) | 140 | for (lockp = &inode->i_flock; *lockp != NULL; lockp = &(*lockp)->fl_next) |
141 | 141 | ||
142 | LIST_HEAD(file_lock_list); | 142 | static LIST_HEAD(file_lock_list); |
143 | |||
144 | EXPORT_SYMBOL(file_lock_list); | ||
145 | |||
146 | static LIST_HEAD(blocked_list); | 143 | static LIST_HEAD(blocked_list); |
147 | 144 | ||
148 | static kmem_cache_t *filelock_cache; | 145 | static kmem_cache_t *filelock_cache; |
@@ -153,6 +150,21 @@ static struct file_lock *locks_alloc_lock(void) | |||
153 | return kmem_cache_alloc(filelock_cache, SLAB_KERNEL); | 150 | return kmem_cache_alloc(filelock_cache, SLAB_KERNEL); |
154 | } | 151 | } |
155 | 152 | ||
153 | static void locks_release_private(struct file_lock *fl) | ||
154 | { | ||
155 | if (fl->fl_ops) { | ||
156 | if (fl->fl_ops->fl_release_private) | ||
157 | fl->fl_ops->fl_release_private(fl); | ||
158 | fl->fl_ops = NULL; | ||
159 | } | ||
160 | if (fl->fl_lmops) { | ||
161 | if (fl->fl_lmops->fl_release_private) | ||
162 | fl->fl_lmops->fl_release_private(fl); | ||
163 | fl->fl_lmops = NULL; | ||
164 | } | ||
165 | |||
166 | } | ||
167 | |||
156 | /* Free a lock which is not in use. */ | 168 | /* Free a lock which is not in use. */ |
157 | static void locks_free_lock(struct file_lock *fl) | 169 | static void locks_free_lock(struct file_lock *fl) |
158 | { | 170 | { |
@@ -169,18 +181,7 @@ static void locks_free_lock(struct file_lock *fl) | |||
169 | if (!list_empty(&fl->fl_link)) | 181 | if (!list_empty(&fl->fl_link)) |
170 | panic("Attempting to free lock on active lock list"); | 182 | panic("Attempting to free lock on active lock list"); |
171 | 183 | ||
172 | if (fl->fl_ops) { | 184 | locks_release_private(fl); |
173 | if (fl->fl_ops->fl_release_private) | ||
174 | fl->fl_ops->fl_release_private(fl); | ||
175 | fl->fl_ops = NULL; | ||
176 | } | ||
177 | |||
178 | if (fl->fl_lmops) { | ||
179 | if (fl->fl_lmops->fl_release_private) | ||
180 | fl->fl_lmops->fl_release_private(fl); | ||
181 | fl->fl_lmops = NULL; | ||
182 | } | ||
183 | |||
184 | kmem_cache_free(filelock_cache, fl); | 185 | kmem_cache_free(filelock_cache, fl); |
185 | } | 186 | } |
186 | 187 | ||
@@ -218,24 +219,46 @@ static void init_once(void *foo, kmem_cache_t *cache, unsigned long flags) | |||
218 | locks_init_lock(lock); | 219 | locks_init_lock(lock); |
219 | } | 220 | } |
220 | 221 | ||
222 | static void locks_copy_private(struct file_lock *new, struct file_lock *fl) | ||
223 | { | ||
224 | if (fl->fl_ops) { | ||
225 | if (fl->fl_ops->fl_copy_lock) | ||
226 | fl->fl_ops->fl_copy_lock(new, fl); | ||
227 | new->fl_ops = fl->fl_ops; | ||
228 | } | ||
229 | if (fl->fl_lmops) { | ||
230 | if (fl->fl_lmops->fl_copy_lock) | ||
231 | fl->fl_lmops->fl_copy_lock(new, fl); | ||
232 | new->fl_lmops = fl->fl_lmops; | ||
233 | } | ||
234 | } | ||
235 | |||
221 | /* | 236 | /* |
222 | * Initialize a new lock from an existing file_lock structure. | 237 | * Initialize a new lock from an existing file_lock structure. |
223 | */ | 238 | */ |
224 | void locks_copy_lock(struct file_lock *new, struct file_lock *fl) | 239 | static void __locks_copy_lock(struct file_lock *new, const struct file_lock *fl) |
225 | { | 240 | { |
226 | new->fl_owner = fl->fl_owner; | 241 | new->fl_owner = fl->fl_owner; |
227 | new->fl_pid = fl->fl_pid; | 242 | new->fl_pid = fl->fl_pid; |
228 | new->fl_file = fl->fl_file; | 243 | new->fl_file = NULL; |
229 | new->fl_flags = fl->fl_flags; | 244 | new->fl_flags = fl->fl_flags; |
230 | new->fl_type = fl->fl_type; | 245 | new->fl_type = fl->fl_type; |
231 | new->fl_start = fl->fl_start; | 246 | new->fl_start = fl->fl_start; |
232 | new->fl_end = fl->fl_end; | 247 | new->fl_end = fl->fl_end; |
248 | new->fl_ops = NULL; | ||
249 | new->fl_lmops = NULL; | ||
250 | } | ||
251 | |||
252 | void locks_copy_lock(struct file_lock *new, struct file_lock *fl) | ||
253 | { | ||
254 | locks_release_private(new); | ||
255 | |||
256 | __locks_copy_lock(new, fl); | ||
257 | new->fl_file = fl->fl_file; | ||
233 | new->fl_ops = fl->fl_ops; | 258 | new->fl_ops = fl->fl_ops; |
234 | new->fl_lmops = fl->fl_lmops; | 259 | new->fl_lmops = fl->fl_lmops; |
235 | if (fl->fl_ops && fl->fl_ops->fl_copy_lock) | 260 | |
236 | fl->fl_ops->fl_copy_lock(new, fl); | 261 | locks_copy_private(new, fl); |
237 | if (fl->fl_lmops && fl->fl_lmops->fl_copy_lock) | ||
238 | fl->fl_lmops->fl_copy_lock(new, fl); | ||
239 | } | 262 | } |
240 | 263 | ||
241 | EXPORT_SYMBOL(locks_copy_lock); | 264 | EXPORT_SYMBOL(locks_copy_lock); |
@@ -654,8 +677,9 @@ static int locks_block_on_timeout(struct file_lock *blocker, struct file_lock *w | |||
654 | return result; | 677 | return result; |
655 | } | 678 | } |
656 | 679 | ||
657 | struct file_lock * | 680 | int |
658 | posix_test_lock(struct file *filp, struct file_lock *fl) | 681 | posix_test_lock(struct file *filp, struct file_lock *fl, |
682 | struct file_lock *conflock) | ||
659 | { | 683 | { |
660 | struct file_lock *cfl; | 684 | struct file_lock *cfl; |
661 | 685 | ||
@@ -666,9 +690,13 @@ posix_test_lock(struct file *filp, struct file_lock *fl) | |||
666 | if (posix_locks_conflict(cfl, fl)) | 690 | if (posix_locks_conflict(cfl, fl)) |
667 | break; | 691 | break; |
668 | } | 692 | } |
693 | if (cfl) { | ||
694 | __locks_copy_lock(conflock, cfl); | ||
695 | unlock_kernel(); | ||
696 | return 1; | ||
697 | } | ||
669 | unlock_kernel(); | 698 | unlock_kernel(); |
670 | 699 | return 0; | |
671 | return (cfl); | ||
672 | } | 700 | } |
673 | 701 | ||
674 | EXPORT_SYMBOL(posix_test_lock); | 702 | EXPORT_SYMBOL(posix_test_lock); |
@@ -904,7 +932,8 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request) | |||
904 | fl->fl_start = request->fl_start; | 932 | fl->fl_start = request->fl_start; |
905 | fl->fl_end = request->fl_end; | 933 | fl->fl_end = request->fl_end; |
906 | fl->fl_type = request->fl_type; | 934 | fl->fl_type = request->fl_type; |
907 | fl->fl_u = request->fl_u; | 935 | locks_release_private(fl); |
936 | locks_copy_private(fl, request); | ||
908 | request = fl; | 937 | request = fl; |
909 | added = 1; | 938 | added = 1; |
910 | } | 939 | } |
@@ -1544,7 +1573,7 @@ asmlinkage long sys_flock(unsigned int fd, unsigned int cmd) | |||
1544 | */ | 1573 | */ |
1545 | int fcntl_getlk(struct file *filp, struct flock __user *l) | 1574 | int fcntl_getlk(struct file *filp, struct flock __user *l) |
1546 | { | 1575 | { |
1547 | struct file_lock *fl, file_lock; | 1576 | struct file_lock *fl, cfl, file_lock; |
1548 | struct flock flock; | 1577 | struct flock flock; |
1549 | int error; | 1578 | int error; |
1550 | 1579 | ||
@@ -1568,7 +1597,7 @@ int fcntl_getlk(struct file *filp, struct flock __user *l) | |||
1568 | else | 1597 | else |
1569 | fl = (file_lock.fl_type == F_UNLCK ? NULL : &file_lock); | 1598 | fl = (file_lock.fl_type == F_UNLCK ? NULL : &file_lock); |
1570 | } else { | 1599 | } else { |
1571 | fl = posix_test_lock(filp, &file_lock); | 1600 | fl = (posix_test_lock(filp, &file_lock, &cfl) ? &cfl : NULL); |
1572 | } | 1601 | } |
1573 | 1602 | ||
1574 | flock.l_type = F_UNLCK; | 1603 | flock.l_type = F_UNLCK; |
@@ -1698,7 +1727,7 @@ out: | |||
1698 | */ | 1727 | */ |
1699 | int fcntl_getlk64(struct file *filp, struct flock64 __user *l) | 1728 | int fcntl_getlk64(struct file *filp, struct flock64 __user *l) |
1700 | { | 1729 | { |
1701 | struct file_lock *fl, file_lock; | 1730 | struct file_lock *fl, cfl, file_lock; |
1702 | struct flock64 flock; | 1731 | struct flock64 flock; |
1703 | int error; | 1732 | int error; |
1704 | 1733 | ||
@@ -1722,7 +1751,7 @@ int fcntl_getlk64(struct file *filp, struct flock64 __user *l) | |||
1722 | else | 1751 | else |
1723 | fl = (file_lock.fl_type == F_UNLCK ? NULL : &file_lock); | 1752 | fl = (file_lock.fl_type == F_UNLCK ? NULL : &file_lock); |
1724 | } else { | 1753 | } else { |
1725 | fl = posix_test_lock(filp, &file_lock); | 1754 | fl = (posix_test_lock(filp, &file_lock, &cfl) ? &cfl : NULL); |
1726 | } | 1755 | } |
1727 | 1756 | ||
1728 | flock.l_type = F_UNLCK; | 1757 | flock.l_type = F_UNLCK; |
@@ -1936,21 +1965,6 @@ void locks_remove_flock(struct file *filp) | |||
1936 | } | 1965 | } |
1937 | 1966 | ||
1938 | /** | 1967 | /** |
1939 | * posix_block_lock - blocks waiting for a file lock | ||
1940 | * @blocker: the lock which is blocking | ||
1941 | * @waiter: the lock which conflicts and has to wait | ||
1942 | * | ||
1943 | * lockd needs to block waiting for locks. | ||
1944 | */ | ||
1945 | void | ||
1946 | posix_block_lock(struct file_lock *blocker, struct file_lock *waiter) | ||
1947 | { | ||
1948 | locks_insert_block(blocker, waiter); | ||
1949 | } | ||
1950 | |||
1951 | EXPORT_SYMBOL(posix_block_lock); | ||
1952 | |||
1953 | /** | ||
1954 | * posix_unblock_lock - stop waiting for a file lock | 1968 | * posix_unblock_lock - stop waiting for a file lock |
1955 | * @filp: how the file was opened | 1969 | * @filp: how the file was opened |
1956 | * @waiter: the lock which was waiting | 1970 | * @waiter: the lock which was waiting |