diff options
Diffstat (limited to 'fs/locks.c')
-rw-r--r-- | fs/locks.c | 114 |
1 files changed, 58 insertions, 56 deletions
diff --git a/fs/locks.c b/fs/locks.c index 431a8b871fce..310510637247 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
@@ -458,22 +458,20 @@ static int lease_init(struct file *filp, int type, struct file_lock *fl) | |||
458 | } | 458 | } |
459 | 459 | ||
460 | /* Allocate a file_lock initialised to this type of lease */ | 460 | /* Allocate a file_lock initialised to this type of lease */ |
461 | static int lease_alloc(struct file *filp, int type, struct file_lock **flp) | 461 | static struct file_lock *lease_alloc(struct file *filp, int type) |
462 | { | 462 | { |
463 | struct file_lock *fl = locks_alloc_lock(); | 463 | struct file_lock *fl = locks_alloc_lock(); |
464 | int error = -ENOMEM; | 464 | int error = -ENOMEM; |
465 | 465 | ||
466 | if (fl == NULL) | 466 | if (fl == NULL) |
467 | goto out; | 467 | return ERR_PTR(error); |
468 | 468 | ||
469 | error = lease_init(filp, type, fl); | 469 | error = lease_init(filp, type, fl); |
470 | if (error) { | 470 | if (error) { |
471 | locks_free_lock(fl); | 471 | locks_free_lock(fl); |
472 | fl = NULL; | 472 | return ERR_PTR(error); |
473 | } | 473 | } |
474 | out: | 474 | return fl; |
475 | *flp = fl; | ||
476 | return error; | ||
477 | } | 475 | } |
478 | 476 | ||
479 | /* Check if two locks overlap each other. | 477 | /* Check if two locks overlap each other. |
@@ -661,7 +659,7 @@ static int locks_block_on_timeout(struct file_lock *blocker, struct file_lock *w | |||
661 | return result; | 659 | return result; |
662 | } | 660 | } |
663 | 661 | ||
664 | int | 662 | void |
665 | posix_test_lock(struct file *filp, struct file_lock *fl) | 663 | posix_test_lock(struct file *filp, struct file_lock *fl) |
666 | { | 664 | { |
667 | struct file_lock *cfl; | 665 | struct file_lock *cfl; |
@@ -673,14 +671,12 @@ posix_test_lock(struct file *filp, struct file_lock *fl) | |||
673 | if (posix_locks_conflict(cfl, fl)) | 671 | if (posix_locks_conflict(cfl, fl)) |
674 | break; | 672 | break; |
675 | } | 673 | } |
676 | if (cfl) { | 674 | if (cfl) |
677 | __locks_copy_lock(fl, cfl); | 675 | __locks_copy_lock(fl, cfl); |
678 | unlock_kernel(); | 676 | else |
679 | return 1; | ||
680 | } else | ||
681 | fl->fl_type = F_UNLCK; | 677 | fl->fl_type = F_UNLCK; |
682 | unlock_kernel(); | 678 | unlock_kernel(); |
683 | return 0; | 679 | return; |
684 | } | 680 | } |
685 | 681 | ||
686 | EXPORT_SYMBOL(posix_test_lock); | 682 | EXPORT_SYMBOL(posix_test_lock); |
@@ -1169,9 +1165,9 @@ static void time_out_leases(struct inode *inode) | |||
1169 | * @inode: the inode of the file to return | 1165 | * @inode: the inode of the file to return |
1170 | * @mode: the open mode (read or write) | 1166 | * @mode: the open mode (read or write) |
1171 | * | 1167 | * |
1172 | * break_lease (inlined for speed) has checked there already | 1168 | * break_lease (inlined for speed) has checked there already is at least |
1173 | * is a lease on this file. Leases are broken on a call to open() | 1169 | * some kind of lock (maybe a lease) on this file. Leases are broken on |
1174 | * or truncate(). This function can sleep unless you | 1170 | * a call to open() or truncate(). This function can sleep unless you |
1175 | * specified %O_NONBLOCK to your open(). | 1171 | * specified %O_NONBLOCK to your open(). |
1176 | */ | 1172 | */ |
1177 | int __break_lease(struct inode *inode, unsigned int mode) | 1173 | int __break_lease(struct inode *inode, unsigned int mode) |
@@ -1179,12 +1175,10 @@ int __break_lease(struct inode *inode, unsigned int mode) | |||
1179 | int error = 0, future; | 1175 | int error = 0, future; |
1180 | struct file_lock *new_fl, *flock; | 1176 | struct file_lock *new_fl, *flock; |
1181 | struct file_lock *fl; | 1177 | struct file_lock *fl; |
1182 | int alloc_err; | ||
1183 | unsigned long break_time; | 1178 | unsigned long break_time; |
1184 | int i_have_this_lease = 0; | 1179 | int i_have_this_lease = 0; |
1185 | 1180 | ||
1186 | alloc_err = lease_alloc(NULL, mode & FMODE_WRITE ? F_WRLCK : F_RDLCK, | 1181 | new_fl = lease_alloc(NULL, mode & FMODE_WRITE ? F_WRLCK : F_RDLCK); |
1187 | &new_fl); | ||
1188 | 1182 | ||
1189 | lock_kernel(); | 1183 | lock_kernel(); |
1190 | 1184 | ||
@@ -1212,8 +1206,9 @@ int __break_lease(struct inode *inode, unsigned int mode) | |||
1212 | goto out; | 1206 | goto out; |
1213 | } | 1207 | } |
1214 | 1208 | ||
1215 | if (alloc_err && !i_have_this_lease && ((mode & O_NONBLOCK) == 0)) { | 1209 | if (IS_ERR(new_fl) && !i_have_this_lease |
1216 | error = alloc_err; | 1210 | && ((mode & O_NONBLOCK) == 0)) { |
1211 | error = PTR_ERR(new_fl); | ||
1217 | goto out; | 1212 | goto out; |
1218 | } | 1213 | } |
1219 | 1214 | ||
@@ -1260,7 +1255,7 @@ restart: | |||
1260 | 1255 | ||
1261 | out: | 1256 | out: |
1262 | unlock_kernel(); | 1257 | unlock_kernel(); |
1263 | if (!alloc_err) | 1258 | if (!IS_ERR(new_fl)) |
1264 | locks_free_lock(new_fl); | 1259 | locks_free_lock(new_fl); |
1265 | return error; | 1260 | return error; |
1266 | } | 1261 | } |
@@ -1329,7 +1324,7 @@ int fcntl_getlease(struct file *filp) | |||
1329 | } | 1324 | } |
1330 | 1325 | ||
1331 | /** | 1326 | /** |
1332 | * __setlease - sets a lease on an open file | 1327 | * setlease - sets a lease on an open file |
1333 | * @filp: file pointer | 1328 | * @filp: file pointer |
1334 | * @arg: type of lease to obtain | 1329 | * @arg: type of lease to obtain |
1335 | * @flp: input - file_lock to use, output - file_lock inserted | 1330 | * @flp: input - file_lock to use, output - file_lock inserted |
@@ -1339,18 +1334,24 @@ int fcntl_getlease(struct file *filp) | |||
1339 | * | 1334 | * |
1340 | * Called with kernel lock held. | 1335 | * Called with kernel lock held. |
1341 | */ | 1336 | */ |
1342 | static int __setlease(struct file *filp, long arg, struct file_lock **flp) | 1337 | int setlease(struct file *filp, long arg, struct file_lock **flp) |
1343 | { | 1338 | { |
1344 | struct file_lock *fl, **before, **my_before = NULL, *lease; | 1339 | struct file_lock *fl, **before, **my_before = NULL, *lease; |
1345 | struct dentry *dentry = filp->f_path.dentry; | 1340 | struct dentry *dentry = filp->f_path.dentry; |
1346 | struct inode *inode = dentry->d_inode; | 1341 | struct inode *inode = dentry->d_inode; |
1347 | int error, rdlease_count = 0, wrlease_count = 0; | 1342 | int error, rdlease_count = 0, wrlease_count = 0; |
1348 | 1343 | ||
1344 | if ((current->fsuid != inode->i_uid) && !capable(CAP_LEASE)) | ||
1345 | return -EACCES; | ||
1346 | if (!S_ISREG(inode->i_mode)) | ||
1347 | return -EINVAL; | ||
1348 | error = security_file_lock(filp, arg); | ||
1349 | if (error) | ||
1350 | return error; | ||
1351 | |||
1349 | time_out_leases(inode); | 1352 | time_out_leases(inode); |
1350 | 1353 | ||
1351 | error = -EINVAL; | 1354 | BUG_ON(!(*flp)->fl_lmops->fl_break); |
1352 | if (!flp || !(*flp) || !(*flp)->fl_lmops || !(*flp)->fl_lmops->fl_break) | ||
1353 | goto out; | ||
1354 | 1355 | ||
1355 | lease = *flp; | 1356 | lease = *flp; |
1356 | 1357 | ||
@@ -1418,39 +1419,49 @@ static int __setlease(struct file *filp, long arg, struct file_lock **flp) | |||
1418 | out: | 1419 | out: |
1419 | return error; | 1420 | return error; |
1420 | } | 1421 | } |
1422 | EXPORT_SYMBOL(setlease); | ||
1421 | 1423 | ||
1422 | /** | 1424 | /** |
1423 | * setlease - sets a lease on an open file | 1425 | * vfs_setlease - sets a lease on an open file |
1424 | * @filp: file pointer | 1426 | * @filp: file pointer |
1425 | * @arg: type of lease to obtain | 1427 | * @arg: type of lease to obtain |
1426 | * @lease: file_lock to use | 1428 | * @lease: file_lock to use |
1427 | * | 1429 | * |
1428 | * Call this to establish a lease on the file. | 1430 | * Call this to establish a lease on the file. |
1429 | * The fl_lmops fl_break function is required by break_lease | 1431 | * The (*lease)->fl_lmops->fl_break operation must be set; if not, |
1432 | * break_lease will oops! | ||
1433 | * | ||
1434 | * This will call the filesystem's setlease file method, if | ||
1435 | * defined. Note that there is no getlease method; instead, the | ||
1436 | * filesystem setlease method should call back to setlease() to | ||
1437 | * add a lease to the inode's lease list, where fcntl_getlease() can | ||
1438 | * find it. Since fcntl_getlease() only reports whether the current | ||
1439 | * task holds a lease, a cluster filesystem need only do this for | ||
1440 | * leases held by processes on this node. | ||
1441 | * | ||
1442 | * There is also no break_lease method; filesystems that | ||
1443 | * handle their own leases shoud break leases themselves from the | ||
1444 | * filesystem's open, create, and (on truncate) setattr methods. | ||
1445 | * | ||
1446 | * Warning: the only current setlease methods exist only to disable | ||
1447 | * leases in certain cases. More vfs changes may be required to | ||
1448 | * allow a full filesystem lease implementation. | ||
1430 | */ | 1449 | */ |
1431 | 1450 | ||
1432 | int setlease(struct file *filp, long arg, struct file_lock **lease) | 1451 | int vfs_setlease(struct file *filp, long arg, struct file_lock **lease) |
1433 | { | 1452 | { |
1434 | struct dentry *dentry = filp->f_path.dentry; | ||
1435 | struct inode *inode = dentry->d_inode; | ||
1436 | int error; | 1453 | int error; |
1437 | 1454 | ||
1438 | if ((current->fsuid != inode->i_uid) && !capable(CAP_LEASE)) | ||
1439 | return -EACCES; | ||
1440 | if (!S_ISREG(inode->i_mode)) | ||
1441 | return -EINVAL; | ||
1442 | error = security_file_lock(filp, arg); | ||
1443 | if (error) | ||
1444 | return error; | ||
1445 | |||
1446 | lock_kernel(); | 1455 | lock_kernel(); |
1447 | error = __setlease(filp, arg, lease); | 1456 | if (filp->f_op && filp->f_op->setlease) |
1457 | error = filp->f_op->setlease(filp, arg, lease); | ||
1458 | else | ||
1459 | error = setlease(filp, arg, lease); | ||
1448 | unlock_kernel(); | 1460 | unlock_kernel(); |
1449 | 1461 | ||
1450 | return error; | 1462 | return error; |
1451 | } | 1463 | } |
1452 | 1464 | EXPORT_SYMBOL_GPL(vfs_setlease); | |
1453 | EXPORT_SYMBOL(setlease); | ||
1454 | 1465 | ||
1455 | /** | 1466 | /** |
1456 | * fcntl_setlease - sets a lease on an open file | 1467 | * fcntl_setlease - sets a lease on an open file |
@@ -1469,14 +1480,6 @@ int fcntl_setlease(unsigned int fd, struct file *filp, long arg) | |||
1469 | struct inode *inode = dentry->d_inode; | 1480 | struct inode *inode = dentry->d_inode; |
1470 | int error; | 1481 | int error; |
1471 | 1482 | ||
1472 | if ((current->fsuid != inode->i_uid) && !capable(CAP_LEASE)) | ||
1473 | return -EACCES; | ||
1474 | if (!S_ISREG(inode->i_mode)) | ||
1475 | return -EINVAL; | ||
1476 | error = security_file_lock(filp, arg); | ||
1477 | if (error) | ||
1478 | return error; | ||
1479 | |||
1480 | locks_init_lock(&fl); | 1483 | locks_init_lock(&fl); |
1481 | error = lease_init(filp, arg, &fl); | 1484 | error = lease_init(filp, arg, &fl); |
1482 | if (error) | 1485 | if (error) |
@@ -1484,15 +1487,15 @@ int fcntl_setlease(unsigned int fd, struct file *filp, long arg) | |||
1484 | 1487 | ||
1485 | lock_kernel(); | 1488 | lock_kernel(); |
1486 | 1489 | ||
1487 | error = __setlease(filp, arg, &flp); | 1490 | error = vfs_setlease(filp, arg, &flp); |
1488 | if (error || arg == F_UNLCK) | 1491 | if (error || arg == F_UNLCK) |
1489 | goto out_unlock; | 1492 | goto out_unlock; |
1490 | 1493 | ||
1491 | error = fasync_helper(fd, filp, 1, &flp->fl_fasync); | 1494 | error = fasync_helper(fd, filp, 1, &flp->fl_fasync); |
1492 | if (error < 0) { | 1495 | if (error < 0) { |
1493 | /* remove lease just inserted by __setlease */ | 1496 | /* remove lease just inserted by setlease */ |
1494 | flp->fl_type = F_UNLCK | F_INPROGRESS; | 1497 | flp->fl_type = F_UNLCK | F_INPROGRESS; |
1495 | flp->fl_break_time = jiffies- 10; | 1498 | flp->fl_break_time = jiffies - 10; |
1496 | time_out_leases(inode); | 1499 | time_out_leases(inode); |
1497 | goto out_unlock; | 1500 | goto out_unlock; |
1498 | } | 1501 | } |
@@ -1597,8 +1600,7 @@ asmlinkage long sys_flock(unsigned int fd, unsigned int cmd) | |||
1597 | /** | 1600 | /** |
1598 | * vfs_test_lock - test file byte range lock | 1601 | * vfs_test_lock - test file byte range lock |
1599 | * @filp: The file to test lock for | 1602 | * @filp: The file to test lock for |
1600 | * @fl: The lock to test | 1603 | * @fl: The lock to test; also used to hold result |
1601 | * @conf: Place to return a copy of the conflicting lock, if found | ||
1602 | * | 1604 | * |
1603 | * Returns -ERRNO on failure. Indicates presence of conflicting lock by | 1605 | * Returns -ERRNO on failure. Indicates presence of conflicting lock by |
1604 | * setting conf->fl_type to something other than F_UNLCK. | 1606 | * setting conf->fl_type to something other than F_UNLCK. |
@@ -2274,7 +2276,7 @@ static int __init filelock_init(void) | |||
2274 | { | 2276 | { |
2275 | filelock_cache = kmem_cache_create("file_lock_cache", | 2277 | filelock_cache = kmem_cache_create("file_lock_cache", |
2276 | sizeof(struct file_lock), 0, SLAB_PANIC, | 2278 | sizeof(struct file_lock), 0, SLAB_PANIC, |
2277 | init_once, NULL); | 2279 | init_once); |
2278 | return 0; | 2280 | return 0; |
2279 | } | 2281 | } |
2280 | 2282 | ||