summaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
authorTrond Myklebust <trond.myklebust@hammerspace.com>2019-07-11 19:02:18 -0400
committerTrond Myklebust <trond.myklebust@hammerspace.com>2019-07-15 10:11:20 -0400
commit50c8000744463aa8534de0d739b50ed4f06f8275 (patch)
tree89f5d13630aa386fa91dc06b32bf2bfd66b19581 /fs/nfs
parent5b596830d9710e3554354f717dc56f8640841c82 (diff)
downloadlinux-0-day-50c8000744463aa8534de0d739b50ed4f06f8275.tar.gz
linux-0-day-50c8000744463aa8534de0d739b50ed4f06f8275.tar.xz
NFSv4: Validate the stateid before applying it to state recovery
If the stateid is the zero or invalid stateid, then it is pointless to attempt to use it for recovery. In that case, try to fall back to using the open state stateid, or just doing a general recovery of all state on a given inode. Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Diffstat (limited to 'fs/nfs')
-rw-r--r--fs/nfs/nfs4proc.c21
1 files changed, 19 insertions, 2 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index ab362636443d4..52de7245a2ee5 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -428,6 +428,22 @@ static int nfs4_delay(long *timeout, bool interruptible)
return nfs4_delay_killable(timeout);
}
+static const nfs4_stateid *
+nfs4_recoverable_stateid(const nfs4_stateid *stateid)
+{
+ if (!stateid)
+ return NULL;
+ switch (stateid->type) {
+ case NFS4_OPEN_STATEID_TYPE:
+ case NFS4_LOCK_STATEID_TYPE:
+ case NFS4_DELEGATION_STATEID_TYPE:
+ return stateid;
+ default:
+ break;
+ }
+ return NULL;
+}
+
/* This is the error handling routine for processes that are allowed
* to sleep.
*/
@@ -436,7 +452,7 @@ static int nfs4_do_handle_exception(struct nfs_server *server,
{
struct nfs_client *clp = server->nfs_client;
struct nfs4_state *state = exception->state;
- const nfs4_stateid *stateid = exception->stateid;
+ const nfs4_stateid *stateid;
struct inode *inode = exception->inode;
int ret = errorcode;
@@ -444,8 +460,9 @@ static int nfs4_do_handle_exception(struct nfs_server *server,
exception->recovering = 0;
exception->retry = 0;
+ stateid = nfs4_recoverable_stateid(exception->stateid);
if (stateid == NULL && state != NULL)
- stateid = &state->stateid;
+ stateid = nfs4_recoverable_stateid(&state->stateid);
switch(errorcode) {
case 0: