All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/2] NFSD: add FREE_STATEID and TEST_STATEID operations
@ 2011-05-20 20:12 bjschuma
  2011-05-20 20:12 ` [PATCH 1/2] NFSD: added FREE_STATEID operation bjschuma
                   ` (2 more replies)
  0 siblings, 3 replies; 18+ messages in thread
From: bjschuma @ 2011-05-20 20:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Bryan Schumaker

From: Bryan Schumaker <bjschuma@netapp.com>

These patches add FREE_STATEID and TEST_STATEID to the NFS server.  I
appreciate any comments, especially if there is a better way of doing things.

v2:
- FREE_STATEID
  - Free open, lock, and delegation state ids correctly
  - Use the check_for_locks() function to check for locks

- TEST_STATEID
  - Remove openmode check
  - Sanity check on size of stateid list
  - Delay decoding stateid list until encoding the reply

v3:
- FREE_STATEID
  - Open stateids and delegations are never freeable (return nfserr_locks_held)

- TEST_STATEID
  - Remove unused arguments from a function call
  - Store and use the HAS_SESSION flag for validating stateids

Thanks!

- Bryan

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH 1/2] NFSD: added FREE_STATEID operation
  2011-05-20 20:12 [PATCH v2 0/2] NFSD: add FREE_STATEID and TEST_STATEID operations bjschuma
@ 2011-05-20 20:12 ` bjschuma
  2011-05-20 20:16   ` Bryan Schumaker
  2011-05-20 20:13 ` [PATCH 2/2] NFSD: Added TEST_STATEID operation bjschuma
  2011-05-20 20:13 ` [PATCH v2 0/2] NFSD: add FREE_STATEID and TEST_STATEID operations Bryan Schumaker
  2 siblings, 1 reply; 18+ messages in thread
From: bjschuma @ 2011-05-20 20:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Bryan Schumaker

From: Bryan Schumaker <bjschuma@netapp.com>

This operation is used by the client to tell the server to free a
stateid.

Signed-off-by: Bryan Schumaker <bjschuma@netapp.com>
---
 fs/nfsd/nfs4proc.c  |    5 +++
 fs/nfsd/nfs4state.c |  101 +++++++++++++++++++++++++++++++++++++++++++++++++++
 fs/nfsd/nfs4xdr.c   |   32 +++++++++++++++-
 fs/nfsd/xdr4.h      |    8 ++++
 4 files changed, 144 insertions(+), 2 deletions(-)

diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 3a6dbd7..7e00116 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -1412,6 +1412,11 @@ static struct nfsd4_operation nfsd4_ops[] = {
 		.op_flags = OP_HANDLES_WRONGSEC,
 		.op_name = "OP_SECINFO_NO_NAME",
 	},
+	[OP_FREE_STATEID] = {
+		.op_func = (nfsd4op_func)nfsd4_free_stateid,
+		.op_flags = ALLOWED_WITHOUT_FH,
+		.op_name = "OP_FREE_STATEID",
+	},
 };
 
 static const char *nfsd4_op_name(unsigned opnum)
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index a2ea14f..c8c1cad 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -60,9 +60,12 @@ static u64 current_sessionid = 1;
 
 /* forward declarations */
 static struct nfs4_stateid * find_stateid(stateid_t *stid, int flags);
+static struct nfs4_stateid * search_for_stateid(stateid_t *stid);
+static struct nfs4_delegation * search_for_delegation(stateid_t *stid);
 static struct nfs4_delegation * find_delegation_stateid(struct inode *ino, stateid_t *stid);
 static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery";
 static void nfs4_set_recdir(char *recdir);
+static int check_for_locks(struct nfs4_file *filp, struct nfs4_stateowner *lowner);
 
 /* Locking: */
 
@@ -3133,6 +3136,11 @@ static int is_delegation_stateid(stateid_t *stateid)
 	return stateid->si_fileid == 0;
 }
 
+static int is_open_stateid(struct nfs4_stateid *stateid)
+{
+	return stateid->st_openstp == NULL;
+}
+
 /*
 * Checks for stateid operations
 */
@@ -3212,6 +3220,53 @@ out:
 	return status;
 }
 
+static __be32
+nfsd4_free_delegation_stateid(stateid_t *stateid)
+{
+	struct nfs4_delegation *dp = search_for_delegation(stateid);
+	if (dp)
+		return nfserr_locks_held;
+	return nfserr_bad_stateid;
+}
+
+static __be32
+nfsd4_free_lock_stateid(stateid_t *stateid, struct nfs4_stateid *stp)
+{
+	if (check_for_locks(stp->st_file, stp->st_stateowner))
+		return nfserr_locks_held;
+	release_lock_stateid(stp);
+	return nfs_ok;
+}
+
+/*
+ * Free a state id
+ */
+__be32
+nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+		   struct nfsd4_free_stateid *free_stateid)
+{
+	stateid_t *stateid = &free_stateid->fr_stateid;
+	struct nfs4_stateid *stp;
+
+	if (is_delegation_stateid(stateid))
+		return nfsd4_free_delegation_stateid(stateid);
+
+	stp = search_for_stateid(stateid);
+	if (!stp)
+		return nfserr_bad_stateid;
+	if (stateid->si_generation != 0) {
+		if (stateid->si_generation < stp->st_stateid.si_generation)
+			return nfserr_old_stateid;
+		if (stateid->si_generation > stp->st_stateid.si_generation)
+			return nfserr_bad_stateid;
+	}
+
+	if (is_open_stateid(stp))
+		return nfserr_locks_held;
+	else
+		return nfsd4_free_lock_stateid(stateid, stp);
+}
+
 static inline int
 setlkflg (int type)
 {
@@ -3590,6 +3645,14 @@ static struct list_head lock_ownerid_hashtbl[LOCK_HASH_SIZE];
 static struct list_head	lock_ownerstr_hashtbl[LOCK_HASH_SIZE];
 static struct list_head lockstateid_hashtbl[STATEID_HASH_SIZE];
 
+static int
+same_stateid(stateid_t *id_one, stateid_t *id_two)
+{
+	if (id_one->si_stateownerid != id_two->si_stateownerid)
+		return 0;
+	return id_one->si_fileid == id_two->si_fileid;
+}
+
 static struct nfs4_stateid *
 find_stateid(stateid_t *stid, int flags)
 {
@@ -3619,6 +3682,44 @@ find_stateid(stateid_t *stid, int flags)
 	return NULL;
 }
 
+static struct nfs4_stateid *
+search_for_stateid(stateid_t *stid)
+{
+	struct nfs4_stateid *local;
+	unsigned int hashval = stateid_hashval(stid->si_stateownerid, stid->si_fileid);
+
+	list_for_each_entry(local, &lockstateid_hashtbl[hashval], st_hash) {
+		if (same_stateid(&local->st_stateid, stid))
+			return local;
+	}
+
+	list_for_each_entry(local, &stateid_hashtbl[hashval], st_hash) {
+		if (same_stateid(&local->st_stateid, stid))
+			return local;
+	}
+	return NULL;
+}
+
+static struct nfs4_delegation *
+search_for_delegation(stateid_t *stid)
+{
+	struct nfs4_file *fp;
+	struct nfs4_delegation *dp;
+	struct list_head *pos;
+	int i;
+
+	for (i = 0; i < FILE_HASH_SIZE; i++) {
+		list_for_each_entry(fp, &file_hashtbl[i], fi_hash) {
+			list_for_each(pos, &fp->fi_delegations) {
+				dp = list_entry(pos, struct nfs4_delegation, dl_perfile);
+				if (same_stateid(&dp->dl_stateid, stid))
+					return dp;
+			}
+		}
+	}
+	return NULL;
+}
+
 static struct nfs4_delegation *
 find_delegation_stateid(struct inode *ino, stateid_t *stid)
 {
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 195a91d..5da6874 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -1246,6 +1246,19 @@ nfsd4_decode_destroy_session(struct nfsd4_compoundargs *argp,
 }
 
 static __be32
+nfsd4_decode_free_stateid(struct nfsd4_compoundargs *argp,
+			  struct nfsd4_free_stateid *free_stateid)
+{
+	DECODE_HEAD;
+
+	READ_BUF(sizeof(stateid_t));
+	READ32(free_stateid->fr_stateid.si_generation);
+	COPYMEM(&free_stateid->fr_stateid.si_opaque, sizeof(stateid_opaque_t));
+
+	DECODE_TAIL;
+}
+
+static __be32
 nfsd4_decode_sequence(struct nfsd4_compoundargs *argp,
 		      struct nfsd4_sequence *seq)
 {
@@ -1370,7 +1383,7 @@ static nfsd4_dec nfsd41_dec_ops[] = {
 	[OP_EXCHANGE_ID]	= (nfsd4_dec)nfsd4_decode_exchange_id,
 	[OP_CREATE_SESSION]	= (nfsd4_dec)nfsd4_decode_create_session,
 	[OP_DESTROY_SESSION]	= (nfsd4_dec)nfsd4_decode_destroy_session,
-	[OP_FREE_STATEID]	= (nfsd4_dec)nfsd4_decode_notsupp,
+	[OP_FREE_STATEID]	= (nfsd4_dec)nfsd4_decode_free_stateid,
 	[OP_GET_DIR_DELEGATION]	= (nfsd4_dec)nfsd4_decode_notsupp,
 	[OP_GETDEVICEINFO]	= (nfsd4_dec)nfsd4_decode_notsupp,
 	[OP_GETDEVICELIST]	= (nfsd4_dec)nfsd4_decode_notsupp,
@@ -3115,6 +3128,21 @@ nfsd4_encode_destroy_session(struct nfsd4_compoundres *resp, int nfserr,
 	return nfserr;
 }
 
+static __be32
+nfsd4_encode_free_stateid(struct nfsd4_compoundres *resp, int nfserr,
+			  struct nfsd4_free_stateid *free_stateid)
+{
+	__be32 *p;
+
+	if (nfserr)
+		return nfserr;
+
+	RESERVE_SPACE(4);
+	WRITE32(nfserr);
+	ADJUST_ARGS();
+	return nfserr;
+}
+
 __be32
 nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr,
 		      struct nfsd4_sequence *seq)
@@ -3196,7 +3224,7 @@ static nfsd4_enc nfsd4_enc_ops[] = {
 	[OP_EXCHANGE_ID]	= (nfsd4_enc)nfsd4_encode_exchange_id,
 	[OP_CREATE_SESSION]	= (nfsd4_enc)nfsd4_encode_create_session,
 	[OP_DESTROY_SESSION]	= (nfsd4_enc)nfsd4_encode_destroy_session,
-	[OP_FREE_STATEID]	= (nfsd4_enc)nfsd4_encode_noop,
+	[OP_FREE_STATEID]	= (nfsd4_enc)nfsd4_encode_free_stateid,
 	[OP_GET_DIR_DELEGATION]	= (nfsd4_enc)nfsd4_encode_noop,
 	[OP_GETDEVICEINFO]	= (nfsd4_enc)nfsd4_encode_noop,
 	[OP_GETDEVICELIST]	= (nfsd4_enc)nfsd4_encode_noop,
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
index 366401e..ed1784d 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -342,6 +342,11 @@ struct nfsd4_setclientid_confirm {
 	nfs4_verifier	sc_confirm;
 };
 
+struct nfsd4_free_stateid {
+	stateid_t	fr_stateid;         /* request */
+	__be32		fr_status;          /* response */
+};
+
 /* also used for NVERIFY */
 struct nfsd4_verify {
 	u32		ve_bmval[3];        /* request */
@@ -432,6 +437,7 @@ struct nfsd4_op {
 		struct nfsd4_destroy_session	destroy_session;
 		struct nfsd4_sequence		sequence;
 		struct nfsd4_reclaim_complete	reclaim_complete;
+		struct nfsd4_free_stateid	free_stateid;
 	} u;
 	struct nfs4_replay *			replay;
 };
@@ -564,6 +570,8 @@ extern __be32 nfsd4_delegreturn(struct svc_rqst *rqstp,
 		struct nfsd4_compound_state *, struct nfsd4_delegreturn *dr);
 extern __be32 nfsd4_renew(struct svc_rqst *rqstp,
 			  struct nfsd4_compound_state *, clientid_t *clid);
+extern __be32 nfsd4_free_stateid(struct svc_rqst *rqstp,
+		struct nfsd4_compound_state *, struct nfsd4_free_stateid *free_stateid);
 #endif
 
 /*
-- 
1.7.5.2


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 2/2] NFSD: Added TEST_STATEID operation
  2011-05-20 20:12 [PATCH v2 0/2] NFSD: add FREE_STATEID and TEST_STATEID operations bjschuma
  2011-05-20 20:12 ` [PATCH 1/2] NFSD: added FREE_STATEID operation bjschuma
@ 2011-05-20 20:13 ` bjschuma
  2011-06-29 19:49   ` Bryan Schumaker
  2011-05-20 20:13 ` [PATCH v2 0/2] NFSD: add FREE_STATEID and TEST_STATEID operations Bryan Schumaker
  2 siblings, 1 reply; 18+ messages in thread
From: bjschuma @ 2011-05-20 20:13 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Bryan Schumaker

From: Bryan Schumaker <bjschuma@netapp.com>

This operation is used by the client to check the validity of a list of
stateids.

Signed-off-by: Bryan Schumaker <bjschuma@netapp.com>
---
 fs/nfsd/nfs4proc.c  |    5 +++
 fs/nfsd/nfs4state.c |   47 ++++++++++++++++++++++++++++
 fs/nfsd/nfs4xdr.c   |   85 +++++++++++++++++++++++++++++++++++++++++++++++++--
 fs/nfsd/state.h     |    1 +
 fs/nfsd/xdr4.h      |   17 ++++++++++
 5 files changed, 152 insertions(+), 3 deletions(-)

diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 7e00116..a856f30 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -1412,6 +1412,11 @@ static struct nfsd4_operation nfsd4_ops[] = {
 		.op_flags = OP_HANDLES_WRONGSEC,
 		.op_name = "OP_SECINFO_NO_NAME",
 	},
+	[OP_TEST_STATEID] = {
+		.op_func = (nfsd4op_func)nfsd4_test_stateid,
+		.op_flags = ALLOWED_WITHOUT_FH,
+		.op_name = "OP_TEST_STATEID",
+	},
 	[OP_FREE_STATEID] = {
 		.op_func = (nfsd4op_func)nfsd4_free_stateid,
 		.op_flags = ALLOWED_WITHOUT_FH,
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index c8c1cad..0aa394d 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -37,6 +37,7 @@
 #include <linux/slab.h>
 #include <linux/namei.h>
 #include <linux/swap.h>
+#include <linux/pagemap.h>
 #include <linux/sunrpc/svcauth_gss.h>
 #include <linux/sunrpc/clnt.h>
 #include "xdr4.h"
@@ -3141,6 +3142,32 @@ static int is_open_stateid(struct nfs4_stateid *stateid)
 	return stateid->st_openstp == NULL;
 }
 
+static __be32 nfs4_validate_stateid(stateid_t *stateid, int flags)
+{
+	struct nfs4_stateid *stp = NULL;
+	__be32 status = nfserr_stale_stateid;
+
+	if (STALE_STATEID(stateid))
+		goto out;
+
+	status = nfserr_expired;
+	stp = search_for_stateid(stateid);
+	if (!stp)
+		goto out;
+	status = nfserr_bad_stateid;
+
+	if (!stp->st_stateowner->so_confirmed)
+		goto out;
+
+	status = check_stateid_generation(stateid, &stp->st_stateid, flags);
+	if (status)
+		goto out;
+
+	status = nfs_ok;
+out:
+	return status;
+}
+
 /*
 * Checks for stateid operations
 */
@@ -3239,6 +3266,26 @@ nfsd4_free_lock_stateid(stateid_t *stateid, struct nfs4_stateid *stp)
 }
 
 /*
+ * Test if the stateid is valid
+ */
+__be32
+nfsd4_test_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+		   struct nfsd4_test_stateid *test_stateid)
+{
+	test_stateid->ts_has_session = nfsd4_has_session(cstate);
+	return nfs_ok;
+}
+
+__be32
+nfsd4_do_test_stateid(stateid_t *stateid, int flags)
+{
+	__be32 ret = nfs4_validate_stateid(stateid, flags);
+	if (!ret)
+		ret = nfs4_validate_stateid(stateid, flags);
+	return ret;
+}
+
+/*
  * Free a state id
  */
 __be32
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 5da6874..a042174 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -44,13 +44,14 @@
 #include <linux/namei.h>
 #include <linux/statfs.h>
 #include <linux/utsname.h>
+#include <linux/pagemap.h>
 #include <linux/sunrpc/svcauth_gss.h>
 
 #include "idmap.h"
 #include "acl.h"
 #include "xdr4.h"
 #include "vfs.h"
-
+#include "state.h"
 
 #define NFSDDBG_FACILITY		NFSDDBG_XDR
 
@@ -131,6 +132,22 @@ xdr_error:					\
 	}					\
 } while (0)
 
