aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd/vfs.c
diff options
context:
space:
mode:
authorJeff Layton <jlayton@redhat.com>2010-03-19 08:06:28 -0400
committerJ. Bruce Fields <bfields@citi.umich.edu>2010-03-22 15:37:53 -0400
commit91885258e8343bb65c08f668d7e6c16563eb4284 (patch)
tree3178dabadca5342d63cc1d20ea843539a180aa94 /fs/nfsd/vfs.c
parent61f8603d93fa0b0e2f73be7a4f048696417a24a3 (diff)
nfsd: don't break lease while servicing a COMMIT
This is the second attempt to fix the problem whereby a COMMIT call causes a lease break and triggers a possible deadlock. The problem is that nfsd attempts to break a lease on a COMMIT call. This triggers a delegation recall if the lease is held for a delegation. If the client is the one holding the delegation and it's the same one on which it's issuing the COMMIT, then it can't return that delegation until the COMMIT is complete. But, nfsd won't complete the COMMIT until the delegation is returned. The client and server are essentially deadlocked until the state is marked bad (due to the client not responding on the callback channel). The first patch attempted to deal with this by eliminating the open of the file altogether and simply had nfsd_commit pass a NULL file pointer to the vfs_fsync_range. That would conflict with some work in progress by Christoph Hellwig to clean up the fsync interface, so this patch takes a different approach. This declares a new NFSD_MAY_NOT_BREAK_LEASE access flag that indicates to nfsd_open that it should not break any leases when opening the file, and has nfsd_commit set that flag on the nfsd_open call. For now, this patch leaves nfsd_commit opening the file with write access since I'm not clear on what sort of access would be more appropriate. Signed-off-by: Jeff Layton <jlayton@redhat.com> Cc: stable@kernel.org Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Diffstat (limited to 'fs/nfsd/vfs.c')
-rw-r--r--fs/nfsd/vfs.c8
1 files changed, 5 insertions, 3 deletions
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index a11b0e8678ee..c2dcb4c2b1fc 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -723,7 +723,7 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
723 struct inode *inode; 723 struct inode *inode;
724 int flags = O_RDONLY|O_LARGEFILE; 724 int flags = O_RDONLY|O_LARGEFILE;
725 __be32 err; 725 __be32 err;
726 int host_err; 726 int host_err = 0;
727 727
728 validate_process_creds(); 728 validate_process_creds();
729 729
@@ -760,7 +760,8 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
760 * Check to see if there are any leases on this file. 760 * Check to see if there are any leases on this file.
761 * This may block while leases are broken. 761 * This may block while leases are broken.
762 */ 762 */
763 host_err = break_lease(inode, O_NONBLOCK | ((access & NFSD_MAY_WRITE) ? O_WRONLY : 0)); 763 if (!(access & NFSD_MAY_NOT_BREAK_LEASE))
764 host_err = break_lease(inode, O_NONBLOCK | ((access & NFSD_MAY_WRITE) ? O_WRONLY : 0));
764 if (host_err == -EWOULDBLOCK) 765 if (host_err == -EWOULDBLOCK)
765 host_err = -ETIMEDOUT; 766 host_err = -ETIMEDOUT;
766 if (host_err) /* NOMEM or WOULDBLOCK */ 767 if (host_err) /* NOMEM or WOULDBLOCK */
@@ -1168,7 +1169,8 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp,
1168 goto out; 1169 goto out;
1169 } 1170 }
1170 1171
1171 err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_WRITE, &file); 1172 err = nfsd_open(rqstp, fhp, S_IFREG,
1173 NFSD_MAY_WRITE|NFSD_MAY_NOT_BREAK_LEASE, &file);
1172 if (err) 1174 if (err)
1173 goto out; 1175 goto out;
1174 if (EX_ISSYNC(fhp->fh_export)) { 1176 if (EX_ISSYNC(fhp->fh_export)) {