aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Layton <jlayton@primarydata.com>2014-08-22 10:55:47 -0400
committerJeff Layton <jlayton@primarydata.com>2014-10-07 14:06:12 -0400
commit1c7dd2ff430fa14b45c9def54468e3a25ab8342b (patch)
treea80695c6ca57be5da96c63b67d1264507bfe509e
parente6f5c78930e409f3a6b37f5484313a416359ac7f (diff)
locks: define a lm_setup handler for leases
...and move the fasync setup into it for fcntl lease calls. At the same time, change the semantics of how the file_lock double-pointer is handled. Up until now, on a successful lease return you got a pointer to the lock on the list. This is bad, since that pointer can no longer be relied on as valid once the inode->i_lock has been released. Change the code to instead just zero out the pointer if the lease we passed in ended up being used. Then the callers can just check to see if it's NULL after the call and free it if it isn't. The priv argument has the same semantics. The lm_setup function can zero the pointer out to signal to the caller that it should not be freed after the function returns. Signed-off-by: Jeff Layton <jlayton@primarydata.com> Reviewed-by: Christoph Hellwig <hch@lst.de>
-rw-r--r--fs/locks.c92
-rw-r--r--fs/nfsd/nfs4state.c6
-rw-r--r--include/linux/fs.h1
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
435static void
436lease_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
435static const struct lock_manager_operations lease_manager_ops = { 452static 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
1654out_setup:
1655 if (lease->fl_lmops->lm_setup)
1656 lease->fl_lmops->lm_setup(lease, priv);
1634out: 1657out:
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;
1638out_unlink: 1663out_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}
1705EXPORT_SYMBOL(generic_setlease); 1731EXPORT_SYMBOL(generic_setlease);
1706 1732
1707static 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
1730int 1750int
1731vfs_setlease(struct file *filp, long arg, struct file_lock **lease, void **priv) 1751vfs_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}
1742EXPORT_SYMBOL_GPL(vfs_setlease); 1764EXPORT_SYMBOL_GPL(vfs_setlease);
1743 1765
1744static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg) 1766static 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);
1778out_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
879struct lock_manager { 880struct lock_manager {