+static void save_buf(struct nfsd4_compoundargs *argp, struct nfsd4_saved_compoundargs *savep)
+{
+	savep->p        = argp->p;
+	savep->end      = argp->end;
+	savep->pagelen  = argp->pagelen;
+	savep->pagelist = argp->pagelist;
+}
+
+static void restore_buf(struct nfsd4_compoundargs *argp, struct nfsd4_saved_compoundargs *savep)
+{
+	argp->p        = savep->p;
+	argp->end      = savep->end;
+	argp->pagelen  = savep->pagelen;
+	argp->pagelist = savep->pagelist;
+}
+
 static __be32 *read_buf(struct nfsd4_compoundargs *argp, u32 nbytes)
 {
 	/* We want more bytes than seem to be available.
@@ -1274,6 +1291,40 @@ nfsd4_decode_sequence(struct nfsd4_compoundargs *argp,
 	DECODE_TAIL;
 }
 
+static __be32
+nfsd4_decode_test_stateid(struct nfsd4_compoundargs *argp, struct nfsd4_test_stateid *test_stateid)
+{
+	unsigned int nbytes;
+	stateid_t si;
+	int i;
+	__be32 *p;
+	__be32 status;
+
+	READ_BUF(4);
+	test_stateid->ts_num_ids = ntohl(*p++);
+
+	nbytes = test_stateid->ts_num_ids * sizeof(stateid_t);
+	if (nbytes > (u32)((char *)argp->end - (char *)argp->p))
+		goto xdr_error;
+
+	test_stateid->ts_saved_args = argp;
+	save_buf(argp, &test_stateid->ts_savedp);
+
+	for (i = 0; i < test_stateid->ts_num_ids; i++) {
+		status = nfsd4_decode_stateid(argp, &si);
+		if (status)
+			return status;
+	}
+
+	status = 0;
+out:
+	return status;
+xdr_error:
+	dprintk("NFSD: xdr error (%s:%d)\n", __FILE__, __LINE__);
+	status = nfserr_bad_xdr;
+	goto out;
+}
+
 static __be32 nfsd4_decode_reclaim_complete(struct nfsd4_compoundargs *argp, struct nfsd4_reclaim_complete *rc)
 {
 	DECODE_HEAD;
@@ -1393,7 +1444,7 @@ static nfsd4_dec nfsd41_dec_ops[] = {
 	[OP_SECINFO_NO_NAME]	= (nfsd4_dec)nfsd4_decode_secinfo_no_name,
 	[OP_SEQUENCE]		= (nfsd4_dec)nfsd4_decode_sequence,
 	[OP_SET_SSV]		= (nfsd4_dec)nfsd4_decode_notsupp,
-	[OP_TEST_STATEID]	= (nfsd4_dec)nfsd4_decode_notsupp,
+	[OP_TEST_STATEID]	= (nfsd4_dec)nfsd4_decode_test_stateid,
 	[OP_WANT_DELEGATION]	= (nfsd4_dec)nfsd4_decode_notsupp,
 	[OP_DESTROY_CLIENTID]	= (nfsd4_dec)nfsd4_decode_notsupp,
 	[OP_RECLAIM_COMPLETE]	= (nfsd4_dec)nfsd4_decode_reclaim_complete,
@@ -3166,6 +3217,34 @@ nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr,
 	return 0;
 }
 
+__be32
+nfsd4_encode_test_stateid(struct nfsd4_compoundres *resp, int nfserr,
+			  struct nfsd4_test_stateid *test_stateid)
+{
+	struct nfsd4_compoundargs *argp;
+	stateid_t si;
+	__be32 *p;
+	int i;
+	int valid;
+
+	restore_buf(test_stateid->ts_saved_args, &test_stateid->ts_savedp);
+	argp = test_stateid->ts_saved_args;
+
+	RESERVE_SPACE(4);
+	*p++ = htonl(test_stateid->ts_num_ids);
+	resp->p = p;
+
+	for (i = 0; i < test_stateid->ts_num_ids; i++) {
+		nfsd4_decode_stateid(argp, &si);
+		valid = nfsd4_do_test_stateid(&si, test_stateid->ts_has_session);
+		RESERVE_SPACE(4);
+		*p++ = htonl(valid);
+		resp->p = p;
+	}
+
+	return nfserr;
+}
+
 static __be32
 nfsd4_encode_noop(struct nfsd4_compoundres *resp, __be32 nfserr, void *p)
 {
@@ -3234,7 +3313,7 @@ static nfsd4_enc nfsd4_enc_ops[] = {
 	[OP_SECINFO_NO_NAME]	= (nfsd4_enc)nfsd4_encode_secinfo_no_name,
 	[OP_SEQUENCE]		= (nfsd4_enc)nfsd4_encode_sequence,
 	[OP_SET_SSV]		= (nfsd4_enc)nfsd4_encode_noop,
-	[OP_TEST_STATEID]	= (nfsd4_enc)nfsd4_encode_noop,
+	[OP_TEST_STATEID]	= (nfsd4_enc)nfsd4_encode_test_stateid,
 	[OP_WANT_DELEGATION]	= (nfsd4_enc)nfsd4_encode_noop,
 	[OP_DESTROY_CLIENTID]	= (nfsd4_enc)nfsd4_encode_noop,
 	[OP_RECLAIM_COMPLETE]	= (nfsd4_enc)nfsd4_encode_noop,
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 6bd2f3c..d26164e 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -482,6 +482,7 @@ extern void nfsd4_recdir_purge_old(void);
 extern int nfsd4_create_clid_dir(struct nfs4_client *clp);
 extern void nfsd4_remove_clid_dir(struct nfs4_client *clp);
 extern void release_session_client(struct nfsd4_session *);
+extern __be32 nfsd4_do_test_stateid(stateid_t *, int);
 
 static inline void
 nfs4_put_stateowner(struct nfs4_stateowner *so)
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
index ed1784d..02fb0e0 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -342,6 +342,20 @@ struct nfsd4_setclientid_confirm {
 	nfs4_verifier	sc_confirm;
 };
 
+struct nfsd4_saved_compoundargs {
+	__be32 *p;
+	__be32 *end;
+	int pagelen;
+	struct page **pagelist;
+};
+
+struct nfsd4_test_stateid {
+	__be32		ts_num_ids;
+	__be32		ts_has_session;
+	struct nfsd4_compoundargs *ts_saved_args;
+	struct nfsd4_saved_compoundargs ts_savedp;
+};
+
 struct nfsd4_free_stateid {
 	stateid_t	fr_stateid;         /* request */
 	__be32		fr_status;          /* response */
@@ -437,6 +451,7 @@ struct nfsd4_op {
 		struct nfsd4_destroy_session	destroy_session;
 		struct nfsd4_sequence		sequence;
 		struct nfsd4_reclaim_complete	reclaim_complete;
+		struct nfsd4_test_stateid	test_stateid;
 		struct nfsd4_free_stateid	free_stateid;
 	} u;
 	struct nfs4_replay *			replay;
@@ -570,6 +585,8 @@ extern __be32 nfsd4_delegreturn(struct svc_rqst *rqstp,
 		struct nfsd4_compound_state *, struct nfsd4_delegreturn *dr);
 extern __be32 nfsd4_renew(struct svc_rqst *rqstp,
 			  struct nfsd4_compound_state *, clientid_t *clid);
+extern __be32 nfsd4_test_stateid(struct svc_rqst *rqstp,
+		struct nfsd4_compound_state *, struct nfsd4_test_stateid *test_stateid);
 extern __be32 nfsd4_free_stateid(struct svc_rqst *rqstp,
 		struct nfsd4_compound_state *, struct nfsd4_free_stateid *free_stateid);
 #endif
-- 
1.7.5.2


^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [PATCH v2 0/2] NFSD: add FREE_STATEID and TEST_STATEID operations
  2011-05-20 20:12 [PATCH v2 0/2] NFSD: add FREE_STATEID and TEST_STATEID operations bjschuma
  2011-05-20 20:12 ` [PATCH 1/2] NFSD: added FREE_STATEID operation bjschuma
  2011-05-20 20:13 ` [PATCH 2/2] NFSD: Added TEST_STATEID operation bjschuma
@ 2011-05-20 20:13 ` Bryan Schumaker
  2 siblings, 0 replies; 18+ messages in thread
From: Bryan Schumaker @ 2011-05-20 20:13 UTC (permalink / raw)
  To: bjschuma; +Cc: bfields, linux-nfs

The subject should read "v3" here.  Sorry about that.

- Bryan

On 05/20/2011 04:12 PM, bjschuma@netapp.com wrote:
> From: Bryan Schumaker <bjschuma@netapp.com>
> 
> These patches add FREE_STATEID and TEST_STATEID to the NFS server.  I
> appreciate any comments, especially if there is a better way of doing things.
> 
> v2:
> - FREE_STATEID
>   - Free open, lock, and delegation state ids correctly
>   - Use the check_for_locks() function to check for locks
> 
> - TEST_STATEID
>   - Remove openmode check
>   - Sanity check on size of stateid list
>   - Delay decoding stateid list until encoding the reply
> 
> v3:
> - FREE_STATEID
>   - Open stateids and delegations are never freeable (return nfserr_locks_held)
> 
> - TEST_STATEID
>   - Remove unused arguments from a function call
>   - Store and use the HAS_SESSION flag for validating stateids
> 
> Thanks!
> 
> - Bryan


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 1/2] NFSD: added FREE_STATEID operation
  2011-05-20 20:12 ` [PATCH 1/2] NFSD: added FREE_STATEID operation bjschuma
@ 2011-05-20 20:16   ` Bryan Schumaker
  2011-05-25 15:05     ` J. Bruce Fields
  0 siblings, 1 reply; 18+ messages in thread
From: Bryan Schumaker @ 2011-05-20 20:16 UTC (permalink / raw)
  To: bjschuma; +Cc: bfields, linux-nfs

On 05/20/2011 04:12 PM, bjschuma@netapp.com wrote:
> From: Bryan Schumaker <bjschuma@netapp.com>
> 
> This operation is used by the client to tell the server to free a
> stateid.
> 
> Signed-off-by: Bryan Schumaker <bjschuma@netapp.com>
> ---
>  fs/nfsd/nfs4proc.c  |    5 +++
>  fs/nfsd/nfs4state.c |  101 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  fs/nfsd/nfs4xdr.c   |   32 +++++++++++++++-
>  fs/nfsd/xdr4.h      |    8 ++++
>  4 files changed, 144 insertions(+), 2 deletions(-)
> 
> diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
> index 3a6dbd7..7e00116 100644
> --- a/fs/nfsd/nfs4proc.c
> +++ b/fs/nfsd/nfs4proc.c
> @@ -1412,6 +1412,11 @@ static struct nfsd4_operation nfsd4_ops[] = {
>  		.op_flags = OP_HANDLES_WRONGSEC,
>  		.op_name = "OP_SECINFO_NO_NAME",
>  	},
> +	[OP_FREE_STATEID] = {
> +		.op_func = (nfsd4op_func)nfsd4_free_stateid,
> +		.op_flags = ALLOWED_WITHOUT_FH,
> +		.op_name = "OP_FREE_STATEID",
> +	},
>  };
>  
>  static const char *nfsd4_op_name(unsigned opnum)
> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> index a2ea14f..c8c1cad 100644
> --- a/fs/nfsd/nfs4state.c
> +++ b/fs/nfsd/nfs4state.c
> @@ -60,9 +60,12 @@ static u64 current_sessionid = 1;
>  
>  /* forward declarations */
>  static struct nfs4_stateid * find_stateid(stateid_t *stid, int flags);
> +static struct nfs4_stateid * search_for_stateid(stateid_t *stid);
> +static struct nfs4_delegation * search_for_delegation(stateid_t *stid);
>  static struct nfs4_delegation * find_delegation_stateid(struct inode *ino, stateid_t *stid);
>  static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery";
>  static void nfs4_set_recdir(char *recdir);
> +static int check_for_locks(struct nfs4_file *filp, struct nfs4_stateowner *lowner);
>  
>  /* Locking: */
>  
> @@ -3133,6 +3136,11 @@ static int is_delegation_stateid(stateid_t *stateid)
>  	return stateid->si_fileid == 0;
>  }
>  
> +static int is_open_stateid(struct nfs4_stateid *stateid)
> +{
> +	return stateid->st_openstp == NULL;
> +}
> +
>  /*
>  * Checks for stateid operations
>  */
> @@ -3212,6 +3220,53 @@ out:
>  	return status;
>  }
>  
> +static __be32
> +nfsd4_free_delegation_stateid(stateid_t *stateid)
> +{
> +	struct nfs4_delegation *dp = search_for_delegation(stateid);
> +	if (dp)
> +		return nfserr_locks_held;
> +	return nfserr_bad_stateid;
> +}
> +
> +static __be32
> +nfsd4_free_lock_stateid(stateid_t *stateid, struct nfs4_stateid *stp)
> +{
> +	if (check_for_locks(stp->st_file, stp->st_stateowner))

I'm not sure if stateids are unique to (file, stateowner), but I'm not sure how else to check for locks at the moment.

> +		return nfserr_locks_held;
> +	release_lock_stateid(stp);
> +	return nfs_ok;
> +}
> +
> +/*
> + * Free a state id
> + */
> +__be32
> +nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
> +		   struct nfsd4_free_stateid *free_stateid)
> +{
> +	stateid_t *stateid = &free_stateid->fr_stateid;
> +	struct nfs4_stateid *stp;
> +
> +	if (is_delegation_stateid(stateid))
> +		return nfsd4_free_delegation_stateid(stateid);
> +
> +	stp = search_for_stateid(stateid);
> +	if (!stp)
> +		return nfserr_bad_stateid;
> +	if (stateid->si_generation != 0) {
> +		if (stateid->si_generation < stp->st_stateid.si_generation)
> +			return nfserr_old_stateid;
> +		if (stateid->si_generation > stp->st_stateid.si_generation)
> +			return nfserr_bad_stateid;
> +	}
> +
> +	if (is_open_stateid(stp))
> +		return nfserr_locks_held;
> +	else
> +		return nfsd4_free_lock_stateid(stateid, stp);
> +}
> +
>  static inline int
>  setlkflg (int type)
>  {
> @@ -3590,6 +3645,14 @@ static struct list_head lock_ownerid_hashtbl[LOCK_HASH_SIZE];
>  static struct list_head	lock_ownerstr_hashtbl[LOCK_HASH_SIZE];
>  static struct list_head lockstateid_hashtbl[STATEID_HASH_SIZE];
>  
> +static int
> +same_stateid(stateid_t *id_one, stateid_t *id_two)
> +{
> +	if (id_one->si_stateownerid != id_two->si_stateownerid)
> +		return 0;
> +	return id_one->si_fileid == id_two->si_fileid;
> +}
> +
>  static struct nfs4_stateid *
>  find_stateid(stateid_t *stid, int flags)
>  {
> @@ -3619,6 +3682,44 @@ find_stateid(stateid_t *stid, int flags)
>  	return NULL;
>  }
>  
> +static struct nfs4_stateid *
> +search_for_stateid(stateid_t *stid)
> +{
> +	struct nfs4_stateid *local;
> +	unsigned int hashval = stateid_hashval(stid->si_stateownerid, stid->si_fileid);
> +
> +	list_for_each_entry(local, &lockstateid_hashtbl[hashval], st_hash) {
> +		if (same_stateid(&local->st_stateid, stid))
> +			return local;
> +	}
> +
> +	list_for_each_entry(local, &stateid_hashtbl[hashval], st_hash) {
> +		if (same_stateid(&local->st_stateid, stid))
> +			return local;
> +	}
> +	return NULL;
> +}
> +
> +static struct nfs4_delegation *
> +search_for_delegation(stateid_t *stid)
> +{
> +	struct nfs4_file *fp;
> +	struct nfs4_delegation *dp;
> +	struct list_head *pos;
> +	int i;
> +
> +	for (i = 0; i < FILE_HASH_SIZE; i++) {
> +		list_for_each_entry(fp, &file_hashtbl[i], fi_hash) {
> +			list_for_each(pos, &fp->fi_delegations) {
> +				dp = list_entry(pos, struct nfs4_delegation, dl_perfile);
> +				if (same_stateid(&dp->dl_stateid, stid))
> +					return dp;
> +			}
> +		}
> +	}
> +	return NULL;
> +}
> +
>  static struct nfs4_delegation *
>  find_delegation_stateid(struct inode *ino, stateid_t *stid)
>  {
> diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
> index 195a91d..5da6874 100644
> --- a/fs/nfsd/nfs4xdr.c
> +++ b/fs/nfsd/nfs4xdr.c
> @@ -1246,6 +1246,19 @@ nfsd4_decode_destroy_session(struct nfsd4_compoundargs *argp,
>  }
>  
>  static __be32
> +nfsd4_decode_free_stateid(struct nfsd4_compoundargs *argp,
> +			  struct nfsd4_free_stateid *free_stateid)
> +{
> +	DECODE_HEAD;
> +
> +	READ_BUF(sizeof(stateid_t));
> +	READ32(free_stateid->fr_stateid.si_generation);
> +	COPYMEM(&free_stateid->fr_stateid.si_opaque, sizeof(stateid_opaque_t));
> +
> +	DECODE_TAIL;
> +}
> +
> +static __be32
>  nfsd4_decode_sequence(struct nfsd4_compoundargs *argp,
>  		      struct nfsd4_sequence *seq)
>  {
> @@ -1370,7 +1383,7 @@ static nfsd4_dec nfsd41_dec_ops[] = {
>  	[OP_EXCHANGE_ID]	= (nfsd4_dec)nfsd4_decode_exchange_id,
>  	[OP_CREATE_SESSION]	= (nfsd4_dec)nfsd4_decode_create_session,
>  	[OP_DESTROY_SESSION]	= (nfsd4_dec)nfsd4_decode_destroy_session,
> -	[OP_FREE_STATEID]	= (nfsd4_dec)nfsd4_decode_notsupp,
> +	[OP_FREE_STATEID]	= (nfsd4_dec)nfsd4_decode_free_stateid,
>  	[OP_GET_DIR_DELEGATION]	= (nfsd4_dec)nfsd4_decode_notsupp,
>  	[OP_GETDEVICEINFO]	= (nfsd4_dec)nfsd4_decode_notsupp,
>  	[OP_GETDEVICELIST]	= (nfsd4_dec)nfsd4_decode_notsupp,
> @@ -3115,6 +3128,21 @@ nfsd4_encode_destroy_session(struct nfsd4_compoundres *resp, int nfserr,
>  	return nfserr;
>  }
>  
> +static __be32
> +nfsd4_encode_free_stateid(struct nfsd4_compoundres *resp, int nfserr,
> +			  struct nfsd4_free_stateid *free_stateid)
> +{
> +	__be32 *p;
> +
> +	if (nfserr)
> +		return nfserr;
> +
> +	RESERVE_SPACE(4);
> +	WRITE32(nfserr);
> +	ADJUST_ARGS();
> +	return nfserr;
> +}
> +
>  __be32
>  nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr,
>  		      struct nfsd4_sequence *seq)
> @@ -3196,7 +3224,7 @@ static nfsd4_enc nfsd4_enc_ops[] = {
>  	[OP_EXCHANGE_ID]	= (nfsd4_enc)nfsd4_encode_exchange_id,
>  	[OP_CREATE_SESSION]	= (nfsd4_enc)nfsd4_encode_create_session,
>  	[OP_DESTROY_SESSION]	= (nfsd4_enc)nfsd4_encode_destroy_session,
> -	[OP_FREE_STATEID]	= (nfsd4_enc)nfsd4_encode_noop,
> +	[OP_FREE_STATEID]	= (nfsd4_enc)nfsd4_encode_free_stateid,
>  	[OP_GET_DIR_DELEGATION]	= (nfsd4_enc)nfsd4_encode_noop,
>  	[OP_GETDEVICEINFO]	= (nfsd4_enc)nfsd4_encode_noop,
>  	[OP_GETDEVICELIST]	= (nfsd4_enc)nfsd4_encode_noop,
> diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
> index 366401e..ed1784d 100644
> --- a/fs/nfsd/xdr4.h
> +++ b/fs/nfsd/xdr4.h
> @@ -342,6 +342,11 @@ struct nfsd4_setclientid_confirm {
>  	nfs4_verifier	sc_confirm;
>  };
>  
> +struct nfsd4_free_stateid {
> +	stateid_t	fr_stateid;         /* request */
> +	__be32		fr_status;          /* response */
> +};
> +
>  /* also used for NVERIFY */
>  struct nfsd4_verify {
>  	u32		ve_bmval[3];        /* request */
> @@ -432,6 +437,7 @@ struct nfsd4_op {
>  		struct nfsd4_destroy_session	destroy_session;
>  		struct nfsd4_sequence		sequence;
>  		struct nfsd4_reclaim_complete	reclaim_complete;
> +		struct nfsd4_free_stateid	free_stateid;
>  	} u;
>  	struct nfs4_replay *			replay;
>  };
> @@ -564,6 +570,8 @@ extern __be32 nfsd4_delegreturn(struct svc_rqst *rqstp,
>  		struct nfsd4_compound_state *, struct nfsd4_delegreturn *dr);
>  extern __be32 nfsd4_renew(struct svc_rqst *rqstp,
>  			  struct nfsd4_compound_state *, clientid_t *clid);
> +extern __be32 nfsd4_free_stateid(struct svc_rqst *rqstp,
> +		struct nfsd4_compound_state *, struct nfsd4_free_stateid *free_stateid);
>  #endif
>  
>  /*


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 1/2] NFSD: added FREE_STATEID operation
  2011-05-20 20:16   ` Bryan Schumaker
@ 2011-05-25 15:05     ` J. Bruce Fields
  2011-05-31 14:52       ` Bryan Schumaker
  0 siblings, 1 reply; 18+ messages in thread
From: J. Bruce Fields @ 2011-05-25 15:05 UTC (permalink / raw)
  To: Bryan Schumaker; +Cc: linux-nfs

On Fri, May 20, 2011 at 04:16:18PM -0400, Bryan Schumaker wrote:
> On 05/20/2011 04:12 PM, bjschuma@netapp.com wrote:
> > From: Bryan Schumaker <bjschuma@netapp.com>
> > +static __be32
> > +nfsd4_free_delegation_stateid(stateid_t *stateid)
> > +{
> > +	struct nfs4_delegation *dp = search_for_delegation(stateid);
> > +	if (dp)
> > +		return nfserr_locks_held;
> > +	return nfserr_bad_stateid;
> > +}
> > +
> > +static __be32
> > +nfsd4_free_lock_stateid(stateid_t *stateid, struct nfs4_stateid *stp)
> > +{
> > +	if (check_for_locks(stp->st_file, stp->st_stateowner))
> 
> I'm not sure if stateids are unique to (file, stateowner), but I'm not sure how else to check for locks at the moment.

Actually, looking... there's a one-to-one lockowner<->lockstateid
correspondance.  Which is dumb.

The server's handling of lock state needs more serious help than I
realized!

I think your patch is OK now, though.

--b.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 1/2] NFSD: added FREE_STATEID operation
  2011-05-25 15:05     ` J. Bruce Fields
@ 2011-05-31 14:52       ` Bryan Schumaker
  0 siblings, 0 replies; 18+ messages in thread
From: Bryan Schumaker @ 2011-05-31 14:52 UTC (permalink / raw)
  To: J. Bruce Fields; +Cc: linux-nfs

On 05/25/2011 11:05 AM, J. Bruce Fields wrote:
> On Fri, May 20, 2011 at 04:16:18PM -0400, Bryan Schumaker wrote:
>> On 05/20/2011 04:12 PM, bjschuma@netapp.com wrote:
>>> From: Bryan Schumaker <bjschuma@netapp.com>
>>> +static __be32
>>> +nfsd4_free_delegation_stateid(stateid_t *stateid)
>>> +{
>>> +	struct nfs4_delegation *dp = search_for_delegation(stateid);
>>> +	if (dp)
>>> +		return nfserr_locks_held;
>>> +	return nfserr_bad_stateid;
>>> +}
>>> +
>>> +static __be32
>>> +nfsd4_free_lock_stateid(stateid_t *stateid, struct nfs4_stateid *stp)
>>> +{
>>> +	if (check_for_locks(stp->st_file, stp->st_stateowner))
>>
>> I'm not sure if stateids are unique to (file, stateowner), but I'm not sure how else to check for locks at the moment.
> 
> Actually, looking... there's a one-to-one lockowner<->lockstateid
> correspondance.  Which is dumb.
> 
> The server's handling of lock state needs more serious help than I
> realized!
> 
> I think your patch is OK now, though.

Thanks for the reviews!

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


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 2/2] NFSD: Added TEST_STATEID operation
  2011-05-20 20:13 ` [PATCH 2/2] NFSD: Added TEST_STATEID operation bjschuma
@ 2011-06-29 19:49   ` Bryan Schumaker
  2011-06-29 19:54     ` J. Bruce Fields
  0 siblings, 1 reply; 18+ messages in thread
From: Bryan Schumaker @ 2011-06-29 19:49 UTC (permalink / raw)
  To: bjschuma; +Cc: bfields, linux-nfs

On 05/20/2011 04:13 PM, bjschuma@netapp.com wrote:
> From: Bryan Schumaker <bjschuma@netapp.com>
> 
> This operation is used by the client to check the validity of a list of
> stateids.
> 
> Signed-off-by: Bryan Schumaker <bjschuma@netapp.com>
> ---
>  fs/nfsd/nfs4proc.c  |    5 +++
>  fs/nfsd/nfs4state.c |   47 ++++++++++++++++++++++++++++
>  fs/nfsd/nfs4xdr.c   |   85 +++++++++++++++++++++++++++++++++++++++++++++++++--
>  fs/nfsd/state.h     |    1 +
>  fs/nfsd/xdr4.h      |   17 ++++++++++
>  5 files changed, 152 insertions(+), 3 deletions(-)
> 
> diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
> index 7e00116..a856f30 100644
> --- a/fs/nfsd/nfs4proc.c
> +++ b/fs/nfsd/nfs4proc.c
> @@ -1412,6 +1412,11 @@ static struct nfsd4_operation nfsd4_ops[] = {
>  		.op_flags = OP_HANDLES_WRONGSEC,
>  		.op_name = "OP_SECINFO_NO_NAME",
>  	},
> +	[OP_TEST_STATEID] = {
> +		.op_func = (nfsd4op_func)nfsd4_test_stateid,
> +		.op_flags = ALLOWED_WITHOUT_FH,
> +		.op_name = "OP_TEST_STATEID",
> +	},
>  	[OP_FREE_STATEID] = {
>  		.op_func = (nfsd4op_func)nfsd4_free_stateid,
>  		.op_flags = ALLOWED_WITHOUT_FH,
> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> index c8c1cad..0aa394d 100644
> --- a/fs/nfsd/nfs4state.c
> +++ b/fs/nfsd/nfs4state.c
> @@ -37,6 +37,7 @@
>  #include <linux/slab.h>
>  #include <linux/namei.h>
>  #include <linux/swap.h>
> +#include <linux/pagemap.h>
>  #include <linux/sunrpc/svcauth_gss.h>
>  #include <linux/sunrpc/clnt.h>
>  #include "xdr4.h"
> @@ -3141,6 +3142,32 @@ static int is_open_stateid(struct nfs4_stateid *stateid)
>  	return stateid->st_openstp == NULL;
>  }
>  
> +static __be32 nfs4_validate_stateid(stateid_t *stateid, int flags)
> +{
> +	struct nfs4_stateid *stp = NULL;
> +	__be32 status = nfserr_stale_stateid;
> +
> +	if (STALE_STATEID(stateid))
> +		goto out;
> +
> +	status = nfserr_expired;
> +	stp = search_for_stateid(stateid);
> +	if (!stp)
> +		goto out;
> +	status = nfserr_bad_stateid;
> +
> +	if (!stp->st_stateowner->so_confirmed)
> +		goto out;
> +
> +	status = check_stateid_generation(stateid, &stp->st_stateid, flags);
> +	if (status)
> +		goto out;
> +
> +	status = nfs_ok;
> +out:
> +	return status;
> +}
> +
>  /*
>  * Checks for stateid operations
>  */
> @@ -3239,6 +3266,26 @@ nfsd4_free_lock_stateid(stateid_t *stateid, struct nfs4_stateid *stp)
>  }
>  
>  /*
> + * Test if the stateid is valid
> + */
> +__be32
> +nfsd4_test_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
> +		   struct nfsd4_test_stateid *test_stateid)
> +{
> +	test_stateid->ts_has_session = nfsd4_has_session(cstate);
> +	return nfs_ok;
> +}
> +
> +__be32
> +nfsd4_do_test_stateid(stateid_t *stateid, int flags)
> +{
> +	__be32 ret = nfs4_validate_stateid(stateid, flags);
> +	if (!ret)
> +		ret = nfs4_validate_stateid(stateid, flags);
> +	return ret;

Looking back at this, I'm not convinced that I need to call nfs4_validate_stateid() twice with the same stateid and flags.  What is the status of these patches?  Should I resubmit everything or send in a small patch to fix this?

- Bryan

> +}
> +
> +/*
>   * Free a state id
>   */
>  __be32
> diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
> index 5da6874..a042174 100644
> --- a/fs/nfsd/nfs4xdr.c
> +++ b/fs/nfsd/nfs4xdr.c
> @@ -44,13 +44,14 @@
>  #include <linux/namei.h>
>  #include <linux/statfs.h>
>  #include <linux/utsname.h>
> +#include <linux/pagemap.h>
>  #include <linux/sunrpc/svcauth_gss.h>
>  
>  #include "idmap.h"
>  #include "acl.h"
>  #include "xdr4.h"
>  #include "vfs.h"
> -
> +#include "state.h"
>  
>  #define NFSDDBG_FACILITY		NFSDDBG_XDR
>  
> @@ -131,6 +132,22 @@ xdr_error:					\
>  	}					\
>  } while (0)
>  
> +static void save_buf(struct nfsd4_compoundargs *argp, struct nfsd4_saved_compoundargs *savep)
> +{
> +	savep->p        = argp->p;
> +	savep->end      = argp->end;
> +	savep->pagelen  = argp->pagelen;
> +	savep->pagelist = argp->pagelist;
> +}
> +
> +static void restore_buf(struct nfsd4_compoundargs *argp, struct nfsd4_saved_compoundargs *savep)
> +{
> +	argp->p        = savep->p;
> +	argp->end      = savep->end;
> +	argp->pagelen  = savep->pagelen;
> +	argp->pagelist = savep->pagelist;
> +}
> +
>  static __be32 *read_buf(struct nfsd4_compoundargs *argp, u32 nbytes)
>  {
>  	/* We want more bytes than seem to be available.
> @@ -1274,6 +1291,40 @@ nfsd4_decode_sequence(struct nfsd4_compoundargs *argp,
>  	DECODE_TAIL;
>  }
>  
> +static __be32
> +nfsd4_decode_test_stateid(struct nfsd4_compoundargs *argp, struct nfsd4_test_stateid *test_stateid)
> +{
> +	unsigned int nbytes;
> +	stateid_t si;
> +	int i;
> +	__be32 *p;
> +	__be32 status;
> +
> +	READ_BUF(4);
> +	test_stateid->ts_num_ids = ntohl(*p++);
> +
> +	nbytes = test_stateid->ts_num_ids * sizeof(stateid_t);
> +	if (nbytes > (u32)((char *)argp->end - (char *)argp->p))
> +		goto xdr_error;
> +
> +	test_stateid->ts_saved_args = argp;
> +	save_buf(argp, &test_stateid->ts_savedp);
> +
> +	for (i = 0; i < test_stateid->ts_num_ids; i++) {
> +		status = nfsd4_decode_stateid(argp, &si);
> +		if (status)
> +			return status;
> +	}
> +
> +	status = 0;
> +out:
> +	return status;
> +xdr_error:
> +	dprintk("NFSD: xdr error (%s:%d)\n", __FILE__, __LINE__);
> +	status = nfserr_bad_xdr;
> +	goto out;
> +}
> +
>  static __be32 nfsd4_decode_reclaim_complete(struct nfsd4_compoundargs *argp, struct nfsd4_reclaim_complete *rc)
>  {
>  	DECODE_HEAD;
> @@ -1393,7 +1444,7 @@ static nfsd4_dec nfsd41_dec_ops[] = {
>  	[OP_SECINFO_NO_NAME]	= (nfsd4_dec)nfsd4_decode_secinfo_no_name,
>  	[OP_SEQUENCE]		= (nfsd4_dec)nfsd4_decode_sequence,
>  	[OP_SET_SSV]		= (nfsd4_dec)nfsd4_decode_notsupp,
> -	[OP_TEST_STATEID]	= (nfsd4_dec)nfsd4_decode_notsupp,
> +	[OP_TEST_STATEID]	= (nfsd4_dec)nfsd4_decode_test_stateid,
>  	[OP_WANT_DELEGATION]	= (nfsd4_dec)nfsd4_decode_notsupp,
>  	[OP_DESTROY_CLIENTID]	= (nfsd4_dec)nfsd4_decode_notsupp,
>  	[OP_RECLAIM_COMPLETE]	= (nfsd4_dec)nfsd4_decode_reclaim_complete,
> @@ -3166,6 +3217,34 @@ nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr,
>  	return 0;
>  }
>  
> +__be32
> +nfsd4_encode_test_stateid(struct nfsd4_compoundres *resp, int nfserr,
> +			  struct nfsd4_test_stateid *test_stateid)
> +{
> +	struct nfsd4_compoundargs *argp;
> +	stateid_t si;
> +	__be32 *p;
> +	int i;
> +	int valid;
> +
> +	restore_buf(test_stateid->ts_saved_args, &test_stateid->ts_savedp);
> +	argp = test_stateid->ts_saved_args;
> +
> +	RESERVE_SPACE(4);
> +	*p++ = htonl(test_stateid->ts_num_ids);
> +	resp->p = p;
> +
> +	for (i = 0; i < test_stateid->ts_num_ids; i++) {
> +		nfsd4_decode_stateid(argp, &si);
> +		valid = nfsd4_do_test_stateid(&si, test_stateid->ts_has_session);
> +		RESERVE_SPACE(4);
> +		*p++ = htonl(valid);
> +		resp->p = p;
> +	}
> +
> +	return nfserr;
> +}
> +
>  static __be32
>  nfsd4_encode_noop(struct nfsd4_compoundres *resp, __be32 nfserr, void *p)
>  {
> @@ -3234,7 +3313,7 @@ static nfsd4_enc nfsd4_enc_ops[] = {
>  	[OP_SECINFO_NO_NAME]	= (nfsd4_enc)nfsd4_encode_secinfo_no_name,
>  	[OP_SEQUENCE]		= (nfsd4_enc)nfsd4_encode_sequence,
>  	[OP_SET_SSV]		= (nfsd4_enc)nfsd4_encode_noop,
> -	[OP_TEST_STATEID]	= (nfsd4_enc)nfsd4_encode_noop,
> +	[OP_TEST_STATEID]	= (nfsd4_enc)nfsd4_encode_test_stateid,
>  	[OP_WANT_DELEGATION]	= (nfsd4_enc)nfsd4_encode_noop,
>  	[OP_DESTROY_CLIENTID]	= (nfsd4_enc)nfsd4_encode_noop,
>  	[OP_RECLAIM_COMPLETE]	= (nfsd4_enc)nfsd4_encode_noop,
> diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
> index 6bd2f3c..d26164e 100644
> --- a/fs/nfsd/state.h
> +++ b/fs/nfsd/state.h
> @@ -482,6 +482,7 @@ extern void nfsd4_recdir_purge_old(void);
>  extern int nfsd4_create_clid_dir(struct nfs4_client *clp);
>  extern void nfsd4_remove_clid_dir(struct nfs4_client *clp);
>  extern void release_session_client(struct nfsd4_session *);
> +extern __be32 nfsd4_do_test_stateid(stateid_t *, int);
>  
>  static inline void
>  nfs4_put_stateowner(struct nfs4_stateowner *so)
> diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
> index ed1784d..02fb0e0 100644
> --- a/fs/nfsd/xdr4.h
> +++ b/fs/nfsd/xdr4.h
> @@ -342,6 +342,20 @@ struct nfsd4_setclientid_confirm {
>  	nfs4_verifier	sc_confirm;
>  };
>  
> +struct nfsd4_saved_compoundargs {
> +	__be32 *p;
> +	__be32 *end;
> +	int pagelen;
> +	struct page **pagelist;
> +};
> +
> +struct nfsd4_test_stateid {
> +	__be32		ts_num_ids;
> +	__be32		ts_has_session;
> +	struct nfsd4_compoundargs *ts_saved_args;
> +	struct nfsd4_saved_compoundargs ts_savedp;
> +};
> +
>  struct nfsd4_free_stateid {
>  	stateid_t	fr_stateid;         /* request */
>  	__be32		fr_status;          /* response */
> @@ -437,6 +451,7 @@ struct nfsd4_op {
>  		struct nfsd4_destroy_session	destroy_session;
>  		struct nfsd4_sequence		sequence;
>  		struct nfsd4_reclaim_complete	reclaim_complete;
> +		struct nfsd4_test_stateid	test_stateid;
>  		struct nfsd4_free_stateid	free_stateid;
>  	} u;
>  	struct nfs4_replay *			replay;
> @@ -570,6 +585,8 @@ extern __be32 nfsd4_delegreturn(struct svc_rqst *rqstp,
>  		struct nfsd4_compound_state *, struct nfsd4_delegreturn *dr);
>  extern __be32 nfsd4_renew(struct svc_rqst *rqstp,
>  			  struct nfsd4_compound_state *, clientid_t *clid);
> +extern __be32 nfsd4_test_stateid(struct svc_rqst *rqstp,
> +		struct nfsd4_compound_state *, struct nfsd4_test_stateid *test_stateid);
>  extern __be32 nfsd4_free_stateid(struct svc_rqst *rqstp,
>  		struct nfsd4_compound_state *, struct nfsd4_free_stateid *free_stateid);
>  #endif


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 2/2] NFSD: Added TEST_STATEID operation
  2011-06-29 19:49   ` Bryan Schumaker
@ 2011-06-29 19:54     ` J. Bruce Fields
  2011-06-29 20:34       ` Bryan Schumaker
  0 siblings, 1 reply; 18+ messages in thread
From: J. Bruce Fields @ 2011-06-29 19:54 UTC (permalink / raw)
  To: Bryan Schumaker; +Cc: linux-nfs

On Wed, Jun 29, 2011 at 03:49:10PM -0400, Bryan Schumaker wrote:
> On 05/20/2011 04:13 PM, bjschuma@netapp.com wrote:
> > +__be32
> > +nfsd4_do_test_stateid(stateid_t *stateid, int flags)
> > +{
> > +	__be32 ret = nfs4_validate_stateid(stateid, flags);
> > +	if (!ret)
> > +		ret = nfs4_validate_stateid(stateid, flags);
> > +	return ret;
> 
> Looking back at this, I'm not convinced that I need to call nfs4_validate_stateid() twice with the same stateid and flags.  What is the status of these patches?  Should I resubmit everything or send in a small patch to fix this?

Whoops, lazy review on my part....

Looks like I'd applied that locally but not pushed it out to my public
tree yet, so I could still take a replacement.

How are you testing these, by the way?  On second thoughts, I think I
may have already asked you that, and forgotten the answer, so don't
bother answering here--just add some text to the changelog and then I'll
know how to find the answer next time.

--b.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 2/2] NFSD: Added TEST_STATEID operation
  2011-06-29 19:54     ` J. Bruce Fields
