diff options
Diffstat (limited to 'fs/locks.c')
-rw-r--r-- | fs/locks.c | 91 |
1 files changed, 52 insertions, 39 deletions
diff --git a/fs/locks.c b/fs/locks.c index 50ec15927aab..8729347bcd1a 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> |
@@ -186,7 +185,7 @@ void locks_release_private(struct file_lock *fl) | |||
186 | EXPORT_SYMBOL_GPL(locks_release_private); | 185 | EXPORT_SYMBOL_GPL(locks_release_private); |
187 | 186 | ||
188 | /* Free a lock which is not in use. */ | 187 | /* Free a lock which is not in use. */ |
189 | static void locks_free_lock(struct file_lock *fl) | 188 | void locks_free_lock(struct file_lock *fl) |
190 | { | 189 | { |
191 | BUG_ON(waitqueue_active(&fl->fl_wait)); | 190 | BUG_ON(waitqueue_active(&fl->fl_wait)); |
192 | BUG_ON(!list_empty(&fl->fl_block)); | 191 | BUG_ON(!list_empty(&fl->fl_block)); |
@@ -195,6 +194,7 @@ static void locks_free_lock(struct file_lock *fl) | |||
195 | locks_release_private(fl); | 194 | locks_release_private(fl); |
196 | kmem_cache_free(filelock_cache, fl); | 195 | kmem_cache_free(filelock_cache, fl); |
197 | } | 196 | } |
197 | EXPORT_SYMBOL(locks_free_lock); | ||
198 | 198 | ||
199 | void locks_init_lock(struct file_lock *fl) | 199 | void locks_init_lock(struct file_lock *fl) |
200 | { | 200 | { |
@@ -234,11 +234,8 @@ static void locks_copy_private(struct file_lock *new, struct file_lock *fl) | |||
234 | fl->fl_ops->fl_copy_lock(new, fl); | 234 | fl->fl_ops->fl_copy_lock(new, fl); |
235 | new->fl_ops = fl->fl_ops; | 235 | new->fl_ops = fl->fl_ops; |
236 | } | 236 | } |
237 | if (fl->fl_lmops) { | 237 | if (fl->fl_lmops) |
238 | if (fl->fl_lmops->fl_copy_lock) | ||
239 | fl->fl_lmops->fl_copy_lock(new, fl); | ||
240 | new->fl_lmops = fl->fl_lmops; | 238 | new->fl_lmops = fl->fl_lmops; |
241 | } | ||
242 | } | 239 | } |
243 | 240 | ||
244 | /* | 241 | /* |
@@ -1371,20 +1368,22 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp) | |||
1371 | struct inode *inode = dentry->d_inode; | 1368 | struct inode *inode = dentry->d_inode; |
1372 | int error, rdlease_count = 0, wrlease_count = 0; | 1369 | int error, rdlease_count = 0, wrlease_count = 0; |
1373 | 1370 | ||
1371 | lease = *flp; | ||
1372 | |||
1373 | error = -EACCES; | ||
1374 | if ((current_fsuid() != inode->i_uid) && !capable(CAP_LEASE)) | 1374 | if ((current_fsuid() != inode->i_uid) && !capable(CAP_LEASE)) |
1375 | return -EACCES; | 1375 | goto out; |
1376 | error = -EINVAL; | ||
1376 | if (!S_ISREG(inode->i_mode)) | 1377 | if (!S_ISREG(inode->i_mode)) |
1377 | return -EINVAL; | 1378 | goto out; |
1378 | error = security_file_lock(filp, arg); | 1379 | error = security_file_lock(filp, arg); |
1379 | if (error) | 1380 | if (error) |
1380 | return error; | 1381 | goto out; |
1381 | 1382 | ||
1382 | time_out_leases(inode); | 1383 | time_out_leases(inode); |
1383 | 1384 | ||
1384 | BUG_ON(!(*flp)->fl_lmops->fl_break); | 1385 | BUG_ON(!(*flp)->fl_lmops->fl_break); |
1385 | 1386 | ||
1386 | lease = *flp; | ||
1387 | |||
1388 | if (arg != F_UNLCK) { | 1387 | if (arg != F_UNLCK) { |
1389 | error = -EAGAIN; | 1388 | error = -EAGAIN; |
1390 | if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0)) | 1389 | if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0)) |
@@ -1425,8 +1424,9 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp) | |||
1425 | goto out; | 1424 | goto out; |
1426 | 1425 | ||
1427 | if (my_before != NULL) { | 1426 | if (my_before != NULL) { |
1428 | *flp = *my_before; | ||
1429 | error = lease->fl_lmops->fl_change(my_before, arg); | 1427 | error = lease->fl_lmops->fl_change(my_before, arg); |
1428 | if (!error) | ||
1429 | *flp = *my_before; | ||
1430 | goto out; | 1430 | goto out; |
1431 | } | 1431 | } |
1432 | 1432 | ||
@@ -1441,7 +1441,6 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp) | |||
1441 | return 0; | 1441 | return 0; |
1442 | 1442 | ||
1443 | out: | 1443 | out: |
1444 | locks_free_lock(lease); | ||
1445 | return error; | 1444 | return error; |
1446 | } | 1445 | } |
1447 | EXPORT_SYMBOL(generic_setlease); | 1446 | EXPORT_SYMBOL(generic_setlease); |
@@ -1493,21 +1492,19 @@ int vfs_setlease(struct file *filp, long arg, struct file_lock **lease) | |||
1493 | } | 1492 | } |
1494 | EXPORT_SYMBOL_GPL(vfs_setlease); | 1493 | EXPORT_SYMBOL_GPL(vfs_setlease); |
1495 | 1494 | ||
1496 | /** | 1495 | static int do_fcntl_delete_lease(struct file *filp) |
1497 | * fcntl_setlease - sets a lease on an open file | ||
1498 | * @fd: open file descriptor | ||
1499 | * @filp: file pointer | ||
1500 | * @arg: type of lease to obtain | ||
1501 | * | ||
1502 | * Call this fcntl to establish a lease on the file. | ||
1503 | * Note that you also need to call %F_SETSIG to | ||
1504 | * receive a signal when the lease is broken. | ||
1505 | */ | ||
1506 | int fcntl_setlease(unsigned int fd, struct file *filp, long arg) | ||
1507 | { | 1496 | { |
1508 | struct file_lock *fl; | 1497 | struct file_lock fl, *flp = &fl; |
1498 | |||
1499 | lease_init(filp, F_UNLCK, flp); | ||
1500 | |||
1501 | return vfs_setlease(filp, F_UNLCK, &flp); | ||
1502 | } | ||
1503 | |||
1504 | static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg) | ||
1505 | { | ||
1506 | struct file_lock *fl, *ret; | ||
1509 | struct fasync_struct *new; | 1507 | struct fasync_struct *new; |
1510 | struct inode *inode = filp->f_path.dentry->d_inode; | ||
1511 | int error; | 1508 | int error; |
1512 | 1509 | ||
1513 | fl = lease_alloc(filp, arg); | 1510 | fl = lease_alloc(filp, arg); |
@@ -1519,10 +1516,16 @@ int fcntl_setlease(unsigned int fd, struct file *filp, long arg) | |||
1519 | locks_free_lock(fl); | 1516 | locks_free_lock(fl); |
1520 | return -ENOMEM; | 1517 | return -ENOMEM; |
1521 | } | 1518 | } |
1519 | ret = fl; | ||
1522 | lock_flocks(); | 1520 | lock_flocks(); |
1523 | error = __vfs_setlease(filp, arg, &fl); | 1521 | error = __vfs_setlease(filp, arg, &ret); |
1524 | if (error || arg == F_UNLCK) | 1522 | if (error) { |
1525 | goto out_unlock; | 1523 | unlock_flocks(); |
1524 | locks_free_lock(fl); | ||
1525 | goto out_free_fasync; | ||
1526 | } | ||
1527 | if (ret != fl) | ||
1528 | locks_free_lock(fl); | ||
1526 | 1529 | ||
1527 | /* | 1530 | /* |
1528 | * fasync_insert_entry() returns the old entry if any. | 1531 | * fasync_insert_entry() returns the old entry if any. |
@@ -1530,26 +1533,36 @@ int fcntl_setlease(unsigned int fd, struct file *filp, long arg) | |||
1530 | * inserted it into the fasync list. Clear new so that | 1533 | * inserted it into the fasync list. Clear new so that |
1531 | * we don't release it here. | 1534 | * we don't release it here. |
1532 | */ | 1535 | */ |
1533 | if (!fasync_insert_entry(fd, filp, &fl->fl_fasync, new)) | 1536 | if (!fasync_insert_entry(fd, filp, &ret->fl_fasync, new)) |
1534 | new = NULL; | 1537 | new = NULL; |
1535 | 1538 | ||
1536 | if (error < 0) { | ||
1537 | /* remove lease just inserted by setlease */ | ||
1538 | fl->fl_type = F_UNLCK | F_INPROGRESS; | ||
1539 | fl->fl_break_time = jiffies - 10; | ||
1540 | time_out_leases(inode); | ||
1541 | goto out_unlock; | ||
1542 | } | ||
1543 | |||
1544 | error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0); | 1539 | error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0); |
1545 | out_unlock: | ||
1546 | unlock_flocks(); | 1540 | unlock_flocks(); |
1541 | |||
1542 | out_free_fasync: | ||
1547 | if (new) | 1543 | if (new) |
1548 | fasync_free(new); | 1544 | fasync_free(new); |
1549 | return error; | 1545 | return error; |
1550 | } | 1546 | } |
1551 | 1547 | ||
1552 | /** | 1548 | /** |
1549 | * fcntl_setlease - sets a lease on an open file | ||
1550 | * @fd: open file descriptor | ||
1551 | * @filp: file pointer | ||
1552 | * @arg: type of lease to obtain | ||
1553 | * | ||
1554 | * Call this fcntl to establish a lease on the file. | ||
1555 | * Note that you also need to call %F_SETSIG to | ||
1556 | * receive a signal when the lease is broken. | ||
1557 | */ | ||
1558 | int fcntl_setlease(unsigned int fd, struct file *filp, long arg) | ||
1559 | { | ||
1560 | if (arg == F_UNLCK) | ||
1561 | return do_fcntl_delete_lease(filp); | ||
1562 | return do_fcntl_add_lease(fd, filp, arg); | ||
1563 | } | ||
1564 | |||
1565 | /** | ||
1553 | * flock_lock_file_wait - Apply a FLOCK-style lock to a file | 1566 | * flock_lock_file_wait - Apply a FLOCK-style lock to a file |
1554 | * @filp: The file to apply the lock to | 1567 | * @filp: The file to apply the lock to |
1555 | * @fl: The lock to be applied | 1568 | * @fl: The lock to be applied |