diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2012-03-07 16:39:06 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-04-02 12:27:13 -0400 |
commit | 6e8768d198a2ea5f31dbd2fe679a62c605fcdbbd (patch) | |
tree | 4ce2349bbf32cb3d899bf613ead396f57dc72d7d | |
parent | 5353a89765846be06f238a00ce9b38de14f69281 (diff) |
NFSv4: Return the delegation if the server returns NFS4ERR_OPENMODE
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>
-rw-r--r-- | fs/nfs/nfs4_fs.h | 1 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 13 |
2 files changed, 13 insertions, 1 deletions
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 414ed1d27c9..e1c1365ba83 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
@@ -209,6 +209,7 @@ struct nfs4_exception { | |||
209 | long timeout; | 209 | long timeout; |
210 | int retry; | 210 | int retry; |
211 | struct nfs4_state *state; | 211 | struct nfs4_state *state; |
212 | struct inode *inode; | ||
212 | }; | 213 | }; |
213 | 214 | ||
214 | struct nfs4_state_recovery_ops { | 215 | struct nfs4_state_recovery_ops { |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index ae317fd9d24..301b0c95dcb 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -254,18 +254,28 @@ static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struc | |||
254 | { | 254 | { |
255 | struct nfs_client *clp = server->nfs_client; | 255 | struct nfs_client *clp = server->nfs_client; |
256 | struct nfs4_state *state = exception->state; | 256 | struct nfs4_state *state = exception->state; |
257 | struct inode *inode = exception->inode; | ||
257 | int ret = errorcode; | 258 | int ret = errorcode; |
258 | 259 | ||
259 | exception->retry = 0; | 260 | exception->retry = 0; |
260 | switch(errorcode) { | 261 | switch(errorcode) { |
261 | case 0: | 262 | case 0: |
262 | return 0; | 263 | return 0; |
264 | case -NFS4ERR_OPENMODE: | ||
265 | if (nfs_have_delegation(inode, FMODE_READ)) { | ||
266 | nfs_inode_return_delegation(inode); | ||
267 | exception->retry = 1; | ||
268 | return 0; | ||
269 | } | ||
270 | if (state == NULL) | ||
271 | break; | ||
272 | nfs4_schedule_stateid_recovery(server, state); | ||
273 | goto wait_on_recovery; | ||
263 | case -NFS4ERR_DELEG_REVOKED: | 274 | case -NFS4ERR_DELEG_REVOKED: |
264 | case -NFS4ERR_ADMIN_REVOKED: | 275 | case -NFS4ERR_ADMIN_REVOKED: |
265 | case -NFS4ERR_BAD_STATEID: | 276 | case -NFS4ERR_BAD_STATEID: |
266 | if (state != NULL) | 277 | if (state != NULL) |
267 | nfs_remove_bad_delegation(state->inode); | 278 | nfs_remove_bad_delegation(state->inode); |
268 | case -NFS4ERR_OPENMODE: | ||
269 | if (state == NULL) | 279 | if (state == NULL) |
270 | break; | 280 | break; |
271 | nfs4_schedule_stateid_recovery(server, state); | 281 | nfs4_schedule_stateid_recovery(server, state); |
@@ -1870,6 +1880,7 @@ static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, | |||
1870 | struct nfs_server *server = NFS_SERVER(inode); | 1880 | struct nfs_server *server = NFS_SERVER(inode); |
1871 | struct nfs4_exception exception = { | 1881 | struct nfs4_exception exception = { |
1872 | .state = state, | 1882 | .state = state, |
1883 | .inode = inode, | ||
1873 | }; | 1884 | }; |
1874 | int err; | 1885 | int err; |
1875 | do { | 1886 | do { |