@ 2011-06-29 20:34       ` Bryan Schumaker
  2011-06-29 20:40         ` J. Bruce Fields
  0 siblings, 1 reply; 18+ messages in thread
From: Bryan Schumaker @ 2011-06-29 20:34 UTC (permalink / raw)
  To: J. Bruce Fields; +Cc: linux-nfs

On 06/29/2011 03:54 PM, J. Bruce Fields wrote:
> On Wed, Jun 29, 2011 at 03:49:10PM -0400, Bryan Schumaker wrote:
>> On 05/20/2011 04:13 PM, bjschuma@netapp.com wrote:
>>> +__be32
>>> +nfsd4_do_test_stateid(stateid_t *stateid, int flags)
>>> +{
>>> +	__be32 ret = nfs4_validate_stateid(stateid, flags);
>>> +	if (!ret)
>>> +		ret = nfs4_validate_stateid(stateid, flags);
>>> +	return ret;
>>
>> Looking back at this, I'm not convinced that I need to call nfs4_validate_stateid() twice with the same stateid and flags.  What is the status of these patches?  Should I resubmit everything or send in a small patch to fix this?
> 
> Whoops, lazy review on my part....
> 
> Looks like I'd applied that locally but not pushed it out to my public
> tree yet, so I could still take a replacement.

Ok, sounds good.
> 
> How are you testing these, by the way?  On second thoughts, I think I
> may have already asked you that, and forgotten the answer, so don't
> bother answering here--just add some text to the changelog and then I'll
> know how to find the answer next time.

I found this as I was going through my fault injection code.  I'm going to double check these with my fault injection changes and then try to send in updates for both next week.

- Bryan

> 
> --b.


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 2/2] NFSD: Added TEST_STATEID operation
  2011-06-29 20:34       ` Bryan Schumaker
@ 2011-06-29 20:40         ` J. Bruce Fields
  2011-07-12 10:59           ` J. Bruce Fields
  0 siblings, 1 reply; 18+ messages in thread
From: J. Bruce Fields @ 2011-06-29 20:40 UTC (permalink / raw)
  To: Bryan Schumaker; +Cc: linux-nfs

On Wed, Jun 29, 2011 at 04:34:38PM -0400, Bryan Schumaker wrote:
> On 06/29/2011 03:54 PM, J. Bruce Fields wrote:
> > On Wed, Jun 29, 2011 at 03:49:10PM -0400, Bryan Schumaker wrote:
> >> On 05/20/2011 04:13 PM, bjschuma@netapp.com wrote:
> >>> +__be32
> >>> +nfsd4_do_test_stateid(stateid_t *stateid, int flags)
> >>> +{
> >>> +	__be32 ret = nfs4_validate_stateid(stateid, flags);
> >>> +	if (!ret)
> >>> +		ret = nfs4_validate_stateid(stateid, flags);
> >>> +	return ret;
> >>
> >> Looking back at this, I'm not convinced that I need to call nfs4_validate_stateid() twice with the same stateid and flags.  What is the status of these patches?  Should I resubmit everything or send in a small patch to fix this?
> > 
> > Whoops, lazy review on my part....
> > 
> > Looks like I'd applied that locally but not pushed it out to my public
> > tree yet, so I could still take a replacement.
> 
> Ok, sounds good.
> > 
> > How are you testing these, by the way?  On second thoughts, I think I
> > may have already asked you that, and forgotten the answer, so don't
> > bother answering here--just add some text to the changelog and then I'll
> > know how to find the answer next time.
> 
> I found this as I was going through my fault injection code.  I'm going to double check these with my fault injection changes and then try to send in updates for both next week.

Sounds good, thanks Bryan.--b.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 2/2] NFSD: Added TEST_STATEID operation
  2011-06-29 20:40         ` J. Bruce Fields
