diff options
-rw-r--r-- | fs/locks.c | 92 | ||||
-rw-r--r-- | fs/nfsd/nfs4state.c | 6 | ||||
-rw-r--r-- | include/linux/fs.h | 1 |
3 files changed, 51 insertions, 48 deletions
diff --git a/fs/locks.c b/fs/locks.c index 4fa269b0bdef..a237ba632e8d 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
@@ -432,9 +432,27 @@ static void lease_break_callback(struct file_lock *fl) | |||
432 | kill_fasync(&fl->fl_fasync, SIGIO, POLL_MSG); | 432 | kill_fasync(&fl->fl_fasync, SIGIO, POLL_MSG); |
433 | } | 433 | } |
434 | 434 | ||
435 | static void | ||
436 | lease_setup(struct file_lock *fl, void **priv) | ||
437 | { | ||
438 | struct file *filp = fl->fl_file; | ||
439 | struct fasync_struct *fa = *priv; | ||
440 | |||
441 | /* | ||
442 | * fasync_insert_entry() returns the old entry if any. If there was no | ||
443 | * old entry, then it used "priv" and inserted it into the fasync list. | ||
444 | * Clear the pointer to indicate that it shouldn't be freed. | ||
445 | */ | ||
446 | if (!fasync_insert_entry(fa->fa_fd, filp, &fl->fl_fasync, fa)) | ||
447 | *priv = NULL; | ||
448 | |||
449 | __f_setown(filp, task_pid(current), PIDTYPE_PID, 0); | ||
450 | } | ||
451 | |||
435 | static const struct lock_manager_operations lease_manager_ops = { | 452 | static const struct lock_manager_operations lease_manager_ops = { |
436 | .lm_break = lease_break_callback, | 453 | .lm_break = lease_break_callback, |
437 | .lm_change = lease_modify, | 454 | .lm_change = lease_modify, |
455 | .lm_setup = lease_setup, | ||
438 | }; | 456 | }; |
439 | 457 | ||
440 | /* | 458 | /* |
@@ -1607,10 +1625,11 @@ generic_add_lease(struct file *filp, long arg, struct file_lock **flp, void **pr | |||
1607 | } | 1625 | } |
1608 | 1626 | ||
1609 | if (my_before != NULL) { | 1627 | if (my_before != NULL) { |
1628 | lease = *my_before; | ||
1610 | error = lease->fl_lmops->lm_change(my_before, arg); | 1629 | error = lease->fl_lmops->lm_change(my_before, arg); |
1611 | if (!error) | 1630 | if (error) |
1612 | *flp = *my_before; | 1631 | goto out; |
1613 | goto out; | 1632 | goto out_setup; |
1614 | } | 1633 | } |
1615 | 1634 | ||
1616 | error = -EINVAL; | 1635 | error = -EINVAL; |
@@ -1631,9 +1650,15 @@ generic_add_lease(struct file *filp, long arg, struct file_lock **flp, void **pr | |||
1631 | error = check_conflicting_open(dentry, arg); | 1650 | error = check_conflicting_open(dentry, arg); |
1632 | if (error) | 1651 | if (error) |
1633 | goto out_unlink; | 1652 | goto out_unlink; |
1653 | |||
1654 | out_setup: | ||
1655 | if (lease->fl_lmops->lm_setup) | ||
1656 | lease->fl_lmops->lm_setup(lease, priv); | ||
1634 | out: | 1657 | out: |
1635 | if (is_deleg) | 1658 | if (is_deleg) |
1636 | mutex_unlock(&inode->i_mutex); | 1659 | mutex_unlock(&inode->i_mutex); |
1660 | if (!error && !my_before) | ||
1661 | *flp = NULL; | ||
1637 | return error; | 1662 | return error; |
1638 | out_unlink: | 1663 | out_unlink: |
1639 | locks_unlink_lock(before); | 1664 | locks_unlink_lock(before); |
@@ -1661,10 +1686,11 @@ static int generic_delete_lease(struct file *filp) | |||
1661 | 1686 | ||
1662 | /** | 1687 | /** |
1663 | * generic_setlease - sets a lease on an open file | 1688 | * generic_setlease - sets a lease on an open file |
1664 | * @filp: file pointer | 1689 | * @filp: file pointer |
1665 | * @arg: type of lease to obtain | 1690 | * @arg: type of lease to obtain |
1666 | * @flp: input - file_lock to use, output - file_lock inserted | 1691 | * @flp: input - file_lock to use, output - file_lock inserted |
1667 | * @priv: private data for lm_setup | 1692 | * @priv: private data for lm_setup (may be NULL if lm_setup |
1693 | * doesn't require it) | ||
1668 | * | 1694 | * |
1669 | * The (input) flp->fl_lmops->lm_break function is required | 1695 | * The (input) flp->fl_lmops->lm_break function is required |
1670 | * by break_lease(). | 1696 | * by break_lease(). |
@@ -1704,29 +1730,23 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp, | |||
1704 | } | 1730 | } |
1705 | EXPORT_SYMBOL(generic_setlease); | 1731 | EXPORT_SYMBOL(generic_setlease); |
1706 | 1732 | ||
1707 | static int | ||
1708 | __vfs_setlease(struct file *filp, long arg, struct file_lock **lease, void **priv) | ||
1709 | { | ||
1710 | if (filp->f_op->setlease) | ||
1711 | return filp->f_op->setlease(filp, arg, lease, priv); | ||
1712 | else | ||
1713 | return generic_setlease(filp, arg, lease, priv); | ||
1714 | } | ||
1715 | |||
1716 | /** | 1733 | /** |
1717 | * vfs_setlease - sets a lease on an open file | 1734 | * vfs_setlease - sets a lease on an open file |
1718 | * @filp: file pointer | 1735 | * @filp: file pointer |
1719 | * @arg: type of lease to obtain | 1736 | * @arg: type of lease to obtain |
1720 | * @lease: file_lock to use when adding a lease | 1737 | * @lease: file_lock to use when adding a lease |
1721 | * @priv: private info for lm_setup when adding a lease | 1738 | * @priv: private info for lm_setup when adding a lease (may be |
1739 | * NULL if lm_setup doesn't require it) | ||
1722 | * | 1740 | * |
1723 | * Call this to establish a lease on the file. The "lease" argument is not | 1741 | * Call this to establish a lease on the file. The "lease" argument is not |
1724 | * used for F_UNLCK requests and may be NULL. For commands that set or alter | 1742 | * used for F_UNLCK requests and may be NULL. For commands that set or alter |
1725 | * an existing lease, the (*lease)->fl_lmops->lm_break operation must be set; | 1743 | * an existing lease, the (*lease)->fl_lmops->lm_break operation must be set; |
1726 | * if not, this function will return -ENOLCK (and generate a scary-looking | 1744 | * if not, this function will return -ENOLCK (and generate a scary-looking |
1727 | * stack trace). | 1745 | * stack trace). |
1746 | * | ||
1747 | * The "priv" pointer is passed directly to the lm_setup function as-is. It | ||
1748 | * may be NULL if the lm_setup operation doesn't require it. | ||
1728 | */ | 1749 | */ |
1729 | |||
1730 | int | 1750 | int |
1731 | vfs_setlease(struct file *filp, long arg, struct file_lock **lease, void **priv) | 1751 | vfs_setlease(struct file *filp, long arg, struct file_lock **lease, void **priv) |
1732 | { | 1752 | { |
@@ -1734,17 +1754,18 @@ vfs_setlease(struct file *filp, long arg, struct file_lock **lease, void **priv) | |||
1734 | int error; | 1754 | int error; |
1735 | 1755 | ||
1736 | spin_lock(&inode->i_lock); | 1756 | spin_lock(&inode->i_lock); |
1737 | error = __vfs_setlease(filp, arg, lease, priv); | 1757 | if (filp->f_op->setlease) |
1758 | error = filp->f_op->setlease(filp, arg, lease, priv); | ||
1759 | else | ||
1760 | error = generic_setlease(filp, arg, lease, priv); | ||
1738 | spin_unlock(&inode->i_lock); | 1761 | spin_unlock(&inode->i_lock); |
1739 | |||
1740 | return error; | 1762 | return error; |
1741 | } | 1763 | } |
1742 | EXPORT_SYMBOL_GPL(vfs_setlease); | 1764 | EXPORT_SYMBOL_GPL(vfs_setlease); |
1743 | 1765 | ||
1744 | static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg) | 1766 | static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg) |
1745 | { | 1767 | { |
1746 | struct file_lock *fl, *ret; | 1768 | struct file_lock *fl; |
1747 | struct inode *inode = file_inode(filp); | ||
1748 | struct fasync_struct *new; | 1769 | struct fasync_struct *new; |
1749 | int error; | 1770 | int error; |
1750 | 1771 | ||
@@ -1757,26 +1778,9 @@ static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg) | |||
1757 | locks_free_lock(fl); | 1778 | locks_free_lock(fl); |
1758 | return -ENOMEM; | 1779 | return -ENOMEM; |
1759 | } | 1780 | } |
1760 | ret = fl; | 1781 | new->fa_fd = fd; |
1761 | spin_lock(&inode->i_lock); | ||
1762 | error = __vfs_setlease(filp, arg, &ret, NULL); | ||
1763 | if (error) | ||
1764 | goto out_unlock; | ||
1765 | if (ret == fl) | ||
1766 | fl = NULL; | ||
1767 | 1782 | ||
1768 | /* | 1783 | error = vfs_setlease(filp, arg, &fl, (void **)&new); |
1769 | * fasync_insert_entry() returns the old entry if any. | ||
1770 | * If there was no old entry, then it used 'new' and | ||
1771 | * inserted it into the fasync list. Clear new so that | ||
1772 | * we don't release it here. | ||
1773 | */ | ||
1774 | if (!fasync_insert_entry(fd, filp, &ret->fl_fasync, new)) | ||
1775 | new = NULL; | ||
1776 | |||
1777 | __f_setown(filp, task_pid(current), PIDTYPE_PID, 0); | ||
1778 | out_unlock: | ||
1779 | spin_unlock(&inode->i_lock); | ||
1780 | if (fl) | 1784 | if (fl) |
1781 | locks_free_lock(fl); | 1785 | locks_free_lock(fl); |
1782 | if (new) | 1786 | if (new) |
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 7c803db2a027..5349528136e2 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -3793,12 +3793,10 @@ static int nfs4_setlease(struct nfs4_delegation *dp) | |||
3793 | fl->fl_file = filp; | 3793 | fl->fl_file = filp; |
3794 | ret = fl; | 3794 | ret = fl; |
3795 | status = vfs_setlease(filp, fl->fl_type, &fl, NULL); | 3795 | status = vfs_setlease(filp, fl->fl_type, &fl, NULL); |
3796 | if (status) { | 3796 | if (fl) |
3797 | locks_free_lock(fl); | 3797 | locks_free_lock(fl); |
3798 | if (status) | ||
3798 | goto out_fput; | 3799 | goto out_fput; |
3799 | } | ||
3800 | if (ret != fl) | ||
3801 | locks_free_lock(fl); | ||
3802 | spin_lock(&state_lock); | 3800 | spin_lock(&state_lock); |
3803 | spin_lock(&fp->fi_lock); | 3801 | spin_lock(&fp->fi_lock); |
3804 | /* Did the lease get broken before we took the lock? */ | 3802 | /* Did the lease get broken before we took the lock? */ |
diff --git a/include/linux/fs.h b/include/linux/fs.h index f1870eb67b02..9a6d56154dd5 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -874,6 +874,7 @@ struct lock_manager_operations { | |||
874 | int (*lm_grant)(struct file_lock *, int); | 874 | int (*lm_grant)(struct file_lock *, int); |
875 | void (*lm_break)(struct file_lock *); | 875 | void (*lm_break)(struct file_lock *); |
876 | int (*lm_change)(struct file_lock **, int); | 876 | int (*lm_change)(struct file_lock **, int); |
877 | void (*lm_setup)(struct file_lock *, void **); | ||
877 | }; | 878 | }; |
878 | 879 | ||
879 | struct lock_manager { | 880 | struct lock_manager { |