| From 3114ea7a24d3264c090556a2444fc6d2c06176d4 Mon Sep 17 00:00:00 2001 |
| From: Trond Myklebust <Trond.Myklebust@netapp.com> |
| Date: Wed, 7 Mar 2012 16:39:06 -0500 |
| Subject: NFSv4: Return the delegation if the server returns NFS4ERR_OPENMODE |
| |
| From: Trond Myklebust <Trond.Myklebust@netapp.com> |
| |
| commit 3114ea7a24d3264c090556a2444fc6d2c06176d4 upstream. |
| |
| If a setattr() fails because of an NFS4ERR_OPENMODE error, it is |
| probably due to us holding a read delegation. Ensure that the |
| recovery routines return that delegation in this case. |
| |
| Reported-by: Miklos Szeredi <miklos@szeredi.hu> |
| Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| fs/nfs/nfs4_fs.h | 1 + |
| fs/nfs/nfs4proc.c | 13 ++++++++++++- |
| 2 files changed, 13 insertions(+), 1 deletion(-) |
| |
| --- a/fs/nfs/nfs4_fs.h |
| +++ b/fs/nfs/nfs4_fs.h |
| @@ -191,6 +191,7 @@ struct nfs4_exception { |
| long timeout; |
| int retry; |
| struct nfs4_state *state; |
| + struct inode *inode; |
| }; |
| |
| struct nfs4_state_recovery_ops { |
| --- a/fs/nfs/nfs4proc.c |
| +++ b/fs/nfs/nfs4proc.c |
| @@ -257,18 +257,28 @@ static int nfs4_handle_exception(struct |
| { |
| struct nfs_client *clp = server->nfs_client; |
| struct nfs4_state *state = exception->state; |
| + struct inode *inode = exception->inode; |
| int ret = errorcode; |
| |
| exception->retry = 0; |
| switch(errorcode) { |
| case 0: |
| return 0; |
| + case -NFS4ERR_OPENMODE: |
| + if (nfs_have_delegation(inode, FMODE_READ)) { |
| + nfs_inode_return_delegation(inode); |
| + exception->retry = 1; |
| + return 0; |
| + } |
| + if (state == NULL) |
| + break; |
| + nfs4_schedule_stateid_recovery(server, state); |
| + goto wait_on_recovery; |
| case -NFS4ERR_DELEG_REVOKED: |
| case -NFS4ERR_ADMIN_REVOKED: |
| case -NFS4ERR_BAD_STATEID: |
| if (state != NULL) |
| nfs_remove_bad_delegation(state->inode); |
| - case -NFS4ERR_OPENMODE: |
| if (state == NULL) |
| break; |
| nfs4_schedule_stateid_recovery(server, state); |
| @@ -1901,6 +1911,7 @@ static int nfs4_do_setattr(struct inode |
| struct nfs_server *server = NFS_SERVER(inode); |
| struct nfs4_exception exception = { |
| .state = state, |
| + .inode = inode, |
| }; |
| int err; |
| do { |