@ 2011-07-12 10:59           ` J. Bruce Fields
  2011-07-12 12:40             ` Bryan Schumaker
  0 siblings, 1 reply; 18+ messages in thread
From: J. Bruce Fields @ 2011-07-12 10:59 UTC (permalink / raw)
  To: Bryan Schumaker; +Cc: linux-nfs

On Wed, Jun 29, 2011 at 04:40:59PM -0400, J. Bruce Fields wrote:
> On Wed, Jun 29, 2011 at 04:34:38PM -0400, Bryan Schumaker wrote:
> > On 06/29/2011 03:54 PM, J. Bruce Fields wrote:
> > > On Wed, Jun 29, 2011 at 03:49:10PM -0400, Bryan Schumaker wrote:
> > >> On 05/20/2011 04:13 PM, bjschuma@netapp.com wrote:
> > >>> +__be32
> > >>> +nfsd4_do_test_stateid(stateid_t *stateid, int flags)
> > >>> +{
> > >>> +	__be32 ret = nfs4_validate_stateid(stateid, flags);
> > >>> +	if (!ret)
> > >>> +		ret = nfs4_validate_stateid(stateid, flags);
> > >>> +	return ret;
> > >>
> > >> Looking back at this, I'm not convinced that I need to call nfs4_validate_stateid() twice with the same stateid and flags.  What is the status of these patches?  Should I resubmit everything or send in a small patch to fix this?
> > > 
> > > Whoops, lazy review on my part....
> > > 
> > > Looks like I'd applied that locally but not pushed it out to my public
> > > tree yet, so I could still take a replacement.
> > 
> > Ok, sounds good.
> > > 
> > > How are you testing these, by the way?  On second thoughts, I think I
> > > may have already asked you that, and forgotten the answer, so don't
> > > bother answering here--just add some text to the changelog and then I'll
> > > know how to find the answer next time.
> > 
> > I found this as I was going through my fault injection code.  I'm going to double check these with my fault injection changes and then try to send in updates for both next week.
> 
> Sounds good, thanks Bryan.--b.

Are those still on the way?  (Or did you send and I missed them?  If so,
if you wouldn't mind resending....)

--b.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 2/2] NFSD: Added TEST_STATEID operation
  2011-07-12 10:59           ` J. Bruce Fields
@ 2011-07-12 12:40             ` Bryan Schumaker
  2011-07-12 12:42               ` J. Bruce Fields
  0 siblings, 1 reply; 18+ messages in thread
From: Bryan Schumaker @ 2011-07-12 12:40 UTC (permalink / raw)
  To: J. Bruce Fields; +Cc: linux-nfs

On 07/12/2011 06:59 AM, J. Bruce Fields wrote:
> On Wed, Jun 29, 2011 at 04:40:59PM -0400, J. Bruce Fields wrote:
>> On Wed, Jun 29, 2011 at 04:34:38PM -0400, Bryan Schumaker wrote:
>>> On 06/29/2011 03:54 PM, J. Bruce Fields wrote:
>>>> On Wed, Jun 29, 2011 at 03:49:10PM -0400, Bryan Schumaker wrote:
>>>>> On 05/20/2011 04:13 PM, bjschuma@netapp.com wrote:
>>>>>> +__be32
>>>>>> +nfsd4_do_test_stateid(stateid_t *stateid, int flags)
>>>>>> +{
>>>>>> +	__be32 ret = nfs4_validate_stateid(stateid, flags);
>>>>>> +	if (!ret)
>>>>>> +		ret = nfs4_validate_stateid(stateid, flags);
>>>>>> +	return ret;
>>>>>
>>>>> Looking back at this, I'm not convinced that I need to call nfs4_validate_stateid() twice with the same stateid and flags.  What is the status of these patches?  Should I resubmit everything or send in a small patch to fix this?
>>>>
>>>> Whoops, lazy review on my part....
>>>>
>>>> Looks like I'd applied that locally but not pushed it out to my public
>>>> tree yet, so I could still take a replacement.
>>>
>>> Ok, sounds good.
>>>>
>>>> How are you testing these, by the way?  On second thoughts, I think I
>>>> may have already asked you that, and forgotten the answer, so don't
>>>> bother answering here--just add some text to the changelog and then I'll
>>>> know how to find the answer next time.
>>>
>>> I found this as I was going through my fault injection code.  I'm going to double check these with my fault injection changes and then try to send in updates for both next week.
>>
>> Sounds good, thanks Bryan.--b.
> 
> Are those still on the way?  (Or did you send and I missed them?  If so,
> if you wouldn't mind resending....)

I sent them out last Friday.  I'll resend.

- Bryan
> 
> --b.


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 2/2] NFSD: Added TEST_STATEID operation
  2011-07-12 12:40             ` Bryan Schumaker
@ 2011-07-12 12:42               ` J. Bruce Fields
  0 siblings, 0 replies; 18+ messages in thread
From: J. Bruce Fields @ 2011-07-12 12:42 UTC (permalink / raw)
  To: Bryan Schumaker; +Cc: linux-nfs

On Tue, Jul 12, 2011 at 08:40:11AM -0400, Bryan Schumaker wrote:
> On 07/12/2011 06:59 AM, J. Bruce Fields wrote:
> > On Wed, Jun 29, 2011 at 04:40:59PM -0400, J. Bruce Fields wrote:
> >> On Wed, Jun 29, 2011 at 04:34:38PM -0400, Bryan Schumaker wrote:
> >>> On 06/29/2011 03:54 PM, J. Bruce Fields wrote:
> >>>> On Wed, Jun 29, 2011 at 03:49:10PM -0400, Bryan Schumaker wrote:
> >>>>> On 05/20/2011 04:13 PM, bjschuma@netapp.com wrote:
> >>>>>> +__be32
> >>>>>> +nfsd4_do_test_stateid(stateid_t *stateid, int flags)
> >>>>>> +{
> >>>>>> +	__be32 ret = nfs4_validate_stateid(stateid, flags);
> >>>>>> +	if (!ret)
> >>>>>> +		ret = nfs4_validate_stateid(stateid, flags);
> >>>>>> +	return ret;
> >>>>>
> >>>>> Looking back at this, I'm not convinced that I need to call nfs4_validate_stateid() twice with the same stateid and flags.  What is the status of these patches?  Should I resubmit everything or send in a small patch to fix this?
> >>>>
> >>>> Whoops, lazy review on my part....
> >>>>
> >>>> Looks like I'd applied that locally but not pushed it out to my public
> >>>> tree yet, so I could still take a replacement.
> >>>
> >>> Ok, sounds good.
> >>>>
> >>>> How are you testing these, by the way?  On second thoughts, I think I
> >>>> may have already asked you that, and forgotten the answer, so don't
> >>>> bother answering here--just add some text to the changelog and then I'll
> >>>> know how to find the answer next time.
> >>>
> >>> I found this as I was going through my fault injection code.  I'm going to double check these with my fault injection changes and then try to send in updates for both next week.
> >>
> >> Sounds good, thanks Bryan.--b.
> > 
> > Are those still on the way?  (Or did you send and I missed them?  If so,
> > if you wouldn't mind resending....)
> 
> I sent them out last Friday.  I'll resend.

Whoops, sorry about that--thanks for resending.--b.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 1/2] NFSD: added FREE_STATEID operation
  2011-05-11 14:41     ` Bryan Schumaker
@ 2011-05-13 21:36       ` J. Bruce Fields
  0 siblings, 0 replies; 18+ messages in thread
From: J. Bruce Fields @ 2011-05-13 21:36 UTC (permalink / raw)
  To: Bryan Schumaker; +Cc: linux-nfs

On Wed, May 11, 2011 at 10:41:01AM -0400, Bryan Schumaker wrote:
> On 05/09/2011 08:36 PM, J. Bruce Fields wrote:
> > On Fri, May 06, 2011 at 02:57:34PM -0400, bjschuma@netapp.com wrote:
> >> +		release_open_stateid(stp);
> > 
> > OK, but it might not be a lock stateid.  (I assume free_stateid can be
> > called on *any* kind of stateid?)
> 
> I thought release_open_stateid() freed all stateids, not just the lock stateid...

Lock stateid's are released by release_lock_stateid(), delegation
stateid's (actually embedded in a struct nfs4_delegation) by
unhash_delegation().

--b.

> 
> > 
> > --b.
> > 
> >> +	return nfs_ok;
> >> +}
> >> +
> >>  static inline int
> >>  setlkflg (int type)
> >>  {
> >> @@ -3619,6 +3653,28 @@ find_stateid(stateid_t *stid, int flags)
> >>  	return NULL;
> >>  }
> >>  
> >> +static struct nfs4_stateid *
> >> +search_for_stateid(stateid_t *stid)
> >> +{
> >> +	struct nfs4_stateid *local;
> >> +	u32 st_id = stid->si_stateownerid;
> >> +	u32 f_id  = stid->si_fileid;
> >> +	unsigned int hashval = stateid_hashval(st_id, f_id);
> >> +
> >> +	list_for_each_entry(local, &lockstateid_hashtbl[hashval], st_hash) {
> >> +		if ((local->st_stateid.si_stateownerid == st_id) &&
> >> +		    (local->st_stateid.si_fileid == f_id))
> >> +			return local;
> >> +	}
> >> +
> >> +	list_for_each_entry(local, &stateid_hashtbl[hashval], st_hash) {
> >> +		if ((local->st_stateid.si_stateownerid == st_id) &&
> >> +		    (local->st_stateid.si_fileid == f_id))
> >> +			return local;
> >> +	}
> >> +	return NULL;
> >> +}
> >> +
> >>  static struct nfs4_delegation *
> >>  find_delegation_stateid(struct inode *ino, stateid_t *stid)
> >>  {
> >> diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
> >> index 195a91d..5da6874 100644
> >> --- a/fs/nfsd/nfs4xdr.c
> >> +++ b/fs/nfsd/nfs4xdr.c
> >> @@ -1246,6 +1246,19 @@ nfsd4_decode_destroy_session(struct nfsd4_compoundargs *argp,
> >>  }
> >>  
> >>  static __be32
> >> +nfsd4_decode_free_stateid(struct nfsd4_compoundargs *argp,
> >> +			  struct nfsd4_free_stateid *free_stateid)
> >> +{
> >> +	DECODE_HEAD;
> >> +
> >> +	READ_BUF(sizeof(stateid_t));
> >> +	READ32(free_stateid->fr_stateid.si_generation);
> >> +	COPYMEM(&free_stateid->fr_stateid.si_opaque, sizeof(stateid_opaque_t));
> >> +
> >> +	DECODE_TAIL;
> >> +}
> >> +
> >> +static __be32
> >>  nfsd4_decode_sequence(struct nfsd4_compoundargs *argp,
> >>  		      struct nfsd4_sequence *seq)
> >>  {
> >> @@ -1370,7 +1383,7 @@ static nfsd4_dec nfsd41_dec_ops[] = {
> >>  	[OP_EXCHANGE_ID]	= (nfsd4_dec)nfsd4_decode_exchange_id,
> >>  	[OP_CREATE_SESSION]	= (nfsd4_dec)nfsd4_decode_create_session,
> >>  	[OP_DESTROY_SESSION]	= (nfsd4_dec)nfsd4_decode_destroy_session,
> >> -	[OP_FREE_STATEID]	= (nfsd4_dec)nfsd4_decode_notsupp,
> >> +	[OP_FREE_STATEID]	= (nfsd4_dec)nfsd4_decode_free_stateid,
> >>  	[OP_GET_DIR_DELEGATION]	= (nfsd4_dec)nfsd4_decode_notsupp,
> >>  	[OP_GETDEVICEINFO]	= (nfsd4_dec)nfsd4_decode_notsupp,
> >>  	[OP_GETDEVICELIST]	= (nfsd4_dec)nfsd4_decode_notsupp,
> >> @@ -3115,6 +3128,21 @@ nfsd4_encode_destroy_session(struct nfsd4_compoundres *resp, int nfserr,
> >>  	return nfserr;
> >>  }
> >>  
> >> +static __be32
> >> +nfsd4_encode_free_stateid(struct nfsd4_compoundres *resp, int nfserr,
> >> +			  struct nfsd4_free_stateid *free_stateid)
> >> +{
> >> +	__be32 *p;
> >> +
> >> +	if (nfserr)
> >> +		return nfserr;
> >> +
> >> +	RESERVE_SPACE(4);
> >> +	WRITE32(nfserr);
> >> +	ADJUST_ARGS();
> >> +	return nfserr;
> >> +}
> >> +
> >>  __be32
> >>  nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr,
> >>  		      struct nfsd4_sequence *seq)
> >> @@ -3196,7 +3224,7 @@ static nfsd4_enc nfsd4_enc_ops[] = {
> >>  	[OP_EXCHANGE_ID]	= (nfsd4_enc)nfsd4_encode_exchange_id,
> >>  	[OP_CREATE_SESSION]	= (nfsd4_enc)nfsd4_encode_create_session,
> >>  	[OP_DESTROY_SESSION]	= (nfsd4_enc)nfsd4_encode_destroy_session,
> >> -	[OP_FREE_STATEID]	= (nfsd4_enc)nfsd4_encode_noop,
> >> +	[OP_FREE_STATEID]	= (nfsd4_enc)nfsd4_encode_free_stateid,
> >>  	[OP_GET_DIR_DELEGATION]	= (nfsd4_enc)nfsd4_encode_noop,
> >>  	[OP_GETDEVICEINFO]	= (nfsd4_enc)nfsd4_encode_noop,
> >>  	[OP_GETDEVICELIST]	= (nfsd4_enc)nfsd4_encode_noop,
> >> diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
> >> index 366401e..ed1784d 100644
> >> --- a/fs/nfsd/xdr4.h
> >> +++ b/fs/nfsd/xdr4.h
> >> @@ -342,6 +342,11 @@ struct nfsd4_setclientid_confirm {
> >>  	nfs4_verifier	sc_confirm;
> >>  };
> >>  
> >> +struct nfsd4_free_stateid {
> >> +	stateid_t	fr_stateid;         /* request */
> >> +	__be32		fr_status;          /* response */
> >> +};
> >> +
> >>  /* also used for NVERIFY */
> >>  struct nfsd4_verify {
> >>  	u32		ve_bmval[3];        /* request */
> >> @@ -432,6 +437,7 @@ struct nfsd4_op {
> >>  		struct nfsd4_destroy_session	destroy_session;
> >>  		struct nfsd4_sequence		sequence;
> >>  		struct nfsd4_reclaim_complete	reclaim_complete;
> >> +		struct nfsd4_free_stateid	free_stateid;
> >>  	} u;
> >>  	struct nfs4_replay *			replay;
> >>  };
> >> @@ -564,6 +570,8 @@ extern __be32 nfsd4_delegreturn(struct svc_rqst *rqstp,
> >>  		struct nfsd4_compound_state *, struct nfsd4_delegreturn *dr);
> >>  extern __be32 nfsd4_renew(struct svc_rqst *rqstp,
> >>  			  struct nfsd4_compound_state *, clientid_t *clid);
> >> +extern __be32 nfsd4_free_stateid(struct svc_rqst *rqstp,
> >> +		struct nfsd4_compound_state *, struct nfsd4_free_stateid *free_stateid);
> >>  #endif
> >>  
> >>  /*
> >> -- 
> >> 1.7.5.1
> >>
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 1/2] NFSD: added FREE_STATEID operation
  2011-05-10  0:36   ` J. Bruce Fields
@ 2011-05-11 14:41     ` Bryan Schumaker
  2011-05-13 21:36       ` J. Bruce Fields
  0 siblings, 1 reply; 18+ messages in thread
From: Bryan Schumaker @ 2011-05-11 14:41 UTC (permalink / raw)
  To: J. Bruce Fields; +Cc: linux-nfs

On 05/09/2011 08:36 PM, J. Bruce Fields wrote:
> On Fri, May 06, 2011 at 02:57:34PM -0400, bjschuma@netapp.com wrote:
>> From: Bryan Schumaker <bjschuma@netapp.com>
>>
>> This operation is used by the client to tell the server to free a
>> stateid.
>>
>> Signed-off-by: Bryan Schumaker <bjschuma@netapp.com>
>> ---
>>  fs/nfsd/nfs4proc.c  |    5 ++++
>>  fs/nfsd/nfs4state.c |   56 +++++++++++++++++++++++++++++++++++++++++++++++++++
>>  fs/nfsd/nfs4xdr.c   |   32 +++++++++++++++++++++++++++-
>>  fs/nfsd/xdr4.h      |    8 +++++++
>>  4 files changed, 99 insertions(+), 2 deletions(-)
>>
>> diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
>> index 3a6dbd7..7e00116 100644
>> --- a/fs/nfsd/nfs4proc.c
>> +++ b/fs/nfsd/nfs4proc.c
>> @@ -1412,6 +1412,11 @@ static struct nfsd4_operation nfsd4_ops[] = {
>>  		.op_flags = OP_HANDLES_WRONGSEC,
>>  		.op_name = "OP_SECINFO_NO_NAME",
>>  	},
>> +	[OP_FREE_STATEID] = {
>> +		.op_func = (nfsd4op_func)nfsd4_free_stateid,
>> +		.op_flags = ALLOWED_WITHOUT_FH,
>> +		.op_name = "OP_FREE_STATEID",
>> +	},
>>  };
>>  
>>  static const char *nfsd4_op_name(unsigned opnum)
>> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
>> index a2ea14f..6beec13 100644
>> --- a/fs/nfsd/nfs4state.c
>> +++ b/fs/nfsd/nfs4state.c
>> @@ -60,6 +60,7 @@ static u64 current_sessionid = 1;
>>  
>>  /* forward declarations */
>>  static struct nfs4_stateid * find_stateid(stateid_t *stid, int flags);
>> +static struct nfs4_stateid * search_for_stateid(stateid_t *stid);
>>  static struct nfs4_delegation * find_delegation_stateid(struct inode *ino, stateid_t *stid);
>>  static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery";
>>  static void nfs4_set_recdir(char *recdir);
>> @@ -316,6 +317,12 @@ static struct list_head	unconf_id_hashtbl[CLIENT_HASH_SIZE];
>>  static struct list_head client_lru;
>>  static struct list_head close_lru;
>>  
>> +static int
>> +stateid_has_locks(struct nfs4_stateid *stp)
>> +{
>> +	return list_empty(&stp->st_lockowners);
>> +}
> 
> There may be lockowners that aren't associated with any current locks.
> 
> The only way we have to check this currently is to walk through the
> i_flock list for the given inode, like check_for_locks() does.  That may
> be the expedient thing to do for now.

