summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/nfsd/nfssvc.c23
1 files changed, 17 insertions, 6 deletions
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index b8e8d80e984c..a8ea4dbfa56b 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -966,6 +966,20 @@ nfsd(void *vrqstp)
return 0;
}
+/*
+ * Set rq_status_counter back to an even value, indicating that the rqstp
+ * fields are no longer meaningful to a lockless reader. This pairs with the
+ * odd-valued store made once the request has been decoded, and must run on
+ * every return path that follows it so that the seq-lock like protocol used
+ * by nfsd_nl_rpc_status_get_dumpit() is not left permanently odd. The store
+ * also advances the counter so a concurrent reader detects the transition.
+ */
+static void nfsd_status_counter_set_idle(struct svc_rqst *rqstp)
+{
+ smp_store_release(&rqstp->rq_status_counter,
+ (rqstp->rq_status_counter | 1) + 1);
+}
+
/**
* nfsd_dispatch - Process an NFS or NFSACL or LOCALIO Request
* @rqstp: incoming request
@@ -1028,14 +1042,9 @@ int nfsd_dispatch(struct svc_rqst *rqstp)
if (!proc->pc_encode(rqstp, &rqstp->rq_res_stream))
goto out_encode_err;
- /*
- * Release rq_status_counter setting it to an even value after the rpc
- * request has been properly processed.
- */
- smp_store_release(&rqstp->rq_status_counter, rqstp->rq_status_counter + 1);
-
nfsd_cache_update(rqstp, rp, ntli->ntli_cachetype, nfs_reply);
out_cached_reply:
+ nfsd_status_counter_set_idle(rqstp);
return 1;
out_decode_err:
@@ -1046,12 +1055,14 @@ out_decode_err:
out_update_drop:
nfsd_cache_update(rqstp, rp, RC_NOCACHE, NULL);
out_dropit:
+ nfsd_status_counter_set_idle(rqstp);
return 0;
out_encode_err:
trace_nfsd_cant_encode_err(rqstp);
nfsd_cache_update(rqstp, rp, RC_NOCACHE, NULL);
*statp = rpc_system_err;
+ nfsd_status_counter_set_idle(rqstp);
return 1;
}