From 05fa3135fdc7b9b510b502a35b6b97d2b38c6f48 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Sat, 30 Oct 2010 17:31:15 -0400 Subject: locks: fix setlease methods to free passed-in lock We modified setlease to require the caller to allocate the new lease in the case of creating a new lease, but forgot to fix up the filesystem methods. Cc: Steven Whitehouse Cc: Steve French Cc: Trond Myklebust Signed-off-by: J. Bruce Fields Acked-by: Arnd Bergmann Signed-off-by: Linus Torvalds --- fs/nfs/file.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'fs/nfs/file.c') diff --git a/fs/nfs/file.c b/fs/nfs/file.c index e756075637b..1e524fb73ba 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -884,6 +884,7 @@ static int nfs_setlease(struct file *file, long arg, struct file_lock **fl) dprintk("NFS: setlease(%s/%s, arg=%ld)\n", file->f_path.dentry->d_parent->d_name.name, file->f_path.dentry->d_name.name, arg); - + if (arg != F_UNLCK) + locks_free_lock(*fl); return -EINVAL; } -- cgit v1.2.3-70-g09d2 From 51ee4b84f5c86935b438d6636f34b523edb415a8 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 31 Oct 2010 08:35:10 -0400 Subject: locks: let the caller free file_lock on ->setlease failure The caller allocated it, the caller should free it. The only issue so far is that we could change the flp pointer even on an error return if the fl_change callback failed. But we can simply move the flp assignment after the fl_change invocation, as the callers don't care about the flp return value if the setlease call failed. Signed-off-by: Christoph Hellwig Signed-off-by: Linus Torvalds --- fs/cifs/cifsfs.c | 5 +---- fs/gfs2/file.c | 2 -- fs/locks.c | 20 +++++++++++--------- fs/nfs/file.c | 2 -- fs/nfsd/nfs4state.c | 1 + 5 files changed, 13 insertions(+), 17 deletions(-) (limited to 'fs/nfs/file.c') diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 54745b6c3db..75c4eaa7958 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -625,11 +625,8 @@ static int cifs_setlease(struct file *file, long arg, struct file_lock **lease) knows that the file won't be changed on the server by anyone else */ return generic_setlease(file, arg, lease); - else { - if (arg != F_UNLCK) - locks_free_lock(*lease); + else return -EAGAIN; - } } struct file_system_type cifs_fs_type = { diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c index ac943c1307b..aa996471ec5 100644 --- a/fs/gfs2/file.c +++ b/fs/gfs2/file.c @@ -629,8 +629,6 @@ static ssize_t gfs2_file_aio_write(struct kiocb *iocb, const struct iovec *iov, static int gfs2_setlease(struct file *file, long arg, struct file_lock **fl) { - if (arg != F_UNLCK) - locks_free_lock(*fl); return -EINVAL; } diff --git a/fs/locks.c b/fs/locks.c index 5b526a97788..a2ab790471b 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -1428,8 +1428,9 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp) goto out; if (my_before != NULL) { - *flp = *my_before; error = lease->fl_lmops->fl_change(my_before, arg); + if (!error) + *flp = *my_before; goto out; } @@ -1444,8 +1445,6 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp) return 0; out: - if (arg != F_UNLCK) - locks_free_lock(lease); return error; } EXPORT_SYMBOL(generic_setlease); @@ -1524,8 +1523,11 @@ static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg) } lock_flocks(); error = __vfs_setlease(filp, arg, &fl); - if (error) - goto out_unlock; + if (error) { + unlock_flocks(); + locks_free_lock(fl); + goto out_free_fasync; + } /* * fasync_insert_entry() returns the old entry if any. @@ -1541,12 +1543,12 @@ static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg) fl->fl_type = F_UNLCK | F_INPROGRESS; fl->fl_break_time = jiffies - 10; time_out_leases(inode); - goto out_unlock; + } else { + error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0); } - - error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0); -out_unlock: unlock_flocks(); + +out_free_fasync: if (new) fasync_free(new); return error; diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 1e524fb73ba..60677f9f131 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -884,7 +884,5 @@ static int nfs_setlease(struct file *file, long arg, struct file_lock **fl) dprintk("NFS: setlease(%s/%s, arg=%ld)\n", file->f_path.dentry->d_parent->d_name.name, file->f_path.dentry->d_name.name, arg); - if (arg != F_UNLCK) - locks_free_lock(*fl); return -EINVAL; } diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index b7f818b0580..f1e5ec6b510 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -2652,6 +2652,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta if ((status = vfs_setlease(fl->fl_file, fl->fl_type, &fl))) { dprintk("NFSD: setlease failed [%d], no delegation\n", status); dp->dl_flock = NULL; + locks_free_lock(fl); unhash_delegation(dp); flag = NFS4_OPEN_DELEGATE_NONE; goto out; -- cgit v1.2.3-70-g09d2 From 21ac19d484a8ffb66f64487846c8d53afef04d2b Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Sun, 28 Nov 2010 21:04:05 +0000 Subject: NFS: Fix fcntl F_GETLK not reporting some conflicts The commit 129a84de2347002f09721cda3155ccfd19fade40 (locks: fix F_GETLK regression (failure to find conflicts)) fixed the posix_test_lock() function by itself, however, its usage in NFS changed by the commit 9d6a8c5c213e34c475e72b245a8eb709258e968c (locks: give posix_test_lock same interface as ->lock) remained broken - subsequent NFS-specific locking code received F_UNLCK instead of the user-specified lock type. To fix the problem, fl->fl_type needs to be saved before the posix_test_lock() call and restored if no local conflicts were reported. Reference: https://bugzilla.kernel.org/show_bug.cgi?id=23892 Tested-by: Alexander Morozov Signed-off-by: Sergey Vlasov Cc: Signed-off-by: Trond Myklebust --- fs/nfs/file.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'fs/nfs/file.c') diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 60677f9f131..7bf029ef408 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -693,6 +693,7 @@ do_getlk(struct file *filp, int cmd, struct file_lock *fl, int is_local) { struct inode *inode = filp->f_mapping->host; int status = 0; + unsigned int saved_type = fl->fl_type; /* Try local locking first */ posix_test_lock(filp, fl); @@ -700,6 +701,7 @@ do_getlk(struct file *filp, int cmd, struct file_lock *fl, int is_local) /* found a conflict */ goto out; } + fl->fl_type = saved_type; if (nfs_have_delegation(inode, FMODE_READ)) goto out_noconflict; -- cgit v1.2.3-70-g09d2