diff options
Diffstat (limited to 'fs/locks.c')
-rw-r--r-- | fs/locks.c | 302 |
1 files changed, 170 insertions, 132 deletions
diff --git a/fs/locks.c b/fs/locks.c index ab24d49fc048..b286539d547a 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
@@ -122,7 +122,6 @@ | |||
122 | #include <linux/module.h> | 122 | #include <linux/module.h> |
123 | #include <linux/security.h> | 123 | #include <linux/security.h> |
124 | #include <linux/slab.h> | 124 | #include <linux/slab.h> |
125 | #include <linux/smp_lock.h> | ||
126 | #include <linux/syscalls.h> | 125 | #include <linux/syscalls.h> |
127 | #include <linux/time.h> | 126 | #include <linux/time.h> |
128 | #include <linux/rcupdate.h> | 127 | #include <linux/rcupdate.h> |
@@ -142,14 +141,49 @@ int lease_break_time = 45; | |||
142 | 141 | ||
143 | static LIST_HEAD(file_lock_list); | 142 | static LIST_HEAD(file_lock_list); |
144 | static LIST_HEAD(blocked_list); | 143 | static LIST_HEAD(blocked_list); |
144 | static DEFINE_SPINLOCK(file_lock_lock); | ||
145 | |||
146 | /* | ||
147 | * Protects the two list heads above, plus the inode->i_flock list | ||
148 | */ | ||
149 | void lock_flocks(void) | ||
150 | { | ||
151 | spin_lock(&file_lock_lock); | ||
152 | } | ||
153 | EXPORT_SYMBOL_GPL(lock_flocks); | ||
154 | |||
155 | void unlock_flocks(void) | ||
156 | { | ||
157 | spin_unlock(&file_lock_lock); | ||
158 | } | ||
159 | EXPORT_SYMBOL_GPL(unlock_flocks); | ||
145 | 160 | ||
146 | static struct kmem_cache *filelock_cache __read_mostly; | 161 | static struct kmem_cache *filelock_cache __read_mostly; |
147 | 162 | ||
163 | static void locks_init_lock_always(struct file_lock *fl) | ||
164 | { | ||
165 | fl->fl_next = NULL; | ||
166 | fl->fl_fasync = NULL; | ||
167 | fl->fl_owner = NULL; | ||
168 | fl->fl_pid = 0; | ||
169 | fl->fl_nspid = NULL; | ||
170 | fl->fl_file = NULL; | ||
171 | fl->fl_flags = 0; | ||
172 | fl->fl_type = 0; | ||
173 | fl->fl_start = fl->fl_end = 0; | ||
174 | } | ||
175 | |||
148 | /* Allocate an empty lock structure. */ | 176 | /* Allocate an empty lock structure. */ |
149 | static struct file_lock *locks_alloc_lock(void) | 177 | struct file_lock *locks_alloc_lock(void) |
150 | { | 178 | { |
151 | return kmem_cache_alloc(filelock_cache, GFP_KERNEL); | 179 | struct file_lock *fl = kmem_cache_alloc(filelock_cache, GFP_KERNEL); |
180 | |||
181 | if (fl) | ||
182 | locks_init_lock_always(fl); | ||
183 | |||
184 | return fl; | ||
152 | } | 185 | } |
186 | EXPORT_SYMBOL_GPL(locks_alloc_lock); | ||
153 | 187 | ||
154 | void locks_release_private(struct file_lock *fl) | 188 | void locks_release_private(struct file_lock *fl) |
155 | { | 189 | { |
@@ -168,7 +202,7 @@ void locks_release_private(struct file_lock *fl) | |||
168 | EXPORT_SYMBOL_GPL(locks_release_private); | 202 | EXPORT_SYMBOL_GPL(locks_release_private); |
169 | 203 | ||
170 | /* Free a lock which is not in use. */ | 204 | /* Free a lock which is not in use. */ |
171 | static void locks_free_lock(struct file_lock *fl) | 205 | void locks_free_lock(struct file_lock *fl) |
172 | { | 206 | { |
173 | BUG_ON(waitqueue_active(&fl->fl_wait)); | 207 | BUG_ON(waitqueue_active(&fl->fl_wait)); |
174 | BUG_ON(!list_empty(&fl->fl_block)); | 208 | BUG_ON(!list_empty(&fl->fl_block)); |
@@ -177,23 +211,16 @@ static void locks_free_lock(struct file_lock *fl) | |||
177 | locks_release_private(fl); | 211 | locks_release_private(fl); |
178 | kmem_cache_free(filelock_cache, fl); | 212 | kmem_cache_free(filelock_cache, fl); |
179 | } | 213 | } |
214 | EXPORT_SYMBOL(locks_free_lock); | ||
180 | 215 | ||
181 | void locks_init_lock(struct file_lock *fl) | 216 | void locks_init_lock(struct file_lock *fl) |
182 | { | 217 | { |
183 | INIT_LIST_HEAD(&fl->fl_link); | 218 | INIT_LIST_HEAD(&fl->fl_link); |
184 | INIT_LIST_HEAD(&fl->fl_block); | 219 | INIT_LIST_HEAD(&fl->fl_block); |
185 | init_waitqueue_head(&fl->fl_wait); | 220 | init_waitqueue_head(&fl->fl_wait); |
186 | fl->fl_next = NULL; | ||
187 | fl->fl_fasync = NULL; | ||
188 | fl->fl_owner = NULL; | ||
189 | fl->fl_pid = 0; | ||
190 | fl->fl_nspid = NULL; | ||
191 | fl->fl_file = NULL; | ||
192 | fl->fl_flags = 0; | ||
193 | fl->fl_type = 0; | ||
194 | fl->fl_start = fl->fl_end = 0; | ||
195 | fl->fl_ops = NULL; | 221 | fl->fl_ops = NULL; |
196 | fl->fl_lmops = NULL; | 222 | fl->fl_lmops = NULL; |
223 | locks_init_lock_always(fl); | ||
197 | } | 224 | } |
198 | 225 | ||
199 | EXPORT_SYMBOL(locks_init_lock); | 226 | EXPORT_SYMBOL(locks_init_lock); |
@@ -216,11 +243,8 @@ static void locks_copy_private(struct file_lock *new, struct file_lock *fl) | |||
216 | fl->fl_ops->fl_copy_lock(new, fl); | 243 | fl->fl_ops->fl_copy_lock(new, fl); |
217 | new->fl_ops = fl->fl_ops; | 244 | new->fl_ops = fl->fl_ops; |
218 | } | 245 | } |
219 | if (fl->fl_lmops) { | 246 | if (fl->fl_lmops) |
220 | if (fl->fl_lmops->fl_copy_lock) | ||
221 | fl->fl_lmops->fl_copy_lock(new, fl); | ||
222 | new->fl_lmops = fl->fl_lmops; | 247 | new->fl_lmops = fl->fl_lmops; |
223 | } | ||
224 | } | 248 | } |
225 | 249 | ||
226 | /* | 250 | /* |
@@ -400,17 +424,7 @@ static int flock64_to_posix_lock(struct file *filp, struct file_lock *fl, | |||
400 | fl->fl_ops = NULL; | 424 | fl->fl_ops = NULL; |
401 | fl->fl_lmops = NULL; | 425 | fl->fl_lmops = NULL; |
402 | 426 | ||
403 | switch (l->l_type) { | 427 | return assign_type(fl, l->l_type); |
404 | case F_RDLCK: | ||
405 | case F_WRLCK: | ||
406 | case F_UNLCK: | ||
407 | fl->fl_type = l->l_type; | ||
408 | break; | ||
409 | default: | ||
410 | return -EINVAL; | ||
411 | } | ||
412 | |||
413 | return (0); | ||
414 | } | 428 | } |
415 | #endif | 429 | #endif |
416 | 430 | ||
@@ -429,15 +443,9 @@ static void lease_release_private_callback(struct file_lock *fl) | |||
429 | fl->fl_file->f_owner.signum = 0; | 443 | fl->fl_file->f_owner.signum = 0; |
430 | } | 444 | } |
431 | 445 | ||
432 | static int lease_mylease_callback(struct file_lock *fl, struct file_lock *try) | ||
433 | { | ||
434 | return fl->fl_file == try->fl_file; | ||
435 | } | ||
436 | |||
437 | static const struct lock_manager_operations lease_manager_ops = { | 446 | static const struct lock_manager_operations lease_manager_ops = { |
438 | .fl_break = lease_break_callback, | 447 | .fl_break = lease_break_callback, |
439 | .fl_release_private = lease_release_private_callback, | 448 | .fl_release_private = lease_release_private_callback, |
440 | .fl_mylease = lease_mylease_callback, | ||
441 | .fl_change = lease_modify, | 449 | .fl_change = lease_modify, |
442 | }; | 450 | }; |
443 | 451 | ||
@@ -511,9 +519,9 @@ static void __locks_delete_block(struct file_lock *waiter) | |||
511 | */ | 519 | */ |
512 | static void locks_delete_block(struct file_lock *waiter) | 520 | static void locks_delete_block(struct file_lock *waiter) |
513 | { | 521 | { |
514 | lock_kernel(); | 522 | lock_flocks(); |
515 | __locks_delete_block(waiter); | 523 | __locks_delete_block(waiter); |
516 | unlock_kernel(); | 524 | unlock_flocks(); |
517 | } | 525 | } |
518 | 526 | ||
519 | /* Insert waiter into blocker's block list. | 527 | /* Insert waiter into blocker's block list. |
@@ -644,7 +652,7 @@ posix_test_lock(struct file *filp, struct file_lock *fl) | |||
644 | { | 652 | { |
645 | struct file_lock *cfl; | 653 | struct file_lock *cfl; |
646 | 654 | ||
647 | lock_kernel(); | 655 | lock_flocks(); |
648 | for (cfl = filp->f_path.dentry->d_inode->i_flock; cfl; cfl = cfl->fl_next) { | 656 | for (cfl = filp->f_path.dentry->d_inode->i_flock; cfl; cfl = cfl->fl_next) { |
649 | if (!IS_POSIX(cfl)) | 657 | if (!IS_POSIX(cfl)) |
650 | continue; | 658 | continue; |
@@ -657,7 +665,7 @@ posix_test_lock(struct file *filp, struct file_lock *fl) | |||
657 | fl->fl_pid = pid_vnr(cfl->fl_nspid); | 665 | fl->fl_pid = pid_vnr(cfl->fl_nspid); |
658 | } else | 666 | } else |
659 | fl->fl_type = F_UNLCK; | 667 | fl->fl_type = F_UNLCK; |
660 | unlock_kernel(); | 668 | unlock_flocks(); |
661 | return; | 669 | return; |
662 | } | 670 | } |
663 | EXPORT_SYMBOL(posix_test_lock); | 671 | EXPORT_SYMBOL(posix_test_lock); |
@@ -730,18 +738,16 @@ static int flock_lock_file(struct file *filp, struct file_lock *request) | |||
730 | int error = 0; | 738 | int error = 0; |
731 | int found = 0; | 739 | int found = 0; |
732 | 740 | ||
733 | lock_kernel(); | 741 | if (!(request->fl_flags & FL_ACCESS) && (request->fl_type != F_UNLCK)) { |
734 | if (request->fl_flags & FL_ACCESS) | ||
735 | goto find_conflict; | ||
736 | |||
737 | if (request->fl_type != F_UNLCK) { | ||
738 | error = -ENOMEM; | ||
739 | new_fl = locks_alloc_lock(); | 742 | new_fl = locks_alloc_lock(); |
740 | if (new_fl == NULL) | 743 | if (!new_fl) |
741 | goto out; | 744 | return -ENOMEM; |
742 | error = 0; | ||
743 | } | 745 | } |
744 | 746 | ||
747 | lock_flocks(); | ||
748 | if (request->fl_flags & FL_ACCESS) | ||
749 | goto find_conflict; | ||
750 | |||
745 | for_each_lock(inode, before) { | 751 | for_each_lock(inode, before) { |
746 | struct file_lock *fl = *before; | 752 | struct file_lock *fl = *before; |
747 | if (IS_POSIX(fl)) | 753 | if (IS_POSIX(fl)) |
@@ -767,8 +773,11 @@ static int flock_lock_file(struct file *filp, struct file_lock *request) | |||
767 | * If a higher-priority process was blocked on the old file lock, | 773 | * If a higher-priority process was blocked on the old file lock, |
768 | * give it the opportunity to lock the file. | 774 | * give it the opportunity to lock the file. |
769 | */ | 775 | */ |
770 | if (found) | 776 | if (found) { |
777 | unlock_flocks(); | ||
771 | cond_resched(); | 778 | cond_resched(); |
779 | lock_flocks(); | ||
780 | } | ||
772 | 781 | ||
773 | find_conflict: | 782 | find_conflict: |
774 | for_each_lock(inode, before) { | 783 | for_each_lock(inode, before) { |
@@ -794,7 +803,7 @@ find_conflict: | |||
794 | error = 0; | 803 | error = 0; |
795 | 804 | ||
796 | out: | 805 | out: |
797 | unlock_kernel(); | 806 | unlock_flocks(); |
798 | if (new_fl) | 807 | if (new_fl) |
799 | locks_free_lock(new_fl); | 808 | locks_free_lock(new_fl); |
800 | return error; | 809 | return error; |
@@ -823,7 +832,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str | |||
823 | new_fl2 = locks_alloc_lock(); | 832 | new_fl2 = locks_alloc_lock(); |
824 | } | 833 | } |
825 | 834 | ||
826 | lock_kernel(); | 835 | lock_flocks(); |
827 | if (request->fl_type != F_UNLCK) { | 836 | if (request->fl_type != F_UNLCK) { |
828 | for_each_lock(inode, before) { | 837 | for_each_lock(inode, before) { |
829 | fl = *before; | 838 | fl = *before; |
@@ -991,7 +1000,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str | |||
991 | locks_wake_up_blocks(left); | 1000 | locks_wake_up_blocks(left); |
992 | } | 1001 | } |
993 | out: | 1002 | out: |
994 | unlock_kernel(); | 1003 | unlock_flocks(); |
995 | /* | 1004 | /* |
996 | * Free any unused locks. | 1005 | * Free any unused locks. |
997 | */ | 1006 | */ |
@@ -1066,14 +1075,14 @@ int locks_mandatory_locked(struct inode *inode) | |||
1066 | /* | 1075 | /* |
1067 | * Search the lock list for this inode for any POSIX locks. | 1076 | * Search the lock list for this inode for any POSIX locks. |
1068 | */ | 1077 | */ |
1069 | lock_kernel(); | 1078 | lock_flocks(); |
1070 | for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { | 1079 | for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { |
1071 | if (!IS_POSIX(fl)) | 1080 | if (!IS_POSIX(fl)) |
1072 | continue; | 1081 | continue; |
1073 | if (fl->fl_owner != owner) | 1082 | if (fl->fl_owner != owner) |
1074 | break; | 1083 | break; |
1075 | } | 1084 | } |
1076 | unlock_kernel(); | 1085 | unlock_flocks(); |
1077 | return fl ? -EAGAIN : 0; | 1086 | return fl ? -EAGAIN : 0; |
1078 | } | 1087 | } |
1079 | 1088 | ||
@@ -1186,7 +1195,7 @@ int __break_lease(struct inode *inode, unsigned int mode) | |||
1186 | 1195 | ||
1187 | new_fl = lease_alloc(NULL, want_write ? F_WRLCK : F_RDLCK); | 1196 | new_fl = lease_alloc(NULL, want_write ? F_WRLCK : F_RDLCK); |
1188 | 1197 | ||
1189 | lock_kernel(); | 1198 | lock_flocks(); |
1190 | 1199 | ||
1191 | time_out_leases(inode); | 1200 | time_out_leases(inode); |
1192 | 1201 | ||
@@ -1247,8 +1256,10 @@ restart: | |||
1247 | break_time++; | 1256 | break_time++; |
1248 | } | 1257 | } |
1249 | locks_insert_block(flock, new_fl); | 1258 | locks_insert_block(flock, new_fl); |
1259 | unlock_flocks(); | ||
1250 | error = wait_event_interruptible_timeout(new_fl->fl_wait, | 1260 | error = wait_event_interruptible_timeout(new_fl->fl_wait, |
1251 | !new_fl->fl_next, break_time); | 1261 | !new_fl->fl_next, break_time); |
1262 | lock_flocks(); | ||
1252 | __locks_delete_block(new_fl); | 1263 | __locks_delete_block(new_fl); |
1253 | if (error >= 0) { | 1264 | if (error >= 0) { |
1254 | if (error == 0) | 1265 | if (error == 0) |
@@ -1263,7 +1274,7 @@ restart: | |||
1263 | } | 1274 | } |
1264 | 1275 | ||
1265 | out: | 1276 | out: |
1266 | unlock_kernel(); | 1277 | unlock_flocks(); |
1267 | if (!IS_ERR(new_fl)) | 1278 | if (!IS_ERR(new_fl)) |
1268 | locks_free_lock(new_fl); | 1279 | locks_free_lock(new_fl); |
1269 | return error; | 1280 | return error; |
@@ -1319,7 +1330,7 @@ int fcntl_getlease(struct file *filp) | |||
1319 | struct file_lock *fl; | 1330 | struct file_lock *fl; |
1320 | int type = F_UNLCK; | 1331 | int type = F_UNLCK; |
1321 | 1332 | ||
1322 | lock_kernel(); | 1333 | lock_flocks(); |
1323 | time_out_leases(filp->f_path.dentry->d_inode); | 1334 | time_out_leases(filp->f_path.dentry->d_inode); |
1324 | for (fl = filp->f_path.dentry->d_inode->i_flock; fl && IS_LEASE(fl); | 1335 | for (fl = filp->f_path.dentry->d_inode->i_flock; fl && IS_LEASE(fl); |
1325 | fl = fl->fl_next) { | 1336 | fl = fl->fl_next) { |
@@ -1328,7 +1339,7 @@ int fcntl_getlease(struct file *filp) | |||
1328 | break; | 1339 | break; |
1329 | } | 1340 | } |
1330 | } | 1341 | } |
1331 | unlock_kernel(); | 1342 | unlock_flocks(); |
1332 | return type; | 1343 | return type; |
1333 | } | 1344 | } |
1334 | 1345 | ||
@@ -1341,41 +1352,37 @@ int fcntl_getlease(struct file *filp) | |||
1341 | * The (input) flp->fl_lmops->fl_break function is required | 1352 | * The (input) flp->fl_lmops->fl_break function is required |
1342 | * by break_lease(). | 1353 | * by break_lease(). |
1343 | * | 1354 | * |
1344 | * Called with kernel lock held. | 1355 | * Called with file_lock_lock held. |
1345 | */ | 1356 | */ |
1346 | int generic_setlease(struct file *filp, long arg, struct file_lock **flp) | 1357 | int generic_setlease(struct file *filp, long arg, struct file_lock **flp) |
1347 | { | 1358 | { |
1348 | struct file_lock *fl, **before, **my_before = NULL, *lease; | 1359 | struct file_lock *fl, **before, **my_before = NULL, *lease; |
1349 | struct file_lock *new_fl = NULL; | ||
1350 | struct dentry *dentry = filp->f_path.dentry; | 1360 | struct dentry *dentry = filp->f_path.dentry; |
1351 | struct inode *inode = dentry->d_inode; | 1361 | struct inode *inode = dentry->d_inode; |
1352 | int error, rdlease_count = 0, wrlease_count = 0; | 1362 | int error, rdlease_count = 0, wrlease_count = 0; |
1353 | 1363 | ||
1364 | lease = *flp; | ||
1365 | |||
1366 | error = -EACCES; | ||
1354 | if ((current_fsuid() != inode->i_uid) && !capable(CAP_LEASE)) | 1367 | if ((current_fsuid() != inode->i_uid) && !capable(CAP_LEASE)) |
1355 | return -EACCES; | 1368 | goto out; |
1369 | error = -EINVAL; | ||
1356 | if (!S_ISREG(inode->i_mode)) | 1370 | if (!S_ISREG(inode->i_mode)) |
1357 | return -EINVAL; | 1371 | goto out; |
1358 | error = security_file_lock(filp, arg); | 1372 | error = security_file_lock(filp, arg); |
1359 | if (error) | 1373 | if (error) |
1360 | return error; | 1374 | goto out; |
1361 | 1375 | ||
1362 | time_out_leases(inode); | 1376 | time_out_leases(inode); |
1363 | 1377 | ||
1364 | BUG_ON(!(*flp)->fl_lmops->fl_break); | 1378 | BUG_ON(!(*flp)->fl_lmops->fl_break); |
1365 | 1379 | ||
1366 | lease = *flp; | ||
1367 | |||
1368 | if (arg != F_UNLCK) { | 1380 | if (arg != F_UNLCK) { |
1369 | error = -ENOMEM; | ||
1370 | new_fl = locks_alloc_lock(); | ||
1371 | if (new_fl == NULL) | ||
1372 | goto out; | ||
1373 | |||
1374 | error = -EAGAIN; | 1381 | error = -EAGAIN; |
1375 | if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0)) | 1382 | if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0)) |
1376 | goto out; | 1383 | goto out; |
1377 | if ((arg == F_WRLCK) | 1384 | if ((arg == F_WRLCK) |
1378 | && ((atomic_read(&dentry->d_count) > 1) | 1385 | && ((dentry->d_count > 1) |
1379 | || (atomic_read(&inode->i_count) > 1))) | 1386 | || (atomic_read(&inode->i_count) > 1))) |
1380 | goto out; | 1387 | goto out; |
1381 | } | 1388 | } |
@@ -1391,7 +1398,7 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp) | |||
1391 | for (before = &inode->i_flock; | 1398 | for (before = &inode->i_flock; |
1392 | ((fl = *before) != NULL) && IS_LEASE(fl); | 1399 | ((fl = *before) != NULL) && IS_LEASE(fl); |
1393 | before = &fl->fl_next) { | 1400 | before = &fl->fl_next) { |
1394 | if (lease->fl_lmops->fl_mylease(fl, lease)) | 1401 | if (fl->fl_file == filp) |
1395 | my_before = before; | 1402 | my_before = before; |
1396 | else if (fl->fl_type == (F_INPROGRESS | F_UNLCK)) | 1403 | else if (fl->fl_type == (F_INPROGRESS | F_UNLCK)) |
1397 | /* | 1404 | /* |
@@ -1410,12 +1417,12 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp) | |||
1410 | goto out; | 1417 | goto out; |
1411 | 1418 | ||
1412 | if (my_before != NULL) { | 1419 | if (my_before != NULL) { |
1413 | *flp = *my_before; | ||
1414 | error = lease->fl_lmops->fl_change(my_before, arg); | 1420 | error = lease->fl_lmops->fl_change(my_before, arg); |
1421 | if (!error) | ||
1422 | *flp = *my_before; | ||
1415 | goto out; | 1423 | goto out; |
1416 | } | 1424 | } |
1417 | 1425 | ||
1418 | error = 0; | ||
1419 | if (arg == F_UNLCK) | 1426 | if (arg == F_UNLCK) |
1420 | goto out; | 1427 | goto out; |
1421 | 1428 | ||
@@ -1423,20 +1430,23 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp) | |||
1423 | if (!leases_enable) | 1430 | if (!leases_enable) |
1424 | goto out; | 1431 | goto out; |
1425 | 1432 | ||
1426 | locks_copy_lock(new_fl, lease); | 1433 | locks_insert_lock(before, lease); |
1427 | locks_insert_lock(before, new_fl); | ||
1428 | |||
1429 | *flp = new_fl; | ||
1430 | return 0; | 1434 | return 0; |
1431 | 1435 | ||
1432 | out: | 1436 | out: |
1433 | if (new_fl != NULL) | ||
1434 | locks_free_lock(new_fl); | ||
1435 | return error; | 1437 | return error; |
1436 | } | 1438 | } |
1437 | EXPORT_SYMBOL(generic_setlease); | 1439 | EXPORT_SYMBOL(generic_setlease); |
1438 | 1440 | ||
1439 | /** | 1441 | static int __vfs_setlease(struct file *filp, long arg, struct file_lock **lease) |
1442 | { | ||
1443 | if (filp->f_op && filp->f_op->setlease) | ||
1444 | return filp->f_op->setlease(filp, arg, lease); | ||
1445 | else | ||
1446 | return generic_setlease(filp, arg, lease); | ||
1447 | } | ||
1448 | |||
1449 | /** | ||
1440 | * vfs_setlease - sets a lease on an open file | 1450 | * vfs_setlease - sets a lease on an open file |
1441 | * @filp: file pointer | 1451 | * @filp: file pointer |
1442 | * @arg: type of lease to obtain | 1452 | * @arg: type of lease to obtain |
@@ -1467,17 +1477,67 @@ int vfs_setlease(struct file *filp, long arg, struct file_lock **lease) | |||
1467 | { | 1477 | { |
1468 | int error; | 1478 | int error; |
1469 | 1479 | ||
1470 | lock_kernel(); | 1480 | lock_flocks(); |
1471 | if (filp->f_op && filp->f_op->setlease) | 1481 | error = __vfs_setlease(filp, arg, lease); |
1472 | error = filp->f_op->setlease(filp, arg, lease); | 1482 | unlock_flocks(); |
1473 | else | ||
1474 | error = generic_setlease(filp, arg, lease); | ||
1475 | unlock_kernel(); | ||
1476 | 1483 | ||
1477 | return error; | 1484 | return error; |
1478 | } | 1485 | } |
1479 | EXPORT_SYMBOL_GPL(vfs_setlease); | 1486 | EXPORT_SYMBOL_GPL(vfs_setlease); |
1480 | 1487 | ||
1488 | static int do_fcntl_delete_lease(struct file *filp) | ||
1489 | { | ||
1490 | struct file_lock fl, *flp = &fl; | ||
1491 | |||
1492 | lease_init(filp, F_UNLCK, flp); | ||
1493 | |||
1494 | return vfs_setlease(filp, F_UNLCK, &flp); | ||
1495 | } | ||
1496 | |||
1497 | static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg) | ||
1498 | { | ||
1499 | struct file_lock *fl, *ret; | ||
1500 | struct fasync_struct *new; | ||
1501 | int error; | ||
1502 | |||
1503 | fl = lease_alloc(filp, arg); | ||
1504 | if (IS_ERR(fl)) | ||
1505 | return PTR_ERR(fl); | ||
1506 | |||
1507 | new = fasync_alloc(); | ||
1508 | if (!new) { | ||
1509 | locks_free_lock(fl); | ||
1510 | return -ENOMEM; | ||
1511 | } | ||
1512 | ret = fl; | ||
1513 | lock_flocks(); | ||
1514 | error = __vfs_setlease(filp, arg, &ret); | ||
1515 | if (error) { | ||
1516 | unlock_flocks(); | ||
1517 | locks_free_lock(fl); | ||
1518 | goto out_free_fasync; | ||
1519 | } | ||
1520 | if (ret != fl) | ||
1521 | locks_free_lock(fl); | ||
1522 | |||
1523 | /* | ||
1524 | * fasync_insert_entry() returns the old entry if any. | ||
1525 | * If there was no old entry, then it used 'new' and | ||
1526 | * inserted it into the fasync list. Clear new so that | ||
1527 | * we don't release it here. | ||
1528 | */ | ||
1529 | if (!fasync_insert_entry(fd, filp, &ret->fl_fasync, new)) | ||
1530 | new = NULL; | ||
1531 | |||
1532 | error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0); | ||
1533 | unlock_flocks(); | ||
1534 | |||
1535 | out_free_fasync: | ||
1536 | if (new) | ||
1537 | fasync_free(new); | ||
1538 | return error; | ||
1539 | } | ||
1540 | |||
1481 | /** | 1541 | /** |
1482 | * fcntl_setlease - sets a lease on an open file | 1542 | * fcntl_setlease - sets a lease on an open file |
1483 | * @fd: open file descriptor | 1543 | * @fd: open file descriptor |
@@ -1490,34 +1550,9 @@ EXPORT_SYMBOL_GPL(vfs_setlease); | |||
1490 | */ | 1550 | */ |
1491 | int fcntl_setlease(unsigned int fd, struct file *filp, long arg) | 1551 | int fcntl_setlease(unsigned int fd, struct file *filp, long arg) |
1492 | { | 1552 | { |
1493 | struct file_lock fl, *flp = &fl; | 1553 | if (arg == F_UNLCK) |
1494 | struct inode *inode = filp->f_path.dentry->d_inode; | 1554 | return do_fcntl_delete_lease(filp); |
1495 | int error; | 1555 | return do_fcntl_add_lease(fd, filp, arg); |
1496 | |||
1497 | locks_init_lock(&fl); | ||
1498 | error = lease_init(filp, arg, &fl); | ||
1499 | if (error) | ||
1500 | return error; | ||
1501 | |||
1502 | lock_kernel(); | ||
1503 | |||
1504 | error = vfs_setlease(filp, arg, &flp); | ||
1505 | if (error || arg == F_UNLCK) | ||
1506 | goto out_unlock; | ||
1507 | |||
1508 | error = fasync_helper(fd, filp, 1, &flp->fl_fasync); | ||
1509 | if (error < 0) { | ||
1510 | /* remove lease just inserted by setlease */ | ||
1511 | flp->fl_type = F_UNLCK | F_INPROGRESS; | ||
1512 | flp->fl_break_time = jiffies - 10; | ||
1513 | time_out_leases(inode); | ||
1514 | goto out_unlock; | ||
1515 | } | ||
1516 | |||
1517 | error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0); | ||
1518 | out_unlock: | ||
1519 | unlock_kernel(); | ||
1520 | return error; | ||
1521 | } | 1556 | } |
1522 | 1557 | ||
1523 | /** | 1558 | /** |
@@ -2020,7 +2055,7 @@ void locks_remove_flock(struct file *filp) | |||
2020 | fl.fl_ops->fl_release_private(&fl); | 2055 | fl.fl_ops->fl_release_private(&fl); |
2021 | } | 2056 | } |
2022 | 2057 | ||
2023 | lock_kernel(); | 2058 | lock_flocks(); |
2024 | before = &inode->i_flock; | 2059 | before = &inode->i_flock; |
2025 | 2060 | ||
2026 | while ((fl = *before) != NULL) { | 2061 | while ((fl = *before) != NULL) { |
@@ -2038,7 +2073,7 @@ void locks_remove_flock(struct file *filp) | |||
2038 | } | 2073 | } |
2039 | before = &fl->fl_next; | 2074 | before = &fl->fl_next; |
2040 | } | 2075 | } |
2041 | unlock_kernel(); | 2076 | unlock_flocks(); |
2042 | } | 2077 | } |
2043 | 2078 | ||
2044 | /** | 2079 | /** |
@@ -2053,12 +2088,12 @@ posix_unblock_lock(struct file *filp, struct file_lock *waiter) | |||
2053 | { | 2088 | { |
2054 | int status = 0; | 2089 | int status = 0; |
2055 | 2090 | ||
2056 | lock_kernel(); | 2091 | lock_flocks(); |
2057 | if (waiter->fl_next) | 2092 | if (waiter->fl_next) |
2058 | __locks_delete_block(waiter); | 2093 | __locks_delete_block(waiter); |
2059 | else | 2094 | else |
2060 | status = -ENOENT; | 2095 | status = -ENOENT; |
2061 | unlock_kernel(); | 2096 | unlock_flocks(); |
2062 | return status; | 2097 | return status; |
2063 | } | 2098 | } |
2064 | 2099 | ||
@@ -2085,7 +2120,7 @@ EXPORT_SYMBOL_GPL(vfs_cancel_lock); | |||
2085 | #include <linux/seq_file.h> | 2120 | #include <linux/seq_file.h> |
2086 | 2121 | ||
2087 | static void lock_get_status(struct seq_file *f, struct file_lock *fl, | 2122 | static void lock_get_status(struct seq_file *f, struct file_lock *fl, |
2088 | int id, char *pfx) | 2123 | loff_t id, char *pfx) |
2089 | { | 2124 | { |
2090 | struct inode *inode = NULL; | 2125 | struct inode *inode = NULL; |
2091 | unsigned int fl_pid; | 2126 | unsigned int fl_pid; |
@@ -2098,7 +2133,7 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl, | |||
2098 | if (fl->fl_file != NULL) | 2133 | if (fl->fl_file != NULL) |
2099 | inode = fl->fl_file->f_path.dentry->d_inode; | 2134 | inode = fl->fl_file->f_path.dentry->d_inode; |
2100 | 2135 | ||
2101 | seq_printf(f, "%d:%s ", id, pfx); | 2136 | seq_printf(f, "%lld:%s ", id, pfx); |
2102 | if (IS_POSIX(fl)) { | 2137 | if (IS_POSIX(fl)) { |
2103 | seq_printf(f, "%6s %s ", | 2138 | seq_printf(f, "%6s %s ", |
2104 | (fl->fl_flags & FL_ACCESS) ? "ACCESS" : "POSIX ", | 2139 | (fl->fl_flags & FL_ACCESS) ? "ACCESS" : "POSIX ", |
@@ -2161,30 +2196,33 @@ static int locks_show(struct seq_file *f, void *v) | |||
2161 | 2196 | ||
2162 | fl = list_entry(v, struct file_lock, fl_link); | 2197 | fl = list_entry(v, struct file_lock, fl_link); |
2163 | 2198 | ||
2164 | lock_get_status(f, fl, (long)f->private, ""); | 2199 | lock_get_status(f, fl, *((loff_t *)f->private), ""); |
2165 | 2200 | ||
2166 | list_for_each_entry(bfl, &fl->fl_block, fl_block) | 2201 | list_for_each_entry(bfl, &fl->fl_block, fl_block) |
2167 | lock_get_status(f, bfl, (long)f->private, " ->"); | 2202 | lock_get_status(f, bfl, *((loff_t *)f->private), " ->"); |
2168 | 2203 | ||
2169 | f->private++; | ||
2170 | return 0; | 2204 | return 0; |
2171 | } | 2205 | } |
2172 | 2206 | ||
2173 | static void *locks_start(struct seq_file *f, loff_t *pos) | 2207 | static void *locks_start(struct seq_file *f, loff_t *pos) |
2174 | { | 2208 | { |
2175 | lock_kernel(); | 2209 | loff_t *p = f->private; |
2176 | f->private = (void *)1; | 2210 | |
2211 | lock_flocks(); | ||
2212 | *p = (*pos + 1); | ||
2177 | return seq_list_start(&file_lock_list, *pos); | 2213 | return seq_list_start(&file_lock_list, *pos); |
2178 | } | 2214 | } |
2179 | 2215 | ||
2180 | static void *locks_next(struct seq_file *f, void *v, loff_t *pos) | 2216 | static void *locks_next(struct seq_file *f, void *v, loff_t *pos) |
2181 | { | 2217 | { |
2218 | loff_t *p = f->private; | ||
2219 | ++*p; | ||
2182 | return seq_list_next(v, &file_lock_list, pos); | 2220 | return seq_list_next(v, &file_lock_list, pos); |
2183 | } | 2221 | } |
2184 | 2222 | ||
2185 | static void locks_stop(struct seq_file *f, void *v) | 2223 | static void locks_stop(struct seq_file *f, void *v) |
2186 | { | 2224 | { |
2187 | unlock_kernel(); | 2225 | unlock_flocks(); |
2188 | } | 2226 | } |
2189 | 2227 | ||
2190 | static const struct seq_operations locks_seq_operations = { | 2228 | static const struct seq_operations locks_seq_operations = { |
@@ -2196,14 +2234,14 @@ static const struct seq_operations locks_seq_operations = { | |||
2196 | 2234 | ||
2197 | static int locks_open(struct inode *inode, struct file *filp) | 2235 | static int locks_open(struct inode *inode, struct file *filp) |
2198 | { | 2236 | { |
2199 | return seq_open(filp, &locks_seq_operations); | 2237 | return seq_open_private(filp, &locks_seq_operations, sizeof(loff_t)); |
2200 | } | 2238 | } |
2201 | 2239 | ||
2202 | static const struct file_operations proc_locks_operations = { | 2240 | static const struct file_operations proc_locks_operations = { |
2203 | .open = locks_open, | 2241 | .open = locks_open, |
2204 | .read = seq_read, | 2242 | .read = seq_read, |
2205 | .llseek = seq_lseek, | 2243 | .llseek = seq_lseek, |
2206 | .release = seq_release, | 2244 | .release = seq_release_private, |
2207 | }; | 2245 | }; |
2208 | 2246 | ||
2209 | static int __init proc_locks_init(void) | 2247 | static int __init proc_locks_init(void) |
@@ -2231,7 +2269,7 @@ int lock_may_read(struct inode *inode, loff_t start, unsigned long len) | |||
2231 | { | 2269 | { |
2232 | struct file_lock *fl; | 2270 | struct file_lock *fl; |
2233 | int result = 1; | 2271 | int result = 1; |
2234 | lock_kernel(); | 2272 | lock_flocks(); |
2235 | for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { | 2273 | for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { |
2236 | if (IS_POSIX(fl)) { | 2274 | if (IS_POSIX(fl)) { |
2237 | if (fl->fl_type == F_RDLCK) | 2275 | if (fl->fl_type == F_RDLCK) |
@@ -2248,7 +2286,7 @@ int lock_may_read(struct inode *inode, loff_t start, unsigned long len) | |||
2248 | result = 0; | 2286 | result = 0; |
2249 | break; | 2287 | break; |
2250 | } | 2288 | } |
2251 | unlock_kernel(); | 2289 | unlock_flocks(); |
2252 | return result; | 2290 | return result; |
2253 | } | 2291 | } |
2254 | 2292 | ||
@@ -2271,7 +2309,7 @@ int lock_may_write(struct inode *inode, loff_t start, unsigned long len) | |||
2271 | { | 2309 | { |
2272 | struct file_lock *fl; | 2310 | struct file_lock *fl; |
2273 | int result = 1; | 2311 | int result = 1; |
2274 | lock_kernel(); | 2312 | lock_flocks(); |
2275 | for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { | 2313 | for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { |
2276 | if (IS_POSIX(fl)) { | 2314 | if (IS_POSIX(fl)) { |
2277 | if ((fl->fl_end < start) || (fl->fl_start > (start + len))) | 2315 | if ((fl->fl_end < start) || (fl->fl_start > (start + len))) |
@@ -2286,7 +2324,7 @@ int lock_may_write(struct inode *inode, loff_t start, unsigned long len) | |||
2286 | result = 0; | 2324 | result = 0; |
2287 | break; | 2325 | break; |
2288 | } | 2326 | } |
2289 | unlock_kernel(); | 2327 | unlock_flocks(); |
2290 | return result; | 2328 | return result; |
2291 | } | 2329 | } |
2292 | 2330 | ||