[PATCH 3/3] NFSD deferral processing

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Andy Adamson <andros@xxxxxxxxxx>

Use a slab cache for nfsd4_compound_state allocation

Save the struct nfsd4_compound_state and set the save_state callback for
each request for potential deferral handling.

If an NFSv4 operation causes a deferral, the save_state callback is called
by svc_defer which saves the defer_data with the deferral, and sets the
restore_state deferral callback.

fh_put is called so that the deferral is not referencing the file handles,
allowing umount of the file system.

Signed-off-by: Andy Adamson<andros@xxxxxxxxxx>
---
 fs/nfsd/nfs4proc.c        |   45 ++++++++++++++++++---------------------------
 fs/nfsd/nfs4state.c       |   37 +++++++++++++++++++++++++++++++++++++
 include/linux/nfsd/xdr4.h |    6 ++++++
 3 files changed, 61 insertions(+), 27 deletions(-)

diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 97f2d25..c556e77 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -813,29 +813,6 @@ static inline void nfsd4_increment_op_stats(u32 opnum)
 		nfsdstats.nfs4_opcount[opnum]++;
 }
 
-static void cstate_free(struct nfsd4_compound_state *cstate)
-{
-	if (cstate == NULL)
-		return;
-	fh_put(&cstate->current_fh);
-	fh_put(&cstate->save_fh);
-	BUG_ON(cstate->replay_owner);
-	kfree(cstate);
-}
-
-static struct nfsd4_compound_state *cstate_alloc(void)
-{
-	struct nfsd4_compound_state *cstate;
-
-	cstate = kmalloc(sizeof(struct nfsd4_compound_state), GFP_KERNEL);
-	if (cstate == NULL)
-		return NULL;
-	fh_init(&cstate->current_fh, NFS4_FHSIZE);
-	fh_init(&cstate->save_fh, NFS4_FHSIZE);
-	cstate->replay_owner = NULL;
-	return cstate;
-}
-
 /*
  * RPC deferral callbacks
  */
@@ -925,8 +902,7 @@ nfsd4_return_deferred_respages(struct svc_deferred_req *dreq)
 static void
 nfsd4_release_deferred_state(struct svc_deferred_req *dreq)
 {
-	nfsd4_return_deferred_respages(dreq);
-	cstate_free(dreq->defer_data);
+	nfsd4_cstate_free(dreq->defer_data, dreq);
 }
 
 static void
@@ -1015,12 +991,23 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
 		goto out;
 
 	status = nfserr_resource;
-	cstate = cstate_alloc();
+	cstate = nfsd4_cstate_alloc(rqstp);
 	if (cstate == NULL)
 		goto out;
 
+	if (rqstp->rq_deferred && rqstp->rq_deferred->defer_data) {
+		resp->opcnt = cstate->last_op_cnt;
+		resp->p = cstate->last_op_p;
+		fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_NOP);
+		fh_verify(rqstp, &cstate->save_fh, 0, NFSD_MAY_NOP);
+	}
+	/* Reset to NULL in svc_process */
+	rqstp->rq_defer_data = cstate;
+	rqstp->rq_save_state = nfsd4_save_deferred_state;
+
 	status = nfs_ok;
 	while (!status && resp->opcnt < args->opcnt) {
+		cstate->last_op_p = resp->p;
 		op = &args->ops[resp->opcnt++];
 
 		dprintk("nfsv4 compound op #%d/%d: %d (%s)\n",
@@ -1085,8 +1072,12 @@ encode_op:
 
 		nfsd4_increment_op_stats(op->opnum);
 	}
+	if (status == nfserr_dropit) {
+		cstate->last_op_cnt = resp->opcnt - 1;
+		return status;
+	}
 
-	cstate_free(cstate);
+	nfsd4_cstate_free(cstate, rqstp->rq_deferred);
 out:
 	nfsd4_release_compoundargs(args);
 	dprintk("nfsv4 compound returned %d\n", ntohl(status));
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 0cc7ff5..6ab67fc 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -90,6 +90,7 @@ static struct kmem_cache *stateowner_slab = NULL;
 static struct kmem_cache *file_slab = NULL;
 static struct kmem_cache *stateid_slab = NULL;
 static struct kmem_cache *deleg_slab = NULL;
+static struct kmem_cache *cstate_slab;
 
 void
 nfs4_lock_state(void)
@@ -441,6 +442,37 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir)
 	return clp;
 }
 
