Now that we have a saner internal API for managing leases, we no longer need to mandate that the inode->i_lock be held over most of the lease code. Push it down into generic_add_lease and generic_delete_lease. With this change ->setlease calls can now block, which is a necessary (but not sufficient!) step toward allowing leases to work with distributed filesystems. Signed-off-by: Jeff Layton <jlayton@xxxxxxxxxxxxxxx> --- fs/locks.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/fs/locks.c b/fs/locks.c index b35b706c05fe..49210d5cbf41 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -1335,6 +1335,8 @@ static void time_out_leases(struct inode *inode) struct file_lock **before; struct file_lock *fl; + lockdep_assert_held(&inode->i_lock); + before = &inode->i_flock; while ((fl = *before) && IS_LEASE(fl) && lease_breaking(fl)) { trace_time_out_leases(inode, fl); @@ -1595,6 +1597,9 @@ generic_add_lease(struct file *filp, long arg, struct file_lock **flp, void **au return -EINVAL; } + spin_lock(&inode->i_lock); + time_out_leases(inode); + error = check_conflicting_open(dentry, arg); if (error) goto out; @@ -1660,6 +1665,7 @@ out_setup: if (lease->fl_lmops->lm_setup) lease->fl_lmops->lm_setup(lease, aux); out: + spin_unlock(&inode->i_lock); if (is_deleg) mutex_unlock(&inode->i_mutex); if (!error && !my_before) @@ -1672,18 +1678,22 @@ out_unlink: static int generic_delete_lease(struct file *filp) { + int error = -EAGAIN; struct file_lock *fl, **before; struct dentry *dentry = filp->f_path.dentry; struct inode *inode = dentry->d_inode; + spin_lock(&inode->i_lock); + time_out_leases(inode); for (before = &inode->i_flock; ((fl = *before) != NULL) && IS_LEASE(fl); before = &fl->fl_next) { if (fl->fl_file != filp) continue; - return fl->fl_lmops->lm_change(before, F_UNLCK); + error = fl->fl_lmops->lm_change(before, F_UNLCK); } - return -EAGAIN; + spin_unlock(&inode->i_lock); + return error; } /** @@ -1702,8 +1712,7 @@ static int generic_delete_lease(struct file *filp) int generic_setlease(struct file *filp, long arg, struct file_lock **flp, void **aux) { - struct dentry *dentry = filp->f_path.dentry; - struct inode *inode = dentry->d_inode; + struct inode *inode = file_inode(filp); int error; if ((!uid_eq(current_fsuid(), inode->i_uid)) && !capable(CAP_LEASE)) @@ -1714,8 +1723,6 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp, if (error) return error; - time_out_leases(inode); - switch (arg) { case F_UNLCK: return generic_delete_lease(filp); @@ -1759,16 +1766,10 @@ EXPORT_SYMBOL(generic_setlease); int vfs_setlease(struct file *filp, long arg, struct file_lock **lease, void **aux) { - struct inode *inode = file_inode(filp); - int error; - - spin_lock(&inode->i_lock); if (filp->f_op->setlease) - error = filp->f_op->setlease(filp, arg, lease, aux); + return filp->f_op->setlease(filp, arg, lease, aux); else - error = generic_setlease(filp, arg, lease, aux); - spin_unlock(&inode->i_lock); - return error; + return generic_setlease(filp, arg, lease, aux); } EXPORT_SYMBOL_GPL(vfs_setlease); -- 1.9.3 -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html