| From 55ef1274dddd4de387c54d110e354ffbb6cdc706 Mon Sep 17 00:00:00 2001 |
| From: J. Bruce Fields <bfields@citi.umich.edu> |
| Date: Sat, 20 Dec 2008 11:58:38 -0800 |
| Subject: nfsd: Ensure nfsv4 calls the underlying filesystem on LOCKT |
| |
| From: J. Bruce Fields <bfields@citi.umich.edu> |
| |
| commit 55ef1274dddd4de387c54d110e354ffbb6cdc706 upstream. |
| |
| Since nfsv4 allows LOCKT without an open, but the ->lock() method is a |
| file method, we fake up a struct file in the nfsv4 code with just the |
| fields we need initialized. But we forgot to initialize the file |
| operations, with the result that LOCKT never results in a call to the |
| filesystem's ->lock() method (if it exists). |
| |
| We could just add that one more initialization. But this hack of faking |
| up a struct file with only some fields initialized seems the kind of |
| thing that might cause more problems in the future. We should either do |
| an open and get a real struct file, or make lock-testing an inode (not a |
| file) method. |
| |
| This patch does the former. |
| |
| Reported-by: Marc Eshel <eshel@almaden.ibm.com> |
| Tested-by: Marc Eshel <eshel@almaden.ibm.com> |
| Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| |
| --- |
| fs/nfsd/nfs4state.c | 30 ++++++++++++++++++++---------- |
| 1 file changed, 20 insertions(+), 10 deletions(-) |
| |
| --- a/fs/nfsd/nfs4state.c |
| +++ b/fs/nfsd/nfs4state.c |
| @@ -2767,6 +2767,25 @@ out: |
| } |
| |
| /* |
| + * The NFSv4 spec allows a client to do a LOCKT without holding an OPEN, |
| + * so we do a temporary open here just to get an open file to pass to |
| + * vfs_test_lock. (Arguably perhaps test_lock should be done with an |
| + * inode operation.) |
| + */ |
| +static int nfsd_test_lock(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file_lock *lock) |
| +{ |
| + struct file *file; |
| + int err; |
| + |
| + err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file); |
| + if (err) |
| + return err; |
| + err = vfs_test_lock(file, lock); |
| + nfsd_close(file); |
| + return err; |
| +} |
| + |
| +/* |
| * LOCKT operation |
| */ |
| __be32 |
| @@ -2774,7 +2793,6 @@ nfsd4_lockt(struct svc_rqst *rqstp, stru |
| struct nfsd4_lockt *lockt) |
| { |
| struct inode *inode; |
| - struct file file; |
| struct file_lock file_lock; |
| int error; |
| __be32 status; |
| @@ -2832,16 +2850,8 @@ nfsd4_lockt(struct svc_rqst *rqstp, stru |
| |
| nfs4_transform_lock_offset(&file_lock); |
| |
| - /* vfs_test_lock uses the struct file _only_ to resolve the inode. |
| - * since LOCKT doesn't require an OPEN, and therefore a struct |
| - * file may not exist, pass vfs_test_lock a struct file with |
| - * only the dentry:inode set. |
| - */ |
| - memset(&file, 0, sizeof (struct file)); |
| - file.f_path.dentry = cstate->current_fh.fh_dentry; |
| - |
| status = nfs_ok; |
| - error = vfs_test_lock(&file, &file_lock); |
| + error = nfsd_test_lock(rqstp, &cstate->current_fh, &file_lock); |
| if (error) { |
| status = nfserrno(error); |
| goto out; |