+void nfsd4_cstate_free(struct nfsd4_compound_state *cstate,
+		       struct svc_deferred_req *dreq)
+{
+	if (dreq && dreq->release_state)
+		nfsd4_return_deferred_respages(dreq);
+	if (cstate == NULL)
+		return;
+	fh_put(&cstate->current_fh);
+	fh_put(&cstate->save_fh);
+	BUG_ON(cstate->replay_owner);
+	kmem_cache_free(cstate_slab, cstate);
+}
+
+struct nfsd4_compound_state *nfsd4_cstate_alloc(struct svc_rqst *rqstp)
+{
+	struct nfsd4_compound_state *cstate;
+
+	if (rqstp->rq_deferred && rqstp->rq_deferred->defer_data) {
+		cstate = rqstp->rq_deferred->defer_data;
+		goto out;
+	}
+	cstate = kmem_cache_alloc(cstate_slab, GFP_KERNEL);
+	if (cstate == NULL)
+		return NULL;
+	fh_init(&cstate->current_fh, NFS4_FHSIZE);
+	fh_init(&cstate->save_fh, NFS4_FHSIZE);
+	cstate->replay_owner = NULL;
+out:
+	return cstate;
+}
+
 static void copy_verf(struct nfs4_client *target, nfs4_verifier *source)
 {
 	memcpy(target->cl_verifier.data, source->data,
@@ -940,6 +972,7 @@ nfsd4_free_slabs(void)
 	nfsd4_free_slab(&file_slab);
 	nfsd4_free_slab(&stateid_slab);
 	nfsd4_free_slab(&deleg_slab);
+	nfsd4_free_slab(&cstate_slab);
 }
 
 static int
@@ -961,6 +994,10 @@ nfsd4_init_slabs(void)
 			sizeof(struct nfs4_delegation), 0, 0, NULL);
 	if (deleg_slab == NULL)
 		goto out_nomem;
+	cstate_slab = kmem_cache_create("nfsd4_compound_states",
+			sizeof(struct nfsd4_compound_state), 0, 0, NULL);
+	if (cstate_slab == NULL)
+		goto out_nomem;
 	return 0;
 out_nomem:
 	nfsd4_free_slabs();
diff --git a/include/linux/nfsd/xdr4.h b/include/linux/nfsd/xdr4.h
index 27bd3e3..ced602c 100644
--- a/include/linux/nfsd/xdr4.h
+++ b/include/linux/nfsd/xdr4.h
@@ -48,6 +48,8 @@ struct nfsd4_compound_state {
 	struct svc_fh current_fh;
 	struct svc_fh save_fh;
 	struct nfs4_stateowner *replay_owner;
+	__be32 *last_op_p;
+	u32 last_op_cnt;
 };
 
 struct nfsd4_change_info {
@@ -442,6 +444,10 @@ void nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op);
 __be32 nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
 		       struct dentry *dentry, __be32 *buffer, int *countp,
 		       u32 *bmval, struct svc_rqst *, int ignore_crossmnt);
+extern void nfsd4_return_deferred_respages(struct svc_deferred_req *dreq);
+extern struct nfsd4_compound_state *nfsd4_cstate_alloc(struct svc_rqst *rqstp);
+extern void nfsd4_cstate_free(struct nfsd4_compound_state *cstate,
+		struct svc_deferred_req *dreq);
 extern __be32 nfsd4_setclientid(struct svc_rqst *rqstp,
 		struct nfsd4_compound_state *,
 		struct nfsd4_setclientid *setclid);
-- 
1.5.4.3

--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Filesystem Development]     [Linux USB Development]     [Linux Media Development]     [Video for Linux]     [Linux NILFS]     [Linux Audio Users]     [Yosemite Info]     [Linux SCSI]

  Powered by Linux