Ok, I'll change it to use check_for_locks() for now.

> 
> (It would be simpler if we could, say, keep a count of the locks
> associated with each lock stateid.  That's not as easy as it sounds,
> thanks to merging and splitting of byte-range locks.  But we could use
> callbacks from locks.c to do it.  I think that's what I'd really like to
> do.)
> 
>> +
>>  /*
>>   * We store the NONE, READ, WRITE, and BOTH bits separately in the
>>   * st_{access,deny}_bmap field of the stateid, in order to track not
>> @@ -3212,6 +3219,33 @@ out:
>>  	return status;
>>  }
>>  
>> +/*
>> + * Free a state id
>> + */
>> +__be32
>> +nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
>> +		   struct nfsd4_free_stateid *free_stateid)
>> +{
>> +	struct nfs4_stateid *stp = NULL;
>> +	stateid_t *stateid = &free_stateid->fr_stateid;
>> +
>> +	stp = search_for_stateid(stateid);
>> +	if (!stp)
>> +		return nfserr_bad_stateid;
>> +	if (stateid->si_generation != 0) {
>> +		if (stateid->si_generation < stp->st_stateid.si_generation)
>> +			return nfserr_old_stateid;
>> +		if (stateid->si_generation > stp->st_stateid.si_generation)
>> +			return nfserr_bad_stateid;
>> +	}
>> +
>> +	if (stateid_has_locks(stp))
>> +		return nfserr_locks_held;
>> +	if (stp)
> 
> Already checked this above.

Good catch, I'll remove the extra check.

> 
>> +		release_open_stateid(stp);
> 
> OK, but it might not be a lock stateid.  (I assume free_stateid can be
> called on *any* kind of stateid?)

I thought release_open_stateid() freed all stateids, not just the lock stateid...

> 
> --b.
> 
>> +	return nfs_ok;
>> +}
>> +
>>  static inline int
>>  setlkflg (int type)
>>  {
>> @@ -3619,6 +3653,28 @@ find_stateid(stateid_t *stid, int flags)
>>  	return NULL;
>>  }
>>  
>> +static struct nfs4_stateid *
>> +search_for_stateid(stateid_t *stid)
>> +{
>> +	struct nfs4_stateid *local;
>> +	u32 st_id = stid->si_stateownerid;
>> +	u32 f_id  = stid->si_fileid;
>> +	unsigned int hashval = stateid_hashval(st_id, f_id);
>> +
>> +	list_for_each_entry(local, &lockstateid_hashtbl[hashval], st_hash) {
>> +		if ((local->st_stateid.si_stateownerid == st_id) &&
>> +		    (local->st_stateid.si_fileid == f_id))
>> +			return local;
>> +	}
>> +
>> +	list_for_each_entry(local, &stateid_hashtbl[hashval], st_hash) {
>> +		if ((local->st_stateid.si_stateownerid == st_id) &&
>> +		    (local->st_stateid.si_fileid == f_id))
>> +			return local;
>> +	}
>> +	return NULL;
>> +}
>> +
>>  static struct nfs4_delegation *
>>  find_delegation_stateid(struct inode *ino, stateid_t *stid)
>>  {
>> diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
>> index 195a91d..5da6874 100644
>> --- a/fs/nfsd/nfs4xdr.c
>> +++ b/fs/nfsd/nfs4xdr.c
>> @@ -1246,6 +1246,19 @@ nfsd4_decode_destroy_session(struct nfsd4_compoundargs *argp,
>>  }
>>  
>>  static __be32
>> +nfsd4_decode_free_stateid(struct nfsd4_compoundargs *argp,
>> +			  struct nfsd4_free_stateid *free_stateid)
>> +{
>> +	DECODE_HEAD;
>> +
>> +	READ_BUF(sizeof(stateid_t));
>> +	READ32(free_stateid->fr_stateid.si_generation);
>> +	COPYMEM(&free_stateid->fr_stateid.si_opaque, sizeof(stateid_opaque_t));
>> +
>> +	DECODE_TAIL;
>> +}
>> +
>> +static __be32
>>  nfsd4_decode_sequence(struct nfsd4_compoundargs *argp,
>>  		      struct nfsd4_sequence *seq)
>>  {
>> @@ -1370,7 +1383,7 @@ static nfsd4_dec nfsd41_dec_ops[] = {
>>  	[OP_EXCHANGE_ID]	= (nfsd4_dec)nfsd4_decode_exchange_id,
>>  	[OP_CREATE_SESSION]	= (nfsd4_dec)nfsd4_decode_create_session,
>>  	[OP_DESTROY_SESSION]	= (nfsd4_dec)nfsd4_decode_destroy_session,
>> -	[OP_FREE_STATEID]	= (nfsd4_dec)nfsd4_decode_notsupp,
>> +	[OP_FREE_STATEID]	= (nfsd4_dec)nfsd4_decode_free_stateid,
>>  	[OP_GET_DIR_DELEGATION]	= (nfsd4_dec)nfsd4_decode_notsupp,
>>  	[OP_GETDEVICEINFO]	= (nfsd4_dec)nfsd4_decode_notsupp,
>>  	[OP_GETDEVICELIST]	= (nfsd4_dec)nfsd4_decode_notsupp,
>> @@ -3115,6 +3128,21 @@ nfsd4_encode_destroy_session(struct nfsd4_compoundres *resp, int nfserr,
>>  	return nfserr;
>>  }
>>  
>> +static __be32
>> +nfsd4_encode_free_stateid(struct nfsd4_compoundres *resp, int nfserr,
>> +			  struct nfsd4_free_stateid *free_stateid)
>> +{
>> +	__be32 *p;
>> +
>> +	if (nfserr)
>> +		return nfserr;
>> +
>> +	RESERVE_SPACE(4);
>> +	WRITE32(nfserr);
>> +	ADJUST_ARGS();
>> +	return nfserr;
>> +}
>> +
>>  __be32
>>  nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr,
>>  		      struct nfsd4_sequence *seq)
>> @@ -3196,7 +3224,7 @@ static nfsd4_enc nfsd4_enc_ops[] = {
>>  	[OP_EXCHANGE_ID]	= (nfsd4_enc)nfsd4_encode_exchange_id,
>>  	[OP_CREATE_SESSION]	= (nfsd4_enc)nfsd4_encode_create_session,
>>  	[OP_DESTROY_SESSION]	= (nfsd4_enc)nfsd4_encode_destroy_session,
>> -	[OP_FREE_STATEID]	= (nfsd4_enc)nfsd4_encode_noop,
>> +	[OP_FREE_STATEID]	= (nfsd4_enc)nfsd4_encode_free_stateid,
>>  	[OP_GET_DIR_DELEGATION]	= (nfsd4_enc)nfsd4_encode_noop,
>>  	[OP_GETDEVICEINFO]	= (nfsd4_enc)nfsd4_encode_noop,
>>  	[OP_GETDEVICELIST]	= (nfsd4_enc)nfsd4_encode_noop,
>> diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
>> index 366401e..ed1784d 100644
>> --- a/fs/nfsd/xdr4.h
>> +++ b/fs/nfsd/xdr4.h
>> @@ -342,6 +342,11 @@ struct nfsd4_setclientid_confirm {
>>  	nfs4_verifier	sc_confirm;
>>  };
>>  
>> +struct nfsd4_free_stateid {
>> +	stateid_t	fr_stateid;         /* request */
>> +	__be32		fr_status;          /* response */
>> +};
>> +
>>  /* also used for NVERIFY */
>>  struct nfsd4_verify {
>>  	u32		ve_bmval[3];        /* request */
>> @@ -432,6 +437,7 @@ struct nfsd4_op {
>>  		struct nfsd4_destroy_session	destroy_session;
>>  		struct nfsd4_sequence		sequence;
>>  		struct nfsd4_reclaim_complete	reclaim_complete;
>> +		struct nfsd4_free_stateid	free_stateid;
>>  	} u;
>>  	struct nfs4_replay *			replay;
>>  };
>> @@ -564,6 +570,8 @@ extern __be32 nfsd4_delegreturn(struct svc_rqst *rqstp,
>>  		struct nfsd4_compound_state *, struct nfsd4_delegreturn *dr);
>>  extern __be32 nfsd4_renew(struct svc_rqst *rqstp,
>>  			  struct nfsd4_compound_state *, clientid_t *clid);
>> +extern __be32 nfsd4_free_stateid(struct svc_rqst *rqstp,
>> +		struct nfsd4_compound_state *, struct nfsd4_free_stateid *free_stateid);
>>  #endif
>>  
>>  /*
>> -- 
>> 1.7.5.1
>>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 1/2] NFSD: added FREE_STATEID operation
  2011-05-06 18:57 ` [PATCH 1/2] NFSD: added FREE_STATEID operation bjschuma
@ 2011-05-10  0:36   ` J. Bruce Fields
  2011-05-11 14:41     ` Bryan Schumaker
  0 siblings, 1 reply; 18+ messages in thread
From: J. Bruce Fields @ 2011-05-10  0:36 UTC (permalink / raw)
  To: bjschuma; +Cc: linux-nfs

On Fri, May 06, 2011 at 02:57:34PM -0400, bjschuma@netapp.com wrote:
> From: Bryan Schumaker <bjschuma@netapp.com>
> 
> This operation is used by the client to tell the server to free a
> stateid.
> 
> Signed-off-by: Bryan Schumaker <bjschuma@netapp.com>
> ---
>  fs/nfsd/nfs4proc.c  |    5 ++++
>  fs/nfsd/nfs4state.c |   56 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  fs/nfsd/nfs4xdr.c   |   32 +++++++++++++++++++++++++++-
>  fs/nfsd/xdr4.h      |    8 +++++++
>  4 files changed, 99 insertions(+), 2 deletions(-)
> 
> diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
> index 3a6dbd7..7e00116 100644
> --- a/fs/nfsd/nfs4proc.c
> +++ b/fs/nfsd/nfs4proc.c
> @@ -1412,6 +1412,11 @@ static struct nfsd4_operation nfsd4_ops[] = {
>  		.op_flags = OP_HANDLES_WRONGSEC,
>  		.op_name = "OP_SECINFO_NO_NAME",
>  	},
> +	[OP_FREE_STATEID] = {
> +		.op_func = (nfsd4op_func)nfsd4_free_stateid,
> +		.op_flags = ALLOWED_WITHOUT_FH,
> +		.op_name = "OP_FREE_STATEID",
> +	},
>  };
>  
>  static const char *nfsd4_op_name(unsigned opnum)
> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> index a2ea14f..6beec13 100644
> --- a/fs/nfsd/nfs4state.c
> +++ b/fs/nfsd/nfs4state.c
> @@ -60,6 +60,7 @@ static u64 current_sessionid = 1;
>  
>  /* forward declarations */
>  static struct nfs4_stateid * find_stateid(stateid_t *stid, int flags);
> +static struct nfs4_stateid * search_for_stateid(stateid_t *stid);
>  static struct nfs4_delegation * find_delegation_stateid(struct inode *ino, stateid_t *stid);
>  static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery";
>  static void nfs4_set_recdir(char *recdir);
> @@ -316,6 +317,12 @@ static struct list_head	unconf_id_hashtbl[CLIENT_HASH_SIZE];
>  static struct list_head client_lru;
>  static struct list_head close_lru;
>  
> +static int
> +stateid_has_locks(struct nfs4_stateid *stp)
> +{
> +	return list_empty(&stp->st_lockowners);
> +}

There may be lockowners that aren't associated with any current locks.

The only way we have to check this currently is to walk through the
i_flock list for the given inode, like check_for_locks() does.  That may
be the expedient thing to do for now.

(It would be simpler if we could, say, keep a count of the locks
associated with each lock stateid.  That's not as easy as it sounds,
thanks to merging and splitting of byte-range locks.  But we could use
callbacks from locks.c to do it.  I think that's what I'd really like to
do.)

> +
>  /*
>   * We store the NONE, READ, WRITE, and BOTH bits separately in the
>   * st_{access,deny}_bmap field of the stateid, in order to track not
> @@ -3212,6 +3219,33 @@ out:
>  	return status;
>  }
>  
> +/*
> + * Free a state id
> + */
> +__be32
> +nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
> +		   struct nfsd4_free_stateid *free_stateid)
> +{
> +	struct nfs4_stateid *stp = NULL;
> +	stateid_t *stateid = &free_stateid->fr_stateid;
> +
> +	stp = search_for_stateid(stateid);
> +	if (!stp)
> +		return nfserr_bad_stateid;
> +	if (stateid->si_generation != 0) {
> +		if (stateid->si_generation < stp->st_stateid.si_generation)
> +			return nfserr_old_stateid;
> +		if (stateid->si_generation > stp->st_stateid.si_generation)
> +			return nfserr_bad_stateid;
> +	}
> +
> +	if (stateid_has_locks(stp))
> +		return nfserr_locks_held;
> +	if (stp)

Already checked this above.

> +		release_open_stateid(stp);

OK, but it might not be a lock stateid.  (I assume free_stateid can be
called on *any* kind of stateid?)

--b.

> +	return nfs_ok;
> +}
> +
>  static inline int
>  setlkflg (int type)
>  {
> @@ -3619,6 +3653,28 @@ find_stateid(stateid_t *stid, int flags)
>  	return NULL;
>  }
>  
> +static struct nfs4_stateid *
> +search_for_stateid(stateid_t *stid)
> +{
> +	struct nfs4_stateid *local;
> +	u32 st_id = stid->si_stateownerid;
> +	u32 f_id  = stid->si_fileid;
> +	unsigned int hashval = stateid_hashval(st_id, f_id);
> +
> +	list_for_each_entry(local, &lockstateid_hashtbl[hashval], st_hash) {
> +		if ((local->st_stateid.si_stateownerid == st_id) &&
> +		    (local->st_stateid.si_fileid == f_id))
> +			return local;
> +	}
> +
> +	list_for_each_entry(local, &stateid_hashtbl[hashval], st_hash) {
> +		if ((local->st_stateid.si_stateownerid == st_id) &&
> +		    (local->st_stateid.si_fileid == f_id))
> +			return local;
> +	}
> +	return NULL;
> +}
> +
>  static struct nfs4_delegation *
>  find_delegation_stateid(struct inode *ino, stateid_t *stid)
>  {
> diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
> index 195a91d..5da6874 100644
> --- a/fs/nfsd/nfs4xdr.c
> +++ b/fs/nfsd/nfs4xdr.c
> @@ -1246,6 +1246,19 @@ nfsd4_decode_destroy_session(struct nfsd4_compoundargs *argp,
>  }
>  
>  static __be32
> +nfsd4_decode_free_stateid(struct nfsd4_compoundargs *argp,
> +			  struct nfsd4_free_stateid *free_stateid)
> +{
> +	DECODE_HEAD;
> +
> +	READ_BUF(sizeof(stateid_t));
> +	READ32(free_stateid->fr_stateid.si_generation);
> +	COPYMEM(&free_stateid->fr_stateid.si_opaque, sizeof(stateid_opaque_t));
> +
> +	DECODE_TAIL;
> +}
> +
> +static __be32
>  nfsd4_decode_sequence(struct nfsd4_compoundargs *argp,
>  		      struct nfsd4_sequence *seq)
>  {
> @@ -1370,7 +1383,7 @@ static nfsd4_dec nfsd41_dec_ops[] = {
>  	[OP_EXCHANGE_ID]	= (nfsd4_dec)nfsd4_decode_exchange_id,
>  	[OP_CREATE_SESSION]	= (nfsd4_dec)nfsd4_decode_create_session,
>  	[OP_DESTROY_SESSION]	= (nfsd4_dec)nfsd4_decode_destroy_session,
> -	[OP_FREE_STATEID]	= (nfsd4_dec)nfsd4_decode_notsupp,
> +	[OP_FREE_STATEID]	= (nfsd4_dec)nfsd4_decode_free_stateid,
>  	[OP_GET_DIR_DELEGATION]	= (nfsd4_dec)nfsd4_decode_notsupp,
>  	[OP_GETDEVICEINFO]	= (nfsd4_dec)nfsd4_decode_notsupp,
>  	[OP_GETDEVICELIST]	= (nfsd4_dec)nfsd4_decode_notsupp,
> @@ -3115,6 +3128,21 @@ nfsd4_encode_destroy_session(struct nfsd4_compoundres *resp, int nfserr,
>  	return nfserr;
>  }
>  
> +static __be32
> +nfsd4_encode_free_stateid(struct nfsd4_compoundres *resp, int nfserr,
> +			  struct nfsd4_free_stateid *free_stateid)
> +{
> +	__be32 *p;
> +
> +	if (nfserr)
> +		return nfserr;
> +
> +	RESERVE_SPACE(4);
> +	WRITE32(nfserr);
> +	ADJUST_ARGS();
> +	return nfserr;
> +}
> +
>  __be32
>  nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr,
>  		      struct nfsd4_sequence *seq)
> @@ -3196,7 +3224,7 @@ static nfsd4_enc nfsd4_enc_ops[] = {
>  	[OP_EXCHANGE_ID]	= (nfsd4_enc)nfsd4_encode_exchange_id,
>  	[OP_CREATE_SESSION]	= (nfsd4_enc)nfsd4_encode_create_session,
>  	[OP_DESTROY_SESSION]	= (nfsd4_enc)nfsd4_encode_destroy_session,
> -	[OP_FREE_STATEID]	= (nfsd4_enc)nfsd4_encode_noop,
> +	[OP_FREE_STATEID]	= (nfsd4_enc)nfsd4_encode_free_stateid,
>  	[OP_GET_DIR_DELEGATION]	= (nfsd4_enc)nfsd4_encode_noop,
>  	[OP_GETDEVICEINFO]	= (nfsd4_enc)nfsd4_encode_noop,
>  	[OP_GETDEVICELIST]	= (nfsd4_enc)nfsd4_encode_noop,
> diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
> index 366401e..ed1784d 100644
> --- a/fs/nfsd/xdr4.h
> +++ b/fs/nfsd/xdr4.h
> @@ -342,6 +342,11 @@ struct nfsd4_setclientid_confirm {
>  	nfs4_verifier	sc_confirm;
>  };
>  
> +struct nfsd4_free_stateid {
> +	stateid_t	fr_stateid;         /* request */
> +	__be32		fr_status;          /* response */
> +};
> +
>  /* also used for NVERIFY */
>  struct nfsd4_verify {
>  	u32		ve_bmval[3];        /* request */
> @@ -432,6 +437,7 @@ struct nfsd4_op {
>  		struct nfsd4_destroy_session	destroy_session;
>  		struct nfsd4_sequence		sequence;
>  		struct nfsd4_reclaim_complete	reclaim_complete;
> +		struct nfsd4_free_stateid	free_stateid;
>  	} u;
>  	struct nfs4_replay *			replay;
>  };
> @@ -564,6 +570,8 @@ extern __be32 nfsd4_delegreturn(struct svc_rqst *rqstp,
>  		struct nfsd4_compound_state *, struct nfsd4_delegreturn *dr);
>  extern __be32 nfsd4_renew(struct svc_rqst *rqstp,
>  			  struct nfsd4_compound_state *, clientid_t *clid);
> +extern __be32 nfsd4_free_stateid(struct svc_rqst *rqstp,
> +		struct nfsd4_compound_state *, struct nfsd4_free_stateid *free_stateid);
>  #endif
>  
>  /*
> -- 
> 1.7.5.1
> 

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH 1/2] NFSD: added FREE_STATEID operation
  2011-05-06 18:57 [PATCH " bjschuma
@ 2011-05-06 18:57 ` bjschuma
  2011-05-10  0:36   ` J. Bruce Fields
  0 siblings, 1 reply; 18+ messages in thread
From: bjschuma @ 2011-05-06 18:57 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Bryan Schumaker

From: Bryan Schumaker <bjschuma@netapp.com>

This operation is used by the client to tell the server to free a
stateid.

Signed-off-by: Bryan Schumaker <bjschuma@netapp.com>
---
 fs/nfsd/nfs4proc.c  |    5 ++++
 fs/nfsd/nfs4state.c |   56 +++++++++++++++++++++++++++++++++++++++++++++++++++
 fs/nfsd/nfs4xdr.c   |   32 +++++++++++++++++++++++++++-
 fs/nfsd/xdr4.h      |    8 +++++++
 4 files changed, 99 insertions(+), 2 deletions(-)

diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 3a6dbd7..7e00116 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -1412,6 +1412,11 @@ static struct nfsd4_operation nfsd4_ops[] = {
 		.op_flags = OP_HANDLES_WRONGSEC,
 		.op_name = "OP_SECINFO_NO_NAME",
 	},
+	[OP_FREE_STATEID] = {
+		.op_func = (nfsd4op_func)nfsd4_free_stateid,
+		.op_flags = ALLOWED_WITHOUT_FH,
+		.op_name = "OP_FREE_STATEID",
+	},
 };
 
 static const char *nfsd4_op_name(unsigned opnum)
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index a2ea14f..6beec13 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -60,6 +60,7 @@ static u64 current_sessionid = 1;
 
 /* forward declarations */
 static struct nfs4_stateid * find_stateid(stateid_t *stid, int flags);
+static struct nfs4_stateid * search_for_stateid(stateid_t *stid);
 static struct nfs4_delegation * find_delegation_stateid(struct inode *ino, stateid_t *stid);
 static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery";
 static void nfs4_set_recdir(char *recdir);
@@ -316,6 +317,12 @@ static struct list_head	unconf_id_hashtbl[CLIENT_HASH_SIZE];
 static struct list_head client_lru;
 static struct list_head close_lru;
 
+static int
+stateid_has_locks(struct nfs4_stateid *stp)
+{
+	return list_empty(&stp->st_lockowners);
+}
+
 /*
  * We store the NONE, READ, WRITE, and BOTH bits separately in the
  * st_{access,deny}_bmap field of the stateid, in order to track not
@@ -3212,6 +3219,33 @@ out:
 	return status;
 }
 
+/*
+ * Free a state id
+ */
+__be32
+nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+		   struct nfsd4_free_stateid *free_stateid)
+{
+	struct nfs4_stateid *stp = NULL;
+	stateid_t *stateid = &free_stateid->fr_stateid;
+
+	stp = search_for_stateid(stateid);
+	if (!stp)
+		return nfserr_bad_stateid;
+	if (stateid->si_generation != 0) {
+		if (stateid->si_generation < stp->st_stateid.si_generation)
+			return nfserr_old_stateid;
+		if (stateid->si_generation > stp->st_stateid.si_generation)
+			return nfserr_bad_stateid;
+	}
+
+	if (stateid_has_locks(stp))
+		return nfserr_locks_held;
+	if (stp)
+		release_open_stateid(stp);
+	return nfs_ok;
+}
+
 static inline int
 setlkflg (int type)
 {
@@ -3619,6 +3653,28 @@ find_stateid(stateid_t *stid, int flags)
 	return NULL;
 }
 
+static struct nfs4_stateid *
+search_for_stateid(stateid_t *stid)
+{
+	struct nfs4_stateid *local;
+	u32 st_id = stid->si_stateownerid;
+	u32 f_id  = stid->si_fileid;
+	unsigned int hashval = stateid_hashval(st_id, f_id);
+
+	list_for_each_entry(local, &lockstateid_hashtbl[hashval], st_hash) {
+		if ((local->st_stateid.si_stateownerid == st_id) &&
+		    (local->st_stateid.si_fileid == f_id))
+			return local;
+	}
+
+	list_for_each_entry(local, &stateid_hashtbl[hashval], st_hash) {
+		if ((local->st_stateid.si_stateownerid == st_id) &&
+		    (local->st_stateid.si_fileid == f_id))
+			return local;
+	}
+	return NULL;
+}
+
 static struct nfs4_delegation *
 find_delegation_stateid(struct inode *ino, stateid_t *stid)
 {
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 195a91d..5da6874 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -1246,6 +1246,19 @@ nfsd4_decode_destroy_session(struct nfsd4_compoundargs *argp,
 }
 
 static __be32
+nfsd4_decode_free_stateid(struct nfsd4_compoundargs *argp,
+			  struct nfsd4_free_stateid *free_stateid)
+{
+	DECODE_HEAD;
+
+	READ_BUF(sizeof(stateid_t));
+	READ32(free_stateid->fr_stateid.si_generation);
+	COPYMEM(&free_stateid->fr_stateid.si_opaque, sizeof(stateid_opaque_t));
+
+	DECODE_TAIL;
+}
+
+static __be32
 nfsd4_decode_sequence(struct nfsd4_compoundargs *argp,
 		      struct nfsd4_sequence *seq)
 {
@@ -1370,7 +1383,7 @@ static nfsd4_dec nfsd41_dec_ops[] = {
 	[OP_EXCHANGE_ID]	= (nfsd4_dec)nfsd4_decode_exchange_id,
 	[OP_CREATE_SESSION]	= (nfsd4_dec)nfsd4_decode_create_session,
 	[OP_DESTROY_SESSION]	= (nfsd4_dec)nfsd4_decode_destroy_session,
-	[OP_FREE_STATEID]	= (nfsd4_dec)nfsd4_decode_notsupp,
+	[OP_FREE_STATEID]	= (nfsd4_dec)nfsd4_decode_free_stateid,
 	[OP_GET_DIR_DELEGATION]	= (nfsd4_dec)nfsd4_decode_notsupp,
 	[OP_GETDEVICEINFO]	= (nfsd4_dec)nfsd4_decode_notsupp,
 	[OP_GETDEVICELIST]	= (nfsd4_dec)nfsd4_decode_notsupp,
@@ -3115,6 +3128,21 @@ nfsd4_encode_destroy_session(struct nfsd4_compoundres *resp, int nfserr,
 	return nfserr;
 }
 
+static __be32
+nfsd4_encode_free_stateid(struct nfsd4_compoundres *resp, int nfserr,
+			  struct nfsd4_free_stateid *free_stateid)
+{
+	__be32 *p;
+
+	if (nfserr)
+		return nfserr;
+
+	RESERVE_SPACE(4);
+	WRITE32(nfserr);
+	ADJUST_ARGS();
+	return nfserr;
+}
+
 __be32
 nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr,
 		      struct nfsd4_sequence *seq)
@@ -3196,7 +3224,7 @@ static nfsd4_enc nfsd4_enc_ops[] = {
 	[OP_EXCHANGE_ID]	= (nfsd4_enc)nfsd4_encode_exchange_id,
 	[OP_CREATE_SESSION]	= (nfsd4_enc)nfsd4_encode_create_session,
 	[OP_DESTROY_SESSION]	= (nfsd4_enc)nfsd4_encode_destroy_session,
-	[OP_FREE_STATEID]	= (nfsd4_enc)nfsd4_encode_noop,
+	[OP_FREE_STATEID]	= (nfsd4_enc)nfsd4_encode_free_stateid,
 	[OP_GET_DIR_DELEGATION]	= (nfsd4_enc)nfsd4_encode_noop,
 	[OP_GETDEVICEINFO]	= (nfsd4_enc)nfsd4_encode_noop,
 	[OP_GETDEVICELIST]	= (nfsd4_enc)nfsd4_encode_noop,
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
index 366401e..ed1784d 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -342,6 +342,11 @@ struct nfsd4_setclientid_confirm {
 	nfs4_verifier	sc_confirm;
 };
 
+struct nfsd4_free_stateid {
+	stateid_t	fr_stateid;         /* request */
+	__be32		fr_status;          /* response */
+};
+
 /* also used for NVERIFY */
 struct nfsd4_verify {
 	u32		ve_bmval[3];        /* request */
@@ -432,6 +437,7 @@ struct nfsd4_op {
 		struct nfsd4_destroy_session	destroy_session;
 		struct nfsd4_sequence		sequence;
 		struct nfsd4_reclaim_complete	reclaim_complete;
+		struct nfsd4_free_stateid	free_stateid;
 	} u;
 	struct nfs4_replay *			replay;
 };
@@ -564,6 +570,8 @@ extern __be32 nfsd4_delegreturn(struct svc_rqst *rqstp,
 		struct nfsd4_compound_state *, struct nfsd4_delegreturn *dr);
 extern __be32 nfsd4_renew(struct svc_rqst *rqstp,
 			  struct nfsd4_compound_state *, clientid_t *clid);
+extern __be32 nfsd4_free_stateid(struct svc_rqst *rqstp,
+		struct nfsd4_compound_state *, struct nfsd4_free_stateid *free_stateid);
 #endif
 
 /*
-- 
1.7.5.1


^ permalink raw reply related	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2011-07-12 12:42 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-05-20 20:12 [PATCH v2 0/2] NFSD: add FREE_STATEID and TEST_STATEID operations bjschuma
2011-05-20 20:12 ` [PATCH 1/2] NFSD: added FREE_STATEID operation bjschuma
2011-05-20 20:16   ` Bryan Schumaker
2011-05-25 15:05     ` J. Bruce Fields
2011-05-31 14:52       ` Bryan Schumaker
2011-05-20 20:13 ` [PATCH 2/2] NFSD: Added TEST_STATEID operation bjschuma
2011-06-29 19:49   ` Bryan Schumaker
2011-06-29 19:54     ` J. Bruce Fields
2011-06-29 20:34       ` Bryan Schumaker
2011-06-29 20:40         ` J. Bruce Fields
2011-07-12 10:59           ` J. Bruce Fields
2011-07-12 12:40             ` Bryan Schumaker
2011-07-12 12:42               ` J. Bruce Fields
2011-05-20 20:13 ` [PATCH v2 0/2] NFSD: add FREE_STATEID and TEST_STATEID operations Bryan Schumaker
  -- strict thread matches above, loose matches on Subject: below --
2011-05-06 18:57 [PATCH " bjschuma
2011-05-06 18:57 ` [PATCH 1/2] NFSD: added FREE_STATEID operation bjschuma
2011-05-10  0:36   ` J. Bruce Fields
2011-05-11 14:41     ` Bryan Schumaker
2011-05-13 21:36       ` J. Bruce Fields

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.