Commit 0ceaf6c700f8245946a163e387add8675a0c302f
Committed by
Linus Torvalds
1 parent
0d07025eff
Exists in
master
and in
20 other branches
locks: prevent ENOMEM on lease unlock
Removing a lock shouldn't require any allocations; a failure due to ENOMEM leaves the caller with a choice between retrying or giving up and leaking an unused lease. Next we should split the other lease calls into add and delete cases. I wanted to start with just the bugfix. Signed-off-by: J. Bruce Fields <bfields@redhat.com> Acked-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Showing 1 changed file with 30 additions and 13 deletions Side-by-side Diff
fs/locks.c
... | ... | @@ -1441,7 +1441,8 @@ |
1441 | 1441 | return 0; |
1442 | 1442 | |
1443 | 1443 | out: |
1444 | - locks_free_lock(lease); | |
1444 | + if (arg != F_UNLCK) | |
1445 | + locks_free_lock(lease); | |
1445 | 1446 | return error; |
1446 | 1447 | } |
1447 | 1448 | EXPORT_SYMBOL(generic_setlease); |
1448 | 1449 | |
... | ... | @@ -1493,18 +1494,17 @@ |
1493 | 1494 | } |
1494 | 1495 | EXPORT_SYMBOL_GPL(vfs_setlease); |
1495 | 1496 | |
1496 | -/** | |
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) | |
1497 | +static int do_fcntl_delete_lease(struct file *filp) | |
1507 | 1498 | { |
1499 | + struct file_lock fl, *flp = &fl; | |
1500 | + | |
1501 | + lease_init(filp, F_UNLCK, flp); | |
1502 | + | |
1503 | + return vfs_setlease(filp, F_UNLCK, &flp); | |
1504 | +} | |
1505 | + | |
1506 | +static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg) | |
1507 | +{ | |
1508 | 1508 | struct file_lock *fl; |
1509 | 1509 | struct fasync_struct *new; |
1510 | 1510 | struct inode *inode = filp->f_path.dentry->d_inode; |
... | ... | @@ -1521,7 +1521,7 @@ |
1521 | 1521 | } |
1522 | 1522 | lock_flocks(); |
1523 | 1523 | error = __vfs_setlease(filp, arg, &fl); |
1524 | - if (error || arg == F_UNLCK) | |
1524 | + if (error) | |
1525 | 1525 | goto out_unlock; |
1526 | 1526 | |
1527 | 1527 | /* |
... | ... | @@ -1547,6 +1547,23 @@ |
1547 | 1547 | if (new) |
1548 | 1548 | fasync_free(new); |
1549 | 1549 | return error; |
1550 | +} | |
1551 | + | |
1552 | +/** | |
1553 | + * fcntl_setlease - sets a lease on an open file | |
1554 | + * @fd: open file descriptor | |
1555 | + * @filp: file pointer | |
1556 | + * @arg: type of lease to obtain | |
1557 | + * | |
1558 | + * Call this fcntl to establish a lease on the file. | |
1559 | + * Note that you also need to call %F_SETSIG to | |
1560 | + * receive a signal when the lease is broken. | |
1561 | + */ | |
1562 | +int fcntl_setlease(unsigned int fd, struct file *filp, long arg) | |
1563 | +{ | |
1564 | + if (arg == F_UNLCK) | |
1565 | + return do_fcntl_delete_lease(filp); | |
1566 | + return do_fcntl_add_lease(fd, filp, arg); | |
1550 | 1567 | } |
1551 | 1568 | |
1552 | 1569 | /** |