All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/70] NFSd lock scalability patches
@ 2014-04-18 18:43 Trond Myklebust
  2014-04-18 18:43 ` [PATCH 01/70] NFSd: Ensure we clear the cstate->slot in nfsd4_proc_compound Trond Myklebust
                   ` (3 more replies)
  0 siblings, 4 replies; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:43 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

Hi Bruce,

In accordance with the traditional Good Friday theme of "suffering", here
is the first draft of the NFSd lock scalability patches for your perusal.
I've only done light testing so far, but since there is a total of 70
patches to review, I figured you might want to start sooner rather than
waiting for the QA folks to finish testing.

During the process, I did notice a bug or two in the existing NFSd code,
and so the first 3 patches are bugfixes that you may want to apply
irrespectively.

In general, what I've tried to do is add reference counting wherever
there is a need to carry structures around outside locks, and to
ensure that we make structures invisible to lookups before we attempt
to free them.

There are still a few optimisations that might be worth considering in
order to reduce the frequency of global locks that are taken. Suggestions
include:
1) Caching the nfs4_client in the struct nfsd4_compound_state
2) Caching the current/save_stateid as references to the actual nfs4_stid in the struct nfsd4_compound_state
3) Converting the stateid/sessionid/clientid global table lookups to use RCU.
4) Converting the file_hashtbl lookups to use RCU

Cheers
  Trond

Benny Halevy (4):
  nfsd4: rename recall_lock to state_lock
  nfsd4: use cl_lock to synchronize all stateid idr calls
  nfsd4: hash deleg stateid only on successful nfs4_set_delegation
  nfsd4: use state_lock for delegation hashing

Trond Myklebust (66):
  NFSd: Ensure we clear the cstate->slot in nfsd4_proc_compound
  NFSd: Move default initialisers from create_client() to alloc_client()
  NFSd: call rpc_destroy_wait_queue() from free_client()
  NFSd: Remove 'inline' designation for free_client()
  NFSd: Mark nfs4_free_lockowner and nfs4_free_openowner as static
    functions
  NFSd: Avoid taking state_lock while holding inode lock in
    nfsd_break_one_deleg
  NFSd: Ensure delegation setup is safe w.r.t. break_lease()
  NFSd: Add fine grained protection for the nfs4_file->fi_stateids list
  NFSd: Clean up nfs4_preprocess_stateid_op
  NFSd: Add a mutex to protect the NFSv4.0 open owner replay cache
  NFSd: Add locking to the nfs4_file->fi_fds[] array
  NFSd: Protect the nfs4_file delegation fields using the fi_lock
  NFSd: Lock owners are not per open stateid
  NFSd: Clean up helper __release_lock_stateid
  NFSd: Allow lockowners to hold several stateids
  NFSd: NFSv4 lock-owners are not associated to a specific file
  NFSd: Get rid of the lockowner_ino_hashtbl
  NFSd: Cleanup nfs4svc_encode_compoundres
  NFSd: Don't get a session reference without a client reference
  NFSd: Move the delegation reference counter into the struct nfs4_stid
  NFSd: Simplify stateid management
  NFSd: Fix delegation revocation
  NFSd: Don't let the laundromat reap clients that are referenced
  NFSd: Add reference counting to the lock and open stateids
  NFSd: Add a struct nfs4_file field to struct nfs4_stid
  NFSd: Replace delegation->dl_file with the dl_stid.sc_file
  NFSd: Replace nfs4_ol_stateid->st_file with the st_stid.sc_file
  NFSd: Ensure stateids remain unique until they are freed
  NFSd: Ensure atomicity of stateid destruction and idr tree removal
  NFSd: Fix atomicity of delegation counter
  NFSd: Slight cleanup of find_stateid()
  NFSd: Add reference counting to find_stateid
  NFSd: nfs4_preprocess_seqid_op should only set *stpp on success
  NFSd: Add reference counting to lock stateids
  NFSd: nfsd4_locku() must reference the lock stateid
  NFSd: Ensure that nfs4_open_delegation() references the delegation
    stateid
  NFSd: nfsd4_process_open2() must reference the delegation stateid
  NFSd: nfsd4_process_open2() must reference the open stateid
  NFSd: Prepare nfsd4_close() for open stateid referencing
  NFSd: nfsd4_open_confirm() must reference the open stateid
  NFSd: Add reference counting to nfs4_preprocess_confirmed_seqid_op
  NFSd: Migrate the stateid reference into nfs4_preprocess_seqid_op
  NFSd: Migrate the stateid reference into nfs4_lookup_stateid()
  NFSd: Migrate the stateid reference into nfs4_find_stateid_by_type()
  NFSd: Cleanup - Let nfsd4_lookup_stateid() take a cstate argument
  NFSd: Use the session->se_client  in lookup_clientid()
  NFSd: Convert nfsd4_process_open1() to work with lookup_clientid()
  NFSd: Convert nfs4_check_open_reclaim() to work with lookup_clientid()
  NFSd: Ensure struct nfs4_client is unhashed before we try to destroy
    it
  NFSd: Ensure that the laundromat unhashes the client before releasing
    locks
  NFSd: Don't require client_lock in free_client
  NFSd: Move create_client() call outside the lock
  NFSd: Protect unconfirmed client creation using client_lock
  NFSd: Protect session creation and client confirm using client_lock
  NFSd: Protect nfsd4_destroy_clientid using client_lock
  NFSd: Ensure lookup_clientid() takes client_lock
  NFSd: Remove nfs4_lock_state(): nfs4_preprocess_stateid_op()
  NFSd: Remove nfs4_lock_state(): nfsd4_test_stateid/nfsd4_free_stateid
  NFSd: Remove nfs4_lock_state(): nfsd4_release_lockowner
  NFSd: Remove nfs4_lock_state(): nfsd4_lock/locku/lockt()
  NFSd: Remove nfs4_lock_state(): nfsd4_open_downgrade + nfsd4_close
  NFSd: Remove nfs4_lock_state(): nfsd4_delegreturn()
  NFSd: Remove nfs4_lock_state(): nfsd4_open and nfsd4_open_confirm
  NFSd: Remove nfs4_lock_state(): exchange_id, create/destroy_session()
  NFSd: Remove nfs4_lock_state(): setclientid, setclientid_confirm,
    renew
  NFSd: Remove nfs4_lock_state(): reclaim_complete()

 fs/nfsd/netns.h        |    4 -
 fs/nfsd/nfs4callback.c |   18 +-
 fs/nfsd/nfs4proc.c     |   28 +-
 fs/nfsd/nfs4state.c    | 1239 ++++++++++++++++++++++++++++++------------------
 fs/nfsd/nfs4xdr.c      |   15 +-
 fs/nfsd/state.h        |   46 +-
 fs/nfsd/xdr4.h         |   21 +-
 7 files changed, 819 insertions(+), 552 deletions(-)

-- 
1.9.0


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

* [PATCH 01/70] NFSd: Ensure we clear the cstate->slot in nfsd4_proc_compound
  2014-04-18 18:43 [PATCH 00/70] NFSd lock scalability patches Trond Myklebust
@ 2014-04-18 18:43 ` Trond Myklebust
  2014-04-18 18:43   ` [PATCH 02/70] NFSd: Move default initialisers from create_client() to alloc_client() Trond Myklebust
  2014-05-06 15:32   ` [PATCH 01/70] NFSd: Ensure we clear the cstate->slot in nfsd4_proc_compound Bruce Fields
  2014-04-19 15:04 ` [PATCH 00/70] NFSd lock scalability patches Christoph Hellwig
                   ` (2 subsequent siblings)
  3 siblings, 2 replies; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:43 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

Otherwise, we may end up triggering all those nfsd4_has_session()
tests.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4proc.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index d543222babf3..8eabbfb25441 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -1293,6 +1293,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
 	cstate->minorversion = args->minorversion;
 	cstate->replay_owner = NULL;
 	cstate->session = NULL;
+	cstate->slot = NULL;
 	fh_init(current_fh, NFS4_FHSIZE);
 	fh_init(save_fh, NFS4_FHSIZE);
 	/*
-- 
1.9.0


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

* [PATCH 02/70] NFSd: Move default initialisers from create_client() to alloc_client()
  2014-04-18 18:43 ` [PATCH 01/70] NFSd: Ensure we clear the cstate->slot in nfsd4_proc_compound Trond Myklebust
@ 2014-04-18 18:43   ` Trond Myklebust
  2014-04-18 18:43     ` [PATCH 03/70] NFSd: call rpc_destroy_wait_queue() from free_client() Trond Myklebust
  2014-05-06 16:37     ` [PATCH 02/70] NFSd: Move default initialisers from create_client() to alloc_client() Bruce Fields
  2014-05-06 15:32   ` [PATCH 01/70] NFSd: Ensure we clear the cstate->slot in nfsd4_proc_compound Bruce Fields
  1 sibling, 2 replies; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:43 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

Aside from making it clearer what is non-trivial in create_client(), it
also fixes a bug whereby we can call free_client() before idr_init()
has been called.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 3ba65979a3cd..230d21cb1717 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1078,6 +1078,18 @@ static struct nfs4_client *alloc_client(struct xdr_netobj name)
 		return NULL;
 	}
 	clp->cl_name.len = name.len;
+	INIT_LIST_HEAD(&clp->cl_sessions);
+	idr_init(&clp->cl_stateids);
+	atomic_set(&clp->cl_refcount, 0);
+	clp->cl_cb_state = NFSD4_CB_UNKNOWN;
+	INIT_LIST_HEAD(&clp->cl_idhash);
+	INIT_LIST_HEAD(&clp->cl_openowners);
+	INIT_LIST_HEAD(&clp->cl_delegations);
+	INIT_LIST_HEAD(&clp->cl_lru);
+	INIT_LIST_HEAD(&clp->cl_callbacks);
+	INIT_LIST_HEAD(&clp->cl_revoked);
+	spin_lock_init(&clp->cl_lock);
+	rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table");
 	return clp;
 }
 
@@ -1347,7 +1359,6 @@ static struct nfs4_client *create_client(struct xdr_netobj name,
 	if (clp == NULL)
 		return NULL;
 
-	INIT_LIST_HEAD(&clp->cl_sessions);
 	ret = copy_cred(&clp->cl_cred, &rqstp->rq_cred);
 	if (ret) {
 		spin_lock(&nn->client_lock);
@@ -1355,20 +1366,9 @@ static struct nfs4_client *create_client(struct xdr_netobj name,
 		spin_unlock(&nn->client_lock);
 		return NULL;
 	}
-	idr_init(&clp->cl_stateids);
-	atomic_set(&clp->cl_refcount, 0);
-	clp->cl_cb_state = NFSD4_CB_UNKNOWN;
-	INIT_LIST_HEAD(&clp->cl_idhash);
-	INIT_LIST_HEAD(&clp->cl_openowners);
-	INIT_LIST_HEAD(&clp->cl_delegations);
-	INIT_LIST_HEAD(&clp->cl_lru);
-	INIT_LIST_HEAD(&clp->cl_callbacks);
-	INIT_LIST_HEAD(&clp->cl_revoked);
-	spin_lock_init(&clp->cl_lock);
 	nfsd4_init_callback(&clp->cl_cb_null);
 	clp->cl_time = get_seconds();
 	clear_bit(0, &clp->cl_cb_slot_busy);
-	rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table");
 	copy_verf(clp, verf);
 	rpc_copy_addr((struct sockaddr *) &clp->cl_addr, sa);
 	gen_confirm(clp);
-- 
1.9.0


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

* [PATCH 03/70] NFSd: call rpc_destroy_wait_queue() from free_client()
  2014-04-18 18:43   ` [PATCH 02/70] NFSd: Move default initialisers from create_client() to alloc_client() Trond Myklebust
@ 2014-04-18 18:43     ` Trond Myklebust
  2014-04-18 18:43       ` [PATCH 04/70] NFSd: Remove 'inline' designation for free_client() Trond Myklebust
  2014-05-06 16:37       ` [PATCH 03/70] NFSd: call rpc_destroy_wait_queue() from free_client() Bruce Fields
  2014-05-06 16:37     ` [PATCH 02/70] NFSd: Move default initialisers from create_client() to alloc_client() Bruce Fields
  1 sibling, 2 replies; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:43 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

Mainly to ensure that we don't leave any hanging timers.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 230d21cb1717..32b699bebb9c 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1107,6 +1107,7 @@ free_client(struct nfs4_client *clp)
 		WARN_ON_ONCE(atomic_read(&ses->se_ref));
 		free_session(ses);
 	}
+	rpc_destroy_wait_queue(&clp->cl_cb_waitq);
 	free_svc_cred(&clp->cl_cred);
 	kfree(clp->cl_name.data);
 	idr_destroy(&clp->cl_stateids);
-- 
1.9.0


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

* [PATCH 04/70] NFSd: Remove 'inline' designation for free_client()
  2014-04-18 18:43     ` [PATCH 03/70] NFSd: call rpc_destroy_wait_queue() from free_client() Trond Myklebust
@ 2014-04-18 18:43       ` Trond Myklebust
  2014-04-18 18:43         ` [PATCH 05/70] nfsd4: rename recall_lock to state_lock Trond Myklebust
  2014-05-06 16:40         ` [PATCH 04/70] NFSd: Remove 'inline' designation for free_client() Bruce Fields
  2014-05-06 16:37       ` [PATCH 03/70] NFSd: call rpc_destroy_wait_queue() from free_client() Bruce Fields
  1 sibling, 2 replies; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:43 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

It is large, it is used in more than one place, and it is not performance
critical. Let gcc figure out whether it should be inlined...

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 32b699bebb9c..841495aa9170 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1093,7 +1093,7 @@ static struct nfs4_client *alloc_client(struct xdr_netobj name)
 	return clp;
 }
 
-static inline void
+static void
 free_client(struct nfs4_client *clp)
 {
 	struct nfsd_net __maybe_unused *nn = net_generic(clp->net, nfsd_net_id);
-- 
1.9.0


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

* [PATCH 05/70] nfsd4: rename recall_lock to state_lock
  2014-04-18 18:43       ` [PATCH 04/70] NFSd: Remove 'inline' designation for free_client() Trond Myklebust
@ 2014-04-18 18:43         ` Trond Myklebust
  2014-04-18 18:44           ` [PATCH 06/70] nfsd4: use cl_lock to synchronize all stateid idr calls Trond Myklebust
  2014-05-06 16:40         ` [PATCH 04/70] NFSd: Remove 'inline' designation for free_client() Bruce Fields
  1 sibling, 1 reply; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:43 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

From: Benny Halevy <bhalevy@primarydata.com>

Signed-off-by: Benny Halevy <bhalevy@primarydata.com>
---
 fs/nfsd/nfs4state.c | 55 +++++++++++++++++++++++++++--------------------------
 1 file changed, 28 insertions(+), 27 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 841495aa9170..34273ca482c3 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -81,7 +81,7 @@ static DEFINE_MUTEX(client_mutex);
  * effort to decrease the scope of the client_mutex, this spinlock may
  * eventually cover more:
  */
-static DEFINE_SPINLOCK(recall_lock);
+static DEFINE_SPINLOCK(state_lock);
 
 static struct kmem_cache *openowner_slab = NULL;
 static struct kmem_cache *lockowner_slab = NULL;
@@ -235,9 +235,9 @@ static void nfsd4_free_file(struct nfs4_file *f)
 static inline void
 put_nfs4_file(struct nfs4_file *fi)
 {
-	if (atomic_dec_and_lock(&fi->fi_ref, &recall_lock)) {
+	if (atomic_dec_and_lock(&fi->fi_ref, &state_lock)) {
 		hlist_del(&fi->fi_hash);
-		spin_unlock(&recall_lock);
+		spin_unlock(&state_lock);
 		iput(fi->fi_inode);
 		nfsd4_free_file(fi);
 	}
@@ -436,10 +436,10 @@ static void
 unhash_delegation(struct nfs4_delegation *dp)
 {
 	list_del_init(&dp->dl_perclnt);
-	spin_lock(&recall_lock);
+	spin_lock(&state_lock);
 	list_del_init(&dp->dl_perfile);
 	list_del_init(&dp->dl_recall_lru);
-	spin_unlock(&recall_lock);
+	spin_unlock(&state_lock);
 	nfs4_put_deleg_lease(dp->dl_file);
 	put_nfs4_file(dp->dl_file);
 	dp->dl_file = NULL;
@@ -1136,13 +1136,13 @@ destroy_client(struct nfs4_client *clp)
 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
 
 	INIT_LIST_HEAD(&reaplist);
-	spin_lock(&recall_lock);
+	spin_lock(&state_lock);
 	while (!list_empty(&clp->cl_delegations)) {
 		dp = list_entry(clp->cl_delegations.next, struct nfs4_delegation, dl_perclnt);
 		list_del_init(&dp->dl_perclnt);
 		list_move(&dp->dl_recall_lru, &reaplist);
 	}
-	spin_unlock(&recall_lock);
+	spin_unlock(&state_lock);
 	while (!list_empty(&reaplist)) {
 		dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru);
 		destroy_delegation(dp);
@@ -2499,9 +2499,9 @@ static void nfsd4_init_file(struct nfs4_file *fp, struct inode *ino)
 	fp->fi_lease = NULL;
 	memset(fp->fi_fds, 0, sizeof(fp->fi_fds));
 	memset(fp->fi_access, 0, sizeof(fp->fi_access));
-	spin_lock(&recall_lock);
+	spin_lock(&state_lock);
 	hlist_add_head(&fp->fi_hash, &file_hashtbl[hashval]);
-	spin_unlock(&recall_lock);
+	spin_unlock(&state_lock);
 }
 
 static void
@@ -2685,15 +2685,15 @@ find_file(struct inode *ino)
 	unsigned int hashval = file_hashval(ino);
 	struct nfs4_file *fp;
 
-	spin_lock(&recall_lock);
+	spin_lock(&state_lock);
 	hlist_for_each_entry(fp, &file_hashtbl[hashval], fi_hash) {
 		if (fp->fi_inode == ino) {
 			get_nfs4_file(fp);
-			spin_unlock(&recall_lock);
+			spin_unlock(&state_lock);
 			return fp;
 		}
 	}
-	spin_unlock(&recall_lock);
+	spin_unlock(&state_lock);
 	return NULL;
 }
 
@@ -2730,6 +2730,7 @@ static void nfsd_break_one_deleg(struct nfs4_delegation *dp)
 	struct nfs4_client *clp = dp->dl_stid.sc_client;
 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
 
+	lockdep_assert_held(&state_lock);
 	/* We're assuming the state code never drops its reference
 	 * without first removing the lease.  Since we're in this lease
 	 * callback (and since the lease code is serialized by the kernel
@@ -2766,11 +2767,11 @@ static void nfsd_break_deleg_cb(struct file_lock *fl)
 	 */
 	fl->fl_break_time = 0;
 
-	spin_lock(&recall_lock);
+	spin_lock(&state_lock);
 	fp->fi_had_conflict = true;
 	list_for_each_entry(dp, &fp->fi_delegations, dl_perfile)
 		nfsd_break_one_deleg(dp);
-	spin_unlock(&recall_lock);
+	spin_unlock(&state_lock);
 }
 
 static
@@ -3072,15 +3073,15 @@ static int nfs4_set_delegation(struct nfs4_delegation *dp, struct nfs4_file *fp)
 			goto out_free;
 		return 0;
 	}
-	spin_lock(&recall_lock);
+	spin_lock(&state_lock);
 	if (fp->fi_had_conflict) {
-		spin_unlock(&recall_lock);
+		spin_unlock(&state_lock);
 		status = -EAGAIN;
 		goto out_free;
 	}
 	atomic_inc(&fp->fi_delegees);
 	list_add(&dp->dl_perfile, &fp->fi_delegations);
-	spin_unlock(&recall_lock);
+	spin_unlock(&state_lock);
 	list_add(&dp->dl_perclnt, &dp->dl_stid.sc_client->cl_delegations);
 	return 0;
 out_free:
@@ -3422,7 +3423,7 @@ nfs4_laundromat(struct nfsd_net *nn)
 			clp->cl_clientid.cl_id);
 		expire_client(clp);
 	}
-	spin_lock(&recall_lock);
+	spin_lock(&state_lock);
 	list_for_each_safe(pos, next, &nn->del_recall_lru) {
 		dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
 		if (net_generic(dp->dl_stid.sc_client->net, nfsd_net_id) != nn)
@@ -3435,7 +3436,7 @@ nfs4_laundromat(struct nfsd_net *nn)
 		}
 		list_move(&dp->dl_recall_lru, &reaplist);
 	}
-	spin_unlock(&recall_lock);
+	spin_unlock(&state_lock);
 	list_for_each_safe(pos, next, &reaplist) {
 		dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
 		revoke_delegation(dp);
@@ -4900,9 +4901,9 @@ u64 nfsd_forget_client_delegations(struct nfs4_client *clp, u64 max)
 	LIST_HEAD(victims);
 	u64 count;
 
-	spin_lock(&recall_lock);
+	spin_lock(&state_lock);
 	count = nfsd_find_all_delegations(clp, max, &victims);
-	spin_unlock(&recall_lock);
+	spin_unlock(&state_lock);
 
 	list_for_each_entry_safe(dp, next, &victims, dl_recall_lru)
 		revoke_delegation(dp);
@@ -4916,11 +4917,11 @@ u64 nfsd_recall_client_delegations(struct nfs4_client *clp, u64 max)
 	LIST_HEAD(victims);
 	u64 count;
 
-	spin_lock(&recall_lock);
+	spin_lock(&state_lock);
 	count = nfsd_find_all_delegations(clp, max, &victims);
 	list_for_each_entry_safe(dp, next, &victims, dl_recall_lru)
 		nfsd_break_one_deleg(dp);
-	spin_unlock(&recall_lock);
+	spin_unlock(&state_lock);
 
 	return count;
 }
@@ -4929,9 +4930,9 @@ u64 nfsd_print_client_delegations(struct nfs4_client *clp, u64 max)
 {
 	u64 count = 0;
 
-	spin_lock(&recall_lock);
+	spin_lock(&state_lock);
 	count = nfsd_find_all_delegations(clp, max, NULL);
-	spin_unlock(&recall_lock);
+	spin_unlock(&state_lock);
 
 	nfsd_print_count(clp, count, "delegations");
 	return count;
@@ -5149,12 +5150,12 @@ nfs4_state_shutdown_net(struct net *net)
 
 	nfs4_lock_state();
 	INIT_LIST_HEAD(&reaplist);
-	spin_lock(&recall_lock);
+	spin_lock(&state_lock);
 	list_for_each_safe(pos, next, &nn->del_recall_lru) {
 		dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
 		list_move(&dp->dl_recall_lru, &reaplist);
 	}
-	spin_unlock(&recall_lock);
+	spin_unlock(&state_lock);
 	list_for_each_safe(pos, next, &reaplist) {
 		dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
 		destroy_delegation(dp);
-- 
1.9.0


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

* [PATCH 06/70] nfsd4: use cl_lock to synchronize all stateid idr calls
  2014-04-18 18:43         ` [PATCH 05/70] nfsd4: rename recall_lock to state_lock Trond Myklebust
@ 2014-04-18 18:44           ` Trond Myklebust
  2014-04-18 18:44             ` [PATCH 07/70] nfsd4: hash deleg stateid only on successful nfs4_set_delegation Trond Myklebust
  2014-05-06 16:48             ` [PATCH 06/70] nfsd4: use cl_lock to synchronize all stateid idr calls Bruce Fields
  0 siblings, 2 replies; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

From: Benny Halevy <bhalevy@primarydata.com>

Signed-off-by: Benny Halevy <bhalevy@primarydata.com>
---
 fs/nfsd/nfs4state.c | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 34273ca482c3..626f310a74a8 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -334,7 +334,11 @@ kmem_cache *slab)
 	if (!stid)
 		return NULL;
 
-	new_id = idr_alloc_cyclic(stateids, stid, 0, 0, GFP_KERNEL);
+	idr_preload(GFP_KERNEL);
+	spin_lock(&cl->cl_lock);
+	new_id = idr_alloc_cyclic(stateids, stid, 0, 0, GFP_NOWAIT);
+	spin_unlock(&cl->cl_lock);
+	idr_preload_end();
 	if (new_id < 0)
 		goto out_free;
 	stid->sc_client = cl;
@@ -397,9 +401,12 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct sv
 
 static void remove_stid(struct nfs4_stid *s)
 {
-	struct idr *stateids = &s->sc_client->cl_stateids;
+	struct nfs4_client *clp = s->sc_client;
+	struct idr *stateids = &clp->cl_stateids;
 
+	spin_lock(&clp->cl_lock);
 	idr_remove(stateids, s->sc_stateid.si_opaque.so_id);
+	spin_unlock(&clp->cl_lock);
 }
 
 static void nfs4_free_stid(struct kmem_cache *slab, struct nfs4_stid *s)
@@ -1110,7 +1117,9 @@ free_client(struct nfs4_client *clp)
 	rpc_destroy_wait_queue(&clp->cl_cb_waitq);
 	free_svc_cred(&clp->cl_cred);
 	kfree(clp->cl_name.data);
+	spin_lock(&clp->cl_lock);
 	idr_destroy(&clp->cl_stateids);
+	spin_unlock(&clp->cl_lock);
 	kfree(clp);
 }
 
@@ -1329,7 +1338,9 @@ static struct nfs4_stid *find_stateid(struct nfs4_client *cl, stateid_t *t)
 {
 	struct nfs4_stid *ret;
 
+	spin_lock(&cl->cl_lock);
 	ret = idr_find(&cl->cl_stateids, t->si_opaque.so_id);
+	spin_unlock(&cl->cl_lock);
 	if (!ret || !ret->sc_type)
 		return NULL;
 	return ret;
-- 
1.9.0


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

* [PATCH 07/70] nfsd4: hash deleg stateid only on successful nfs4_set_delegation
  2014-04-18 18:44           ` [PATCH 06/70] nfsd4: use cl_lock to synchronize all stateid idr calls Trond Myklebust
@ 2014-04-18 18:44             ` Trond Myklebust
  2014-04-18 18:44               ` [PATCH 08/70] nfsd4: use state_lock for delegation hashing Trond Myklebust
  2014-05-06 16:48             ` [PATCH 06/70] nfsd4: use cl_lock to synchronize all stateid idr calls Bruce Fields
  1 sibling, 1 reply; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

From: Benny Halevy <bhalevy@primarydata.com>

We don't want the stateid to be found in the hash table before the delegation
is granted.

Signed-off-by: Benny Halevy <bhalevy@primarydata.com>
---
 fs/nfsd/nfs4state.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 626f310a74a8..fe8e1bc9578b 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -379,7 +379,6 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct sv
 	dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab));
 	if (dp == NULL)
 		return dp;
-	dp->dl_stid.sc_type = NFS4_DELEG_STID;
 	/*
 	 * delegation seqid's are never incremented.  The 4.1 special
 	 * meaning of seqid 0 isn't meaningful, really, but let's avoid
@@ -3063,6 +3062,7 @@ static int nfs4_setlease(struct nfs4_delegation *dp)
 	fp->fi_lease = fl;
 	fp->fi_deleg_file = get_file(fl->fl_file);
 	atomic_set(&fp->fi_delegees, 1);
+	dp->dl_stid.sc_type = NFS4_DELEG_STID;
 	list_add(&dp->dl_perfile, &fp->fi_delegations);
 	return 0;
 out_free:
@@ -3091,6 +3091,7 @@ static int nfs4_set_delegation(struct nfs4_delegation *dp, struct nfs4_file *fp)
 		goto out_free;
 	}
 	atomic_inc(&fp->fi_delegees);
+	dp->dl_stid.sc_type = NFS4_DELEG_STID;
 	list_add(&dp->dl_perfile, &fp->fi_delegations);
 	spin_unlock(&state_lock);
 	list_add(&dp->dl_perclnt, &dp->dl_stid.sc_client->cl_delegations);
-- 
1.9.0


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

* [PATCH 08/70] nfsd4: use state_lock for delegation hashing
  2014-04-18 18:44             ` [PATCH 07/70] nfsd4: hash deleg stateid only on successful nfs4_set_delegation Trond Myklebust
@ 2014-04-18 18:44               ` Trond Myklebust
  2014-04-18 18:44                 ` [PATCH 09/70] NFSd: Mark nfs4_free_lockowner and nfs4_free_openowner as static functions Trond Myklebust
  2014-04-19 15:56                 ` [PATCH 08/70] nfsd4: use state_lock for delegation hashing Christoph Hellwig
  0 siblings, 2 replies; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

From: Benny Halevy <bhalevy@primarydata.com>

Signed-off-by: Benny Halevy <bhalevy@primarydata.com>
---
 fs/nfsd/nfs4state.c | 21 ++++++++++++++-------
 1 file changed, 14 insertions(+), 7 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index fe8e1bc9578b..45c4b692e30d 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -437,12 +437,20 @@ static void unhash_stid(struct nfs4_stid *s)
 	s->sc_type = 0;
 }
 
+static void
+hash_delegation_locked(struct nfs4_delegation *dp, struct nfs4_file *fp)
+{
+	dp->dl_stid.sc_type = NFS4_DELEG_STID;
+	list_add(&dp->dl_perfile, &fp->fi_delegations);
+	list_add(&dp->dl_perclnt, &dp->dl_stid.sc_client->cl_delegations);
+}
+
 /* Called under the state lock. */
 static void
 unhash_delegation(struct nfs4_delegation *dp)
 {
-	list_del_init(&dp->dl_perclnt);
 	spin_lock(&state_lock);
+	list_del_init(&dp->dl_perclnt);
 	list_del_init(&dp->dl_perfile);
 	list_del_init(&dp->dl_recall_lru);
 	spin_unlock(&state_lock);
@@ -3058,12 +3066,12 @@ static int nfs4_setlease(struct nfs4_delegation *dp)
 	status = vfs_setlease(fl->fl_file, fl->fl_type, &fl);
 	if (status)
 		goto out_free;
-	list_add(&dp->dl_perclnt, &dp->dl_stid.sc_client->cl_delegations);
 	fp->fi_lease = fl;
 	fp->fi_deleg_file = get_file(fl->fl_file);
 	atomic_set(&fp->fi_delegees, 1);
-	dp->dl_stid.sc_type = NFS4_DELEG_STID;
-	list_add(&dp->dl_perfile, &fp->fi_delegations);
+	spin_lock(&state_lock);
+	hash_delegation_locked(dp, fp);
+	spin_unlock(&state_lock);
 	return 0;
 out_free:
 	locks_free_lock(fl);
@@ -3091,10 +3099,8 @@ static int nfs4_set_delegation(struct nfs4_delegation *dp, struct nfs4_file *fp)
 		goto out_free;
 	}
 	atomic_inc(&fp->fi_delegees);
-	dp->dl_stid.sc_type = NFS4_DELEG_STID;
-	list_add(&dp->dl_perfile, &fp->fi_delegations);
+	hash_delegation_locked(dp, fp);
 	spin_unlock(&state_lock);
-	list_add(&dp->dl_perclnt, &dp->dl_stid.sc_client->cl_delegations);
 	return 0;
 out_free:
 	put_nfs4_file(fp);
@@ -4898,6 +4904,7 @@ static u64 nfsd_find_all_delegations(struct nfs4_client *clp, u64 max,
 	struct nfs4_delegation *dp, *next;
 	u64 count = 0;
 
+	lockdep_assert_held(&state_lock);
 	list_for_each_entry_safe(dp, next, &clp->cl_delegations, dl_perclnt) {
 		if (victims)
 			list_move(&dp->dl_recall_lru, victims);
-- 
1.9.0


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

* [PATCH 09/70] NFSd: Mark nfs4_free_lockowner and nfs4_free_openowner as static functions
  2014-04-18 18:44               ` [PATCH 08/70] nfsd4: use state_lock for delegation hashing Trond Myklebust
@ 2014-04-18 18:44                 ` Trond Myklebust
  2014-04-18 18:44                   ` [PATCH 10/70] NFSd: Avoid taking state_lock while holding inode lock in nfsd_break_one_deleg Trond Myklebust
  2014-04-19 15:56                 ` [PATCH 08/70] nfsd4: use state_lock for delegation hashing Christoph Hellwig
  1 sibling, 1 reply; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

They do not need to be used outside fs/nfsd/nfs4state.c

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 24 ++++++++++++------------
 fs/nfsd/state.h     |  2 --
 2 files changed, 12 insertions(+), 14 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 45c4b692e30d..6d691aa2bb27 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -659,6 +659,12 @@ static void unhash_lockowner(struct nfs4_lockowner *lo)
 	}
 }
 
+static void nfs4_free_lockowner(struct nfs4_lockowner *lo)
+{
+	kfree(lo->lo_owner.so_owner.data);
+	kmem_cache_free(lockowner_slab, lo);
+}
+
 static void release_lockowner(struct nfs4_lockowner *lo)
 {
 	unhash_lockowner(lo);
@@ -713,6 +719,12 @@ static void release_last_closed_stateid(struct nfs4_openowner *oo)
 	}
 }
 
+static void nfs4_free_openowner(struct nfs4_openowner *oo)
+{
+	kfree(oo->oo_owner.so_owner.data);
+	kmem_cache_free(openowner_slab, oo);
+}
+
 static void release_openowner(struct nfs4_openowner *oo)
 {
 	unhash_openowner(oo);
@@ -2571,18 +2583,6 @@ out_nomem:
 	return -ENOMEM;
 }
 
-void nfs4_free_openowner(struct nfs4_openowner *oo)
-{
-	kfree(oo->oo_owner.so_owner.data);
-	kmem_cache_free(openowner_slab, oo);
-}
-
-void nfs4_free_lockowner(struct nfs4_lockowner *lo)
-{
-	kfree(lo->lo_owner.so_owner.data);
-	kmem_cache_free(lockowner_slab, lo);
-}
-
 static void init_nfs4_replay(struct nfs4_replay *rp)
 {
 	rp->rp_status = nfserr_serverfault;
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 424d8f5f2317..1aa22f39fc65 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -464,8 +464,6 @@ extern void nfs4_release_reclaim(struct nfsd_net *);
 extern struct nfs4_client_reclaim *nfsd4_find_reclaim_client(const char *recdir,
 							struct nfsd_net *nn);
 extern __be32 nfs4_check_open_reclaim(clientid_t *clid, bool sessions, struct nfsd_net *nn);
-extern void nfs4_free_openowner(struct nfs4_openowner *);
-extern void nfs4_free_lockowner(struct nfs4_lockowner *);
 extern int set_callback_cred(void);
 extern void nfsd4_init_callback(struct nfsd4_callback *);
 extern void nfsd4_probe_callback(struct nfs4_client *clp);
-- 
1.9.0


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

* [PATCH 10/70] NFSd: Avoid taking state_lock while holding inode lock in nfsd_break_one_deleg
  2014-04-18 18:44                 ` [PATCH 09/70] NFSd: Mark nfs4_free_lockowner and nfs4_free_openowner as static functions Trond Myklebust
@ 2014-04-18 18:44                   ` Trond Myklebust
  2014-04-18 18:44                     ` [PATCH 11/70] NFSd: Ensure delegation setup is safe w.r.t. break_lease() Trond Myklebust
  2014-05-06 23:40                     ` [PATCH 10/70] NFSd: Avoid taking state_lock while holding inode lock in nfsd_break_one_deleg Bruce Fields
  0 siblings, 2 replies; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

state_lock is a heavily contended global lock. We don't want to grab
that while simultaneously holding the inode->i_lock
Instead do the list manipulations from the work queue context prior to
starting the rpc call.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4callback.c | 18 ++++++++++++++++--
 fs/nfsd/nfs4state.c    | 25 +++++++++++++++----------
 fs/nfsd/state.h        |  1 +
 3 files changed, 32 insertions(+), 12 deletions(-)

diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index 39c8ef875f91..8626cd6af4d1 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -1009,9 +1009,8 @@ static void nfsd4_process_cb_update(struct nfsd4_callback *cb)
 		run_nfsd4_cb(cb);
 }
 
-static void nfsd4_do_callback_rpc(struct work_struct *w)
+static void nfsd4_run_callback_rpc(struct nfsd4_callback *cb)
 {
-	struct nfsd4_callback *cb = container_of(w, struct nfsd4_callback, cb_work);
 	struct nfs4_client *clp = cb->cb_clp;
 	struct rpc_clnt *clnt;
 
@@ -1029,11 +1028,25 @@ static void nfsd4_do_callback_rpc(struct work_struct *w)
 			cb->cb_ops, cb);
 }
 
+static void nfsd4_do_callback_rpc(struct work_struct *w)
+{
+	struct nfsd4_callback *cb = container_of(w, struct nfsd4_callback, cb_work);
+	nfsd4_run_callback_rpc(cb);
+}
+
 void nfsd4_init_callback(struct nfsd4_callback *cb)
 {
 	INIT_WORK(&cb->cb_work, nfsd4_do_callback_rpc);
 }
 
+static void nfsd4_do_cb_recall(struct work_struct *w)
+{
+	struct nfsd4_callback *cb = container_of(w, struct nfsd4_callback, cb_work);
+
+	nfsd4_prepare_cb_recall(cb->cb_op);
+	nfsd4_run_callback_rpc(cb);
+}
+
 void nfsd4_cb_recall(struct nfs4_delegation *dp)
 {
 	struct nfsd4_callback *cb = &dp->dl_recall;
@@ -1050,6 +1063,7 @@ void nfsd4_cb_recall(struct nfs4_delegation *dp)
 
 	INIT_LIST_HEAD(&cb->cb_per_client);
 	cb->cb_done = true;
+	INIT_WORK(&cb->cb_work, nfsd4_do_cb_recall);
 
 	run_nfsd4_cb(&dp->dl_recall);
 }
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 6d691aa2bb27..85fcbc9ebd40 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -2743,24 +2743,31 @@ out:
 	return ret;
 }
 
-static void nfsd_break_one_deleg(struct nfs4_delegation *dp)
+void nfsd4_prepare_cb_recall(struct nfs4_delegation *dp)
 {
 	struct nfs4_client *clp = dp->dl_stid.sc_client;
 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
 
-	lockdep_assert_held(&state_lock);
+	/*
+	 * We can't do this in nfsd_break_deleg_cb because it is
+	 * already holding inode->i_lock
+	 */
+	spin_lock(&state_lock);
+	if (list_empty(&dp->dl_recall_lru)) {
+		dp->dl_time = get_seconds();
+		list_add_tail(&dp->dl_recall_lru, &nn->del_recall_lru);
+	}
+	spin_unlock(&state_lock);
+}
+
+static void nfsd_break_one_deleg(struct nfs4_delegation *dp)
+{
 	/* We're assuming the state code never drops its reference
 	 * without first removing the lease.  Since we're in this lease
 	 * callback (and since the lease code is serialized by the kernel
 	 * lock) we know the server hasn't removed the lease yet, we know
 	 * it's safe to take a reference: */
 	atomic_inc(&dp->dl_count);
-
-	list_add_tail(&dp->dl_recall_lru, &nn->del_recall_lru);
-
-	/* Only place dl_time is set; protected by i_lock: */
-	dp->dl_time = get_seconds();
-
 	nfsd4_cb_recall(dp);
 }
 
@@ -2785,11 +2792,9 @@ static void nfsd_break_deleg_cb(struct file_lock *fl)
 	 */
 	fl->fl_break_time = 0;
 
-	spin_lock(&state_lock);
 	fp->fi_had_conflict = true;
 	list_for_each_entry(dp, &fp->fi_delegations, dl_perfile)
 		nfsd_break_one_deleg(dp);
-	spin_unlock(&state_lock);
 }
 
 static
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 1aa22f39fc65..02c5a203c738 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -473,6 +473,7 @@ extern void nfsd4_cb_recall(struct nfs4_delegation *dp);
 extern int nfsd4_create_callback_queue(void);
 extern void nfsd4_destroy_callback_queue(void);
 extern void nfsd4_shutdown_callback(struct nfs4_client *);
+extern void nfsd4_prepare_cb_recall(struct nfs4_delegation *dp);
 extern void nfs4_put_delegation(struct nfs4_delegation *dp);
 extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(const char *name,
 							struct nfsd_net *nn);
-- 
1.9.0


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

* [PATCH 11/70] NFSd: Ensure delegation setup is safe w.r.t. break_lease()
  2014-04-18 18:44                   ` [PATCH 10/70] NFSd: Avoid taking state_lock while holding inode lock in nfsd_break_one_deleg Trond Myklebust
@ 2014-04-18 18:44                     ` Trond Myklebust
  2014-04-18 18:44                       ` [PATCH 12/70] NFSd: Add fine grained protection for the nfs4_file->fi_stateids list Trond Myklebust
  2014-05-06 23:41                       ` [PATCH 11/70] NFSd: Ensure delegation setup is safe w.r.t. break_lease() Bruce Fields
  2014-05-06 23:40                     ` [PATCH 10/70] NFSd: Avoid taking state_lock while holding inode lock in nfsd_break_one_deleg Bruce Fields
  1 sibling, 2 replies; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

Ensure that we add/remove the dl_perfile under the inode->i_lock

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 85fcbc9ebd40..3656980b5d19 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -441,7 +441,9 @@ static void
 hash_delegation_locked(struct nfs4_delegation *dp, struct nfs4_file *fp)
 {
 	dp->dl_stid.sc_type = NFS4_DELEG_STID;
+	spin_lock(&fp->fi_inode->i_lock);
 	list_add(&dp->dl_perfile, &fp->fi_delegations);
+	spin_unlock(&fp->fi_inode->i_lock);
 	list_add(&dp->dl_perclnt, &dp->dl_stid.sc_client->cl_delegations);
 }
 
@@ -449,13 +451,19 @@ hash_delegation_locked(struct nfs4_delegation *dp, struct nfs4_file *fp)
 static void
 unhash_delegation(struct nfs4_delegation *dp)
 {
+	struct nfs4_file *fp = dp->dl_file;
+
 	spin_lock(&state_lock);
 	list_del_init(&dp->dl_perclnt);
-	list_del_init(&dp->dl_perfile);
 	list_del_init(&dp->dl_recall_lru);
+	if (!list_empty(&dp->dl_perfile)) {
+		spin_lock(&fp->fi_inode->i_lock);
+		list_del_init(&dp->dl_perfile);
+		spin_unlock(&fp->fi_inode->i_lock);
+	}
 	spin_unlock(&state_lock);
-	nfs4_put_deleg_lease(dp->dl_file);
-	put_nfs4_file(dp->dl_file);
+	nfs4_put_deleg_lease(fp);
+	put_nfs4_file(fp);
 	dp->dl_file = NULL;
 }
 
-- 
1.9.0


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

* [PATCH 12/70] NFSd: Add fine grained protection for the nfs4_file->fi_stateids list
  2014-04-18 18:44                     ` [PATCH 11/70] NFSd: Ensure delegation setup is safe w.r.t. break_lease() Trond Myklebust
@ 2014-04-18 18:44                       ` Trond Myklebust
  2014-04-18 18:44                         ` [PATCH 13/70] NFSd: Clean up nfs4_preprocess_stateid_op Trond Myklebust
  2014-05-06 23:41                       ` [PATCH 11/70] NFSd: Ensure delegation setup is safe w.r.t. break_lease() Bruce Fields
  1 sibling, 1 reply; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 21 ++++++++++++++++++---
 fs/nfsd/state.h     |  1 +
 2 files changed, 19 insertions(+), 3 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 3656980b5d19..f77cc9206373 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -623,7 +623,11 @@ release_all_access(struct nfs4_ol_stateid *stp)
 
 static void unhash_generic_stateid(struct nfs4_ol_stateid *stp)
 {
+	struct nfs4_file *fp = stp->st_file;
+
+	spin_lock(&fp->fi_lock);
 	list_del(&stp->st_perfile);
+	spin_unlock(&fp->fi_lock);
 	list_del(&stp->st_perstateowner);
 }
 
@@ -2530,6 +2534,7 @@ static void nfsd4_init_file(struct nfs4_file *fp, struct inode *ino)
 	unsigned int hashval = file_hashval(ino);
 
 	atomic_set(&fp->fi_ref, 1);
+	spin_lock_init(&fp->fi_lock);
 	INIT_LIST_HEAD(&fp->fi_stateids);
 	INIT_LIST_HEAD(&fp->fi_delegations);
 	fp->fi_inode = igrab(ino);
@@ -2650,7 +2655,6 @@ static void init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp,
 	stp->st_stid.sc_type = NFS4_OPEN_STID;
 	INIT_LIST_HEAD(&stp->st_lockowners);
 	list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids);
-	list_add(&stp->st_perfile, &fp->fi_stateids);
 	stp->st_stateowner = &oo->oo_owner;
 	get_nfs4_file(fp);
 	stp->st_file = fp;
@@ -2659,6 +2663,9 @@ static void init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp,
 	set_access(open->op_share_access, stp);
 	set_deny(open->op_share_deny, stp);
 	stp->st_openstp = NULL;
+	spin_lock(&fp->fi_lock);
+	list_add(&stp->st_perfile, &fp->fi_stateids);
+	spin_unlock(&fp->fi_lock);
 }
 
 static void
@@ -2740,6 +2747,7 @@ nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type)
 		return nfs_ok;
 	ret = nfserr_locked;
 	/* Search for conflicting share reservations */
+	spin_lock(&fp->fi_lock);
 	list_for_each_entry(stp, &fp->fi_stateids, st_perfile) {
 		if (test_deny(deny_type, stp) ||
 		    test_deny(NFS4_SHARE_DENY_BOTH, stp))
@@ -2747,6 +2755,7 @@ nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type)
 	}
 	ret = nfs_ok;
 out:
+	spin_unlock(&fp->fi_lock);
 	put_nfs4_file(fp);
 	return ret;
 }
@@ -2943,6 +2952,7 @@ nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_ol_st
 	struct nfs4_ol_stateid *local;
 	struct nfs4_openowner *oo = open->op_openowner;
 
+	spin_lock(&fp->fi_lock);
 	list_for_each_entry(local, &fp->fi_stateids, st_perfile) {
 		/* ignore lock owners */
 		if (local->st_stateowner->so_is_open_owner == 0)
@@ -2951,9 +2961,12 @@ nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_ol_st
 		if (local->st_stateowner == &oo->oo_owner)
 			*stpp = local;
 		/* check for conflicting share reservations */
-		if (!test_share(local, open))
+		if (!test_share(local, open)) {
+			spin_unlock(&fp->fi_lock);
 			return nfserr_share_denied;
+		}
 	}
+	spin_unlock(&fp->fi_lock);
 	return nfs_ok;
 }
 
@@ -4256,7 +4269,6 @@ alloc_init_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp, struct
 	if (stp == NULL)
 		return NULL;
 	stp->st_stid.sc_type = NFS4_LOCK_STID;
-	list_add(&stp->st_perfile, &fp->fi_stateids);
 	list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids);
 	stp->st_stateowner = &lo->lo_owner;
 	get_nfs4_file(fp);
@@ -4264,6 +4276,9 @@ alloc_init_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp, struct
 	stp->st_access_bmap = 0;
 	stp->st_deny_bmap = open_stp->st_deny_bmap;
 	stp->st_openstp = open_stp;
+	spin_lock(&fp->fi_lock);
+	list_add(&stp->st_perfile, &fp->fi_stateids);
+	spin_unlock(&fp->fi_lock);
 	return stp;
 }
 
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 02c5a203c738..83d9721d9644 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -383,6 +383,7 @@ static inline struct nfs4_lockowner * lockowner(struct nfs4_stateowner *so)
 /* nfs4_file: a file opened by some number of (open) nfs4_stateowners. */
 struct nfs4_file {
 	atomic_t		fi_ref;
+	spinlock_t		fi_lock;
 	struct hlist_node       fi_hash;    /* hash by "struct inode *" */
 	struct list_head        fi_stateids;
 	struct list_head	fi_delegations;
-- 
1.9.0


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

* [PATCH 13/70] NFSd: Clean up nfs4_preprocess_stateid_op
  2014-04-18 18:44                       ` [PATCH 12/70] NFSd: Add fine grained protection for the nfs4_file->fi_stateids list Trond Myklebust
@ 2014-04-18 18:44                         ` Trond Myklebust
  2014-04-18 18:44                           ` [PATCH 14/70] NFSd: Add a mutex to protect the NFSv4.0 open owner replay cache Trond Myklebust
  0 siblings, 1 reply; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

Move the state locking and file descriptor reference out from the
callers and into nfs4_preprocess_stateid_op() itself.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4proc.c  | 11 -----------
 fs/nfsd/nfs4state.c | 19 +++++++++++++------
 2 files changed, 13 insertions(+), 17 deletions(-)

diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 8eabbfb25441..480323443efe 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -786,7 +786,6 @@ nfsd4_read(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	if (!nfsd4_last_compound_op(rqstp))
 		rqstp->rq_splice_ok = false;
 
-	nfs4_lock_state();
 	/* check stateid */
 	if ((status = nfs4_preprocess_stateid_op(SVC_NET(rqstp),
 						 cstate, &read->rd_stateid,
@@ -794,11 +793,8 @@ nfsd4_read(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 		dprintk("NFSD: nfsd4_read: couldn't process stateid!\n");
 		goto out;
 	}
-	if (read->rd_filp)
-		get_file(read->rd_filp);
 	status = nfs_ok;
 out:
-	nfs4_unlock_state();
 	read->rd_rqstp = rqstp;
 	read->rd_fhp = &cstate->current_fh;
 	return status;
@@ -937,10 +933,8 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	int err;
 
 	if (setattr->sa_iattr.ia_valid & ATTR_SIZE) {
-		nfs4_lock_state();
 		status = nfs4_preprocess_stateid_op(SVC_NET(rqstp), cstate,
 			&setattr->sa_stateid, WR_STATE, NULL);
-		nfs4_unlock_state();
 		if (status) {
 			dprintk("NFSD: nfsd4_setattr: couldn't process stateid!\n");
 			return status;
@@ -1006,17 +1000,12 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	if (write->wr_offset >= OFFSET_MAX)
 		return nfserr_inval;
 
-	nfs4_lock_state();
 	status = nfs4_preprocess_stateid_op(SVC_NET(rqstp),
 					cstate, stateid, WR_STATE, &filp);
 	if (status) {
-		nfs4_unlock_state();
 		dprintk("NFSD: nfsd4_write: couldn't process stateid!\n");
 		return status;
 	}
-	if (filp)
-		get_file(filp);
-	nfs4_unlock_state();
 
 	cnt = write->wr_buflen;
 	write->wr_how_written = write->wr_stable_how;
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index f77cc9206373..6827e8698767 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -3699,6 +3699,7 @@ nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate,
 	struct svc_fh *current_fh = &cstate->current_fh;
 	struct inode *ino = current_fh->fh_dentry->d_inode;
 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+	struct file *file = NULL;
 	__be32 status;
 
 	if (filpp)
@@ -3710,10 +3711,12 @@ nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate,
 	if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
 		return check_special_stateids(net, current_fh, stateid, flags);
 
+	nfs4_lock_state();
+
 	status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID,
 				      &s, cstate->minorversion, nn);
 	if (status)
-		return status;
+		goto out;
 	status = check_stateid_generation(stateid, &s->sc_stateid, nfsd4_has_session(cstate));
 	if (status)
 		goto out;
@@ -3724,8 +3727,8 @@ nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate,
 		if (status)
 			goto out;
 		if (filpp) {
-			*filpp = dp->dl_file->fi_deleg_file;
-			if (!*filpp) {
+			file = dp->dl_file->fi_deleg_file;
+			if (!file) {
 				WARN_ON_ONCE(1);
 				status = nfserr_serverfault;
 				goto out;
@@ -3746,16 +3749,20 @@ nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate,
 			goto out;
 		if (filpp) {
 			if (flags & RD_STATE)
-				*filpp = find_readable_file(stp->st_file);
+				file = find_readable_file(stp->st_file);
 			else
-				*filpp = find_writeable_file(stp->st_file);
+				file = find_writeable_file(stp->st_file);
 		}
 		break;
 	default:
-		return nfserr_bad_stateid;
+		status = nfserr_bad_stateid;
+		goto out;
 	}
 	status = nfs_ok;
+	if (file)
+		*filpp = get_file(file);
 out:
+	nfs4_unlock_state();
 	return status;
 }
 
-- 
1.9.0


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

* [PATCH 14/70] NFSd: Add a mutex to protect the NFSv4.0 open owner replay cache
  2014-04-18 18:44                         ` [PATCH 13/70] NFSd: Clean up nfs4_preprocess_stateid_op Trond Myklebust
@ 2014-04-18 18:44                           ` Trond Myklebust
  2014-04-18 18:44                             ` [PATCH 15/70] NFSd: Add locking to the nfs4_file->fi_fds[] array Trond Myklebust
  0 siblings, 1 reply; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

We don't want to rely on the state_lock() for protection in the
case of NFSv4 open owners. Instead, we add a mutex that will
only be taken for NFSv4.0 state mutating operations, and
that will be released once the entire compound is done.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4proc.c  | 13 +++++--------
 fs/nfsd/nfs4state.c | 21 ++++++++-------------
 fs/nfsd/state.h     |  1 +
 fs/nfsd/xdr4.h      | 19 +++++++++++++++++++
 4 files changed, 33 insertions(+), 21 deletions(-)

diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 480323443efe..a23da87b384e 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -470,11 +470,11 @@ out:
 		kfree(resfh);
 	}
 	nfsd4_cleanup_open_state(open, status);
-	if (open->op_openowner && !nfsd4_has_session(cstate))
-		cstate->replay_owner = &open->op_openowner->oo_owner;
+	if (open->op_openowner)
+		nfsd4_cstate_assign_replay(cstate,
+				&open->op_openowner->oo_owner);
 	nfsd4_bump_seqid(cstate, status);
-	if (!cstate->replay_owner)
-		nfs4_unlock_state();
+	nfs4_unlock_state();
 	return status;
 }
 
@@ -1400,10 +1400,7 @@ encode_op:
 			args->ops, args->opcnt, resp->opcnt, op->opnum,
 			be32_to_cpu(status));
 
-		if (cstate->replay_owner) {
-			nfs4_unlock_state();
-			cstate->replay_owner = NULL;
-		}
+		nfsd4_cstate_clear_replay(cstate);
 		/* XXX Ugh, we need to get rid of this kind of special case: */
 		if (op->opnum == OP_READ && op->u.read.rd_filp)
 			fput(op->u.read.rd_filp);
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 6827e8698767..ad7d21e06c36 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -779,7 +779,7 @@ void nfsd4_bump_seqid(struct nfsd4_compound_state *cstate, __be32 nfserr)
 		return;
 
 	if (!seqid_mutating_err(ntohl(nfserr))) {
-		cstate->replay_owner = NULL;
+		nfsd4_cstate_clear_replay(cstate);
 		return;
 	}
 	if (!so)
@@ -2601,6 +2601,7 @@ static void init_nfs4_replay(struct nfs4_replay *rp)
 	rp->rp_status = nfserr_serverfault;
 	rp->rp_buflen = 0;
 	rp->rp_buf = rp->rp_ibuf;
+	mutex_init(&rp->rp_mutex);
 }
 
 static inline void *alloc_stateowner(struct kmem_cache *slab, struct xdr_netobj *owner, struct nfs4_client *clp)
@@ -3886,8 +3887,7 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
 	if (status)
 		return status;
 	*stpp = openlockstateid(s);
-	if (!nfsd4_has_session(cstate))
-		cstate->replay_owner = (*stpp)->st_stateowner;
+	nfsd4_cstate_assign_replay(cstate, (*stpp)->st_stateowner);
 
 	return nfs4_seqid_op_checks(cstate, stateid, seqid, *stpp);
 }
@@ -3945,8 +3945,7 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	status = nfs_ok;
 out:
 	nfsd4_bump_seqid(cstate, status);
-	if (!cstate->replay_owner)
-		nfs4_unlock_state();
+	nfs4_unlock_state();
 	return status;
 }
 
@@ -4028,8 +4027,7 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp,
 	status = nfs_ok;
 out:
 	nfsd4_bump_seqid(cstate, status);
-	if (!cstate->replay_owner)
-		nfs4_unlock_state();
+	nfs4_unlock_state();
 	return status;
 }
 
@@ -4086,8 +4084,7 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 		}
 	}
 out:
-	if (!cstate->replay_owner)
-		nfs4_unlock_state();
+	nfs4_unlock_state();
 	return status;
 }
 
@@ -4495,8 +4492,7 @@ out:
 	if (status && new_state)
 		release_lockowner(lock_sop);
 	nfsd4_bump_seqid(cstate, status);
-	if (!cstate->replay_owner)
-		nfs4_unlock_state();
+	nfs4_unlock_state();
 	if (file_lock)
 		locks_free_lock(file_lock);
 	if (conflock)
@@ -4659,8 +4655,7 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 
 out:
 	nfsd4_bump_seqid(cstate, status);
-	if (!cstate->replay_owner)
-		nfs4_unlock_state();
+	nfs4_unlock_state();
 	if (file_lock)
 		locks_free_lock(file_lock);
 	return status;
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 83d9721d9644..80789aa5b5b4 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -330,6 +330,7 @@ struct nfs4_replay {
 	unsigned int		rp_buflen;
 	char			*rp_buf;
 	struct knfsd_fh		rp_openfh;
+	struct mutex		rp_mutex;
 	char			rp_ibuf[NFSD4_REPLAY_ISIZE];
 };
 
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
index 5ea7df305083..2f887c944048 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -73,6 +73,25 @@ static inline bool nfsd4_has_session(struct nfsd4_compound_state *cs)
 	return cs->slot != NULL;
 }
 
+static inline void nfsd4_cstate_assign_replay(struct nfsd4_compound_state *cstate,
+		struct nfs4_stateowner *so)
+{
+	if (!nfsd4_has_session(cstate)) {
+		mutex_lock(&so->so_replay.rp_mutex);
+		cstate->replay_owner = so;
+	}
+}
+
+static inline void nfsd4_cstate_clear_replay(struct nfsd4_compound_state *cstate)
+{
+	struct nfs4_stateowner *so = cstate->replay_owner;
+
+	if (so != NULL) {
+		cstate->replay_owner = NULL;
+		mutex_unlock(&so->so_replay.rp_mutex);
+	}
+}
+
 struct nfsd4_change_info {
 	u32		atomic;
 	bool		change_supported;
-- 
1.9.0


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

* [PATCH 15/70] NFSd: Add locking to the nfs4_file->fi_fds[] array
  2014-04-18 18:44                           ` [PATCH 14/70] NFSd: Add a mutex to protect the NFSv4.0 open owner replay cache Trond Myklebust
@ 2014-04-18 18:44                             ` Trond Myklebust
  2014-04-18 18:44                               ` [PATCH 16/70] NFSd: Protect the nfs4_file delegation fields using the fi_lock Trond Myklebust
  2014-04-19 14:35                               ` [PATCH 15/70] NFSd: Add locking to the nfs4_file->fi_fds[] array Christoph Hellwig
  0 siblings, 2 replies; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 107 ++++++++++++++++++++++++++++++++++++++++++++--------
 fs/nfsd/state.h     |  26 -------------
 2 files changed, 91 insertions(+), 42 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index ad7d21e06c36..73e7da308d37 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -249,6 +249,54 @@ get_nfs4_file(struct nfs4_file *fi)
 	atomic_inc(&fi->fi_ref);
 }
 
+static struct file *__nfs4_get_fd(struct nfs4_file *f, int oflag)
+{
+	if (f->fi_fds[oflag])
+		return get_file(f->fi_fds[oflag]);
+	return NULL;
+}
+
+/* XXX: for first cut may fall back on returning file that doesn't work
+ * at all? */
+static struct file *find_writeable_file(struct nfs4_file *f)
+{
+	struct file *ret;
+
+	spin_lock(&f->fi_lock);
+	ret = __nfs4_get_fd(f, O_WRONLY);
+	if (!ret)
+		ret = __nfs4_get_fd(f, O_RDWR);
+	spin_unlock(&f->fi_lock);
+	return ret;
+}
+
+static struct file *find_readable_file(struct nfs4_file *f)
+{
+	struct file *ret;
+
+	spin_lock(&f->fi_lock);
+	ret = __nfs4_get_fd(f, O_RDONLY);
+	if (!ret)
+		ret = __nfs4_get_fd(f, O_RDWR);
+	spin_unlock(&f->fi_lock);
+	return ret;
+}
+
+static struct file *find_any_file(struct nfs4_file *f)
+{
+	struct file *ret;
+
+	spin_lock(&f->fi_lock);
+	ret = __nfs4_get_fd(f, O_RDWR);
+	if (!ret) {
+		ret = __nfs4_get_fd(f, O_WRONLY);
+		if (!ret)
+			ret = __nfs4_get_fd(f, O_RDONLY);
+	}
+	spin_unlock(&f->fi_lock);
+	return ret;
+}
+
 static int num_delegations;
 unsigned long max_delegations;
 
@@ -297,20 +345,29 @@ static void nfs4_file_get_access(struct nfs4_file *fp, int oflag)
 		__nfs4_file_get_access(fp, oflag);
 }
 
-static void nfs4_file_put_fd(struct nfs4_file *fp, int oflag)
+static struct file *nfs4_file_put_fd(struct nfs4_file *fp, int oflag)
 {
-	if (fp->fi_fds[oflag]) {
-		fput(fp->fi_fds[oflag]);
-		fp->fi_fds[oflag] = NULL;
-	}
+	struct file *filp;
+
+	filp = fp->fi_fds[oflag];
+	fp->fi_fds[oflag] = NULL;
+	return filp;
 }
 
 static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag)
 {
-	if (atomic_dec_and_test(&fp->fi_access[oflag])) {
-		nfs4_file_put_fd(fp, oflag);
+	if (atomic_dec_and_lock(&fp->fi_access[oflag], &fp->fi_lock)) {
+		struct file *f1 = NULL;
+		struct file *f2 = NULL;
+
+		f1 = nfs4_file_put_fd(fp, oflag);
 		if (atomic_read(&fp->fi_access[1 - oflag]) == 0)
-			nfs4_file_put_fd(fp, O_RDWR);
+			f2 = nfs4_file_put_fd(fp, O_RDWR);
+		spin_unlock(&fp->fi_lock);
+		if (f1)
+			fput(f1);
+		if (f2)
+			fput(f2);
 	}
 }
 
@@ -651,8 +708,10 @@ static void release_lock_stateid(struct nfs4_ol_stateid *stp)
 	unhash_generic_stateid(stp);
 	unhash_stid(&stp->st_stid);
 	file = find_any_file(stp->st_file);
-	if (file)
+	if (file) {
 		locks_remove_posix(file, (fl_owner_t)lockowner(stp->st_stateowner));
+		fput(file);
+	}
 	close_generic_stateid(stp);
 	free_generic_stateid(stp);
 }
@@ -2985,17 +3044,27 @@ static inline int nfs4_access_to_access(u32 nfs4_access)
 static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
 		struct svc_fh *cur_fh, struct nfsd4_open *open)
 {
+	struct file *filp = NULL;
 	__be32 status;
 	int oflag = nfs4_access_to_omode(open->op_share_access);
 	int access = nfs4_access_to_access(open->op_share_access);
 
+	spin_lock(&fp->fi_lock);
 	if (!fp->fi_fds[oflag]) {
-		status = nfsd_open(rqstp, cur_fh, S_IFREG, access,
-			&fp->fi_fds[oflag]);
+		spin_unlock(&fp->fi_lock);
+		status = nfsd_open(rqstp, cur_fh, S_IFREG, access, &filp);
 		if (status)
 			return status;
+		spin_lock(&fp->fi_lock);
+		if (!fp->fi_fds[oflag]) {
+			fp->fi_fds[oflag] = filp;
+			filp = NULL;
+		}
 	}
 	nfs4_file_get_access(fp, oflag);
+	spin_unlock(&fp->fi_lock);
+	if (filp)
+		fput(filp);
 
 	return nfs_ok;
 }
@@ -3094,13 +3163,15 @@ static int nfs4_setlease(struct nfs4_delegation *dp)
 	if (status)
 		goto out_free;
 	fp->fi_lease = fl;
-	fp->fi_deleg_file = get_file(fl->fl_file);
+	fp->fi_deleg_file = fl->fl_file;
 	atomic_set(&fp->fi_delegees, 1);
 	spin_lock(&state_lock);
 	hash_delegation_locked(dp, fp);
 	spin_unlock(&state_lock);
 	return 0;
 out_free:
+	if (fl->fl_file)
+		fput(fl->fl_file);
 	locks_free_lock(fl);
 	return status;
 }
@@ -3734,6 +3805,7 @@ nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate,
 				status = nfserr_serverfault;
 				goto out;
 			}
+			get_file(file);
 		}
 		break;
 	case NFS4_OPEN_STID:
@@ -3761,7 +3833,7 @@ nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate,
 	}
 	status = nfs_ok;
 	if (file)
-		*filpp = get_file(file);
+		*filpp = file;
 out:
 	nfs4_unlock_state();
 	return status;
@@ -4489,6 +4561,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 		break;
 	}
 out:
+	if (filp)
+		fput(filp);
 	if (status && new_state)
 		release_lockowner(lock_sop);
 	nfsd4_bump_seqid(cstate, status);
@@ -4630,7 +4704,7 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	if (!file_lock) {
 		dprintk("NFSD: %s: unable to allocate lock!\n", __func__);
 		status = nfserr_jukebox;
-		goto out;
+		goto fput;
 	}
 	locks_init_lock(file_lock);
 	file_lock->fl_type = F_UNLCK;
@@ -4652,7 +4726,8 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	}
 	update_stateid(&stp->st_stid.sc_stateid);
 	memcpy(&locku->lu_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
-
+fput:
+	fput(filp);
 out:
 	nfsd4_bump_seqid(cstate, status);
 	nfs4_unlock_state();
@@ -4662,7 +4737,7 @@ out:
 
 out_nfserr:
 	status = nfserrno(err);
-	goto out;
+	goto fput;
 }
 
 /*
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 80789aa5b5b4..004733885cca 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -405,32 +405,6 @@ struct nfs4_file {
 	bool			fi_had_conflict;
 };
 
-/* XXX: for first cut may fall back on returning file that doesn't work
- * at all? */
-static inline struct file *find_writeable_file(struct nfs4_file *f)
-{
-	if (f->fi_fds[O_WRONLY])
-		return f->fi_fds[O_WRONLY];
-	return f->fi_fds[O_RDWR];
-}
-
-static inline struct file *find_readable_file(struct nfs4_file *f)
-{
-	if (f->fi_fds[O_RDONLY])
-		return f->fi_fds[O_RDONLY];
-	return f->fi_fds[O_RDWR];
-}
-
-static inline struct file *find_any_file(struct nfs4_file *f)
-{
-	if (f->fi_fds[O_RDWR])
-		return f->fi_fds[O_RDWR];
-	else if (f->fi_fds[O_WRONLY])
-		return f->fi_fds[O_WRONLY];
-	else
-		return f->fi_fds[O_RDONLY];
-}
-
 /* "ol" stands for "Open or Lock".  Better suggestions welcome. */
 struct nfs4_ol_stateid {
 	struct nfs4_stid    st_stid; /* must be first field */
-- 
1.9.0


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

* [PATCH 16/70] NFSd: Protect the nfs4_file delegation fields using the fi_lock
  2014-04-18 18:44                             ` [PATCH 15/70] NFSd: Add locking to the nfs4_file->fi_fds[] array Trond Myklebust
@ 2014-04-18 18:44                               ` Trond Myklebust
  2014-04-18 18:44                                 ` [PATCH 17/70] NFSd: Lock owners are not per open stateid Trond Myklebust
  2014-04-19 14:35                               ` [PATCH 15/70] NFSd: Add locking to the nfs4_file->fi_fds[] array Christoph Hellwig
  1 sibling, 1 reply; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 33 ++++++++++++++++++++++++++-------
 1 file changed, 26 insertions(+), 7 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 73e7da308d37..5105dbc76888 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -479,6 +479,7 @@ nfs4_put_delegation(struct nfs4_delegation *dp)
 	}
 }
 
+/* Call under fp->fi_lock */
 static void nfs4_put_deleg_lease(struct nfs4_file *fp)
 {
 	if (atomic_dec_and_test(&fp->fi_delegees)) {
@@ -511,6 +512,7 @@ unhash_delegation(struct nfs4_delegation *dp)
 	struct nfs4_file *fp = dp->dl_file;
 
 	spin_lock(&state_lock);
+	spin_lock(&fp->fi_lock);
 	list_del_init(&dp->dl_perclnt);
 	list_del_init(&dp->dl_recall_lru);
 	if (!list_empty(&dp->dl_perfile)) {
@@ -518,10 +520,11 @@ unhash_delegation(struct nfs4_delegation *dp)
 		list_del_init(&dp->dl_perfile);
 		spin_unlock(&fp->fi_inode->i_lock);
 	}
-	spin_unlock(&state_lock);
 	nfs4_put_deleg_lease(fp);
-	put_nfs4_file(fp);
 	dp->dl_file = NULL;
+	spin_unlock(&fp->fi_lock);
+	spin_unlock(&state_lock);
+	put_nfs4_file(fp);
 }
 
 
@@ -3153,23 +3156,33 @@ static int nfs4_setlease(struct nfs4_delegation *dp)
 {
 	struct nfs4_file *fp = dp->dl_file;
 	struct file_lock *fl;
-	int status;
+	int status = 0;
 
 	fl = nfs4_alloc_init_lease(dp, NFS4_OPEN_DELEGATE_READ);
 	if (!fl)
 		return -ENOMEM;
 	fl->fl_file = find_readable_file(fp);
+	spin_lock(&state_lock);
+	spin_lock(&fp->fi_lock);
+	/* Race breaker */
+	if (fp->fi_lease) {
+		atomic_inc(&fp->fi_delegees);
+		hash_delegation_locked(dp, fp);
+		goto out_free;
+	}
 	status = vfs_setlease(fl->fl_file, fl->fl_type, &fl);
 	if (status)
 		goto out_free;
 	fp->fi_lease = fl;
 	fp->fi_deleg_file = fl->fl_file;
 	atomic_set(&fp->fi_delegees, 1);
-	spin_lock(&state_lock);
 	hash_delegation_locked(dp, fp);
+	spin_unlock(&fp->fi_lock);
 	spin_unlock(&state_lock);
 	return 0;
 out_free:
+	spin_unlock(&fp->fi_lock);
+	spin_unlock(&state_lock);
 	if (fl->fl_file)
 		fput(fl->fl_file);
 	locks_free_lock(fl);
@@ -3183,23 +3196,29 @@ static int nfs4_set_delegation(struct nfs4_delegation *dp, struct nfs4_file *fp)
 	if (fp->fi_had_conflict)
 		return -EAGAIN;
 	get_nfs4_file(fp);
+	spin_lock(&state_lock);
+	spin_lock(&fp->fi_lock);
 	dp->dl_file = fp;
 	if (!fp->fi_lease) {
+		spin_unlock(&fp->fi_lock);
+		spin_unlock(&state_lock);
 		status = nfs4_setlease(dp);
 		if (status)
 			goto out_free;
 		return 0;
 	}
-	spin_lock(&state_lock);
 	if (fp->fi_had_conflict) {
-		spin_unlock(&state_lock);
 		status = -EAGAIN;
-		goto out_free;
+		goto unlock_and_free;
 	}
 	atomic_inc(&fp->fi_delegees);
 	hash_delegation_locked(dp, fp);
+	spin_unlock(&fp->fi_lock);
 	spin_unlock(&state_lock);
 	return 0;
+unlock_and_free:
+	spin_unlock(&fp->fi_lock);
+	spin_unlock(&state_lock);
 out_free:
 	put_nfs4_file(fp);
 	dp->dl_file = fp;
-- 
1.9.0


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

* [PATCH 17/70] NFSd: Lock owners are not per open stateid
  2014-04-18 18:44                               ` [PATCH 16/70] NFSd: Protect the nfs4_file delegation fields using the fi_lock Trond Myklebust
@ 2014-04-18 18:44                                 ` Trond Myklebust
  2014-04-18 18:44                                   ` [PATCH 18/70] NFSd: Clean up helper __release_lock_stateid Trond Myklebust
  0 siblings, 1 reply; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

In the NFSv4 spec, lock stateids are per-file objects. Lockowners are not.
This patch replaces the current list of lock owners in the open statids
with a list of lock stateids.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 48 +++++++++++++++++++++++++++++++-----------------
 fs/nfsd/state.h     |  3 +--
 2 files changed, 32 insertions(+), 19 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 5105dbc76888..8a12d59c8f36 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -704,10 +704,11 @@ static void free_generic_stateid(struct nfs4_ol_stateid *stp)
 	nfs4_free_stid(stateid_slab, &stp->st_stid);
 }
 
-static void release_lock_stateid(struct nfs4_ol_stateid *stp)
+static void __release_lock_stateid(struct nfs4_ol_stateid *stp)
 {
 	struct file *file;
 
+	list_del(&stp->st_locks);
 	unhash_generic_stateid(stp);
 	unhash_stid(&stp->st_stid);
 	file = find_any_file(stp->st_file);
@@ -724,12 +725,11 @@ static void unhash_lockowner(struct nfs4_lockowner *lo)
 	struct nfs4_ol_stateid *stp;
 
 	list_del(&lo->lo_owner.so_strhash);
-	list_del(&lo->lo_perstateid);
 	list_del(&lo->lo_owner_ino_hash);
 	while (!list_empty(&lo->lo_owner.so_stateids)) {
 		stp = list_first_entry(&lo->lo_owner.so_stateids,
 				struct nfs4_ol_stateid, st_perstateowner);
-		release_lock_stateid(stp);
+		__release_lock_stateid(stp);
 	}
 }
 
@@ -745,22 +745,36 @@ static void release_lockowner(struct nfs4_lockowner *lo)
 	nfs4_free_lockowner(lo);
 }
 
-static void
-release_stateid_lockowners(struct nfs4_ol_stateid *open_stp)
+static void release_lockowner_if_empty(struct nfs4_lockowner *lo)
+{
+	if (list_empty(&lo->lo_owner.so_stateids))
+		release_lockowner(lo);
+}
+
+static void release_lock_stateid(struct nfs4_ol_stateid *stp)
 {
 	struct nfs4_lockowner *lo;
 
-	while (!list_empty(&open_stp->st_lockowners)) {
-		lo = list_entry(open_stp->st_lockowners.next,
-				struct nfs4_lockowner, lo_perstateid);
-		release_lockowner(lo);
+	lo = lockowner(stp->st_stateowner);
+	__release_lock_stateid(stp);
+	release_lockowner_if_empty(lo);
+}
+
+static void release_open_stateid_locks(struct nfs4_ol_stateid *open_stp)
+{
+	struct nfs4_ol_stateid *stp;
+
+	while (!list_empty(&open_stp->st_locks)) {
+		stp = list_entry(open_stp->st_locks.next,
+				struct nfs4_ol_stateid, st_locks);
+		release_lock_stateid(stp);
 	}
 }
 
 static void unhash_open_stateid(struct nfs4_ol_stateid *stp)
 {
 	unhash_generic_stateid(stp);
-	release_stateid_lockowners(stp);
+	release_open_stateid_locks(stp);
 	close_generic_stateid(stp);
 }
 
@@ -2716,7 +2730,7 @@ static void init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp,
 	struct nfs4_openowner *oo = open->op_openowner;
 
 	stp->st_stid.sc_type = NFS4_OPEN_STID;
-	INIT_LIST_HEAD(&stp->st_lockowners);
+	INIT_LIST_HEAD(&stp->st_locks);
 	list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids);
 	stp->st_stateowner = &oo->oo_owner;
 	get_nfs4_file(fp);
@@ -4327,7 +4341,6 @@ static void hash_lockowner(struct nfs4_lockowner *lo, unsigned int strhashval, s
 
 	list_add(&lo->lo_owner.so_strhash, &nn->ownerstr_hashtbl[strhashval]);
 	list_add(&lo->lo_owner_ino_hash, &nn->lockowner_ino_hashtbl[inohash]);
-	list_add(&lo->lo_perstateid, &open_stp->st_lockowners);
 }
 
 /*
@@ -4371,6 +4384,7 @@ alloc_init_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp, struct
 	stp->st_access_bmap = 0;
 	stp->st_deny_bmap = open_stp->st_deny_bmap;
 	stp->st_openstp = open_stp;
+	list_add(&stp->st_locks, &open_stp->st_locks);
 	spin_lock(&fp->fi_lock);
 	list_add(&stp->st_perfile, &fp->fi_stateids);
 	spin_unlock(&fp->fi_lock);
@@ -4962,18 +4976,18 @@ static void nfsd_print_count(struct nfs4_client *clp, unsigned int count,
 	printk(KERN_INFO "NFS Client: %s has %u %s\n", buf, count, type);
 }
 
-static u64 nfsd_foreach_client_lock(struct nfs4_client *clp, u64 max, void (*func)(struct nfs4_lockowner *))
+static u64 nfsd_foreach_client_lock(struct nfs4_client *clp, u64 max, void (*func)(struct nfs4_ol_stateid *))
 {
 	struct nfs4_openowner *oop;
-	struct nfs4_lockowner *lop, *lo_next;
 	struct nfs4_ol_stateid *stp, *st_next;
+	struct nfs4_ol_stateid *lst, *lst_next;
 	u64 count = 0;
 
 	list_for_each_entry(oop, &clp->cl_openowners, oo_perclient) {
 		list_for_each_entry_safe(stp, st_next, &oop->oo_owner.so_stateids, st_perstateowner) {
-			list_for_each_entry_safe(lop, lo_next, &stp->st_lockowners, lo_perstateid) {
+			list_for_each_entry_safe(lst, lst_next, &stp->st_locks, st_locks) {
 				if (func)
-					func(lop);
+					func(lst);
 				if (++count == max)
 					return count;
 			}
@@ -4985,7 +4999,7 @@ static u64 nfsd_foreach_client_lock(struct nfs4_client *clp, u64 max, void (*fun
 
 u64 nfsd_forget_client_locks(struct nfs4_client *clp, u64 max)
 {
-	return nfsd_foreach_client_lock(clp, max, release_lockowner);
+	return nfsd_foreach_client_lock(clp, max, release_lock_stateid);
 }
 
 u64 nfsd_print_client_locks(struct nfs4_client *clp, u64 max)
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 004733885cca..51df8df04d6a 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -367,7 +367,6 @@ struct nfs4_openowner {
 struct nfs4_lockowner {
 	struct nfs4_stateowner	lo_owner; /* must be first element */
 	struct list_head	lo_owner_ino_hash; /* hash by owner,file */
-	struct list_head        lo_perstateid;
 	struct list_head	lo_list; /* for temporary uses */
 };
 
@@ -410,7 +409,7 @@ struct nfs4_ol_stateid {
 	struct nfs4_stid    st_stid; /* must be first field */
 	struct list_head              st_perfile;
 	struct list_head              st_perstateowner;
-	struct list_head              st_lockowners;
+	struct list_head              st_locks;
 	struct nfs4_stateowner      * st_stateowner;
 	struct nfs4_file            * st_file;
 	unsigned long                 st_access_bmap;
-- 
1.9.0


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

* [PATCH 18/70] NFSd: Clean up helper __release_lock_stateid
  2014-04-18 18:44                                 ` [PATCH 17/70] NFSd: Lock owners are not per open stateid Trond Myklebust
@ 2014-04-18 18:44                                   ` Trond Myklebust
  2014-04-18 18:44                                     ` [PATCH 19/70] NFSd: Allow lockowners to hold several stateids Trond Myklebust
  0 siblings, 1 reply; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

Use filp_close() instead of open coding

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 13 ++++++-------
 1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 8a12d59c8f36..0809e8355577 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -704,7 +704,8 @@ static void free_generic_stateid(struct nfs4_ol_stateid *stp)
 	nfs4_free_stid(stateid_slab, &stp->st_stid);
 }
 
-static void __release_lock_stateid(struct nfs4_ol_stateid *stp)
+static void __release_lock_stateid(struct nfs4_lockowner *lo,
+		struct nfs4_ol_stateid *stp)
 {
 	struct file *file;
 
@@ -712,10 +713,8 @@ static void __release_lock_stateid(struct nfs4_ol_stateid *stp)
 	unhash_generic_stateid(stp);
 	unhash_stid(&stp->st_stid);
 	file = find_any_file(stp->st_file);
-	if (file) {
-		locks_remove_posix(file, (fl_owner_t)lockowner(stp->st_stateowner));
-		fput(file);
-	}
+	if (file)
+		filp_close(file, (fl_owner_t)lo);
 	close_generic_stateid(stp);
 	free_generic_stateid(stp);
 }
@@ -729,7 +728,7 @@ static void unhash_lockowner(struct nfs4_lockowner *lo)
 	while (!list_empty(&lo->lo_owner.so_stateids)) {
 		stp = list_first_entry(&lo->lo_owner.so_stateids,
 				struct nfs4_ol_stateid, st_perstateowner);
-		__release_lock_stateid(stp);
+		__release_lock_stateid(lo, stp);
 	}
 }
 
@@ -756,7 +755,7 @@ static void release_lock_stateid(struct nfs4_ol_stateid *stp)
 	struct nfs4_lockowner *lo;
 
 	lo = lockowner(stp->st_stateowner);
-	__release_lock_stateid(stp);
+	__release_lock_stateid(lo, stp);
 	release_lockowner_if_empty(lo);
 }
 
-- 
1.9.0


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

* [PATCH 19/70] NFSd: Allow lockowners to hold several stateids
  2014-04-18 18:44                                   ` [PATCH 18/70] NFSd: Clean up helper __release_lock_stateid Trond Myklebust
@ 2014-04-18 18:44                                     ` Trond Myklebust
  2014-04-18 18:44                                       ` [PATCH 20/70] NFSd: NFSv4 lock-owners are not associated to a specific file Trond Myklebust
  2014-05-07 15:20                                       ` [PATCH 19/70] NFSd: Allow lockowners to hold several stateids Bruce Fields
  0 siblings, 2 replies; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 46 +++++++++++++++++++++++++++++-----------------
 1 file changed, 29 insertions(+), 17 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 0809e8355577..dad2f7b511b8 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -4390,6 +4390,19 @@ alloc_init_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp, struct
 	return stp;
 }
 
+static struct nfs4_ol_stateid *
+find_lock_stateid(struct nfs4_lockowner *lo, struct inode *inode)
+{
+	struct nfs4_ol_stateid *lst;
+
+	list_for_each_entry(lst, &lo->lo_owner.so_stateids, st_perstateowner) {
+		if (lst->st_file->fi_inode == inode)
+			return lst;
+	}
+	return NULL;
+}
+
+
 static int
 check_lock_length(u64 offset, u64 length)
 {
@@ -4419,25 +4432,24 @@ static __be32 lookup_or_create_lock_state(struct nfsd4_compound_state *cstate, s
 
 	lo = find_lockowner_str(fi->fi_inode, &cl->cl_clientid,
 				&lock->v.new.owner, nn);
-	if (lo) {
-		if (!cstate->minorversion)
-			return nfserr_bad_seqid;
-		/* XXX: a lockowner always has exactly one stateid: */
-		*lst = list_first_entry(&lo->lo_owner.so_stateids,
-				struct nfs4_ol_stateid, st_perstateowner);
-		return nfs_ok;
+	if (!lo) {
+		strhashval = ownerstr_hashval(cl->cl_clientid.cl_id,
+				&lock->v.new.owner);
+		lo = alloc_init_lock_stateowner(strhashval, cl, ost, lock);
+		if (lo == NULL)
+			return nfserr_jukebox;
 	}
-	strhashval = ownerstr_hashval(cl->cl_clientid.cl_id,
-			&lock->v.new.owner);
-	lo = alloc_init_lock_stateowner(strhashval, cl, ost, lock);
-	if (lo == NULL)
-		return nfserr_jukebox;
-	*lst = alloc_init_lock_stateid(lo, fi, ost);
+	if (!cstate->minorversion)
+		return nfserr_bad_seqid;
+	*lst = find_lock_stateid(lo, fi->fi_inode);
 	if (*lst == NULL) {
-		release_lockowner(lo);
-		return nfserr_jukebox;
+		*lst = alloc_init_lock_stateid(lo, fi, ost);
+		if (*lst == NULL) {
+			release_lockowner_if_empty(lo);
+			return nfserr_jukebox;
+		}
+		*new = true;
 	}
-	*new = true;
 	return nfs_ok;
 }
 
@@ -4596,7 +4608,7 @@ out:
 	if (filp)
 		fput(filp);
 	if (status && new_state)
-		release_lockowner(lock_sop);
+		release_lockowner_if_empty(lock_sop);
 	nfsd4_bump_seqid(cstate, status);
 	nfs4_unlock_state();
 	if (file_lock)
-- 
1.9.0


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

* [PATCH 20/70] NFSd: NFSv4 lock-owners are not associated to a specific file
  2014-04-18 18:44                                     ` [PATCH 19/70] NFSd: Allow lockowners to hold several stateids Trond Myklebust
@ 2014-04-18 18:44                                       ` Trond Myklebust
  2014-04-18 18:44                                         ` [PATCH 21/70] NFSd: Get rid of the lockowner_ino_hashtbl Trond Myklebust
  2014-05-07 15:20                                       ` [PATCH 19/70] NFSd: Allow lockowners to hold several stateids Bruce Fields
  1 sibling, 1 reply; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

Just like open-owners, lock-owners are associated with a name, a clientid
and, in the case of minor version 0, a sequence id. There is no association
to a file.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 38 +++++++++++++-------------------------
 1 file changed, 13 insertions(+), 25 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index dad2f7b511b8..be48dbc32f97 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -4249,8 +4249,7 @@ last_byte_offset(u64 start, u64 len)
 
 static unsigned int lockowner_ino_hashval(struct inode *inode, u32 cl_id, struct xdr_netobj *ownername)
 {
-	return (file_hashval(inode) + cl_id
-			+ opaque_hashval(ownername->data, ownername->len))
+	return (cl_id + opaque_hashval(ownername->data, ownername->len))
 		& LOCKOWNER_INO_HASH_MASK;
 }
 
@@ -4306,27 +4305,19 @@ nevermind:
 		deny->ld_type = NFS4_WRITE_LT;
 }
 
-static bool same_lockowner_ino(struct nfs4_lockowner *lo, struct inode *inode, clientid_t *clid, struct xdr_netobj *owner)
-{
-	struct nfs4_ol_stateid *lst;
-
-	if (!same_owner_str(&lo->lo_owner, owner, clid))
-		return false;
-	lst = list_first_entry(&lo->lo_owner.so_stateids,
-			       struct nfs4_ol_stateid, st_perstateowner);
-	return lst->st_file->fi_inode == inode;
-}
-
 static struct nfs4_lockowner *
-find_lockowner_str(struct inode *inode, clientid_t *clid,
-		   struct xdr_netobj *owner, struct nfsd_net *nn)
+find_lockowner_str(clientid_t *clid, struct xdr_netobj *owner,
+		struct nfsd_net *nn)
 {
-	unsigned int hashval = lockowner_ino_hashval(inode, clid->cl_id, owner);
-	struct nfs4_lockowner *lo;
+	unsigned int strhashval = ownerstr_hashval(clid->cl_id, owner);
+	struct nfs4_stateowner *so;
 
-	list_for_each_entry(lo, &nn->lockowner_ino_hashtbl[hashval], lo_owner_ino_hash) {
-		if (same_lockowner_ino(lo, inode, clid, owner))
-			return lo;
+	list_for_each_entry(so, &nn->ownerstr_hashtbl[strhashval], so_strhash) {
+		if (so->so_is_open_owner)
+			continue;
+		if (!same_owner_str(so, owner, clid))
+			continue;
+		return lockowner(so);
 	}
 	return NULL;
 }
@@ -4430,8 +4421,7 @@ static __be32 lookup_or_create_lock_state(struct nfsd4_compound_state *cstate, s
 	unsigned int strhashval;
 	struct nfsd_net *nn = net_generic(cl->net, nfsd_net_id);
 
-	lo = find_lockowner_str(fi->fi_inode, &cl->cl_clientid,
-				&lock->v.new.owner, nn);
+	lo = find_lockowner_str(&cl->cl_clientid, &lock->v.new.owner, nn);
 	if (!lo) {
 		strhashval = ownerstr_hashval(cl->cl_clientid.cl_id,
 				&lock->v.new.owner);
@@ -4642,7 +4632,6 @@ __be32
 nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	    struct nfsd4_lockt *lockt)
 {
-	struct inode *inode;
 	struct file_lock *file_lock = NULL;
 	struct nfs4_lockowner *lo;
 	__be32 status;
@@ -4665,7 +4654,6 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0)))
 		goto out;
 
-	inode = cstate->current_fh.fh_dentry->d_inode;
 	file_lock = locks_alloc_lock();
 	if (!file_lock) {
 		dprintk("NFSD: %s: unable to allocate lock!\n", __func__);
@@ -4688,7 +4676,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 		goto out;
 	}
 
-	lo = find_lockowner_str(inode, &lockt->lt_clientid, &lockt->lt_owner, nn);
+	lo = find_lockowner_str(&lockt->lt_clientid, &lockt->lt_owner, nn);
 	if (lo)
 		file_lock->fl_owner = (fl_owner_t)lo;
 	file_lock->fl_pid = current->tgid;
-- 
1.9.0


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

* [PATCH 21/70] NFSd: Get rid of the lockowner_ino_hashtbl
  2014-04-18 18:44                                       ` [PATCH 20/70] NFSd: NFSv4 lock-owners are not associated to a specific file Trond Myklebust
@ 2014-04-18 18:44                                         ` Trond Myklebust
  2014-04-18 18:44                                           ` [PATCH 22/70] NFSd: Cleanup nfs4svc_encode_compoundres Trond Myklebust
  2014-04-19 14:38                                           ` [PATCH 21/70] NFSd: Get rid of the lockowner_ino_hashtbl Christoph Hellwig
  0 siblings, 2 replies; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

It is no longer used.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/netns.h     |  4 ----
 fs/nfsd/nfs4state.c | 26 ++------------------------
 fs/nfsd/state.h     |  1 -
 3 files changed, 2 insertions(+), 29 deletions(-)

diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h
index d32b3aa6600d..beaceac90ad3 100644
--- a/fs/nfsd/netns.h
+++ b/fs/nfsd/netns.h
@@ -29,9 +29,6 @@
 #define CLIENT_HASH_SIZE                (1 << CLIENT_HASH_BITS)
 #define CLIENT_HASH_MASK                (CLIENT_HASH_SIZE - 1)
 
-#define LOCKOWNER_INO_HASH_BITS		8
-#define LOCKOWNER_INO_HASH_SIZE		(1 << LOCKOWNER_INO_HASH_BITS)
-
 #define SESSION_HASH_SIZE	512
 
 struct cld_net;
@@ -67,7 +64,6 @@ struct nfsd_net {
 	struct list_head *unconf_id_hashtbl;
 	struct rb_root unconf_name_tree;
 	struct list_head *ownerstr_hashtbl;
-	struct list_head *lockowner_ino_hashtbl;
 	struct list_head *sessionid_hashtbl;
 	/*
 	 * client_lru holds client queue ordered by nfs4_client.cl_time
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index be48dbc32f97..38ca008c3d41 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -724,7 +724,6 @@ static void unhash_lockowner(struct nfs4_lockowner *lo)
 	struct nfs4_ol_stateid *stp;
 
 	list_del(&lo->lo_owner.so_strhash);
-	list_del(&lo->lo_owner_ino_hash);
 	while (!list_empty(&lo->lo_owner.so_stateids)) {
 		stp = list_first_entry(&lo->lo_owner.so_stateids,
 				struct nfs4_ol_stateid, st_perstateowner);
@@ -4225,8 +4224,6 @@ out:
 
 #define LOFF_OVERFLOW(start, len)      ((u64)(len) > ~(u64)(start))
 
-#define LOCKOWNER_INO_HASH_MASK (LOCKOWNER_INO_HASH_SIZE - 1)
-
 static inline u64
 end_offset(u64 start, u64 len)
 {
@@ -4247,12 +4244,6 @@ last_byte_offset(u64 start, u64 len)
 	return end > start ? end - 1: NFS4_MAX_UINT64;
 }
 
-static unsigned int lockowner_ino_hashval(struct inode *inode, u32 cl_id, struct xdr_netobj *ownername)
-{
-	return (cl_id + opaque_hashval(ownername->data, ownername->len))
-		& LOCKOWNER_INO_HASH_MASK;
-}
-
 /*
  * TODO: Linux file offsets are _signed_ 64-bit quantities, which means that
  * we can't properly handle lock requests that go beyond the (2^63 - 1)-th
@@ -4322,15 +4313,11 @@ find_lockowner_str(clientid_t *clid, struct xdr_netobj *owner,
 	return NULL;
 }
 
-static void hash_lockowner(struct nfs4_lockowner *lo, unsigned int strhashval, struct nfs4_client *clp, struct nfs4_ol_stateid *open_stp)
+static void hash_lockowner(struct nfs4_lockowner *lo, unsigned int strhashval, struct nfs4_client *clp)
 {
-	struct inode *inode = open_stp->st_file->fi_inode;
-	unsigned int inohash = lockowner_ino_hashval(inode,
-			clp->cl_clientid.cl_id, &lo->lo_owner.so_owner);
 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
 
 	list_add(&lo->lo_owner.so_strhash, &nn->ownerstr_hashtbl[strhashval]);
-	list_add(&lo->lo_owner_ino_hash, &nn->lockowner_ino_hashtbl[inohash]);
 }
 
 /*
@@ -4353,7 +4340,7 @@ alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, str
 	/* It is the openowner seqid that will be incremented in encode in the
 	 * case of new lockowners; so increment the lock seqid manually: */
 	lo->lo_owner.so_seqid = lock->lk_new_lock_seqid + 1;
-	hash_lockowner(lo, strhashval, clp, open_stp);
+	hash_lockowner(lo, strhashval, clp);
 	return lo;
 }
 
@@ -5174,10 +5161,6 @@ static int nfs4_state_create_net(struct net *net)
 			OWNER_HASH_SIZE, GFP_KERNEL);
 	if (!nn->ownerstr_hashtbl)
 		goto err_ownerstr;
-	nn->lockowner_ino_hashtbl = kmalloc(sizeof(struct list_head) *
-			LOCKOWNER_INO_HASH_SIZE, GFP_KERNEL);
-	if (!nn->lockowner_ino_hashtbl)
-		goto err_lockowner_ino;
 	nn->sessionid_hashtbl = kmalloc(sizeof(struct list_head) *
 			SESSION_HASH_SIZE, GFP_KERNEL);
 	if (!nn->sessionid_hashtbl)
@@ -5189,8 +5172,6 @@ static int nfs4_state_create_net(struct net *net)
 	}
 	for (i = 0; i < OWNER_HASH_SIZE; i++)
 		INIT_LIST_HEAD(&nn->ownerstr_hashtbl[i]);
-	for (i = 0; i < LOCKOWNER_INO_HASH_SIZE; i++)
-		INIT_LIST_HEAD(&nn->lockowner_ino_hashtbl[i]);
 	for (i = 0; i < SESSION_HASH_SIZE; i++)
 		INIT_LIST_HEAD(&nn->sessionid_hashtbl[i]);
 	nn->conf_name_tree = RB_ROOT;
@@ -5206,8 +5187,6 @@ static int nfs4_state_create_net(struct net *net)
 	return 0;
 
 err_sessionid:
-	kfree(nn->lockowner_ino_hashtbl);
-err_lockowner_ino:
 	kfree(nn->ownerstr_hashtbl);
 err_ownerstr:
 	kfree(nn->unconf_id_hashtbl);
@@ -5239,7 +5218,6 @@ nfs4_state_destroy_net(struct net *net)
 	}
 
 	kfree(nn->sessionid_hashtbl);
-	kfree(nn->lockowner_ino_hashtbl);
 	kfree(nn->ownerstr_hashtbl);
 	kfree(nn->unconf_id_hashtbl);
 	kfree(nn->conf_id_hashtbl);
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 51df8df04d6a..02fc6685ab3f 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -366,7 +366,6 @@ struct nfs4_openowner {
 
 struct nfs4_lockowner {
 	struct nfs4_stateowner	lo_owner; /* must be first element */
-	struct list_head	lo_owner_ino_hash; /* hash by owner,file */
 	struct list_head	lo_list; /* for temporary uses */
 };
 
-- 
1.9.0


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

* [PATCH 22/70] NFSd: Cleanup nfs4svc_encode_compoundres
  2014-04-18 18:44                                         ` [PATCH 21/70] NFSd: Get rid of the lockowner_ino_hashtbl Trond Myklebust
@ 2014-04-18 18:44                                           ` Trond Myklebust
  2014-04-18 18:44                                             ` [PATCH 23/70] NFSd: Don't get a session reference without a client reference Trond Myklebust
  2014-04-19 14:38                                           ` [PATCH 21/70] NFSd: Get rid of the lockowner_ino_hashtbl Christoph Hellwig
  1 sibling, 1 reply; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

Move the slot return, put session etc into a helper in fs/nfsd/nfs4state.c
instead of open coding in nfs4svc_encode_compoundres.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 35 ++++++++++++++++++++++-------------
 fs/nfsd/nfs4xdr.c   | 15 +--------------
 fs/nfsd/state.h     |  1 -
 fs/nfsd/xdr4.h      |  2 +-
 4 files changed, 24 insertions(+), 29 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 38ca008c3d41..9421e56454a2 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -202,18 +202,6 @@ static void put_client_renew_locked(struct nfs4_client *clp)
 		renew_client_locked(clp);
 }
 
-void put_client_renew(struct nfs4_client *clp)
-{
-	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
-
-	if (!atomic_dec_and_lock(&clp->cl_refcount, &nn->client_lock))
-		return;
-	if (!is_client_expired(clp))
-		renew_client_locked(clp);
-	spin_unlock(&nn->client_lock);
-}
-
-
 static inline u32
 opaque_hashval(const void *ptr, int nbytes)
 {
@@ -1657,7 +1645,7 @@ out_err:
 /*
  * Cache a reply. nfsd4_check_resp_size() has bounded the cache size.
  */
-void
+static void
 nfsd4_store_cache_entry(struct nfsd4_compoundres *resp)
 {
 	struct nfsd4_slot *slot = resp->cstate.slot;
@@ -2414,6 +2402,27 @@ out_put_client:
 	goto out_no_session;
 }
 
+void
+nfsd4_sequence_done(struct nfsd4_compoundres *resp)
+{
+	struct nfsd4_compound_state *cs = &resp->cstate;
+
+	if (nfsd4_has_session(cs)) {
+		struct nfs4_client *clp = cs->session->se_client;
+		struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
+
+		if (cs->status != nfserr_replay_cache) {
+			nfsd4_store_cache_entry(resp);
+			cs->slot->sl_flags &= ~NFSD4_SLOT_INUSE;
+		}
+		/* Renew the clientid on success and on replay */
+		spin_lock(&nn->client_lock);
+		nfsd4_put_session(cs->session);
+		put_client_renew_locked(clp);
+		spin_unlock(&nn->client_lock);
+	}
+}
+
 __be32
 nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_destroy_clientid *dc)
 {
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 2723c1badd01..8f6e7a4dc8b0 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -3727,7 +3727,6 @@ nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compo
 	/*
 	 * All that remains is to write the tag and operation count...
 	 */
-	struct nfsd4_compound_state *cs = &resp->cstate;
 	struct kvec *iov;
 	p = resp->tagp;
 	*p++ = htonl(resp->taglen);
@@ -3741,19 +3740,7 @@ nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compo
 		iov = &rqstp->rq_res.head[0];
 	iov->iov_len = ((char*)resp->p) - (char*)iov->iov_base;
 	BUG_ON(iov->iov_len > PAGE_SIZE);
-	if (nfsd4_has_session(cs)) {
-		struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
-		struct nfs4_client *clp = cs->session->se_client;
-		if (cs->status != nfserr_replay_cache) {
-			nfsd4_store_cache_entry(resp);
-			cs->slot->sl_flags &= ~NFSD4_SLOT_INUSE;
-		}
-		/* Renew the clientid on success and on replay */
-		spin_lock(&nn->client_lock);
-		nfsd4_put_session(cs->session);
-		spin_unlock(&nn->client_lock);
-		put_client_renew(clp);
-	}
+	nfsd4_sequence_done(resp);
 	return 1;
 }
 
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 02fc6685ab3f..e5444e0aedad 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -452,7 +452,6 @@ extern void nfs4_put_delegation(struct nfs4_delegation *dp);
 extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(const char *name,
 							struct nfsd_net *nn);
 extern bool nfs4_has_reclaimed_state(const char *name, struct nfsd_net *nn);
-extern void put_client_renew(struct nfs4_client *clp);
 
 /* nfs4recover operations */
 extern int nfsd4_client_tracking_init(struct net *net);
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
index 2f887c944048..a617f1a3ba83 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -592,7 +592,6 @@ extern __be32 nfsd4_setclientid(struct svc_rqst *rqstp,
 extern __be32 nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
 		struct nfsd4_compound_state *,
 		struct nfsd4_setclientid_confirm *setclientid_confirm);
-extern void nfsd4_store_cache_entry(struct nfsd4_compoundres *resp);
 extern __be32 nfsd4_exchange_id(struct svc_rqst *rqstp,
 		struct nfsd4_compound_state *, struct nfsd4_exchange_id *);
 extern __be32 nfsd4_backchannel_ctl(struct svc_rqst *, struct nfsd4_compound_state *, struct nfsd4_backchannel_ctl *);
@@ -603,6 +602,7 @@ extern __be32 nfsd4_create_session(struct svc_rqst *,
 extern __be32 nfsd4_sequence(struct svc_rqst *,
 		struct nfsd4_compound_state *,
 		struct nfsd4_sequence *);
+extern void nfsd4_sequence_done(struct nfsd4_compoundres *resp);
 extern __be32 nfsd4_destroy_session(struct svc_rqst *,
 		struct nfsd4_compound_state *,
 		struct nfsd4_destroy_session *);
-- 
1.9.0


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

* [PATCH 23/70] NFSd: Don't get a session reference without a client reference
  2014-04-18 18:44                                           ` [PATCH 22/70] NFSd: Cleanup nfs4svc_encode_compoundres Trond Myklebust
@ 2014-04-18 18:44                                             ` Trond Myklebust
  2014-04-18 18:44                                               ` [PATCH 24/70] NFSd: Move the delegation reference counter into the struct nfs4_stid Trond Myklebust
  0 siblings, 1 reply; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

If the client were to disappear from underneath us while we're holding
a session reference, things would be bad. This cleanup ensures that
it cannot.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 112 +++++++++++++++++++++++++++++++---------------------
 fs/nfsd/state.h     |   2 -
 2 files changed, 68 insertions(+), 46 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 9421e56454a2..ab66f73643a9 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -102,12 +102,6 @@ static bool is_session_dead(struct nfsd4_session *ses)
 	return ses->se_flags & NFS4_SESSION_DEAD;
 }
 
-void nfsd4_put_session(struct nfsd4_session *ses)
-{
-	if (atomic_dec_and_test(&ses->se_ref) && is_session_dead(ses))
-		free_session(ses);
-}
-
 static __be32 mark_session_dead_locked(struct nfsd4_session *ses, int ref_held_by_me)
 {
 	if (atomic_read(&ses->se_ref) > ref_held_by_me)
@@ -116,14 +110,6 @@ static __be32 mark_session_dead_locked(struct nfsd4_session *ses, int ref_held_b
 	return nfs_ok;
 }
 
-static __be32 nfsd4_get_session_locked(struct nfsd4_session *ses)
-{
-	if (is_session_dead(ses))
-		return nfserr_badsession;
-	atomic_inc(&ses->se_ref);
-	return nfs_ok;
-}
-
 void
 nfs4_unlock_state(void)
 {
@@ -202,6 +188,39 @@ static void put_client_renew_locked(struct nfs4_client *clp)
 		renew_client_locked(clp);
 }
 
+static __be32 nfsd4_get_session_locked(struct nfsd4_session *ses)
+{
+	__be32 status;
+
+	if (is_session_dead(ses))
+		return nfserr_badsession;
+	status = get_client_locked(ses->se_client);
+	if (status)
+		return status;
+	atomic_inc(&ses->se_ref);
+	return nfs_ok;
+}
+
+static void nfsd4_put_session_locked(struct nfsd4_session *ses)
+{
+	struct nfs4_client *clp = ses->se_client;
+
+	if (atomic_dec_and_test(&ses->se_ref) && is_session_dead(ses))
+		free_session(ses);
+	put_client_renew_locked(clp);
+}
+
+static void nfsd4_put_session(struct nfsd4_session *ses)
+{
+	struct nfs4_client *clp = ses->se_client;
+	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
+
+	spin_lock(&nn->client_lock);
+	nfsd4_put_session_locked(ses);
+	spin_unlock(&nn->client_lock);
+}
+
+
 static inline u32
 opaque_hashval(const void *ptr, int nbytes)
 {
@@ -1119,7 +1138,7 @@ static void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, stru
 
 /* caller must hold client_lock */
 static struct nfsd4_session *
-find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid, struct net *net)
+__find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid, struct net *net)
 {
 	struct nfsd4_session *elem;
 	int idx;
@@ -1139,6 +1158,24 @@ find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid, struct net *net)
 	return NULL;
 }
 
+static struct nfsd4_session *
+find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid, struct net *net,
+		__be32 *ret)
+{
+	struct nfsd4_session *session;
+	__be32 status = nfserr_badsession;
+
+	session = __find_in_sessionid_hashtbl(sessionid, net);
+	if (!session)
+		goto out;
+	status = nfsd4_get_session_locked(session);
+	if (status)
+		session = NULL;
+out:
+	*ret = status;
+	return session;
+}
+
 /* caller must hold client_lock */
 static void
 unhash_session(struct nfsd4_session *ses)
@@ -2152,17 +2189,17 @@ __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp,
 	__be32 status;
 	struct nfsd4_conn *conn;
 	struct nfsd4_session *session;
-	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
+	struct net *net = SVC_NET(rqstp);
+	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 
 	if (!nfsd4_last_compound_op(rqstp))
 		return nfserr_not_only_op;
 	nfs4_lock_state();
 	spin_lock(&nn->client_lock);
-	session = find_in_sessionid_hashtbl(&bcts->sessionid, SVC_NET(rqstp));
+	session = find_in_sessionid_hashtbl(&bcts->sessionid, net, &status);
 	spin_unlock(&nn->client_lock);
-	status = nfserr_badsession;
 	if (!session)
-		goto out;
+		goto out_no_session;
 	status = nfserr_wrong_cred;
 	if (!mach_creds_match(session->se_client, rqstp))
 		goto out;
@@ -2176,6 +2213,8 @@ __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp,
 	nfsd4_init_conn(rqstp, conn, session);
 	status = nfs_ok;
 out:
+	nfsd4_put_session(session);
+out_no_session:
 	nfs4_unlock_state();
 	return status;
 }
@@ -2195,7 +2234,8 @@ nfsd4_destroy_session(struct svc_rqst *r,
 	struct nfsd4_session *ses;
 	__be32 status;
 	int ref_held_by_me = 0;
-	struct nfsd_net *nn = net_generic(SVC_NET(r), nfsd_net_id);
+	struct net *net = SVC_NET(r);
+	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 
 	nfs4_lock_state();
 	status = nfserr_not_only_op;
@@ -2206,14 +2246,12 @@ nfsd4_destroy_session(struct svc_rqst *r,
 	}
 	dump_sessionid(__func__, &sessionid->sessionid);
 	spin_lock(&nn->client_lock);
-	ses = find_in_sessionid_hashtbl(&sessionid->sessionid, SVC_NET(r));
-	status = nfserr_badsession;
+	ses = find_in_sessionid_hashtbl(&sessionid->sessionid, net, &status);
 	if (!ses)
 		goto out_client_lock;
 	status = nfserr_wrong_cred;
 	if (!mach_creds_match(ses->se_client, r))
-		goto out_client_lock;
-	nfsd4_get_session_locked(ses);
+		goto out_put_session;
 	status = mark_session_dead_locked(ses, 1 + ref_held_by_me);
 	if (status)
 		goto out_put_session;
@@ -2225,7 +2263,7 @@ nfsd4_destroy_session(struct svc_rqst *r,
 	spin_lock(&nn->client_lock);
 	status = nfs_ok;
 out_put_session:
-	nfsd4_put_session(ses);
+	nfsd4_put_session_locked(ses);
 out_client_lock:
 	spin_unlock(&nn->client_lock);
 out:
@@ -2298,7 +2336,8 @@ nfsd4_sequence(struct svc_rqst *rqstp,
 	struct nfsd4_slot *slot;
 	struct nfsd4_conn *conn;
 	__be32 status;
-	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
+	struct net *net = SVC_NET(rqstp);
+	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 
 	if (resp->opcnt != 1)
 		return nfserr_sequence_pos;
@@ -2312,17 +2351,10 @@ nfsd4_sequence(struct svc_rqst *rqstp,
 		return nfserr_jukebox;
 
 	spin_lock(&nn->client_lock);
-	status = nfserr_badsession;
-	session = find_in_sessionid_hashtbl(&seq->sessionid, SVC_NET(rqstp));
+	session = find_in_sessionid_hashtbl(&seq->sessionid, net, &status);
 	if (!session)
 		goto out_no_session;
 	clp = session->se_client;
-	status = get_client_locked(clp);
-	if (status)
-		goto out_no_session;
-	status = nfsd4_get_session_locked(session);
-	if (status)
-		goto out_put_client;
 
 	status = nfserr_too_many_ops;
 	if (nfsd4_session_too_many_ops(rqstp, session))
@@ -2396,9 +2428,7 @@ out_no_session:
 	spin_unlock(&nn->client_lock);
 	return status;
 out_put_session:
-	nfsd4_put_session(session);
-out_put_client:
-	put_client_renew_locked(clp);
+	nfsd4_put_session_locked(session);
 	goto out_no_session;
 }
 
@@ -2408,18 +2438,12 @@ nfsd4_sequence_done(struct nfsd4_compoundres *resp)
 	struct nfsd4_compound_state *cs = &resp->cstate;
 
 	if (nfsd4_has_session(cs)) {
-		struct nfs4_client *clp = cs->session->se_client;
-		struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
-
 		if (cs->status != nfserr_replay_cache) {
 			nfsd4_store_cache_entry(resp);
 			cs->slot->sl_flags &= ~NFSD4_SLOT_INUSE;
 		}
-		/* Renew the clientid on success and on replay */
-		spin_lock(&nn->client_lock);
+		/* Drop session reference that was taken in nfsd4_sequence() */
 		nfsd4_put_session(cs->session);
-		put_client_renew_locked(clp);
-		spin_unlock(&nn->client_lock);
 	}
 }
 
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index e5444e0aedad..559134675b5a 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -213,8 +213,6 @@ struct nfsd4_session {
 	struct nfsd4_slot	*se_slots[];	/* forward channel slots */
 };
 
-extern void nfsd4_put_session(struct nfsd4_session *ses);
-
 /* formatted contents of nfs4_sessionid */
 struct nfsd4_sessionid {
 	clientid_t	clientid;
-- 
1.9.0


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

* [PATCH 24/70] NFSd: Move the delegation reference counter into the struct nfs4_stid
  2014-04-18 18:44                                             ` [PATCH 23/70] NFSd: Don't get a session reference without a client reference Trond Myklebust
@ 2014-04-18 18:44                                               ` Trond Myklebust
  2014-04-18 18:44                                                 ` [PATCH 25/70] NFSd: Simplify stateid management Trond Myklebust
  0 siblings, 1 reply; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

We will want to add reference counting to the lock stateid and open
stateids too.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 6 +++---
 fs/nfsd/state.h     | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index ab66f73643a9..afb767319f66 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -411,6 +411,7 @@ kmem_cache *slab)
 	stid->sc_stateid.si_opaque.so_clid = cl->cl_clientid;
 	/* Will be incremented before return to client: */
 	stid->sc_stateid.si_generation = 0;
+	atomic_set(&stid->sc_count, 1);
 
 	/*
 	 * It shouldn't be a problem to reuse an opaque stateid value.
@@ -457,7 +458,6 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct sv
 	dp->dl_type = NFS4_OPEN_DELEGATE_READ;
 	fh_copy_shallow(&dp->dl_fh, &current_fh->fh_handle);
 	dp->dl_time = 0;
-	atomic_set(&dp->dl_count, 1);
 	nfsd4_init_callback(&dp->dl_recall);
 	return dp;
 }
@@ -480,7 +480,7 @@ static void nfs4_free_stid(struct kmem_cache *slab, struct nfs4_stid *s)
 void
 nfs4_put_delegation(struct nfs4_delegation *dp)
 {
-	if (atomic_dec_and_test(&dp->dl_count)) {
+	if (atomic_dec_and_test(&dp->dl_stid.sc_count)) {
 		nfs4_free_stid(deleg_slab, &dp->dl_stid);
 		num_delegations--;
 	}
@@ -2892,7 +2892,7 @@ static void nfsd_break_one_deleg(struct nfs4_delegation *dp)
 	 * callback (and since the lease code is serialized by the kernel
 	 * lock) we know the server hasn't removed the lease yet, we know
 	 * it's safe to take a reference: */
-	atomic_inc(&dp->dl_count);
+	atomic_inc(&dp->dl_stid.sc_count);
 	nfsd4_cb_recall(dp);
 }
 
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 559134675b5a..9d0088c244a8 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -74,6 +74,7 @@ struct nfsd4_callback {
 };
 
 struct nfs4_stid {
+	atomic_t sc_count;
 #define NFS4_OPEN_STID 1
 #define NFS4_LOCK_STID 2
 #define NFS4_DELEG_STID 4
@@ -91,7 +92,6 @@ struct nfs4_delegation {
 	struct list_head	dl_perfile;
 	struct list_head	dl_perclnt;
 	struct list_head	dl_recall_lru;  /* delegation recalled */
-	atomic_t		dl_count;       /* ref count */
 	struct nfs4_file	*dl_file;
 	u32			dl_type;
 	time_t			dl_time;
-- 
1.9.0


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

* [PATCH 25/70] NFSd: Simplify stateid management
  2014-04-18 18:44                                               ` [PATCH 24/70] NFSd: Move the delegation reference counter into the struct nfs4_stid Trond Myklebust
@ 2014-04-18 18:44                                                 ` Trond Myklebust
  2014-04-18 18:44                                                   ` [PATCH 26/70] NFSd: Fix delegation revocation Trond Myklebust
  2014-05-07 16:21                                                   ` [PATCH 25/70] NFSd: Simplify stateid management Bruce Fields
  0 siblings, 2 replies; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

Don't allow stateids to clear the open file pointer until they are
being destroyed.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 12 +++++-------
 1 file changed, 5 insertions(+), 7 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index afb767319f66..51ef179339ae 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -394,7 +394,7 @@ kmem_cache *slab)
 	struct nfs4_stid *stid;
 	int new_id;
 
-	stid = kmem_cache_alloc(slab, GFP_KERNEL);
+	stid = kmem_cache_zalloc(slab, GFP_KERNEL);
 	if (!stid)
 		return NULL;
 
@@ -481,6 +481,8 @@ void
 nfs4_put_delegation(struct nfs4_delegation *dp)
 {
 	if (atomic_dec_and_test(&dp->dl_stid.sc_count)) {
+		if (dp->dl_file)
+			put_nfs4_file(dp->dl_file);
 		nfs4_free_stid(deleg_slab, &dp->dl_stid);
 		num_delegations--;
 	}
@@ -528,10 +530,8 @@ unhash_delegation(struct nfs4_delegation *dp)
 		spin_unlock(&fp->fi_inode->i_lock);
 	}
 	nfs4_put_deleg_lease(fp);
-	dp->dl_file = NULL;
 	spin_unlock(&fp->fi_lock);
 	spin_unlock(&state_lock);
-	put_nfs4_file(fp);
 }
 
 
@@ -701,13 +701,13 @@ static void unhash_generic_stateid(struct nfs4_ol_stateid *stp)
 static void close_generic_stateid(struct nfs4_ol_stateid *stp)
 {
 	release_all_access(stp);
-	put_nfs4_file(stp->st_file);
-	stp->st_file = NULL;
 }
 
 static void free_generic_stateid(struct nfs4_ol_stateid *stp)
 {
 	remove_stid(&stp->st_stid);
+	if (stp->st_file)
+		put_nfs4_file(stp->st_file);
 	nfs4_free_stid(stateid_slab, &stp->st_stid);
 }
 
@@ -3265,8 +3265,6 @@ unlock_and_free:
 	spin_unlock(&fp->fi_lock);
 	spin_unlock(&state_lock);
 out_free:
-	put_nfs4_file(fp);
-	dp->dl_file = fp;
 	return status;
 }
 
-- 
1.9.0


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

* [PATCH 26/70] NFSd: Fix delegation revocation
  2014-04-18 18:44                                                 ` [PATCH 25/70] NFSd: Simplify stateid management Trond Myklebust
@ 2014-04-18 18:44                                                   ` Trond Myklebust
  2014-04-18 18:44                                                     ` [PATCH 27/70] NFSd: Don't let the laundromat reap clients that are referenced Trond Myklebust
  2014-05-07 18:46                                                     ` [PATCH 26/70] NFSd: Fix delegation revocation Bruce Fields
  2014-05-07 16:21                                                   ` [PATCH 25/70] NFSd: Simplify stateid management Bruce Fields
  1 sibling, 2 replies; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

Ensure that the delegations cannot be found by the laundromat etc once
we add them to the various 'revoke' lists.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 51 ++++++++++++++++++++++++++++++++-------------------
 1 file changed, 32 insertions(+), 19 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 51ef179339ae..273bdddb2458 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -516,11 +516,10 @@ hash_delegation_locked(struct nfs4_delegation *dp, struct nfs4_file *fp)
 
 /* Called under the state lock. */
 static void
-unhash_delegation(struct nfs4_delegation *dp)
+unhash_delegation_locked(struct nfs4_delegation *dp)
 {
 	struct nfs4_file *fp = dp->dl_file;
 
-	spin_lock(&state_lock);
 	spin_lock(&fp->fi_lock);
 	list_del_init(&dp->dl_perclnt);
 	list_del_init(&dp->dl_recall_lru);
@@ -531,23 +530,32 @@ unhash_delegation(struct nfs4_delegation *dp)
 	}
 	nfs4_put_deleg_lease(fp);
 	spin_unlock(&fp->fi_lock);
-	spin_unlock(&state_lock);
 }
 
+static void
+unhash_delegation(struct nfs4_delegation *dp)
+{
+	spin_lock(&state_lock);
+	unhash_delegation_locked(dp);
+	spin_unlock(&state_lock);
+}
 
-
-static void destroy_revoked_delegation(struct nfs4_delegation *dp)
+static void destroy_delegation(struct nfs4_delegation *dp)
 {
-	list_del_init(&dp->dl_recall_lru);
 	remove_stid(&dp->dl_stid);
 	nfs4_put_delegation(dp);
 }
 
-static void destroy_delegation(struct nfs4_delegation *dp)
+static void unhash_and_destroy_delegation(struct nfs4_delegation *dp)
 {
 	unhash_delegation(dp);
-	remove_stid(&dp->dl_stid);
-	nfs4_put_delegation(dp);
+	destroy_delegation(dp);
+}
+
+static void destroy_revoked_delegation(struct nfs4_delegation *dp)
+{
+	list_del_init(&dp->dl_recall_lru);
+	destroy_delegation(dp);
 }
 
 static void revoke_delegation(struct nfs4_delegation *dp)
@@ -555,11 +563,10 @@ static void revoke_delegation(struct nfs4_delegation *dp)
 	struct nfs4_client *clp = dp->dl_stid.sc_client;
 
 	if (clp->cl_minorversion == 0)
-		destroy_delegation(dp);
+		destroy_revoked_delegation(dp);
 	else {
-		unhash_delegation(dp);
 		dp->dl_stid.sc_type = NFS4_REVOKED_DELEG_STID;
-		list_add(&dp->dl_recall_lru, &clp->cl_revoked);
+		list_move(&dp->dl_recall_lru, &clp->cl_revoked);
 	}
 }
 
@@ -1278,12 +1285,13 @@ destroy_client(struct nfs4_client *clp)
 	spin_lock(&state_lock);
 	while (!list_empty(&clp->cl_delegations)) {
 		dp = list_entry(clp->cl_delegations.next, struct nfs4_delegation, dl_perclnt);
-		list_del_init(&dp->dl_perclnt);
-		list_move(&dp->dl_recall_lru, &reaplist);
+		unhash_delegation_locked(dp);
+		list_add(&dp->dl_recall_lru, &reaplist);
 	}
 	spin_unlock(&state_lock);
 	while (!list_empty(&reaplist)) {
 		dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru);
+		list_del_init(&dp->dl_recall_lru);
 		destroy_delegation(dp);
 	}
 	list_splice_init(&clp->cl_revoked, &reaplist);
@@ -3612,7 +3620,8 @@ nfs4_laundromat(struct nfsd_net *nn)
 				test_val = u;
 			break;
 		}
-		list_move(&dp->dl_recall_lru, &reaplist);
+		unhash_delegation_locked(dp);
+		list_add(&dp->dl_recall_lru, &reaplist);
 	}
 	spin_unlock(&state_lock);
 	list_for_each_safe(pos, next, &reaplist) {
@@ -4245,7 +4254,7 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	if (status)
 		goto out;
 
-	destroy_delegation(dp);
+	unhash_and_destroy_delegation(dp);
 out:
 	nfs4_unlock_state();
 
@@ -5061,8 +5070,10 @@ static u64 nfsd_find_all_delegations(struct nfs4_client *clp, u64 max,
 
 	lockdep_assert_held(&state_lock);
 	list_for_each_entry_safe(dp, next, &clp->cl_delegations, dl_perclnt) {
-		if (victims)
-			list_move(&dp->dl_recall_lru, victims);
+		if (victims) {
+			unhash_delegation_locked(dp);
+			list_add(&dp->dl_recall_lru, victims);
+		}
 		if (++count == max)
 			break;
 	}
@@ -5318,11 +5329,13 @@ nfs4_state_shutdown_net(struct net *net)
 	spin_lock(&state_lock);
 	list_for_each_safe(pos, next, &nn->del_recall_lru) {
 		dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
-		list_move(&dp->dl_recall_lru, &reaplist);
+		unhash_delegation_locked(dp);
+		list_add(&dp->dl_recall_lru, &reaplist);
 	}
 	spin_unlock(&state_lock);
 	list_for_each_safe(pos, next, &reaplist) {
 		dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
+		list_del_init(&dp->dl_recall_lru);
 		destroy_delegation(dp);
 	}
 
-- 
1.9.0


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

* [PATCH 27/70] NFSd: Don't let the laundromat reap clients that are referenced
  2014-04-18 18:44                                                   ` [PATCH 26/70] NFSd: Fix delegation revocation Trond Myklebust
@ 2014-04-18 18:44                                                     ` Trond Myklebust
  2014-04-18 18:44                                                       ` [PATCH 28/70] NFSd: Add reference counting to the lock and open stateids Trond Myklebust
  2014-05-07 19:20                                                       ` [PATCH 27/70] NFSd: Don't let the laundromat reap clients that are referenced Bruce Fields
  2014-05-07 18:46                                                     ` [PATCH 26/70] NFSd: Fix delegation revocation Bruce Fields
  1 sibling, 2 replies; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 273bdddb2458..41314e493110 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -3600,6 +3600,9 @@ nfs4_laundromat(struct nfsd_net *nn)
 				clp->cl_clientid.cl_id);
 			continue;
 		}
+		/* Hey, I'm busy with this guy! */
+		if (atomic_read(&clp->cl_refcount) != 0)
+			continue;
 		list_move(&clp->cl_lru, &reaplist);
 	}
 	spin_unlock(&nn->client_lock);
-- 
1.9.0


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

* [PATCH 28/70] NFSd: Add reference counting to the lock and open stateids
  2014-04-18 18:44                                                     ` [PATCH 27/70] NFSd: Don't let the laundromat reap clients that are referenced Trond Myklebust
@ 2014-04-18 18:44                                                       ` Trond Myklebust
  2014-04-18 18:44                                                         ` [PATCH 29/70] NFSd: Add a struct nfs4_file field to struct nfs4_stid Trond Myklebust
  2014-05-07 19:20                                                       ` [PATCH 27/70] NFSd: Don't let the laundromat reap clients that are referenced Bruce Fields
  1 sibling, 1 reply; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 41314e493110..32ab3f1c83f8 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -710,8 +710,10 @@ static void close_generic_stateid(struct nfs4_ol_stateid *stp)
 	release_all_access(stp);
 }
 
-static void free_generic_stateid(struct nfs4_ol_stateid *stp)
+static void put_generic_stateid(struct nfs4_ol_stateid *stp)
 {
+	if (!atomic_dec_and_test(&stp->st_stid.sc_count))
+		return;
 	remove_stid(&stp->st_stid);
 	if (stp->st_file)
 		put_nfs4_file(stp->st_file);
@@ -730,7 +732,7 @@ static void __release_lock_stateid(struct nfs4_lockowner *lo,
 	if (file)
 		filp_close(file, (fl_owner_t)lo);
 	close_generic_stateid(stp);
-	free_generic_stateid(stp);
+	put_generic_stateid(stp);
 }
 
 static void unhash_lockowner(struct nfs4_lockowner *lo)
@@ -793,7 +795,7 @@ static void unhash_open_stateid(struct nfs4_ol_stateid *stp)
 static void release_open_stateid(struct nfs4_ol_stateid *stp)
 {
 	unhash_open_stateid(stp);
-	free_generic_stateid(stp);
+	put_generic_stateid(stp);
 }
 
 static void unhash_openowner(struct nfs4_openowner *oo)
@@ -814,7 +816,7 @@ static void release_last_closed_stateid(struct nfs4_openowner *oo)
 	struct nfs4_ol_stateid *s = oo->oo_last_closed_stid;
 
 	if (s) {
-		free_generic_stateid(s);
+		put_generic_stateid(s);
 		oo->oo_last_closed_stid = NULL;
 	}
 }
@@ -3512,7 +3514,7 @@ void nfsd4_cleanup_open_state(struct nfsd4_open *open, __be32 status)
 	if (open->op_file)
 		nfsd4_free_file(open->op_file);
 	if (open->op_stp)
-		free_generic_stateid(open->op_stp);
+		put_generic_stateid(open->op_stp);
 }
 
 static __be32 lookup_clientid(clientid_t *clid, bool session, struct nfsd_net *nn, struct nfs4_client **clp)
@@ -4214,7 +4216,7 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	nfsd4_close_open_stateid(stp);
 
 	if (cstate->minorversion)
-		free_generic_stateid(stp);
+		put_generic_stateid(stp);
 	else
 		oo->oo_last_closed_stid = stp;
 
-- 
1.9.0


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

* [PATCH 29/70] NFSd: Add a struct nfs4_file field to struct nfs4_stid
  2014-04-18 18:44                                                       ` [PATCH 28/70] NFSd: Add reference counting to the lock and open stateids Trond Myklebust
@ 2014-04-18 18:44                                                         ` Trond Myklebust
  2014-04-18 18:44                                                           ` [PATCH 30/70] NFSd: Replace delegation->dl_file with the dl_stid.sc_file Trond Myklebust
  2014-05-07 19:25                                                           ` [PATCH 29/70] NFSd: Add a struct nfs4_file field to struct nfs4_stid Bruce Fields
  0 siblings, 2 replies; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

All stateids are associated with a nfs4_file. Let's consolidate...

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 2 ++
 fs/nfsd/state.h     | 1 +
 2 files changed, 3 insertions(+)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 32ab3f1c83f8..5bbef4720e7c 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -474,6 +474,8 @@ static void remove_stid(struct nfs4_stid *s)
 
 static void nfs4_free_stid(struct kmem_cache *slab, struct nfs4_stid *s)
 {
+	if (s->sc_file)
+		put_nfs4_file(s->sc_file);
 	kmem_cache_free(slab, s);
 }
 
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 9d0088c244a8..c6deef936693 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -85,6 +85,7 @@ struct nfs4_stid {
 	unsigned char sc_type;
 	stateid_t sc_stateid;
 	struct nfs4_client *sc_client;
+	struct nfs4_file *sc_file;
 };
 
 struct nfs4_delegation {
-- 
1.9.0


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

* [PATCH 30/70] NFSd: Replace delegation->dl_file with the dl_stid.sc_file
  2014-04-18 18:44                                                         ` [PATCH 29/70] NFSd: Add a struct nfs4_file field to struct nfs4_stid Trond Myklebust
@ 2014-04-18 18:44                                                           ` Trond Myklebust
  2014-04-18 18:44                                                             ` [PATCH 31/70] NFSd: Replace nfs4_ol_stateid->st_file with the st_stid.sc_file Trond Myklebust
                                                                               ` (2 more replies)
  2014-05-07 19:25                                                           ` [PATCH 29/70] NFSd: Add a struct nfs4_file field to struct nfs4_stid Bruce Fields
  1 sibling, 3 replies; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 13 +++++--------
 fs/nfsd/state.h     |  1 -
 2 files changed, 5 insertions(+), 9 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 5bbef4720e7c..48979ee79888 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -454,7 +454,6 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct sv
 	INIT_LIST_HEAD(&dp->dl_perfile);
 	INIT_LIST_HEAD(&dp->dl_perclnt);
 	INIT_LIST_HEAD(&dp->dl_recall_lru);
-	dp->dl_file = NULL;
 	dp->dl_type = NFS4_OPEN_DELEGATE_READ;
 	fh_copy_shallow(&dp->dl_fh, &current_fh->fh_handle);
 	dp->dl_time = 0;
@@ -483,8 +482,6 @@ void
 nfs4_put_delegation(struct nfs4_delegation *dp)
 {
 	if (atomic_dec_and_test(&dp->dl_stid.sc_count)) {
-		if (dp->dl_file)
-			put_nfs4_file(dp->dl_file);
 		nfs4_free_stid(deleg_slab, &dp->dl_stid);
 		num_delegations--;
 	}
@@ -520,7 +517,7 @@ hash_delegation_locked(struct nfs4_delegation *dp, struct nfs4_file *fp)
 static void
 unhash_delegation_locked(struct nfs4_delegation *dp)
 {
-	struct nfs4_file *fp = dp->dl_file;
+	struct nfs4_file *fp = dp->dl_stid.sc_file;
 
 	spin_lock(&fp->fi_lock);
 	list_del_init(&dp->dl_perclnt);
@@ -3204,14 +3201,14 @@ static struct file_lock *nfs4_alloc_init_lease(struct nfs4_delegation *dp, int f
 	fl->fl_flags = FL_DELEG;
 	fl->fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK;
 	fl->fl_end = OFFSET_MAX;
-	fl->fl_owner = (fl_owner_t)(dp->dl_file);
+	fl->fl_owner = (fl_owner_t)(dp->dl_stid.sc_file);
 	fl->fl_pid = current->tgid;
 	return fl;
 }
 
 static int nfs4_setlease(struct nfs4_delegation *dp)
 {
-	struct nfs4_file *fp = dp->dl_file;
+	struct nfs4_file *fp = dp->dl_stid.sc_file;
 	struct file_lock *fl;
 	int status = 0;
 
@@ -3255,7 +3252,7 @@ static int nfs4_set_delegation(struct nfs4_delegation *dp, struct nfs4_file *fp)
 	get_nfs4_file(fp);
 	spin_lock(&state_lock);
 	spin_lock(&fp->fi_lock);
-	dp->dl_file = fp;
+	dp->dl_stid.sc_file = fp;
 	if (!fp->fi_lease) {
 		spin_unlock(&fp->fi_lock);
 		spin_unlock(&state_lock);
@@ -3877,7 +3874,7 @@ nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate,
 		if (status)
 			goto out;
 		if (filpp) {
-			file = dp->dl_file->fi_deleg_file;
+			file = dp->dl_stid.sc_file->fi_deleg_file;
 			if (!file) {
 				WARN_ON_ONCE(1);
 				status = nfserr_serverfault;
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index c6deef936693..de198600616b 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -93,7 +93,6 @@ struct nfs4_delegation {
 	struct list_head	dl_perfile;
 	struct list_head	dl_perclnt;
 	struct list_head	dl_recall_lru;  /* delegation recalled */
-	struct nfs4_file	*dl_file;
 	u32			dl_type;
 	time_t			dl_time;
 /* For recall: */
-- 
1.9.0


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

* [PATCH 31/70] NFSd: Replace nfs4_ol_stateid->st_file with the st_stid.sc_file
  2014-04-18 18:44                                                           ` [PATCH 30/70] NFSd: Replace delegation->dl_file with the dl_stid.sc_file Trond Myklebust
@ 2014-04-18 18:44                                                             ` Trond Myklebust
  2014-04-18 18:44                                                               ` [PATCH 32/70] NFSd: Ensure stateids remain unique until they are freed Trond Myklebust
  2014-04-19 14:40                                                             ` [PATCH 30/70] NFSd: Replace delegation->dl_file with the dl_stid.sc_file Christoph Hellwig
  2014-05-05  9:01                                                             ` Christoph Hellwig
  2 siblings, 1 reply; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 38 ++++++++++++++++++--------------------
 fs/nfsd/state.h     |  1 -
 2 files changed, 18 insertions(+), 21 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 48979ee79888..2cb4124276d0 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -688,7 +688,7 @@ release_all_access(struct nfs4_ol_stateid *stp)
 
 	for (i = 1; i < 4; i++) {
 		if (test_access(i, stp))
-			nfs4_file_put_access(stp->st_file,
+			nfs4_file_put_access(stp->st_stid.sc_file,
 					     nfs4_access_to_omode(i));
 		clear_access(i, stp);
 	}
@@ -696,7 +696,7 @@ release_all_access(struct nfs4_ol_stateid *stp)
 
 static void unhash_generic_stateid(struct nfs4_ol_stateid *stp)
 {
-	struct nfs4_file *fp = stp->st_file;
+	struct nfs4_file *fp = stp->st_stid.sc_file;
 
 	spin_lock(&fp->fi_lock);
 	list_del(&stp->st_perfile);
@@ -714,8 +714,6 @@ static void put_generic_stateid(struct nfs4_ol_stateid *stp)
 	if (!atomic_dec_and_test(&stp->st_stid.sc_count))
 		return;
 	remove_stid(&stp->st_stid);
-	if (stp->st_file)
-		put_nfs4_file(stp->st_file);
 	nfs4_free_stid(stateid_slab, &stp->st_stid);
 }
 
@@ -727,7 +725,7 @@ static void __release_lock_stateid(struct nfs4_lockowner *lo,
 	list_del(&stp->st_locks);
 	unhash_generic_stateid(stp);
 	unhash_stid(&stp->st_stid);
-	file = find_any_file(stp->st_file);
+	file = find_any_file(stp->st_stid.sc_file);
 	if (file)
 		filp_close(file, (fl_owner_t)lo);
 	close_generic_stateid(stp);
@@ -2774,7 +2772,7 @@ static void init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp,
 	list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids);
 	stp->st_stateowner = &oo->oo_owner;
 	get_nfs4_file(fp);
-	stp->st_file = fp;
+	stp->st_stid.sc_file = fp;
 	stp->st_access_bmap = 0;
 	stp->st_deny_bmap = 0;
 	set_access(open->op_share_access, stp);
@@ -3350,7 +3348,7 @@ nfs4_open_delegation(struct net *net, struct svc_fh *fh,
 	dp = alloc_init_deleg(oo->oo_owner.so_client, stp, fh);
 	if (dp == NULL)
 		goto out_no_deleg;
-	status = nfs4_set_delegation(dp, stp->st_file);
+	status = nfs4_set_delegation(dp, stp->st_stid.sc_file);
 	if (status)
 		goto out_free;
 
@@ -3668,7 +3666,7 @@ laundromat_main(struct work_struct *laundry)
 
 static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_ol_stateid *stp)
 {
-	if (fhp->fh_dentry->d_inode != stp->st_file->fi_inode)
+	if (fhp->fh_dentry->d_inode != stp->st_stid.sc_file->fi_inode)
 		return nfserr_bad_stateid;
 	return nfs_ok;
 }
@@ -3897,9 +3895,9 @@ nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate,
 			goto out;
 		if (filpp) {
 			if (flags & RD_STATE)
-				file = find_readable_file(stp->st_file);
+				file = find_readable_file(stp->st_stid.sc_file);
 			else
-				file = find_writeable_file(stp->st_file);
+				file = find_writeable_file(stp->st_stid.sc_file);
 		}
 		break;
 	default:
@@ -3917,7 +3915,7 @@ out:
 static __be32
 nfsd4_free_lock_stateid(struct nfs4_ol_stateid *stp)
 {
-	if (check_for_locks(stp->st_file, lockowner(stp->st_stateowner)))
+	if (check_for_locks(stp->st_stid.sc_file, lockowner(stp->st_stateowner)))
 		return nfserr_locks_held;
 	release_lock_stateid(stp);
 	return nfs_ok;
@@ -4100,7 +4098,7 @@ static inline void nfs4_stateid_downgrade_bit(struct nfs4_ol_stateid *stp, u32 a
 {
 	if (!test_access(access, stp))
 		return;
-	nfs4_file_put_access(stp->st_file, nfs4_access_to_omode(access));
+	nfs4_file_put_access(stp->st_stid.sc_file, nfs4_access_to_omode(access));
 	clear_access(access, stp);
 }
 
@@ -4401,7 +4399,7 @@ alloc_init_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp, struct
 	list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids);
 	stp->st_stateowner = &lo->lo_owner;
 	get_nfs4_file(fp);
-	stp->st_file = fp;
+	stp->st_stid.sc_file = fp;
 	stp->st_access_bmap = 0;
 	stp->st_deny_bmap = open_stp->st_deny_bmap;
 	stp->st_openstp = open_stp;
@@ -4418,7 +4416,7 @@ find_lock_stateid(struct nfs4_lockowner *lo, struct inode *inode)
 	struct nfs4_ol_stateid *lst;
 
 	list_for_each_entry(lst, &lo->lo_owner.so_stateids, st_perstateowner) {
-		if (lst->st_file->fi_inode == inode)
+		if (lst->st_stid.sc_file->fi_inode == inode)
 			return lst;
 	}
 	return NULL;
@@ -4434,7 +4432,7 @@ check_lock_length(u64 offset, u64 length)
 
 static void get_lock_access(struct nfs4_ol_stateid *lock_stp, u32 access)
 {
-	struct nfs4_file *fp = lock_stp->st_file;
+	struct nfs4_file *fp = lock_stp->st_stid.sc_file;
 	int oflag = nfs4_access_to_omode(access);
 
 	if (test_access(access, lock_stp))
@@ -4445,7 +4443,7 @@ static void get_lock_access(struct nfs4_ol_stateid *lock_stp, u32 access)
 
 static __be32 lookup_or_create_lock_state(struct nfsd4_compound_state *cstate, struct nfs4_ol_stateid *ost, struct nfsd4_lock *lock, struct nfs4_ol_stateid **lst, bool *new)
 {
-	struct nfs4_file *fi = ost->st_file;
+	struct nfs4_file *fi = ost->st_stid.sc_file;
 	struct nfs4_openowner *oo = openowner(ost->st_stateowner);
 	struct nfs4_client *cl = oo->oo_owner.so_client;
 	struct nfs4_lockowner *lo;
@@ -4568,14 +4566,14 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	switch (lock->lk_type) {
 		case NFS4_READ_LT:
 		case NFS4_READW_LT:
-			filp = find_readable_file(lock_stp->st_file);
+			filp = find_readable_file(lock_stp->st_stid.sc_file);
 			if (filp)
 				get_lock_access(lock_stp, NFS4_SHARE_ACCESS_READ);
 			file_lock->fl_type = F_RDLCK;
 			break;
 		case NFS4_WRITE_LT:
 		case NFS4_WRITEW_LT:
-			filp = find_writeable_file(lock_stp->st_file);
+			filp = find_writeable_file(lock_stp->st_stid.sc_file);
 			if (filp)
 				get_lock_access(lock_stp, NFS4_SHARE_ACCESS_WRITE);
 			file_lock->fl_type = F_WRLCK;
@@ -4758,7 +4756,7 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 					&stp, nn);
 	if (status)
 		goto out;
-	filp = find_any_file(stp->st_file);
+	filp = find_any_file(stp->st_stid.sc_file);
 	if (!filp) {
 		status = nfserr_lock_range;
 		goto out;
@@ -4862,7 +4860,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
 		list_for_each_entry(stp, &sop->so_stateids,
 				st_perstateowner) {
 			lo = lockowner(sop);
-			if (check_for_locks(stp->st_file, lo))
+			if (check_for_locks(stp->st_stid.sc_file, lo))
 				goto out;
 			list_add(&lo->lo_list, &matches);
 		}
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index de198600616b..0539db97f7d3 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -408,7 +408,6 @@ struct nfs4_ol_stateid {
 	struct list_head              st_perstateowner;
 	struct list_head              st_locks;
 	struct nfs4_stateowner      * st_stateowner;
-	struct nfs4_file            * st_file;
 	unsigned long                 st_access_bmap;
 	unsigned long                 st_deny_bmap;
 	struct nfs4_ol_stateid         * st_openstp;
-- 
1.9.0


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

* [PATCH 32/70] NFSd: Ensure stateids remain unique until they are freed
  2014-04-18 18:44                                                             ` [PATCH 31/70] NFSd: Replace nfs4_ol_stateid->st_file with the st_stid.sc_file Trond Myklebust
@ 2014-04-18 18:44                                                               ` Trond Myklebust
  2014-04-18 18:44                                                                 ` [PATCH 33/70] NFSd: Ensure atomicity of stateid destruction and idr tree removal Trond Myklebust
  0 siblings, 1 reply; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

Add an extra delegation state to allow the stateid to remain in the idr
tree until the last reference has been released.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 8 ++++----
 fs/nfsd/state.h     | 1 +
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 2cb4124276d0..7b897ff03a27 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -473,6 +473,7 @@ static void remove_stid(struct nfs4_stid *s)
 
 static void nfs4_free_stid(struct kmem_cache *slab, struct nfs4_stid *s)
 {
+	remove_stid(s);
 	if (s->sc_file)
 		put_nfs4_file(s->sc_file);
 	kmem_cache_free(slab, s);
@@ -541,7 +542,7 @@ unhash_delegation(struct nfs4_delegation *dp)
 
 static void destroy_delegation(struct nfs4_delegation *dp)
 {
-	remove_stid(&dp->dl_stid);
+	dp->dl_stid.sc_type = NFS4_CLOSED_DELEG_STID;
 	nfs4_put_delegation(dp);
 }
 
@@ -554,7 +555,7 @@ static void unhash_and_destroy_delegation(struct nfs4_delegation *dp)
 static void destroy_revoked_delegation(struct nfs4_delegation *dp)
 {
 	list_del_init(&dp->dl_recall_lru);
-	destroy_delegation(dp);
+	nfs4_put_delegation(dp);
 }
 
 static void revoke_delegation(struct nfs4_delegation *dp)
@@ -713,7 +714,6 @@ static void put_generic_stateid(struct nfs4_ol_stateid *stp)
 {
 	if (!atomic_dec_and_test(&stp->st_stid.sc_count))
 		return;
-	remove_stid(&stp->st_stid);
 	nfs4_free_stid(stateid_slab, &stp->st_stid);
 }
 
@@ -3359,7 +3359,6 @@ nfs4_open_delegation(struct net *net, struct svc_fh *fh,
 	open->op_delegate_type = NFS4_OPEN_DELEGATE_READ;
 	return;
 out_free:
-	remove_stid(&dp->dl_stid);
 	nfs4_put_delegation(dp);
 out_no_deleg:
 	open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE;
@@ -3803,6 +3802,7 @@ static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid)
 	default:
 		printk("unknown stateid type %x\n", s->sc_type);
 	case NFS4_CLOSED_STID:
+	case NFS4_CLOSED_DELEG_STID:
 		return nfserr_bad_stateid;
 	}
 }
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 0539db97f7d3..a4ac75a0de21 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -82,6 +82,7 @@ struct nfs4_stid {
 #define NFS4_CLOSED_STID 8
 /* For a deleg stateid kept around only to process free_stateid's: */
 #define NFS4_REVOKED_DELEG_STID 16
+#define NFS4_CLOSED_DELEG_STID 32
 	unsigned char sc_type;
 	stateid_t sc_stateid;
 	struct nfs4_client *sc_client;
-- 
1.9.0


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

* [PATCH 33/70] NFSd: Ensure atomicity of stateid destruction and idr tree removal
  2014-04-18 18:44                                                               ` [PATCH 32/70] NFSd: Ensure stateids remain unique until they are freed Trond Myklebust
@ 2014-04-18 18:44                                                                 ` Trond Myklebust
  2014-04-18 18:44                                                                   ` [PATCH 34/70] NFSd: Fix atomicity of delegation counter Trond Myklebust
  0 siblings, 1 reply; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 26 +++++++++++++++-----------
 1 file changed, 15 insertions(+), 11 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 7b897ff03a27..f463aaf9cd13 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -461,31 +461,37 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct sv
 	return dp;
 }
 
-static void remove_stid(struct nfs4_stid *s)
+static void remove_stid_locked(struct nfs4_client *clp, struct nfs4_stid *s)
 {
-	struct nfs4_client *clp = s->sc_client;
 	struct idr *stateids = &clp->cl_stateids;
 
-	spin_lock(&clp->cl_lock);
 	idr_remove(stateids, s->sc_stateid.si_opaque.so_id);
-	spin_unlock(&clp->cl_lock);
 }
 
 static void nfs4_free_stid(struct kmem_cache *slab, struct nfs4_stid *s)
 {
-	remove_stid(s);
 	if (s->sc_file)
 		put_nfs4_file(s->sc_file);
 	kmem_cache_free(slab, s);
 }
 
+static bool nfs4_put_stid(struct kmem_cache *slab, struct nfs4_stid *s)
+{
+	struct nfs4_client *clp = s->sc_client;
+
+	if (!atomic_dec_and_lock(&s->sc_count, &clp->cl_lock))
+		return false;
+	remove_stid_locked(clp, s);
+	spin_unlock(&clp->cl_lock);
+	nfs4_free_stid(slab, s);
+	return true;
+}
+
 void
 nfs4_put_delegation(struct nfs4_delegation *dp)
 {
-	if (atomic_dec_and_test(&dp->dl_stid.sc_count)) {
-		nfs4_free_stid(deleg_slab, &dp->dl_stid);
+	if (nfs4_put_stid(deleg_slab, &dp->dl_stid))
 		num_delegations--;
-	}
 }
 
 /* Call under fp->fi_lock */
@@ -712,9 +718,7 @@ static void close_generic_stateid(struct nfs4_ol_stateid *stp)
 
 static void put_generic_stateid(struct nfs4_ol_stateid *stp)
 {
-	if (!atomic_dec_and_test(&stp->st_stid.sc_count))
-		return;
-	nfs4_free_stid(stateid_slab, &stp->st_stid);
+	nfs4_put_stid(stateid_slab, &stp->st_stid);
 }
 
 static void __release_lock_stateid(struct nfs4_lockowner *lo,
-- 
1.9.0


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

* [PATCH 34/70] NFSd: Fix atomicity of delegation counter
  2014-04-18 18:44                                                                 ` [PATCH 33/70] NFSd: Ensure atomicity of stateid destruction and idr tree removal Trond Myklebust
@ 2014-04-18 18:44                                                                   ` Trond Myklebust
  2014-04-18 18:44                                                                     ` [PATCH 35/70] NFSd: Slight cleanup of find_stateid() Trond Myklebust
  2014-04-19 15:51                                                                     ` [PATCH 34/70] NFSd: Fix atomicity of delegation counter Christoph Hellwig
  0 siblings, 2 replies; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 21 ++++++++++++++-------
 1 file changed, 14 insertions(+), 7 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index f463aaf9cd13..87464802126a 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -304,7 +304,7 @@ static struct file *find_any_file(struct nfs4_file *f)
 	return ret;
 }
 
-static int num_delegations;
+static atomic_long_t num_delegations;
 unsigned long max_delegations;
 
 /*
@@ -439,18 +439,19 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct sv
 	struct nfs4_delegation *dp;
 
 	dprintk("NFSD alloc_init_deleg\n");
-	if (num_delegations > max_delegations)
-		return NULL;
+	atomic_long_inc(&num_delegations);
+	smp_mb__after_atomic_inc();
+	if (atomic_long_read(&num_delegations) > max_delegations)
+		goto out_dec;
 	dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab));
 	if (dp == NULL)
-		return dp;
+		goto out_dec;
 	/*
 	 * delegation seqid's are never incremented.  The 4.1 special
 	 * meaning of seqid 0 isn't meaningful, really, but let's avoid
 	 * 0 anyway just for consistency and use 1:
 	 */
 	dp->dl_stid.sc_stateid.si_generation = 1;
-	num_delegations++;
 	INIT_LIST_HEAD(&dp->dl_perfile);
 	INIT_LIST_HEAD(&dp->dl_perclnt);
 	INIT_LIST_HEAD(&dp->dl_recall_lru);
@@ -459,6 +460,10 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct sv
 	dp->dl_time = 0;
 	nfsd4_init_callback(&dp->dl_recall);
 	return dp;
+out_dec:
+	atomic_long_dec(&num_delegations);
+	smp_mb__after_atomic_dec();
+	return NULL;
 }
 
 static void remove_stid_locked(struct nfs4_client *clp, struct nfs4_stid *s)
@@ -490,8 +495,10 @@ static bool nfs4_put_stid(struct kmem_cache *slab, struct nfs4_stid *s)
 void
 nfs4_put_delegation(struct nfs4_delegation *dp)
 {
-	if (nfs4_put_stid(deleg_slab, &dp->dl_stid))
-		num_delegations--;
+	if (nfs4_put_stid(deleg_slab, &dp->dl_stid)) {
+		atomic_long_dec(&num_delegations);
+		smp_mb__after_atomic_dec();
+	}
 }
 
 /* Call under fp->fi_lock */
-- 
1.9.0


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

* [PATCH 35/70] NFSd: Slight cleanup of find_stateid()
  2014-04-18 18:44                                                                   ` [PATCH 34/70] NFSd: Fix atomicity of delegation counter Trond Myklebust
@ 2014-04-18 18:44                                                                     ` Trond Myklebust
  2014-04-18 18:44                                                                       ` [PATCH 36/70] NFSd: Add reference counting to find_stateid Trond Myklebust
  2014-04-19 14:41                                                                       ` [PATCH 35/70] NFSd: Slight cleanup of find_stateid() Christoph Hellwig
  2014-04-19 15:51                                                                     ` [PATCH 34/70] NFSd: Fix atomicity of delegation counter Christoph Hellwig
  1 sibling, 2 replies; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

In preparation of reference counting...

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 26 +++++++++++++++++---------
 1 file changed, 17 insertions(+), 9 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 87464802126a..063ff9aba5d4 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1482,28 +1482,36 @@ static void gen_confirm(struct nfs4_client *clp)
 	memcpy(clp->cl_confirm.data, verf, sizeof(clp->cl_confirm.data));
 }
 
-static struct nfs4_stid *find_stateid(struct nfs4_client *cl, stateid_t *t)
+static struct nfs4_stid *find_stateid_locked(struct nfs4_client *cl, stateid_t *t)
 {
 	struct nfs4_stid *ret;
 
-	spin_lock(&cl->cl_lock);
 	ret = idr_find(&cl->cl_stateids, t->si_opaque.so_id);
-	spin_unlock(&cl->cl_lock);
 	if (!ret || !ret->sc_type)
 		return NULL;
 	return ret;
 }
 
+static struct nfs4_stid *find_stateid(struct nfs4_client *cl, stateid_t *t)
+{
+	struct nfs4_stid *ret;
+
+	spin_lock(&cl->cl_lock);
+	ret = find_stateid_locked(cl, t);
+	spin_unlock(&cl->cl_lock);
+	return ret;
+}
+
 static struct nfs4_stid *find_stateid_by_type(struct nfs4_client *cl, stateid_t *t, char typemask)
 {
 	struct nfs4_stid *s;
 
-	s = find_stateid(cl, t);
-	if (!s)
-		return NULL;
-	if (typemask & s->sc_type)
-		return s;
-	return NULL;
+	spin_lock(&cl->cl_lock);
+	s = find_stateid_locked(cl, t);
+	if (s != NULL && !(typemask & s->sc_type))
+		s = NULL;
+	spin_unlock(&cl->cl_lock);
+	return s;
 }
 
 static struct nfs4_client *create_client(struct xdr_netobj name,
-- 
1.9.0


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

* [PATCH 36/70] NFSd: Add reference counting to find_stateid
  2014-04-18 18:44                                                                     ` [PATCH 35/70] NFSd: Slight cleanup of find_stateid() Trond Myklebust
@ 2014-04-18 18:44                                                                       ` Trond Myklebust
  2014-04-18 18:44                                                                         ` [PATCH 37/70] NFSd: nfs4_preprocess_seqid_op should only set *stpp on success Trond Myklebust
  2014-04-19 14:50                                                                         ` [PATCH 36/70] NFSd: Add reference counting to find_stateid Christoph Hellwig
  2014-04-19 14:41                                                                       ` [PATCH 35/70] NFSd: Slight cleanup of find_stateid() Christoph Hellwig
  1 sibling, 2 replies; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

Ensure the stateids won't be freed while we're inspecting them.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 43 +++++++++++++++++++++++++++++++++++--------
 1 file changed, 35 insertions(+), 8 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 063ff9aba5d4..b9d6da652fb1 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1482,6 +1482,23 @@ static void gen_confirm(struct nfs4_client *clp)
 	memcpy(clp->cl_confirm.data, verf, sizeof(clp->cl_confirm.data));
 }
 
+static void nfs4_put_stateid(struct nfs4_stid *s)
+{
+	if (s == NULL)
+		return;
+	switch (s->sc_type) {
+	case NFS4_OPEN_STID:
+	case NFS4_LOCK_STID:
+	case NFS4_CLOSED_STID:
+		put_generic_stateid(openlockstateid(s));
+		break;
+	case NFS4_DELEG_STID:
+	case NFS4_REVOKED_DELEG_STID:
+	case NFS4_CLOSED_DELEG_STID:
+		nfs4_put_delegation(delegstateid(s));
+	}
+}
+
 static struct nfs4_stid *find_stateid_locked(struct nfs4_client *cl, stateid_t *t)
 {
 	struct nfs4_stid *ret;
@@ -1498,6 +1515,8 @@ static struct nfs4_stid *find_stateid(struct nfs4_client *cl, stateid_t *t)
 
 	spin_lock(&cl->cl_lock);
 	ret = find_stateid_locked(cl, t);
+	if (ret != NULL)
+		atomic_inc(&ret->sc_count);
 	spin_unlock(&cl->cl_lock);
 	return ret;
 }
@@ -3804,26 +3823,33 @@ static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid)
 		return nfserr_bad_stateid;
 	status = check_stateid_generation(stateid, &s->sc_stateid, 1);
 	if (status)
-		return status;
+		goto out_put_stid;
 	switch (s->sc_type) {
 	case NFS4_DELEG_STID:
-		return nfs_ok;
+		status = nfs_ok;
+		break;
 	case NFS4_REVOKED_DELEG_STID:
-		return nfserr_deleg_revoked;
+		status = nfserr_deleg_revoked;
+		break;
 	case NFS4_OPEN_STID:
 	case NFS4_LOCK_STID:
 		ols = openlockstateid(s);
 		if (ols->st_stateowner->so_is_open_owner
 	    			&& !(openowner(ols->st_stateowner)->oo_flags
 						& NFS4_OO_CONFIRMED))
-			return nfserr_bad_stateid;
-		return nfs_ok;
+			status = nfserr_bad_stateid;
+		else
+			status = nfs_ok;
+		break;
 	default:
 		printk("unknown stateid type %x\n", s->sc_type);
 	case NFS4_CLOSED_STID:
 	case NFS4_CLOSED_DELEG_STID:
-		return nfserr_bad_stateid;
+		status = nfserr_bad_stateid;
 	}
+out_put_stid:
+	nfs4_put_stateid(s);
+	return status;
 }
 
 static __be32 nfsd4_lookup_stateid(stateid_t *stateid, unsigned char typemask,
@@ -3976,12 +4002,12 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	switch (s->sc_type) {
 	case NFS4_DELEG_STID:
 		ret = nfserr_locks_held;
-		goto out;
+		break;
 	case NFS4_OPEN_STID:
 	case NFS4_LOCK_STID:
 		ret = check_stateid_generation(stateid, &s->sc_stateid, 1);
 		if (ret)
-			goto out;
+			break;
 		if (s->sc_type == NFS4_LOCK_STID)
 			ret = nfsd4_free_lock_stateid(openlockstateid(s));
 		else
@@ -3995,6 +4021,7 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	default:
 		ret = nfserr_bad_stateid;
 	}
+	nfs4_put_stateid(s);
 out:
 	nfs4_unlock_state();
 	return ret;
-- 
1.9.0


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

* [PATCH 37/70] NFSd: nfs4_preprocess_seqid_op should only set *stpp on success
  2014-04-18 18:44                                                                       ` [PATCH 36/70] NFSd: Add reference counting to find_stateid Trond Myklebust
@ 2014-04-18 18:44                                                                         ` Trond Myklebust
  2014-04-18 18:44                                                                           ` [PATCH 38/70] NFSd: Add reference counting to lock stateids Trond Myklebust
  2014-05-07 19:58                                                                           ` [PATCH 37/70] NFSd: nfs4_preprocess_seqid_op should only set *stpp on success Bruce Fields
  2014-04-19 14:50                                                                         ` [PATCH 36/70] NFSd: Add reference counting to find_stateid Christoph Hellwig
  1 sibling, 2 replies; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index b9d6da652fb1..03a3f51d2828 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -4068,6 +4068,7 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
 {
 	__be32 status;
 	struct nfs4_stid *s;
+	struct nfs4_ol_stateid *stp = NULL;
 
 	dprintk("NFSD: %s: seqid=%d stateid = " STATEID_FMT "\n", __func__,
 		seqid, STATEID_VAL(stateid));
@@ -4077,10 +4078,13 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
 				      cstate->minorversion, nn);
 	if (status)
 		return status;
-	*stpp = openlockstateid(s);
-	nfsd4_cstate_assign_replay(cstate, (*stpp)->st_stateowner);
+	stp = openlockstateid(s);
+	nfsd4_cstate_assign_replay(cstate, stp->st_stateowner);
 
-	return nfs4_seqid_op_checks(cstate, stateid, seqid, *stpp);
+	status = nfs4_seqid_op_checks(cstate, stateid, seqid, stp);
+	if (!status)
+		*stpp = stp;
+	return status;
 }
 
 static __be32 nfs4_preprocess_confirmed_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
-- 
1.9.0


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

* [PATCH 38/70] NFSd: Add reference counting to lock stateids
  2014-04-18 18:44                                                                         ` [PATCH 37/70] NFSd: nfs4_preprocess_seqid_op should only set *stpp on success Trond Myklebust
@ 2014-04-18 18:44                                                                           ` Trond Myklebust
  2014-04-18 18:44                                                                             ` [PATCH 39/70] NFSd: nfsd4_locku() must reference the lock stateid Trond Myklebust
  2014-05-07 19:58                                                                           ` [PATCH 37/70] NFSd: nfs4_preprocess_seqid_op should only set *stpp on success Bruce Fields
  1 sibling, 1 reply; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

Ensure that nfsd4_lock() references the lock stateid while it is
manipulating it.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 03a3f51d2828..d69d96a7d299 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -4445,6 +4445,7 @@ alloc_init_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp, struct
 	stp = nfs4_alloc_stateid(clp);
 	if (stp == NULL)
 		return NULL;
+	atomic_inc(&stp->st_stid.sc_count);
 	stp->st_stid.sc_type = NFS4_LOCK_STID;
 	list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids);
 	stp->st_stateowner = &lo->lo_owner;
@@ -4466,8 +4467,10 @@ find_lock_stateid(struct nfs4_lockowner *lo, struct inode *inode)
 	struct nfs4_ol_stateid *lst;
 
 	list_for_each_entry(lst, &lo->lo_owner.so_stateids, st_perstateowner) {
-		if (lst->st_stid.sc_file->fi_inode == inode)
+		if (lst->st_stid.sc_file->fi_inode == inode) {
+			atomic_inc(&lst->st_stid.sc_count);
 			return lst;
+		}
 	}
 	return NULL;
 }
@@ -4531,7 +4534,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 {
 	struct nfs4_openowner *open_sop = NULL;
 	struct nfs4_lockowner *lock_sop = NULL;
-	struct nfs4_ol_stateid *lock_stp;
+	struct nfs4_ol_stateid *lock_stp = NULL;
 	struct file *filp = NULL;
 	struct file_lock *file_lock = NULL;
 	struct file_lock *conflock = NULL;
@@ -4584,11 +4587,15 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 			goto out;
 		status = lookup_or_create_lock_state(cstate, open_stp, lock,
 							&lock_stp, &new_state);
-	} else
+	} else {
 		status = nfs4_preprocess_seqid_op(cstate,
 				       lock->lk_old_lock_seqid,
 				       &lock->lk_old_lock_stateid,
 				       NFS4_LOCK_STID, &lock_stp, nn);
+		/* FIXME: move into nfs4_preprocess_seqid_op */
+		if (!status)
+			atomic_inc(&lock_stp->st_stid.sc_count);
+	}
 	if (status)
 		goto out;
 	lock_sop = lockowner(lock_stp->st_stateowner);
@@ -4676,6 +4683,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 out:
 	if (filp)
 		fput(filp);
+	if (lock_stp)
+		put_generic_stateid(lock_stp);
 	if (status && new_state)
 		release_lockowner_if_empty(lock_sop);
 	nfsd4_bump_seqid(cstate, status);
-- 
1.9.0


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

* [PATCH 39/70] NFSd: nfsd4_locku() must reference the lock stateid
  2014-04-18 18:44                                                                           ` [PATCH 38/70] NFSd: Add reference counting to lock stateids Trond Myklebust
@ 2014-04-18 18:44                                                                             ` Trond Myklebust
  2014-04-18 18:44                                                                               ` [PATCH 40/70] NFSd: Ensure that nfs4_open_delegation() references the delegation stateid Trond Myklebust
  0 siblings, 1 reply; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

Ensure that nfsd4_locku() keeps a reference to the lock stateid
until it is done working with it.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index d69d96a7d299..822eed0de95d 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -4815,10 +4815,12 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 					&stp, nn);
 	if (status)
 		goto out;
+	/* FIXME: move into nfs4_preprocess_seqid_op */
+	atomic_inc(&stp->st_stid.sc_count);
 	filp = find_any_file(stp->st_stid.sc_file);
 	if (!filp) {
 		status = nfserr_lock_range;
-		goto out;
+		goto put_stateid;
 	}
 	file_lock = locks_alloc_lock();
 	if (!file_lock) {
@@ -4848,6 +4850,8 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	memcpy(&locku->lu_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
 fput:
 	fput(filp);
+put_stateid:
+	put_generic_stateid(stp);
 out:
 	nfsd4_bump_seqid(cstate, status);
 	nfs4_unlock_state();
-- 
1.9.0


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

* [PATCH 40/70] NFSd: Ensure that nfs4_open_delegation() references the delegation stateid
  2014-04-18 18:44                                                                             ` [PATCH 39/70] NFSd: nfsd4_locku() must reference the lock stateid Trond Myklebust
@ 2014-04-18 18:44                                                                               ` Trond Myklebust
  2014-04-18 18:44                                                                                 ` [PATCH 41/70] NFSd: nfsd4_process_open2() must reference " Trond Myklebust
  0 siblings, 1 reply; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

Ensure that nfs4_open_delegation() keeps a reference to the delegation
stateid until it is done working with it.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 822eed0de95d..d1e4f0e07f09 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -520,6 +520,7 @@ static void unhash_stid(struct nfs4_stid *s)
 static void
 hash_delegation_locked(struct nfs4_delegation *dp, struct nfs4_file *fp)
 {
+	atomic_inc(&dp->dl_stid.sc_count);
 	dp->dl_stid.sc_type = NFS4_DELEG_STID;
 	spin_lock(&fp->fi_inode->i_lock);
 	list_add(&dp->dl_perfile, &fp->fi_delegations);
@@ -3395,6 +3396,7 @@ nfs4_open_delegation(struct net *net, struct svc_fh *fh,
 	dprintk("NFSD: delegation stateid=" STATEID_FMT "\n",
 		STATEID_VAL(&dp->dl_stid.sc_stateid));
 	open->op_delegate_type = NFS4_OPEN_DELEGATE_READ;
+	nfs4_put_delegation(dp);
 	return;
 out_free:
 	nfs4_put_delegation(dp);
-- 
1.9.0


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

* [PATCH 41/70] NFSd: nfsd4_process_open2() must reference the delegation stateid
  2014-04-18 18:44                                                                               ` [PATCH 40/70] NFSd: Ensure that nfs4_open_delegation() references the delegation stateid Trond Myklebust
@ 2014-04-18 18:44                                                                                 ` Trond Myklebust
  2014-04-18 18:44                                                                                   ` [PATCH 42/70] NFSd: nfsd4_process_open2() must reference the open stateid Trond Myklebust
  0 siblings, 1 reply; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

Ensure that nfsd4_process_open2() keeps a reference to the delegation
stateid until it is done working with it.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 18 +++++++++++++-----
 1 file changed, 13 insertions(+), 5 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index d1e4f0e07f09..634cd4de9d32 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -3068,6 +3068,8 @@ static struct nfs4_delegation *find_deleg_stateid(struct nfs4_client *cl, statei
 	ret = find_stateid_by_type(cl, s, NFS4_DELEG_STID);
 	if (!ret)
 		return NULL;
+	/* FIXME: move into find_stateid_by_type */
+	atomic_inc(&ret->sc_count);
 	return delegstateid(ret);
 }
 
@@ -3083,14 +3085,18 @@ nfs4_check_deleg(struct nfs4_client *cl, struct nfsd4_open *open,
 {
 	int flags;
 	__be32 status = nfserr_bad_stateid;
+	struct nfs4_delegation *deleg;
 
-	*dp = find_deleg_stateid(cl, &open->op_delegate_stateid);
-	if (*dp == NULL)
+	deleg = find_deleg_stateid(cl, &open->op_delegate_stateid);
+	if (deleg == NULL)
 		goto out;
 	flags = share_access_to_flags(open->op_share_access);
-	status = nfs4_check_delegmode(*dp, flags);
-	if (status)
-		*dp = NULL;
+	status = nfs4_check_delegmode(deleg, flags);
+	if (status) {
+		nfs4_put_delegation(deleg);
+		goto out;
+	}
+	*dp = deleg;
 out:
 	if (!nfsd4_is_deleg_cur(open))
 		return nfs_ok;
@@ -3528,6 +3534,8 @@ out:
 	if (!(open->op_openowner->oo_flags & NFS4_OO_CONFIRMED) &&
 	    !nfsd4_has_session(&resp->cstate))
 		open->op_rflags |= NFS4_OPEN_RESULT_CONFIRM;
+	if (dp)
+		nfs4_put_delegation(dp);
 
 	return status;
 }
-- 
1.9.0


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

* [PATCH 42/70] NFSd: nfsd4_process_open2() must reference the open stateid
  2014-04-18 18:44                                                                                 ` [PATCH 41/70] NFSd: nfsd4_process_open2() must reference " Trond Myklebust
@ 2014-04-18 18:44                                                                                   ` Trond Myklebust
  2014-04-18 18:44                                                                                     ` [PATCH 43/70] NFSd: Prepare nfsd4_close() for open stateid referencing Trond Myklebust
  0 siblings, 1 reply; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

Ensure that nfsd4_process_open2() keeps a reference to the open
stateid until it is done working with it.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 634cd4de9d32..ec7cc90de03a 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -2806,6 +2806,7 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, str
 static void init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *open) {
 	struct nfs4_openowner *oo = open->op_openowner;
 
+	atomic_inc(&stp->st_stid.sc_count);
 	stp->st_stid.sc_type = NFS4_OPEN_STID;
 	INIT_LIST_HEAD(&stp->st_locks);
 	list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids);
@@ -3111,6 +3112,7 @@ nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_ol_st
 {
 	struct nfs4_ol_stateid *local;
 	struct nfs4_openowner *oo = open->op_openowner;
+	struct nfs4_ol_stateid *ret = NULL;
 
 	spin_lock(&fp->fi_lock);
 	list_for_each_entry(local, &fp->fi_stateids, st_perfile) {
@@ -3119,13 +3121,17 @@ nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_ol_st
 			continue;
 		/* remember if we have seen this open owner */
 		if (local->st_stateowner == &oo->oo_owner)
-			*stpp = local;
+			ret = local;
 		/* check for conflicting share reservations */
 		if (!test_share(local, open)) {
 			spin_unlock(&fp->fi_lock);
 			return nfserr_share_denied;
 		}
 	}
+	if (ret) {
+		atomic_inc(&ret->st_stid.sc_count);
+		*stpp = ret;
+	}
 	spin_unlock(&fp->fi_lock);
 	return nfs_ok;
 }
@@ -3536,6 +3542,8 @@ out:
 		open->op_rflags |= NFS4_OPEN_RESULT_CONFIRM;
 	if (dp)
 		nfs4_put_delegation(dp);
+	if (stp)
+		put_generic_stateid(stp);
 
 	return status;
 }
-- 
1.9.0


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

* [PATCH 43/70] NFSd: Prepare nfsd4_close() for open stateid referencing
  2014-04-18 18:44                                                                                   ` [PATCH 42/70] NFSd: nfsd4_process_open2() must reference the open stateid Trond Myklebust
@ 2014-04-18 18:44                                                                                     ` Trond Myklebust
  2014-04-18 18:44                                                                                       ` [PATCH 44/70] NFSd: nfsd4_open_confirm() must reference the open stateid Trond Myklebust
  0 siblings, 1 reply; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

Prepare nfsd4_close for a future where nfs4_preprocess_seqid_op()
hands it a fully referenced open stateid.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index ec7cc90de03a..78dfc3ce98a1 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -4274,6 +4274,8 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	nfsd4_bump_seqid(cstate, status);
 	if (status)
 		goto out; 
+	/* FIXME: move into nfs4_preprocess_seqid_op */
+	atomic_inc(&stp->st_stid.sc_count);
 	oo = openowner(stp->st_stateowner);
 	update_stateid(&stp->st_stid.sc_stateid);
 	memcpy(&close->cl_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
@@ -4285,6 +4287,9 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	else
 		oo->oo_last_closed_stid = stp;
 
+	/* put reference from nfs4_preprocess_seqid_op */
+	put_generic_stateid(stp);
+
 	if (list_empty(&oo->oo_owner.so_stateids)) {
 		if (cstate->minorversion)
 			release_openowner(oo);
-- 
1.9.0


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

* [PATCH 44/70] NFSd: nfsd4_open_confirm() must reference the open stateid
  2014-04-18 18:44                                                                                     ` [PATCH 43/70] NFSd: Prepare nfsd4_close() for open stateid referencing Trond Myklebust
@ 2014-04-18 18:44                                                                                       ` Trond Myklebust
  2014-04-18 18:44                                                                                         ` [PATCH 45/70] NFSd: Add reference counting to nfs4_preprocess_confirmed_seqid_op Trond Myklebust
  0 siblings, 1 reply; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

Ensure that nfsd4_open_confirm() keeps a reference to the open
stateid until it is done working with it.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 78dfc3ce98a1..517e08818df6 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -4144,10 +4144,12 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 					NFS4_OPEN_STID, &stp, nn);
 	if (status)
 		goto out;
+	/* FIXME: move into nfs4_preprocess_seqid_op */
+	atomic_inc(&stp->st_stid.sc_count);
 	oo = openowner(stp->st_stateowner);
 	status = nfserr_bad_stateid;
 	if (oo->oo_flags & NFS4_OO_CONFIRMED)
-		goto out;
+		goto put_stateid;
 	oo->oo_flags |= NFS4_OO_CONFIRMED;
 	update_stateid(&stp->st_stid.sc_stateid);
 	memcpy(&oc->oc_resp_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
@@ -4156,6 +4158,8 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 
 	nfsd4_client_record_create(oo->oo_owner.so_client);
 	status = nfs_ok;
+put_stateid:
+	put_generic_stateid(stp);
 out:
 	nfsd4_bump_seqid(cstate, status);
 	nfs4_unlock_state();
-- 
1.9.0


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

* [PATCH 45/70] NFSd: Add reference counting to nfs4_preprocess_confirmed_seqid_op
  2014-04-18 18:44                                                                                       ` [PATCH 44/70] NFSd: nfsd4_open_confirm() must reference the open stateid Trond Myklebust
@ 2014-04-18 18:44                                                                                         ` Trond Myklebust
  2014-04-18 18:44                                                                                           ` [PATCH 46/70] NFSd: Migrate the stateid reference into nfs4_preprocess_seqid_op Trond Myklebust
  0 siblings, 1 reply; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

Ensure that all the callers put the open stateid after use.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 517e08818df6..ce35edcef193 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -4115,6 +4115,8 @@ static __be32 nfs4_preprocess_confirmed_seqid_op(struct nfsd4_compound_state *cs
 						NFS4_OPEN_STID, stpp, nn);
 	if (status)
 		return status;
+	/* FIXME: move into nfs4_preprocess_seqid_op */
+	atomic_inc(&(*stpp)->st_stid.sc_count);
 	oo = openowner((*stpp)->st_stateowner);
 	if (!(oo->oo_flags & NFS4_OO_CONFIRMED))
 		return nfserr_bad_stateid;
@@ -4228,12 +4230,12 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp,
 	if (!test_access(od->od_share_access, stp)) {
 		dprintk("NFSD: access not a subset current bitmap: 0x%lx, input access=%08x\n",
 			stp->st_access_bmap, od->od_share_access);
-		goto out;
+		goto put_stateid;
 	}
 	if (!test_deny(od->od_share_deny, stp)) {
 		dprintk("NFSD:deny not a subset current bitmap: 0x%lx, input deny=%08x\n",
 			stp->st_deny_bmap, od->od_share_deny);
-		goto out;
+		goto put_stateid;
 	}
 	nfs4_stateid_downgrade(stp, od->od_share_access);
 
@@ -4242,6 +4244,8 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp,
 	update_stateid(&stp->st_stid.sc_stateid);
 	memcpy(&od->od_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
 	status = nfs_ok;
+put_stateid:
+	put_generic_stateid(stp);
 out:
 	nfsd4_bump_seqid(cstate, status);
 	nfs4_unlock_state();
@@ -4562,6 +4566,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	struct nfs4_openowner *open_sop = NULL;
 	struct nfs4_lockowner *lock_sop = NULL;
 	struct nfs4_ol_stateid *lock_stp = NULL;
+	struct nfs4_ol_stateid *open_stp = NULL;
 	struct file *filp = NULL;
 	struct file_lock *file_lock = NULL;
 	struct file_lock *conflock = NULL;
@@ -4588,8 +4593,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	nfs4_lock_state();
 
 	if (lock->lk_is_new) {
-		struct nfs4_ol_stateid *open_stp = NULL;
-
 		if (nfsd4_has_session(cstate))
 			/* See rfc 5661 18.10.3: given clientid is ignored: */
 			memcpy(&lock->v.new.clientid,
@@ -4712,6 +4715,8 @@ out:
 		fput(filp);
 	if (lock_stp)
 		put_generic_stateid(lock_stp);
+	if (open_stp)
+		put_generic_stateid(open_stp);
 	if (status && new_state)
 		release_lockowner_if_empty(lock_sop);
 	nfsd4_bump_seqid(cstate, status);
-- 
1.9.0


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

* [PATCH 46/70] NFSd: Migrate the stateid reference into nfs4_preprocess_seqid_op
  2014-04-18 18:44                                                                                         ` [PATCH 45/70] NFSd: Add reference counting to nfs4_preprocess_confirmed_seqid_op Trond Myklebust
@ 2014-04-18 18:44                                                                                           ` Trond Myklebust
  2014-04-18 18:44                                                                                             ` [PATCH 47/70] NFSd: Migrate the stateid reference into nfs4_lookup_stateid() Trond Myklebust
  0 siblings, 1 reply; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

Allow nfs4_preprocess_seqid_op to take the stateid reference, instead
of having all the callers do so.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 26 +++++++++++---------------
 1 file changed, 11 insertions(+), 15 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index ce35edcef193..8e2e519f9b94 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -4100,8 +4100,11 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
 	nfsd4_cstate_assign_replay(cstate, stp->st_stateowner);
 
 	status = nfs4_seqid_op_checks(cstate, stateid, seqid, stp);
-	if (!status)
+	if (!status) {
+		/* FIXME: move into find_stateid_by_type */
+		atomic_inc(&stp->st_stid.sc_count);
 		*stpp = stp;
+	}
 	return status;
 }
 
@@ -4110,16 +4113,18 @@ static __be32 nfs4_preprocess_confirmed_seqid_op(struct nfsd4_compound_state *cs
 {
 	__be32 status;
 	struct nfs4_openowner *oo;
+	struct nfs4_ol_stateid *stp;
 
 	status = nfs4_preprocess_seqid_op(cstate, seqid, stateid,
-						NFS4_OPEN_STID, stpp, nn);
+						NFS4_OPEN_STID, &stp, nn);
 	if (status)
 		return status;
-	/* FIXME: move into nfs4_preprocess_seqid_op */
-	atomic_inc(&(*stpp)->st_stid.sc_count);
-	oo = openowner((*stpp)->st_stateowner);
-	if (!(oo->oo_flags & NFS4_OO_CONFIRMED))
+	oo = openowner(stp->st_stateowner);
+	if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) {
+		put_generic_stateid(stp);
 		return nfserr_bad_stateid;
+	}
+	*stpp = stp;
 	return nfs_ok;
 }
 
@@ -4146,8 +4151,6 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 					NFS4_OPEN_STID, &stp, nn);
 	if (status)
 		goto out;
-	/* FIXME: move into nfs4_preprocess_seqid_op */
-	atomic_inc(&stp->st_stid.sc_count);
 	oo = openowner(stp->st_stateowner);
 	status = nfserr_bad_stateid;
 	if (oo->oo_flags & NFS4_OO_CONFIRMED)
@@ -4282,8 +4285,6 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	nfsd4_bump_seqid(cstate, status);
 	if (status)
 		goto out; 
-	/* FIXME: move into nfs4_preprocess_seqid_op */
-	atomic_inc(&stp->st_stid.sc_count);
 	oo = openowner(stp->st_stateowner);
 	update_stateid(&stp->st_stid.sc_stateid);
 	memcpy(&close->cl_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
@@ -4622,9 +4623,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 				       lock->lk_old_lock_seqid,
 				       &lock->lk_old_lock_stateid,
 				       NFS4_LOCK_STID, &lock_stp, nn);
-		/* FIXME: move into nfs4_preprocess_seqid_op */
-		if (!status)
-			atomic_inc(&lock_stp->st_stid.sc_count);
 	}
 	if (status)
 		goto out;
@@ -4847,8 +4845,6 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 					&stp, nn);
 	if (status)
 		goto out;
-	/* FIXME: move into nfs4_preprocess_seqid_op */
-	atomic_inc(&stp->st_stid.sc_count);
 	filp = find_any_file(stp->st_stid.sc_file);
 	if (!filp) {
 		status = nfserr_lock_range;
-- 
1.9.0


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

* [PATCH 47/70] NFSd: Migrate the stateid reference into nfs4_lookup_stateid()
  2014-04-18 18:44                                                                                           ` [PATCH 46/70] NFSd: Migrate the stateid reference into nfs4_preprocess_seqid_op Trond Myklebust
@ 2014-04-18 18:44                                                                                             ` Trond Myklebust
  2014-04-18 18:44                                                                                               ` [PATCH 48/70] NFSd: Migrate the stateid reference into nfs4_find_stateid_by_type() Trond Myklebust
  0 siblings, 1 reply; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

Allow nfs4_lookup_stateid to take the stateid reference, instead
of having all the callers do so.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 17 +++++++++++------
 1 file changed, 11 insertions(+), 6 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 8e2e519f9b94..08d8fb501e81 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -3891,6 +3891,8 @@ static __be32 nfsd4_lookup_stateid(stateid_t *stateid, unsigned char typemask,
 	*s = find_stateid_by_type(cl, stateid, typemask);
 	if (!*s)
 		return nfserr_bad_stateid;
+	/* FIXME: move into find_stateid_by_type */
+	atomic_inc(&(*s)->sc_count);
 	return nfs_ok;
 }
 
@@ -3924,7 +3926,7 @@ nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate,
 	status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID,
 				      &s, cstate->minorversion, nn);
 	if (status)
-		goto out;
+		goto unlock_state;
 	status = check_stateid_generation(stateid, &s->sc_stateid, nfsd4_has_session(cstate));
 	if (status)
 		goto out;
@@ -3971,6 +3973,8 @@ nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate,
 	if (file)
 		*filpp = file;
 out:
+	nfs4_put_stateid(s);
+unlock_state:
 	nfs4_unlock_state();
 	return status;
 }
@@ -4100,11 +4104,10 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
 	nfsd4_cstate_assign_replay(cstate, stp->st_stateowner);
 
 	status = nfs4_seqid_op_checks(cstate, stateid, seqid, stp);
-	if (!status) {
-		/* FIXME: move into find_stateid_by_type */
-		atomic_inc(&stp->st_stid.sc_count);
+	if (!status)
 		*stpp = stp;
-	}
+	else
+		put_generic_stateid(stp);
 	return status;
 }
 
@@ -4336,9 +4339,11 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	dp = delegstateid(s);
 	status = check_stateid_generation(stateid, &dp->dl_stid.sc_stateid, nfsd4_has_session(cstate));
 	if (status)
-		goto out;
+		goto put_stateid;
 
 	unhash_and_destroy_delegation(dp);
+put_stateid:
+	nfs4_put_delegation(dp);
 out:
 	nfs4_unlock_state();
 
-- 
1.9.0


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

* [PATCH 48/70] NFSd: Migrate the stateid reference into nfs4_find_stateid_by_type()
  2014-04-18 18:44                                                                                             ` [PATCH 47/70] NFSd: Migrate the stateid reference into nfs4_lookup_stateid() Trond Myklebust
@ 2014-04-18 18:44                                                                                               ` Trond Myklebust
  2014-04-18 18:44                                                                                                 ` [PATCH 49/70] NFSd: Cleanup - Let nfsd4_lookup_stateid() take a cstate argument Trond Myklebust
  0 siblings, 1 reply; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

Allow nfs4_find_stateid_by_type to take the stateid reference, while
still holding the &cl->cl_lock.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 08d8fb501e81..a3b6391a07b7 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1528,8 +1528,12 @@ static struct nfs4_stid *find_stateid_by_type(struct nfs4_client *cl, stateid_t
 
 	spin_lock(&cl->cl_lock);
 	s = find_stateid_locked(cl, t);
-	if (s != NULL && !(typemask & s->sc_type))
-		s = NULL;
+	if (s != NULL) {
+		if (typemask & s->sc_type)
+			atomic_inc(&s->sc_count);
+		else
+			s = NULL;
+	}
 	spin_unlock(&cl->cl_lock);
 	return s;
 }
@@ -3069,8 +3073,6 @@ static struct nfs4_delegation *find_deleg_stateid(struct nfs4_client *cl, statei
 	ret = find_stateid_by_type(cl, s, NFS4_DELEG_STID);
 	if (!ret)
 		return NULL;
-	/* FIXME: move into find_stateid_by_type */
-	atomic_inc(&ret->sc_count);
 	return delegstateid(ret);
 }
 
@@ -3891,8 +3893,6 @@ static __be32 nfsd4_lookup_stateid(stateid_t *stateid, unsigned char typemask,
 	*s = find_stateid_by_type(cl, stateid, typemask);
 	if (!*s)
 		return nfserr_bad_stateid;
-	/* FIXME: move into find_stateid_by_type */
-	atomic_inc(&(*s)->sc_count);
 	return nfs_ok;
 }
 
-- 
1.9.0


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

* [PATCH 49/70] NFSd: Cleanup - Let nfsd4_lookup_stateid() take a cstate argument
  2014-04-18 18:44                                                                                               ` [PATCH 48/70] NFSd: Migrate the stateid reference into nfs4_find_stateid_by_type() Trond Myklebust
@ 2014-04-18 18:44                                                                                                 ` Trond Myklebust
  2014-04-18 18:44                                                                                                   ` [PATCH 50/70] NFSd: Use the session->se_client in lookup_clientid() Trond Myklebust
  0 siblings, 1 reply; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

The cstate already holds information about the session, and hence
the client id, so it makes more sense to pass that information
rather than the current practice of passing a 'minor version' number.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index a3b6391a07b7..888acf114e40 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -3872,12 +3872,14 @@ out_put_stid:
 	return status;
 }
 
-static __be32 nfsd4_lookup_stateid(stateid_t *stateid, unsigned char typemask,
-				   struct nfs4_stid **s, bool sessions,
+static __be32 nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate,
+				   stateid_t *stateid, unsigned char typemask,
+				   struct nfs4_stid **s,
 				   struct nfsd_net *nn)
 {
 	struct nfs4_client *cl;
 	__be32 status;
+	bool sessions = cstate->minorversion != 0;
 
 	if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
 		return nfserr_bad_stateid;
@@ -3923,8 +3925,9 @@ nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate,
 
 	nfs4_lock_state();
 
-	status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID,
-				      &s, cstate->minorversion, nn);
+	status = nfsd4_lookup_stateid(cstate, stateid,
+				      NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID,
+				      &s, nn);
 	if (status)
 		goto unlock_state;
 	status = check_stateid_generation(stateid, &s->sc_stateid, nfsd4_has_session(cstate));
@@ -4096,8 +4099,7 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
 		seqid, STATEID_VAL(stateid));
 
 	*stpp = NULL;
-	status = nfsd4_lookup_stateid(stateid, typemask, &s,
-				      cstate->minorversion, nn);
+	status = nfsd4_lookup_stateid(cstate, stateid, typemask, &s, nn);
 	if (status)
 		return status;
 	stp = openlockstateid(s);
@@ -4332,8 +4334,7 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 		return status;
 
 	nfs4_lock_state();
-	status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID, &s,
-				      cstate->minorversion, nn);
+	status = nfsd4_lookup_stateid(cstate, stateid, NFS4_DELEG_STID, &s, nn);
 	if (status)
 		goto out;
 	dp = delegstateid(s);
-- 
1.9.0


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

* [PATCH 50/70] NFSd: Use the session->se_client  in lookup_clientid()
  2014-04-18 18:44                                                                                                 ` [PATCH 49/70] NFSd: Cleanup - Let nfsd4_lookup_stateid() take a cstate argument Trond Myklebust
@ 2014-04-18 18:44                                                                                                   ` Trond Myklebust
  2014-04-18 18:44                                                                                                     ` [PATCH 51/70] NFSd: Convert nfsd4_process_open1() to work with lookup_clientid() Trond Myklebust
                                                                                                                       ` (2 more replies)
  0 siblings, 3 replies; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

In NFSv4.x with x>0, we want to use the session's pointer to the
nfs4_client in order to optimise away the extra lookup of the clid.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 25 +++++++++++++++----------
 1 file changed, 15 insertions(+), 10 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 888acf114e40..6e2d348d3367 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -3571,13 +3571,19 @@ void nfsd4_cleanup_open_state(struct nfsd4_open *open, __be32 status)
 		put_generic_stateid(open->op_stp);
 }
 
-static __be32 lookup_clientid(clientid_t *clid, bool session, struct nfsd_net *nn, struct nfs4_client **clp)
+static __be32 lookup_clientid(clientid_t *clid, struct nfsd4_session *session, struct nfsd_net *nn, struct nfs4_client **clp)
 {
 	struct nfs4_client *found;
 
-	if (STALE_CLIENTID(clid, nn))
-		return nfserr_stale_clientid;
-	found = find_confirmed_client(clid, session, nn);
+	if (session != NULL) {
+		found = session->se_client;
+		if (!same_clid(&found->cl_clientid, clid))
+			return nfserr_stale_clientid;
+	} else {
+		if (STALE_CLIENTID(clid, nn))
+			return nfserr_stale_clientid;
+		found = find_confirmed_client(clid, false, nn);
+	}
 	if (clp)
 		*clp = found;
 	return found ? nfs_ok : nfserr_expired;
@@ -3594,7 +3600,7 @@ nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	nfs4_lock_state();
 	dprintk("process_renew(%08x/%08x): starting\n", 
 			clid->cl_boot, clid->cl_id);
-	status = lookup_clientid(clid, cstate->minorversion, nn, &clp);
+	status = lookup_clientid(clid, NULL, nn, &clp);
 	if (status)
 		goto out;
 	status = nfserr_cb_path_down;
@@ -3879,14 +3885,13 @@ static __be32 nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate,
 {
 	struct nfs4_client *cl;
 	__be32 status;
-	bool sessions = cstate->minorversion != 0;
 
 	if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
 		return nfserr_bad_stateid;
-	status = lookup_clientid(&stateid->si_opaque.so_clid, sessions,
+	status = lookup_clientid(&stateid->si_opaque.so_clid, cstate->session,
 							nn, &cl);
 	if (status == nfserr_stale_clientid) {
-		if (sessions)
+		if (cstate->session)
 			return nfserr_bad_stateid;
 		return nfserr_stale_stateid;
 	}
@@ -4770,7 +4775,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	nfs4_lock_state();
 
 	if (!nfsd4_has_session(cstate)) {
-		status = lookup_clientid(&lockt->lt_clientid, false, nn, NULL);
+		status = lookup_clientid(&lockt->lt_clientid, NULL, nn, NULL);
 		if (status)
 			goto out;
 	}
@@ -4942,7 +4947,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
 
 	nfs4_lock_state();
 
-	status = lookup_clientid(clid, cstate->minorversion, nn, NULL);
+	status = lookup_clientid(clid, NULL, nn, NULL);
 	if (status)
 		goto out;
 
-- 
1.9.0


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

* [PATCH 51/70] NFSd: Convert nfsd4_process_open1() to work with lookup_clientid()
  2014-04-18 18:44                                                                                                   ` [PATCH 50/70] NFSd: Use the session->se_client in lookup_clientid() Trond Myklebust
@ 2014-04-18 18:44                                                                                                     ` Trond Myklebust
  2014-04-18 18:44                                                                                                       ` [PATCH 52/70] NFSd: Convert nfs4_check_open_reclaim() " Trond Myklebust
  2014-04-19 14:56                                                                                                     ` [PATCH 50/70] NFSd: Use the session->se_client in lookup_clientid() Christoph Hellwig
  2014-05-07 20:18                                                                                                     ` Bruce Fields
  2 siblings, 1 reply; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 6e2d348d3367..d316fe10b9aa 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -70,6 +70,7 @@ static u64 current_sessionid = 1;
 
 /* forward declarations */
 static int check_for_locks(struct nfs4_file *filp, struct nfs4_lockowner *lowner);
+static __be32 lookup_clientid(clientid_t *clid, struct nfsd4_session *session, struct nfsd_net *nn, struct nfs4_client **clp);
 
 /* Locking: */
 
@@ -3022,10 +3023,9 @@ nfsd4_process_open1(struct nfsd4_compound_state *cstate,
 	oo = find_openstateowner_str(strhashval, open, cstate->minorversion, nn);
 	open->op_openowner = oo;
 	if (!oo) {
-		clp = find_confirmed_client(clientid, cstate->minorversion,
-					    nn);
-		if (clp == NULL)
-			return nfserr_expired;
+		status = lookup_clientid(clientid, cstate->session, nn, &clp);
+		if (status)
+			return status;
 		goto new_owner;
 	}
 	if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) {
-- 
1.9.0


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

* [PATCH 52/70] NFSd: Convert nfs4_check_open_reclaim() to work with lookup_clientid()
  2014-04-18 18:44                                                                                                     ` [PATCH 51/70] NFSd: Convert nfsd4_process_open1() to work with lookup_clientid() Trond Myklebust
@ 2014-04-18 18:44                                                                                                       ` Trond Myklebust
  2014-04-18 18:44                                                                                                         ` [PATCH 53/70] NFSd: Ensure struct nfs4_client is unhashed before we try to destroy it Trond Myklebust
  0 siblings, 1 reply; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4proc.c  | 2 +-
 fs/nfsd/nfs4state.c | 7 ++++---
 fs/nfsd/state.h     | 2 +-
 3 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index a23da87b384e..1101bf6b63c8 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -432,7 +432,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 		case NFS4_OPEN_CLAIM_PREVIOUS:
 			open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED;
 			status = nfs4_check_open_reclaim(&open->op_clientid,
-							 cstate->minorversion,
+							 cstate->session,
 							 nn);
 			if (status)
 				goto out;
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index d316fe10b9aa..1708f6b7e9e7 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -5068,13 +5068,14 @@ nfsd4_find_reclaim_client(const char *recdir, struct nfsd_net *nn)
 * Called from OPEN. Look for clientid in reclaim list.
 */
 __be32
-nfs4_check_open_reclaim(clientid_t *clid, bool sessions, struct nfsd_net *nn)
+nfs4_check_open_reclaim(clientid_t *clid, struct nfsd4_session *session, struct nfsd_net *nn)
 {
 	struct nfs4_client *clp;
+	__be32 status;
 
 	/* find clientid in conf_id_hashtbl */
-	clp = find_confirmed_client(clid, sessions, nn);
-	if (clp == NULL)
+	status = lookup_clientid(clid, session, nn, &clp);
+	if (status)
 		return nfserr_reclaim_bad;
 
 	return nfsd4_client_record_check(clp) ? nfserr_reclaim_bad : nfs_ok;
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index a4ac75a0de21..b6187676d991 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -435,7 +435,7 @@ void nfs4_remove_reclaim_record(struct nfs4_client_reclaim *, struct nfsd_net *)
 extern void nfs4_release_reclaim(struct nfsd_net *);
 extern struct nfs4_client_reclaim *nfsd4_find_reclaim_client(const char *recdir,
 							struct nfsd_net *nn);
-extern __be32 nfs4_check_open_reclaim(clientid_t *clid, bool sessions, struct nfsd_net *nn);
+extern __be32 nfs4_check_open_reclaim(clientid_t *clid, struct nfsd4_session *session, struct nfsd_net *nn);
 extern int set_callback_cred(void);
 extern void nfsd4_init_callback(struct nfsd4_callback *);
 extern void nfsd4_probe_callback(struct nfs4_client *clp);
-- 
1.9.0


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

* [PATCH 53/70] NFSd: Ensure struct nfs4_client is unhashed before we try to destroy it
  2014-04-18 18:44                                                                                                       ` [PATCH 52/70] NFSd: Convert nfs4_check_open_reclaim() " Trond Myklebust
@ 2014-04-18 18:44                                                                                                         ` Trond Myklebust
  2014-04-18 18:44                                                                                                           ` [PATCH 54/70] NFSd: Ensure that the laundromat unhashes the client before releasing locks Trond Myklebust
  0 siblings, 1 reply; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

When we remove the nfs4_lock_state() protection, we will need to ensure
that it can't be found by other threads while we're destroying it.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 43 +++++++++++++++++++++++++++++++++----------
 1 file changed, 33 insertions(+), 10 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 1708f6b7e9e7..19f7739a156e 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1273,12 +1273,23 @@ free_client(struct nfs4_client *clp)
 }
 
 /* must be called under the client_lock */
-static inline void
+static void
 unhash_client_locked(struct nfs4_client *clp)
 {
+	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
 	struct nfsd4_session *ses;
 
-	list_del(&clp->cl_lru);
+	/* Mark the client as expired! */
+	clp->cl_time = 0;
+	/* Make it invisible */
+	if (!list_empty(&clp->cl_idhash)) {
+		list_del_init(&clp->cl_idhash);
+		if (test_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags))
+			rb_erase(&clp->cl_namenode, &nn->conf_name_tree);
+		else
+			rb_erase(&clp->cl_namenode, &nn->unconf_name_tree);
+	}
+	list_del_init(&clp->cl_lru);
 	spin_lock(&clp->cl_lock);
 	list_for_each_entry(ses, &clp->cl_sessions, se_perclnt)
 		list_del_init(&ses->se_hash);
@@ -1286,7 +1297,17 @@ unhash_client_locked(struct nfs4_client *clp)
 }
 
 static void
-destroy_client(struct nfs4_client *clp)
+unhash_client(struct nfs4_client *clp)
+{
+	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
+
+	spin_lock(&nn->client_lock);
+	unhash_client_locked(clp);
+	spin_unlock(&nn->client_lock);
+}
+
+static void
+__destroy_client(struct nfs4_client *clp)
 {
 	struct nfs4_openowner *oo;
 	struct nfs4_delegation *dp;
@@ -1318,22 +1339,24 @@ destroy_client(struct nfs4_client *clp)
 	nfsd4_shutdown_callback(clp);
 	if (clp->cl_cb_conn.cb_xprt)
 		svc_xprt_put(clp->cl_cb_conn.cb_xprt);
-	list_del(&clp->cl_idhash);
-	if (test_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags))
-		rb_erase(&clp->cl_namenode, &nn->conf_name_tree);
-	else
-		rb_erase(&clp->cl_namenode, &nn->unconf_name_tree);
 	spin_lock(&nn->client_lock);
-	unhash_client_locked(clp);
 	WARN_ON_ONCE(atomic_read(&clp->cl_refcount));
 	free_client(clp);
 	spin_unlock(&nn->client_lock);
 }
 
+static void
+destroy_client(struct nfs4_client *clp)
+{
+	unhash_client(clp);
+	__destroy_client(clp);
+}
+
 static void expire_client(struct nfs4_client *clp)
 {
+	unhash_client(clp);
 	nfsd4_client_record_remove(clp);
-	destroy_client(clp);
+	__destroy_client(clp);
 }
 
 static void copy_verf(struct nfs4_client *target, nfs4_verifier *source)
-- 
1.9.0


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

* [PATCH 54/70] NFSd: Ensure that the laundromat unhashes the client before releasing locks
  2014-04-18 18:44                                                                                                         ` [PATCH 53/70] NFSd: Ensure struct nfs4_client is unhashed before we try to destroy it Trond Myklebust
@ 2014-04-18 18:44                                                                                                           ` Trond Myklebust
  2014-04-18 18:44                                                                                                             ` [PATCH 55/70] NFSd: Don't require client_lock in free_client Trond Myklebust
  0 siblings, 1 reply; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

If we leave the client on the confirmed/unconfirmed tables, and leave
the sessions visible on the sessionid_hashtbl, then someone might
find them before we've had a chance to destroy them.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 19f7739a156e..55a99ebaf6c9 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -3688,13 +3688,15 @@ nfs4_laundromat(struct nfsd_net *nn)
 		/* Hey, I'm busy with this guy! */
 		if (atomic_read(&clp->cl_refcount) != 0)
 			continue;
-		list_move(&clp->cl_lru, &reaplist);
+		unhash_client_locked(clp);
+		list_add(&clp->cl_lru, &reaplist);
 	}
 	spin_unlock(&nn->client_lock);
 	list_for_each_safe(pos, next, &reaplist) {
 		clp = list_entry(pos, struct nfs4_client, cl_lru);
 		dprintk("NFSD: purging unused client (clientid %08x)\n",
 			clp->cl_clientid.cl_id);
+		list_del_init(&clp->cl_lru);
 		expire_client(clp);
 	}
 	spin_lock(&state_lock);
-- 
1.9.0


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

* [PATCH 55/70] NFSd: Don't require client_lock in free_client
  2014-04-18 18:44                                                                                                           ` [PATCH 54/70] NFSd: Ensure that the laundromat unhashes the client before releasing locks Trond Myklebust
@ 2014-04-18 18:44                                                                                                             ` Trond Myklebust
  2014-04-18 18:44                                                                                                               ` [PATCH 56/70] NFSd: Move create_client() call outside the lock Trond Myklebust
  0 siblings, 1 reply; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

The struct nfs_client is supposed to be invisible and unreferenced
before it gets here.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 10 ----------
 1 file changed, 10 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 55a99ebaf6c9..b2406f20b529 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1252,9 +1252,6 @@ static struct nfs4_client *alloc_client(struct xdr_netobj name)
 static void
 free_client(struct nfs4_client *clp)
 {
-	struct nfsd_net __maybe_unused *nn = net_generic(clp->net, nfsd_net_id);
-
-	lockdep_assert_held(&nn->client_lock);
 	while (!list_empty(&clp->cl_sessions)) {
 		struct nfsd4_session *ses;
 		ses = list_entry(clp->cl_sessions.next, struct nfsd4_session,
@@ -1312,7 +1309,6 @@ __destroy_client(struct nfs4_client *clp)
 	struct nfs4_openowner *oo;
 	struct nfs4_delegation *dp;
 	struct list_head reaplist;
-	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
 
 	INIT_LIST_HEAD(&reaplist);
 	spin_lock(&state_lock);
@@ -1339,10 +1335,7 @@ __destroy_client(struct nfs4_client *clp)
 	nfsd4_shutdown_callback(clp);
 	if (clp->cl_cb_conn.cb_xprt)
 		svc_xprt_put(clp->cl_cb_conn.cb_xprt);
-	spin_lock(&nn->client_lock);
-	WARN_ON_ONCE(atomic_read(&clp->cl_refcount));
 	free_client(clp);
-	spin_unlock(&nn->client_lock);
 }
 
 static void
@@ -1569,7 +1562,6 @@ static struct nfs4_client *create_client(struct xdr_netobj name,
 	struct sockaddr *sa = svc_addr(rqstp);
 	int ret;
 	struct net *net = SVC_NET(rqstp);
-	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 
 	clp = alloc_client(name);
 	if (clp == NULL)
@@ -1577,9 +1569,7 @@ static struct nfs4_client *create_client(struct xdr_netobj name,
 
 	ret = copy_cred(&clp->cl_cred, &rqstp->rq_cred);
 	if (ret) {
-		spin_lock(&nn->client_lock);
 		free_client(clp);
-		spin_unlock(&nn->client_lock);
 		return NULL;
 	}
 	nfsd4_init_callback(&clp->cl_cb_null);
-- 
1.9.0


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

* [PATCH 56/70] NFSd: Move create_client() call outside the lock
  2014-04-18 18:44                                                                                                             ` [PATCH 55/70] NFSd: Don't require client_lock in free_client Trond Myklebust
@ 2014-04-18 18:44                                                                                                               ` Trond Myklebust
  2014-04-18 18:44                                                                                                                 ` [PATCH 57/70] NFSd: Protect unconfirmed client creation using client_lock Trond Myklebust
  0 siblings, 1 reply; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

For efficiency reasons, and because we want to use spin locks.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 35 +++++++++++++++++++----------------
 1 file changed, 19 insertions(+), 16 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index b2406f20b529..79948fd2ad9e 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1888,6 +1888,10 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
 		return nfserr_encr_alg_unsupp;
 	}
 
+	new = create_client(exid->clname, rqstp, &verf);
+	if (new == NULL)
+		return nfserr_jukebox;
+
 	/* Cases below refer to rfc 5661 section 18.35.4: */
 	nfs4_lock_state();
 	conf = find_confirmed_client_by_name(&exid->clname, nn);
@@ -1914,7 +1918,6 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
 			}
 			/* case 6 */
 			exid->flags |= EXCHGID4_FLAG_CONFIRMED_R;
-			new = conf;
 			goto out_copy;
 		}
 		if (!creds_match) { /* case 3 */
@@ -1927,7 +1930,6 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
 		}
 		if (verfs_match) { /* case 2 */
 			conf->cl_exchange_flags |= EXCHGID4_FLAG_CONFIRMED_R;
-			new = conf;
 			goto out_copy;
 		}
 		/* case 5, client reboot */
@@ -1945,29 +1947,28 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
 
 	/* case 1 (normal case) */
 out_new:
-	new = create_client(exid->clname, rqstp, &verf);
-	if (new == NULL) {
-		status = nfserr_jukebox;
-		goto out;
-	}
 	new->cl_minorversion = cstate->minorversion;
 	new->cl_mach_cred = (exid->spa_how == SP4_MACH_CRED);
 
 	gen_clid(new, nn);
 	add_to_unconfirmed(new);
+	conf = new;
+	new = NULL;
 out_copy:
-	exid->clientid.cl_boot = new->cl_clientid.cl_boot;
-	exid->clientid.cl_id = new->cl_clientid.cl_id;
+	exid->clientid.cl_boot = conf->cl_clientid.cl_boot;
+	exid->clientid.cl_id = conf->cl_clientid.cl_id;
 
-	exid->seqid = new->cl_cs_slot.sl_seqid + 1;
-	nfsd4_set_ex_flags(new, exid);
+	exid->seqid = conf->cl_cs_slot.sl_seqid + 1;
+	nfsd4_set_ex_flags(conf, exid);
 
 	dprintk("nfsd4_exchange_id seqid %d flags %x\n",
-		new->cl_cs_slot.sl_seqid, new->cl_exchange_flags);
+		conf->cl_cs_slot.sl_seqid, conf->cl_exchange_flags);
 	status = nfs_ok;
 
 out:
 	nfs4_unlock_state();
+	if (new)
+		free_client(new);
 	return status;
 }
 
@@ -2595,6 +2596,9 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	__be32 			status;
 	struct nfsd_net		*nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
 
+	new = create_client(clname, rqstp, &clverifier);
+	if (new == NULL)
+		return nfserr_jukebox;
 	/* Cases below refer to rfc 3530 section 14.2.33: */
 	nfs4_lock_state();
 	conf = find_confirmed_client_by_name(&clname, nn);
@@ -2615,10 +2619,6 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	unconf = find_unconfirmed_client_by_name(&clname, nn);
 	if (unconf)
 		expire_client(unconf);
-	status = nfserr_jukebox;
-	new = create_client(clname, rqstp, &clverifier);
-	if (new == NULL)
-		goto out;
 	if (conf && same_verf(&conf->cl_verifier, &clverifier))
 		/* case 1: probable callback update */
 		copy_clid(new, conf);
@@ -2630,9 +2630,12 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot;
 	setclid->se_clientid.cl_id = new->cl_clientid.cl_id;
 	memcpy(setclid->se_confirm.data, new->cl_confirm.data, sizeof(setclid->se_confirm.data));
+	new = NULL;
 	status = nfs_ok;
 out:
 	nfs4_unlock_state();
+	if (new)
+		free_client(new);
 	return status;
 }
 
-- 
1.9.0


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

* [PATCH 57/70] NFSd: Protect unconfirmed client creation using client_lock
  2014-04-18 18:44                                                                                                               ` [PATCH 56/70] NFSd: Move create_client() call outside the lock Trond Myklebust
@ 2014-04-18 18:44                                                                                                                 ` Trond Myklebust
  2014-04-18 18:44                                                                                                                   ` [PATCH 58/70] NFSd: Protect session creation and client confirm " Trond Myklebust
  0 siblings, 1 reply; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 31 +++++++++++++++++++++----------
 1 file changed, 21 insertions(+), 10 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 79948fd2ad9e..9c24031757d2 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1633,7 +1633,7 @@ add_to_unconfirmed(struct nfs4_client *clp)
 	add_clp_to_name_tree(clp, &nn->unconf_name_tree);
 	idhashval = clientid_hashval(clp->cl_clientid.cl_id);
 	list_add(&clp->cl_idhash, &nn->unconf_id_hashtbl[idhashval]);
-	renew_client(clp);
+	renew_client_locked(clp);
 }
 
 static void
@@ -1647,7 +1647,7 @@ move_to_confirmed(struct nfs4_client *clp)
 	rb_erase(&clp->cl_namenode, &nn->unconf_name_tree);
 	add_clp_to_name_tree(clp, &nn->conf_name_tree);
 	set_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags);
-	renew_client(clp);
+	renew_client_locked(clp);
 }
 
 static struct nfs4_client *
@@ -1660,7 +1660,7 @@ find_client_in_id_table(struct list_head *tbl, clientid_t *clid, bool sessions)
 		if (same_clid(&clp->cl_clientid, clid)) {
 			if ((bool)clp->cl_minorversion != sessions)
 				return NULL;
-			renew_client(clp);
+			renew_client_locked(clp);
 			return clp;
 		}
 	}
@@ -1859,7 +1859,8 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
 		  struct nfsd4_compound_state *cstate,
 		  struct nfsd4_exchange_id *exid)
 {
-	struct nfs4_client *unconf, *conf, *new;
+	struct nfs4_client *conf, *new;
+	struct nfs4_client *unconf = NULL;
 	__be32 status;
 	char			addr_str[INET6_ADDRSTRLEN];
 	nfs4_verifier		verf = exid->verifier;
@@ -1894,6 +1895,7 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
 
 	/* Cases below refer to rfc 5661 section 18.35.4: */
 	nfs4_lock_state();
+	spin_lock(&nn->client_lock);
 	conf = find_confirmed_client_by_name(&exid->clname, nn);
 	if (conf) {
 		bool creds_match = same_creds(&conf->cl_cred, &rqstp->rq_cred);
@@ -1943,17 +1945,18 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
 
 	unconf  = find_unconfirmed_client_by_name(&exid->clname, nn);
 	if (unconf) /* case 4, possible retry or client restart */
-		expire_client(unconf);
+		unhash_client_locked(unconf);
 
 	/* case 1 (normal case) */
 out_new:
+	if (conf)
+		unhash_client_locked(conf);
 	new->cl_minorversion = cstate->minorversion;
 	new->cl_mach_cred = (exid->spa_how == SP4_MACH_CRED);
 
 	gen_clid(new, nn);
 	add_to_unconfirmed(new);
-	conf = new;
-	new = NULL;
+	swap(new, conf);
 out_copy:
 	exid->clientid.cl_boot = conf->cl_clientid.cl_boot;
 	exid->clientid.cl_id = conf->cl_clientid.cl_id;
@@ -1966,9 +1969,12 @@ out_copy:
 	status = nfs_ok;
 
 out:
+	spin_unlock(&nn->client_lock);
 	nfs4_unlock_state();
 	if (new)
-		free_client(new);
+		expire_client(new);
+	if (unconf)
+		expire_client(unconf);
 	return status;
 }
 
@@ -2592,7 +2598,8 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 {
 	struct xdr_netobj 	clname = setclid->se_name;
 	nfs4_verifier		clverifier = setclid->se_verf;
-	struct nfs4_client	*conf, *unconf, *new;
+	struct nfs4_client	*conf, *new;
+	struct nfs4_client	*unconf = NULL;
 	__be32 			status;
 	struct nfsd_net		*nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
 
@@ -2601,6 +2608,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 		return nfserr_jukebox;
 	/* Cases below refer to rfc 3530 section 14.2.33: */
 	nfs4_lock_state();
+	spin_lock(&nn->client_lock);
 	conf = find_confirmed_client_by_name(&clname, nn);
 	if (conf) {
 		/* case 0: */
@@ -2618,7 +2626,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	}
 	unconf = find_unconfirmed_client_by_name(&clname, nn);
 	if (unconf)
-		expire_client(unconf);
+		unhash_client_locked(unconf);
 	if (conf && same_verf(&conf->cl_verifier, &clverifier))
 		/* case 1: probable callback update */
 		copy_clid(new, conf);
@@ -2633,9 +2641,12 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	new = NULL;
 	status = nfs_ok;
 out:
+	spin_unlock(&nn->client_lock);
 	nfs4_unlock_state();
 	if (new)
 		free_client(new);
+	if (unconf)
+		expire_client(unconf);
 	return status;
 }
 
-- 
1.9.0


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

* [PATCH 58/70] NFSd: Protect session creation and client confirm using client_lock
  2014-04-18 18:44                                                                                                                 ` [PATCH 57/70] NFSd: Protect unconfirmed client creation using client_lock Trond Myklebust
@ 2014-04-18 18:44                                                                                                                   ` Trond Myklebust
  2014-04-18 18:44                                                                                                                     ` [PATCH 59/70] NFSd: Protect nfsd4_destroy_clientid " Trond Myklebust
  2014-05-16 18:19                                                                                                                     ` [PATCH 58/70] NFSd: Protect session creation and client confirm using client_lock Jeff Layton
  0 siblings, 2 replies; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

In particular, we want to ensure that the move_to_confirmed() is
protected by the nn->client_lock spin lock, so that we can use that
when looking up the clientid etc.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 55 ++++++++++++++++++++++++++++++-----------------------
 1 file changed, 31 insertions(+), 24 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 9c24031757d2..f047341678c0 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -130,17 +130,6 @@ static __be32 mark_client_expired_locked(struct nfs4_client *clp)
 	return nfs_ok;
 }
 
-static __be32 mark_client_expired(struct nfs4_client *clp)
-{
-	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
-	__be32 ret;
-
-	spin_lock(&nn->client_lock);
-	ret = mark_client_expired_locked(clp);
-	spin_unlock(&nn->client_lock);
-	return ret;
-}
-
 static __be32 get_client_locked(struct nfs4_client *clp)
 {
 	if (is_client_expired(clp))
@@ -1134,12 +1123,10 @@ static void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, stru
 	new->se_cb_sec = cses->cb_sec;
 	atomic_set(&new->se_ref, 0);
 	idx = hash_sessionid(&new->se_sessionid);
-	spin_lock(&nn->client_lock);
 	list_add(&new->se_hash, &nn->sessionid_hashtbl[idx]);
 	spin_lock(&clp->cl_lock);
 	list_add(&new->se_perclnt, &clp->cl_sessions);
 	spin_unlock(&clp->cl_lock);
-	spin_unlock(&nn->client_lock);
 
 	if (cses->flags & SESSION4_BACK_CHAN) {
 		struct sockaddr *sa = svc_addr(rqstp);
@@ -2118,6 +2105,7 @@ nfsd4_create_session(struct svc_rqst *rqstp,
 {
 	struct sockaddr *sa = svc_addr(rqstp);
 	struct nfs4_client *conf, *unconf;
+	struct nfs4_client *old = NULL;
 	struct nfsd4_session *new;
 	struct nfsd4_conn *conn;
 	struct nfsd4_clid_slot *cs_slot = NULL;
@@ -2144,6 +2132,7 @@ nfsd4_create_session(struct svc_rqst *rqstp,
 		goto out_free_session;
 
 	nfs4_lock_state();
+	spin_lock(&nn->client_lock);
 	unconf = find_unconfirmed_client(&cr_ses->clientid, true, nn);
 	conf = find_confirmed_client(&cr_ses->clientid, true, nn);
 	WARN_ON_ONCE(conf && unconf);
@@ -2162,7 +2151,6 @@ nfsd4_create_session(struct svc_rqst *rqstp,
 			goto out_free_conn;
 		}
 	} else if (unconf) {
-		struct nfs4_client *old;
 		if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) ||
 		    !rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) {
 			status = nfserr_clid_inuse;
@@ -2180,10 +2168,10 @@ nfsd4_create_session(struct svc_rqst *rqstp,
 		}
 		old = find_confirmed_client_by_name(&unconf->cl_name, nn);
 		if (old) {
-			status = mark_client_expired(old);
+			status = mark_client_expired_locked(old);
 			if (status)
 				goto out_free_conn;
-			expire_client(old);
+			unhash_client_locked(old);
 		}
 		move_to_confirmed(unconf);
 		conf = unconf;
@@ -2199,7 +2187,7 @@ nfsd4_create_session(struct svc_rqst *rqstp,
 	cr_ses->flags &= ~SESSION4_RDMA;
 
 	init_session(rqstp, new, conf, cr_ses);
-	nfsd4_init_conn(rqstp, conn, new);
+	nfsd4_get_session_locked(new);
 
 	memcpy(cr_ses->sessionid.data, new->se_sessionid.data,
 	       NFS4_MAX_SESSIONID_LEN);
@@ -2208,11 +2196,20 @@ nfsd4_create_session(struct svc_rqst *rqstp,
 
 	/* cache solo and embedded create sessions under the state lock */
 	nfsd4_cache_create_session(cr_ses, cs_slot, status);
+	spin_unlock(&nn->client_lock);
+	/* init connection and backchannel */
+	nfsd4_init_conn(rqstp, conn, new);
+	nfsd4_put_session(new);
 	nfs4_unlock_state();
+	if (old)
+		expire_client(old);
 	return status;
 out_free_conn:
+	spin_unlock(&nn->client_lock);
 	nfs4_unlock_state();
 	free_conn(conn);
+	if (old)
+		expire_client(old);
 out_free_session:
 	__free_session(new);
 out_release_drc_mem:
@@ -2657,6 +2654,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
 			 struct nfsd4_setclientid_confirm *setclientid_confirm)
 {
 	struct nfs4_client *conf, *unconf;
+	struct nfs4_client *old = NULL;
 	nfs4_verifier confirm = setclientid_confirm->sc_confirm; 
 	clientid_t * clid = &setclientid_confirm->sc_clientid;
 	__be32 status;
@@ -2666,6 +2664,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
 		return nfserr_stale_clientid;
 	nfs4_lock_state();
 
+	spin_lock(&nn->client_lock);
 	conf = find_confirmed_client(clid, false, nn);
 	unconf = find_unconfirmed_client(clid, false, nn);
 	/*
@@ -2689,21 +2688,29 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
 	}
 	status = nfs_ok;
 	if (conf) { /* case 1: callback update */
+		old = unconf;
+		unhash_client_locked(old);
 		nfsd4_change_callback(conf, &unconf->cl_cb_conn);
-		nfsd4_probe_callback(conf);
-		expire_client(unconf);
 	} else { /* case 3: normal case; new or rebooted client */
-		conf = find_confirmed_client_by_name(&unconf->cl_name, nn);
-		if (conf) {
-			status = mark_client_expired(conf);
+		old = find_confirmed_client_by_name(&unconf->cl_name, nn);
+		if (old) {
+			status = mark_client_expired_locked(old);
 			if (status)
 				goto out;
-			expire_client(conf);
+			unhash_client_locked(old);
 		}
 		move_to_confirmed(unconf);
-		nfsd4_probe_callback(unconf);
+		conf = unconf;
 	}
+	get_client_locked(conf);
+	spin_unlock(&nn->client_lock);
+	nfsd4_probe_callback(conf);
+	spin_lock(&nn->client_lock);
+	put_client_renew_locked(conf);
 out:
+	spin_unlock(&nn->client_lock);
+	if (old)
+		expire_client(old);
 	nfs4_unlock_state();
 	return status;
 }
-- 
1.9.0


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

* [PATCH 59/70] NFSd: Protect nfsd4_destroy_clientid using client_lock
  2014-04-18 18:44                                                                                                                   ` [PATCH 58/70] NFSd: Protect session creation and client confirm " Trond Myklebust
@ 2014-04-18 18:44                                                                                                                     ` Trond Myklebust
  2014-04-18 18:44                                                                                                                       ` [PATCH 60/70] NFSd: Ensure lookup_clientid() takes client_lock Trond Myklebust
  2014-05-16 18:19                                                                                                                     ` [PATCH 58/70] NFSd: Protect session creation and client confirm using client_lock Jeff Layton
  1 sibling, 1 reply; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index f047341678c0..6a0c201c670f 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -2518,22 +2518,23 @@ nfsd4_sequence_done(struct nfsd4_compoundres *resp)
 __be32
 nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_destroy_clientid *dc)
 {
-	struct nfs4_client *conf, *unconf, *clp;
+	struct nfs4_client *conf, *unconf;
+	struct nfs4_client *clp= NULL;
 	__be32 status = 0;
 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
 
 	nfs4_lock_state();
+	spin_lock(&nn->client_lock);
 	unconf = find_unconfirmed_client(&dc->clientid, true, nn);
 	conf = find_confirmed_client(&dc->clientid, true, nn);
 	WARN_ON_ONCE(conf && unconf);
 
 	if (conf) {
-		clp = conf;
-
 		if (client_has_state(conf)) {
 			status = nfserr_clientid_busy;
 			goto out;
 		}
+		clp = conf;
 	} else if (unconf)
 		clp = unconf;
 	else {
@@ -2541,12 +2542,16 @@ nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *csta
 		goto out;
 	}
 	if (!mach_creds_match(clp, rqstp)) {
+		clp = NULL;
 		status = nfserr_wrong_cred;
 		goto out;
 	}
-	expire_client(clp);
+	unhash_client_locked(clp);
 out:
+	spin_unlock(&nn->client_lock);
 	nfs4_unlock_state();
+	if (clp)
+		expire_client(clp);
 	return status;
 }
 
-- 
1.9.0


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

* [PATCH 60/70] NFSd: Ensure lookup_clientid() takes client_lock
  2014-04-18 18:44                                                                                                                     ` [PATCH 59/70] NFSd: Protect nfsd4_destroy_clientid " Trond Myklebust
@ 2014-04-18 18:44                                                                                                                       ` Trond Myklebust
  2014-04-18 18:44                                                                                                                         ` [PATCH 61/70] NFSd: Remove nfs4_lock_state(): nfs4_preprocess_stateid_op() Trond Myklebust
  2014-05-05  8:53                                                                                                                         ` [PATCH 60/70] NFSd: Ensure lookup_clientid() takes client_lock Christoph Hellwig
  0 siblings, 2 replies; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

Ensure that the client lookup is done safely under the client_lock.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 35 +++++++++++++++++++++++++++++------
 1 file changed, 29 insertions(+), 6 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 6a0c201c670f..ad79dca31cc4 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -178,6 +178,15 @@ static void put_client_renew_locked(struct nfs4_client *clp)
 		renew_client_locked(clp);
 }
 
+static void put_client_renew(struct nfs4_client *clp)
+{
+	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
+
+	spin_lock(&nn->client_lock);
+	put_client_renew_locked(clp);
+	spin_unlock(&nn->client_lock);
+}
+
 static __be32 nfsd4_get_session_locked(struct nfsd4_session *ses)
 {
 	__be32 status;
@@ -3614,18 +3623,27 @@ static __be32 lookup_clientid(clientid_t *clid, struct nfsd4_session *session, s
 {
 	struct nfs4_client *found;
 
+	spin_lock(&nn->client_lock);
 	if (session != NULL) {
 		found = session->se_client;
 		if (!same_clid(&found->cl_clientid, clid))
-			return nfserr_stale_clientid;
+			goto out_stale;
 	} else {
 		if (STALE_CLIENTID(clid, nn))
-			return nfserr_stale_clientid;
+			goto out_stale;
 		found = find_confirmed_client(clid, false, nn);
 	}
-	if (clp)
-		*clp = found;
+	if (clp) {
+		if (get_client_locked(found) == nfs_ok)
+			*clp = found;
+		else
+			found = NULL;
+	}
+	spin_unlock(&nn->client_lock);
 	return found ? nfs_ok : nfserr_expired;
+out_stale:
+	spin_unlock(&nn->client_lock);
+	return nfserr_stale_clientid;
 }
 
 __be32
@@ -3645,8 +3663,10 @@ nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	status = nfserr_cb_path_down;
 	if (!list_empty(&clp->cl_delegations)
 			&& clp->cl_cb_state != NFSD4_CB_UP)
-		goto out;
+		goto put_client;
 	status = nfs_ok;
+put_client:
+	put_client_renew(clp);
 out:
 	nfs4_unlock_state();
 	return status;
@@ -3939,6 +3959,7 @@ static __be32 nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate,
 	if (status)
 		return status;
 	*s = find_stateid_by_type(cl, stateid, typemask);
+	put_client_renew(cl);
 	if (!*s)
 		return nfserr_bad_stateid;
 	return nfs_ok;
@@ -5119,7 +5140,9 @@ nfs4_check_open_reclaim(clientid_t *clid, struct nfsd4_session *session, struct
 	if (status)
 		return nfserr_reclaim_bad;
 
-	return nfsd4_client_record_check(clp) ? nfserr_reclaim_bad : nfs_ok;
+	status = nfsd4_client_record_check(clp) ? nfserr_reclaim_bad : nfs_ok;
+	put_client_renew(clp);
+	return status;
 }
 
 #ifdef CONFIG_NFSD_FAULT_INJECTION
-- 
1.9.0


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

* [PATCH 61/70] NFSd: Remove nfs4_lock_state(): nfs4_preprocess_stateid_op()
  2014-04-18 18:44                                                                                                                       ` [PATCH 60/70] NFSd: Ensure lookup_clientid() takes client_lock Trond Myklebust
@ 2014-04-18 18:44                                                                                                                         ` Trond Myklebust
  2014-04-18 18:44                                                                                                                           ` [PATCH 62/70] NFSd: Remove nfs4_lock_state(): nfsd4_test_stateid/nfsd4_free_stateid Trond Myklebust
  2014-05-05  8:53                                                                                                                         ` [PATCH 60/70] NFSd: Ensure lookup_clientid() takes client_lock Christoph Hellwig
  1 sibling, 1 reply; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index ad79dca31cc4..67daa70dd9a2 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -3990,13 +3990,11 @@ nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate,
 	if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
 		return check_special_stateids(net, current_fh, stateid, flags);
 
-	nfs4_lock_state();
-
 	status = nfsd4_lookup_stateid(cstate, stateid,
 				      NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID,
 				      &s, nn);
 	if (status)
-		goto unlock_state;
+		return status;
 	status = check_stateid_generation(stateid, &s->sc_stateid, nfsd4_has_session(cstate));
 	if (status)
 		goto out;
@@ -4044,8 +4042,6 @@ nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate,
 		*filpp = file;
 out:
 	nfs4_put_stateid(s);
-unlock_state:
-	nfs4_unlock_state();
 	return status;
 }
 
-- 
1.9.0


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

* [PATCH 62/70] NFSd: Remove nfs4_lock_state(): nfsd4_test_stateid/nfsd4_free_stateid
  2014-04-18 18:44                                                                                                                         ` [PATCH 61/70] NFSd: Remove nfs4_lock_state(): nfs4_preprocess_stateid_op() Trond Myklebust
@ 2014-04-18 18:44                                                                                                                           ` Trond Myklebust
  2014-04-18 18:44                                                                                                                             ` [PATCH 63/70] NFSd: Remove nfs4_lock_state(): nfsd4_release_lockowner Trond Myklebust
  0 siblings, 1 reply; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 67daa70dd9a2..6eac3ce68a8b 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -4064,11 +4064,9 @@ nfsd4_test_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	struct nfsd4_test_stateid_id *stateid;
 	struct nfs4_client *cl = cstate->session->se_client;
 
-	nfs4_lock_state();
 	list_for_each_entry(stateid, &test_stateid->ts_stateid_list, ts_id_list)
 		stateid->ts_id_status =
 			nfsd4_validate_stateid(cl, &stateid->ts_id_stateid);
-	nfs4_unlock_state();
 
 	return nfs_ok;
 }
@@ -4083,7 +4081,6 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	struct nfs4_client *cl = cstate->session->se_client;
 	__be32 ret = nfserr_bad_stateid;
 
-	nfs4_lock_state();
 	s = find_stateid(cl, stateid);
 	if (!s)
 		goto out;
@@ -4111,7 +4108,6 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	}
 	nfs4_put_stateid(s);
 out:
-	nfs4_unlock_state();
 	return ret;
 }
 
-- 
1.9.0


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

* [PATCH 63/70] NFSd: Remove nfs4_lock_state(): nfsd4_release_lockowner
  2014-04-18 18:44                                                                                                                           ` [PATCH 62/70] NFSd: Remove nfs4_lock_state(): nfsd4_test_stateid/nfsd4_free_stateid Trond Myklebust
@ 2014-04-18 18:44                                                                                                                             ` Trond Myklebust
  2014-04-18 18:44                                                                                                                               ` [PATCH 64/70] NFSd: Remove nfs4_lock_state(): nfsd4_lock/locku/lockt() Trond Myklebust
  0 siblings, 1 reply; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 6eac3ce68a8b..67895511cc05 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -4999,8 +4999,6 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
 	dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n",
 		clid->cl_boot, clid->cl_id);
 
-	nfs4_lock_state();
-
 	status = lookup_clientid(clid, NULL, nn, NULL);
 	if (status)
 		goto out;
@@ -5034,7 +5032,6 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
 		release_lockowner(lo);
 	}
 out:
-	nfs4_unlock_state();
 	return status;
 }
 
-- 
1.9.0


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

* [PATCH 64/70] NFSd: Remove nfs4_lock_state(): nfsd4_lock/locku/lockt()
  2014-04-18 18:44                                                                                                                             ` [PATCH 63/70] NFSd: Remove nfs4_lock_state(): nfsd4_release_lockowner Trond Myklebust
@ 2014-04-18 18:44                                                                                                                               ` Trond Myklebust
  2014-04-18 18:44                                                                                                                                 ` [PATCH 65/70] NFSd: Remove nfs4_lock_state(): nfsd4_open_downgrade + nfsd4_close Trond Myklebust
  0 siblings, 1 reply; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 9 ---------
 1 file changed, 9 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 67895511cc05..1e0f5301e2b3 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -4656,8 +4656,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 		return status;
 	}
 
-	nfs4_lock_state();
-
 	if (lock->lk_is_new) {
 		if (nfsd4_has_session(cstate))
 			/* See rfc 5661 18.10.3: given clientid is ignored: */
@@ -4783,7 +4781,6 @@ out:
 	if (status && new_state)
 		release_lockowner_if_empty(lock_sop);
 	nfsd4_bump_seqid(cstate, status);
-	nfs4_unlock_state();
 	if (file_lock)
 		locks_free_lock(file_lock);
 	if (conflock)
@@ -4826,8 +4823,6 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	if (check_lock_length(lockt->lt_offset, lockt->lt_length))
 		 return nfserr_inval;
 
-	nfs4_lock_state();
-
 	if (!nfsd4_has_session(cstate)) {
 		status = lookup_clientid(&lockt->lt_clientid, NULL, nn, NULL);
 		if (status)
@@ -4879,7 +4874,6 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 		nfs4_set_lock_denied(file_lock, &lockt->lt_denied);
 	}
 out:
-	nfs4_unlock_state();
 	if (file_lock)
 		locks_free_lock(file_lock);
 	return status;
@@ -4903,8 +4897,6 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	if (check_lock_length(locku->lu_offset, locku->lu_length))
 		 return nfserr_inval;
 
-	nfs4_lock_state();
-									        
 	status = nfs4_preprocess_seqid_op(cstate, locku->lu_seqid,
 					&locku->lu_stateid, NFS4_LOCK_STID,
 					&stp, nn);
@@ -4947,7 +4939,6 @@ put_stateid:
 	put_generic_stateid(stp);
 out:
 	nfsd4_bump_seqid(cstate, status);
-	nfs4_unlock_state();
 	if (file_lock)
 		locks_free_lock(file_lock);
 	return status;
-- 
1.9.0


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

* [PATCH 65/70] NFSd: Remove nfs4_lock_state(): nfsd4_open_downgrade + nfsd4_close
  2014-04-18 18:44                                                                                                                               ` [PATCH 64/70] NFSd: Remove nfs4_lock_state(): nfsd4_lock/locku/lockt() Trond Myklebust
@ 2014-04-18 18:44                                                                                                                                 ` Trond Myklebust
  2014-04-18 18:45                                                                                                                                   ` [PATCH 66/70] NFSd: Remove nfs4_lock_state(): nfsd4_delegreturn() Trond Myklebust
  0 siblings, 1 reply; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:44 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

---
 fs/nfsd/nfs4state.c | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 1e0f5301e2b3..681b25deac02 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -4288,7 +4288,6 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp,
 		dprintk("NFSD: %s: od_deleg_want=0x%x ignored\n", __func__,
 			od->od_deleg_want);
 
-	nfs4_lock_state();
 	status = nfs4_preprocess_confirmed_seqid_op(cstate, od->od_seqid,
 					&od->od_stateid, &stp, nn);
 	if (status)
@@ -4315,7 +4314,6 @@ put_stateid:
 	put_generic_stateid(stp);
 out:
 	nfsd4_bump_seqid(cstate, status);
-	nfs4_unlock_state();
 	return status;
 }
 
@@ -4341,7 +4339,6 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	dprintk("NFSD: nfsd4_close on file %pd\n", 
 			cstate->current_fh.fh_dentry);
 
-	nfs4_lock_state();
 	status = nfs4_preprocess_seqid_op(cstate, close->cl_seqid,
 					&close->cl_stateid,
 					NFS4_OPEN_STID|NFS4_CLOSED_STID,
@@ -4375,7 +4372,6 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 		}
 	}
 out:
-	nfs4_unlock_state();
 	return status;
 }
 
-- 
1.9.0


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

* [PATCH 66/70] NFSd: Remove nfs4_lock_state(): nfsd4_delegreturn()
  2014-04-18 18:44                                                                                                                                 ` [PATCH 65/70] NFSd: Remove nfs4_lock_state(): nfsd4_open_downgrade + nfsd4_close Trond Myklebust
@ 2014-04-18 18:45                                                                                                                                   ` Trond Myklebust
  2014-04-18 18:45                                                                                                                                     ` [PATCH 67/70] NFSd: Remove nfs4_lock_state(): nfsd4_open and nfsd4_open_confirm Trond Myklebust
  0 siblings, 1 reply; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:45 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 681b25deac02..5f0facdde981 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -4388,7 +4388,6 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0)))
 		return status;
 
-	nfs4_lock_state();
 	status = nfsd4_lookup_stateid(cstate, stateid, NFS4_DELEG_STID, &s, nn);
 	if (status)
 		goto out;
@@ -4401,8 +4400,6 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 put_stateid:
 	nfs4_put_delegation(dp);
 out:
-	nfs4_unlock_state();
-
 	return status;
 }
 
-- 
1.9.0


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

* [PATCH 67/70] NFSd: Remove nfs4_lock_state(): nfsd4_open and nfsd4_open_confirm
  2014-04-18 18:45                                                                                                                                   ` [PATCH 66/70] NFSd: Remove nfs4_lock_state(): nfsd4_delegreturn() Trond Myklebust
@ 2014-04-18 18:45                                                                                                                                     ` Trond Myklebust
  2014-04-18 18:45                                                                                                                                       ` [PATCH 68/70] NFSd: Remove nfs4_lock_state(): exchange_id, create/destroy_session() Trond Myklebust
  0 siblings, 1 reply; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:45 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4proc.c  | 3 ---
 fs/nfsd/nfs4state.c | 6 ------
 2 files changed, 9 deletions(-)

diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 1101bf6b63c8..47aa08ed92aa 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -385,8 +385,6 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	if (nfsd4_has_session(cstate))
 		copy_clientid(&open->op_clientid, cstate->session);
 
-	nfs4_lock_state();
-
 	/* check seqid for replay. set nfs4_owner */
 	resp = rqstp->rq_resp;
 	status = nfsd4_process_open1(&resp->cstate, open, nn);
@@ -474,7 +472,6 @@ out:
 		nfsd4_cstate_assign_replay(cstate,
 				&open->op_openowner->oo_owner);
 	nfsd4_bump_seqid(cstate, status);
-	nfs4_unlock_state();
 	return status;
 }
 
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 5f0facdde981..188eb4cbea95 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -3494,9 +3494,6 @@ static void nfsd4_deleg_xgrade_none_ext(struct nfsd4_open *open,
 	 */
 }
 
-/*
- * called with nfs4_lock_state() held.
- */
 __be32
 nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
 {
@@ -4208,8 +4205,6 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	if (status)
 		return status;
 
-	nfs4_lock_state();
-
 	status = nfs4_preprocess_seqid_op(cstate,
 					oc->oc_seqid, &oc->oc_req_stateid,
 					NFS4_OPEN_STID, &stp, nn);
@@ -4231,7 +4226,6 @@ put_stateid:
 	put_generic_stateid(stp);
 out:
 	nfsd4_bump_seqid(cstate, status);
-	nfs4_unlock_state();
 	return status;
 }
 
-- 
1.9.0


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

* [PATCH 68/70] NFSd: Remove nfs4_lock_state(): exchange_id, create/destroy_session()
  2014-04-18 18:45                                                                                                                                     ` [PATCH 67/70] NFSd: Remove nfs4_lock_state(): nfsd4_open and nfsd4_open_confirm Trond Myklebust
@ 2014-04-18 18:45                                                                                                                                       ` Trond Myklebust
  2014-04-18 18:45                                                                                                                                         ` [PATCH 69/70] NFSd: Remove nfs4_lock_state(): setclientid, setclientid_confirm, renew Trond Myklebust
  0 siblings, 1 reply; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:45 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

Also destroy_clientid and bind_conn_to_session.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 11 -----------
 1 file changed, 11 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 188eb4cbea95..3a0a3e8c9982 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1890,7 +1890,6 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
 		return nfserr_jukebox;
 
 	/* Cases below refer to rfc 5661 section 18.35.4: */
-	nfs4_lock_state();
 	spin_lock(&nn->client_lock);
 	conf = find_confirmed_client_by_name(&exid->clname, nn);
 	if (conf) {
@@ -1966,7 +1965,6 @@ out_copy:
 
 out:
 	spin_unlock(&nn->client_lock);
-	nfs4_unlock_state();
 	if (new)
 		expire_client(new);
 	if (unconf)
@@ -2140,7 +2138,6 @@ nfsd4_create_session(struct svc_rqst *rqstp,
 	if (!conn)
 		goto out_free_session;
 
-	nfs4_lock_state();
 	spin_lock(&nn->client_lock);
 	unconf = find_unconfirmed_client(&cr_ses->clientid, true, nn);
 	conf = find_confirmed_client(&cr_ses->clientid, true, nn);
@@ -2209,13 +2206,11 @@ nfsd4_create_session(struct svc_rqst *rqstp,
 	/* init connection and backchannel */
 	nfsd4_init_conn(rqstp, conn, new);
 	nfsd4_put_session(new);
-	nfs4_unlock_state();
 	if (old)
 		expire_client(old);
 	return status;
 out_free_conn:
 	spin_unlock(&nn->client_lock);
-	nfs4_unlock_state();
 	free_conn(conn);
 	if (old)
 		expire_client(old);
@@ -2271,7 +2266,6 @@ __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp,
 
 	if (!nfsd4_last_compound_op(rqstp))
 		return nfserr_not_only_op;
-	nfs4_lock_state();
 	spin_lock(&nn->client_lock);
 	session = find_in_sessionid_hashtbl(&bcts->sessionid, net, &status);
 	spin_unlock(&nn->client_lock);
@@ -2292,7 +2286,6 @@ __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp,
 out:
 	nfsd4_put_session(session);
 out_no_session:
-	nfs4_unlock_state();
 	return status;
 }
 
@@ -2314,7 +2307,6 @@ nfsd4_destroy_session(struct svc_rqst *r,
 	struct net *net = SVC_NET(r);
 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 
-	nfs4_lock_state();
 	status = nfserr_not_only_op;
 	if (nfsd4_compound_in_session(cstate->session, &sessionid->sessionid)) {
 		if (!nfsd4_last_compound_op(r))
@@ -2344,7 +2336,6 @@ out_put_session:
 out_client_lock:
 	spin_unlock(&nn->client_lock);
 out:
-	nfs4_unlock_state();
 	return status;
 }
 
@@ -2532,7 +2523,6 @@ nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *csta
 	__be32 status = 0;
 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
 
-	nfs4_lock_state();
 	spin_lock(&nn->client_lock);
 	unconf = find_unconfirmed_client(&dc->clientid, true, nn);
 	conf = find_confirmed_client(&dc->clientid, true, nn);
@@ -2558,7 +2548,6 @@ nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *csta
 	unhash_client_locked(clp);
 out:
 	spin_unlock(&nn->client_lock);
-	nfs4_unlock_state();
 	if (clp)
 		expire_client(clp);
 	return status;
-- 
1.9.0


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

* [PATCH 69/70] NFSd: Remove nfs4_lock_state(): setclientid, setclientid_confirm, renew
  2014-04-18 18:45                                                                                                                                       ` [PATCH 68/70] NFSd: Remove nfs4_lock_state(): exchange_id, create/destroy_session() Trond Myklebust
@ 2014-04-18 18:45                                                                                                                                         ` Trond Myklebust
  2014-04-18 18:45                                                                                                                                           ` [PATCH 70/70] NFSd: Remove nfs4_lock_state(): reclaim_complete() Trond Myklebust
  0 siblings, 1 reply; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:45 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 3a0a3e8c9982..36ccc79702dd 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -2607,7 +2607,6 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	if (new == NULL)
 		return nfserr_jukebox;
 	/* Cases below refer to rfc 3530 section 14.2.33: */
-	nfs4_lock_state();
 	spin_lock(&nn->client_lock);
 	conf = find_confirmed_client_by_name(&clname, nn);
 	if (conf) {
@@ -2642,7 +2641,6 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	status = nfs_ok;
 out:
 	spin_unlock(&nn->client_lock);
-	nfs4_unlock_state();
 	if (new)
 		free_client(new);
 	if (unconf)
@@ -2665,7 +2663,6 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
 
 	if (STALE_CLIENTID(clid, nn))
 		return nfserr_stale_clientid;
-	nfs4_lock_state();
 
 	spin_lock(&nn->client_lock);
 	conf = find_confirmed_client(clid, false, nn);
@@ -2714,7 +2711,6 @@ out:
 	spin_unlock(&nn->client_lock);
 	if (old)
 		expire_client(old);
-	nfs4_unlock_state();
 	return status;
 }
 
@@ -3640,7 +3636,6 @@ nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	__be32 status;
 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
 
-	nfs4_lock_state();
 	dprintk("process_renew(%08x/%08x): starting\n", 
 			clid->cl_boot, clid->cl_id);
 	status = lookup_clientid(clid, NULL, nn, &clp);
@@ -3654,7 +3649,6 @@ nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 put_client:
 	put_client_renew(clp);
 out:
-	nfs4_unlock_state();
 	return status;
 }
 
-- 
1.9.0


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

* [PATCH 70/70] NFSd: Remove nfs4_lock_state(): reclaim_complete()
  2014-04-18 18:45                                                                                                                                         ` [PATCH 69/70] NFSd: Remove nfs4_lock_state(): setclientid, setclientid_confirm, renew Trond Myklebust
@ 2014-04-18 18:45                                                                                                                                           ` Trond Myklebust
  0 siblings, 0 replies; 118+ messages in thread
From: Trond Myklebust @ 2014-04-18 18:45 UTC (permalink / raw)
  To: Bruce Fields; +Cc: linux-nfs

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 36ccc79702dd..a71dbf2a7a61 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -2568,7 +2568,6 @@ nfsd4_reclaim_complete(struct svc_rqst *rqstp, struct nfsd4_compound_state *csta
 		 return nfs_ok;
 	}
 
-	nfs4_lock_state();
 	status = nfserr_complete_already;
 	if (test_and_set_bit(NFSD4_CLIENT_RECLAIM_COMPLETE,
 			     &cstate->session->se_client->cl_flags))
@@ -2588,7 +2587,6 @@ nfsd4_reclaim_complete(struct svc_rqst *rqstp, struct nfsd4_compound_state *csta
 	status = nfs_ok;
 	nfsd4_client_record_create(cstate->session->se_client);
 out:
-	nfs4_unlock_state();
 	return status;
 }
 
-- 
1.9.0


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

* Re: [PATCH 15/70] NFSd: Add locking to the nfs4_file->fi_fds[] array
  2014-04-18 18:44                             ` [PATCH 15/70] NFSd: Add locking to the nfs4_file->fi_fds[] array Trond Myklebust
  2014-04-18 18:44                               ` [PATCH 16/70] NFSd: Protect the nfs4_file delegation fields using the fi_lock Trond Myklebust
@ 2014-04-19 14:35                               ` Christoph Hellwig
  2014-04-21 13:01                                 ` Trond Myklebust
  1 sibling, 1 reply; 118+ messages in thread
From: Christoph Hellwig @ 2014-04-19 14:35 UTC (permalink / raw)
  To: Trond Myklebust; +Cc: Bruce Fields, linux-nfs

> +/* XXX: for first cut may fall back on returning file that doesn't work
> + * at all? */

I think moving this code around might be a good opportunity to remove
this confusing comment.

> +static struct file *find_writeable_file(struct nfs4_file *f)
> +{
> +	struct file *ret;
> +
> +	spin_lock(&f->fi_lock);
> +	ret = __nfs4_get_fd(f, O_WRONLY);
> +	if (!ret)
> +		ret = __nfs4_get_fd(f, O_RDWR);
> +	spin_unlock(&f->fi_lock);
> +	return ret;
> +}
> +
> +static struct file *find_readable_file(struct nfs4_file *f)
> +{
> +	struct file *ret;
> +
> +	spin_lock(&f->fi_lock);
> +	ret = __nfs4_get_fd(f, O_RDONLY);
> +	if (!ret)
> +		ret = __nfs4_get_fd(f, O_RDWR);
> +	spin_unlock(&f->fi_lock);
> +	return ret;

Seems like these two functions could be easily consolidated by passing
a single flags argument.


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

* Re: [PATCH 21/70] NFSd: Get rid of the lockowner_ino_hashtbl
  2014-04-18 18:44                                         ` [PATCH 21/70] NFSd: Get rid of the lockowner_ino_hashtbl Trond Myklebust
  2014-04-18 18:44                                           ` [PATCH 22/70] NFSd: Cleanup nfs4svc_encode_compoundres Trond Myklebust
@ 2014-04-19 14:38                                           ` Christoph Hellwig
  2014-04-21 13:08                                             ` Trond Myklebust
  1 sibling, 1 reply; 118+ messages in thread
From: Christoph Hellwig @ 2014-04-19 14:38 UTC (permalink / raw)
  To: Trond Myklebust; +Cc: Bruce Fields, linux-nfs

On Fri, Apr 18, 2014 at 02:44:15PM -0400, Trond Myklebust wrote:
> It is no longer used.

I think this should be folded into the previous patch, which is the
reason why it is unused now.


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

* Re: [PATCH 30/70] NFSd: Replace delegation->dl_file with the dl_stid.sc_file
  2014-04-18 18:44                                                           ` [PATCH 30/70] NFSd: Replace delegation->dl_file with the dl_stid.sc_file Trond Myklebust
  2014-04-18 18:44                                                             ` [PATCH 31/70] NFSd: Replace nfs4_ol_stateid->st_file with the st_stid.sc_file Trond Myklebust
@ 2014-04-19 14:40                                                             ` Christoph Hellwig
  2014-04-21 13:13                                                               ` Trond Myklebust
  2014-05-05  9:01                                                             ` Christoph Hellwig
  2 siblings, 1 reply; 118+ messages in thread
From: Christoph Hellwig @ 2014-04-19 14:40 UTC (permalink / raw)
  To: Trond Myklebust; +Cc: Bruce Fields, linux-nfs

Instead of adding a mostly unused file field to the stid in the previous
patch and starting to use it here I'd recommend merging the two patches.


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

* Re: [PATCH 35/70] NFSd: Slight cleanup of find_stateid()
  2014-04-18 18:44                                                                     ` [PATCH 35/70] NFSd: Slight cleanup of find_stateid() Trond Myklebust
  2014-04-18 18:44                                                                       ` [PATCH 36/70] NFSd: Add reference counting to find_stateid Trond Myklebust
@ 2014-04-19 14:41                                                                       ` Christoph Hellwig
  2014-04-21 13:31                                                                         ` Trond Myklebust
  1 sibling, 1 reply; 118+ messages in thread
From: Christoph Hellwig @ 2014-04-19 14:41 UTC (permalink / raw)
  To: Trond Myklebust; +Cc: Bruce Fields, linux-nfs

> +static struct nfs4_stid *find_stateid_locked(struct nfs4_client *cl, stateid_t *t)
>  {
>  	struct nfs4_stid *ret;
>  
> -	spin_lock(&cl->cl_lock);
>  	ret = idr_find(&cl->cl_stateids, t->si_opaque.so_id);
> -	spin_unlock(&cl->cl_lock);
>  	if (!ret || !ret->sc_type)
>  		return NULL;

Just curious, how can !ret->sc_type happen?


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

* Re: [PATCH 36/70] NFSd: Add reference counting to find_stateid
  2014-04-18 18:44                                                                       ` [PATCH 36/70] NFSd: Add reference counting to find_stateid Trond Myklebust
  2014-04-18 18:44                                                                         ` [PATCH 37/70] NFSd: nfs4_preprocess_seqid_op should only set *stpp on success Trond Myklebust
@ 2014-04-19 14:50                                                                         ` Christoph Hellwig
  2014-04-21 15:37                                                                           ` Trond Myklebust
  1 sibling, 1 reply; 118+ messages in thread
From: Christoph Hellwig @ 2014-04-19 14:50 UTC (permalink / raw)
  To: Trond Myklebust; +Cc: Bruce Fields, linux-nfs

> +static void nfs4_put_stateid(struct nfs4_stid *s)
> +{
> +	if (s == NULL)
> +		return;
> +	switch (s->sc_type) {
> +	case NFS4_OPEN_STID:
> +	case NFS4_LOCK_STID:
> +	case NFS4_CLOSED_STID:
> +		put_generic_stateid(openlockstateid(s));
> +		break;
> +	case NFS4_DELEG_STID:
> +	case NFS4_REVOKED_DELEG_STID:
> +	case NFS4_CLOSED_DELEG_STID:
> +		nfs4_put_delegation(delegstateid(s));
> +	}
> +}

I really don't like the way the inheritance for the stateids works,
a pure put operation shouldn't need this.  I think all this can be
fixed by adding a ->free function pointer to struct nfs4_stid.  At this
point the braindamage of passing a kmem_cache pointer to various
function can be removed (similar to how nfs4_alloc_stid should be
replaced with a nfs4_init_stid that takes an already allocated stid),
and nothing in the normal refcounting path should need these switches.

> @@ -3804,26 +3823,33 @@ static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid)
>  		return nfserr_bad_stateid;
>  	status = check_stateid_generation(stateid, &s->sc_stateid, 1);
>  	if (status)
> -		return status;
> +		goto out_put_stid;
>  	switch (s->sc_type) {
>  	case NFS4_DELEG_STID:
> -		return nfs_ok;
> +		status = nfs_ok;
> +		break;
>  	case NFS4_REVOKED_DELEG_STID:
> -		return nfserr_deleg_revoked;
> +		status = nfserr_deleg_revoked;
> +		break;
>  	case NFS4_OPEN_STID:
>  	case NFS4_LOCK_STID:
>  		ols = openlockstateid(s);
>  		if (ols->st_stateowner->so_is_open_owner
>  	    			&& !(openowner(ols->st_stateowner)->oo_flags
>  						& NFS4_OO_CONFIRMED))
> -			return nfserr_bad_stateid;
> -		return nfs_ok;
> +			status = nfserr_bad_stateid;
> +		else
> +			status = nfs_ok;
> +		break;

Not quite as urgent as for the refcounting, but I think moving more
of these switches on the type into proper methods would improve the
stateid code a lot.


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

* Re: [PATCH 50/70] NFSd: Use the session->se_client  in lookup_clientid()
  2014-04-18 18:44                                                                                                   ` [PATCH 50/70] NFSd: Use the session->se_client in lookup_clientid() Trond Myklebust
  2014-04-18 18:44                                                                                                     ` [PATCH 51/70] NFSd: Convert nfsd4_process_open1() to work with lookup_clientid() Trond Myklebust
@ 2014-04-19 14:56                                                                                                     ` Christoph Hellwig
  2014-05-07 20:18                                                                                                     ` Bruce Fields
  2 siblings, 0 replies; 118+ messages in thread
From: Christoph Hellwig @ 2014-04-19 14:56 UTC (permalink / raw)
  To: Trond Myklebust; +Cc: Bruce Fields, linux-nfs

> -static __be32 lookup_clientid(clientid_t *clid, bool session, struct nfsd_net *nn, struct nfs4_client **clp)
> +static __be32 lookup_clientid(clientid_t *clid, struct nfsd4_session *session, struct nfsd_net *nn, struct nfs4_client **clp)

Please break lines after 80 characters.


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

* Re: [PATCH 00/70] NFSd lock scalability patches
  2014-04-18 18:43 [PATCH 00/70] NFSd lock scalability patches Trond Myklebust
  2014-04-18 18:43 ` [PATCH 01/70] NFSd: Ensure we clear the cstate->slot in nfsd4_proc_compound Trond Myklebust
@ 2014-04-19 15:04 ` Christoph Hellwig
  2014-04-19 20:58 ` Bruce Fields
  2014-04-21 15:01 ` Christoph Hellwig
  3 siblings, 0 replies; 118+ messages in thread
From: Christoph Hellwig @ 2014-04-19 15:04 UTC (permalink / raw)
  To: Trond Myklebust; +Cc: Bruce Fields, linux-nfs

So after this series there are 5 callers of nfs4_lock_state() left,
and I can't see any coherent scheme of what it still protects, but this:

--- snip ---
/* Currently used for almost all code touching nfsv4 state: */
static DEFINE_MUTEX(client_mutex);
--- snip ---

is clearly wrong. I'd suggest you go all the way and remove it entirely.


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

* Re: [PATCH 34/70] NFSd: Fix atomicity of delegation counter
  2014-04-18 18:44                                                                   ` [PATCH 34/70] NFSd: Fix atomicity of delegation counter Trond Myklebust
  2014-04-18 18:44                                                                     ` [PATCH 35/70] NFSd: Slight cleanup of find_stateid() Trond Myklebust
@ 2014-04-19 15:51                                                                     ` Christoph Hellwig
  2014-04-21 15:58                                                                       ` Trond Myklebust
  1 sibling, 1 reply; 118+ messages in thread
From: Christoph Hellwig @ 2014-04-19 15:51 UTC (permalink / raw)
  To: Trond Myklebust; +Cc: Bruce Fields, linux-nfs

On Fri, Apr 18, 2014 at 02:44:28PM -0400, Trond Myklebust wrote:
> Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>

I think at this point nfs4_lock_state() is always held so it's not
quite a fix yet.  If that's not true the patch should be moved earlier
in the series.

> -static int num_delegations;
> +static atomic_long_t num_delegations;

Why the switch from a int to an (atomic) long here?  If that was
intentional it should be documented in the patch description.

> -	if (num_delegations > max_delegations)
> -		return NULL;
> +	atomic_long_inc(&num_delegations);
> +	smp_mb__after_atomic_inc();
> +	if (atomic_long_read(&num_delegations) > max_delegations)
> +		goto out_dec;

Just use atomic_long_inc_return here.

> +out_dec:
> +	atomic_long_dec(&num_delegations);
> +	smp_mb__after_atomic_dec();

I can't see any point for having these barriers.


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

* Re: [PATCH 08/70] nfsd4: use state_lock for delegation hashing
  2014-04-18 18:44               ` [PATCH 08/70] nfsd4: use state_lock for delegation hashing Trond Myklebust
  2014-04-18 18:44                 ` [PATCH 09/70] NFSd: Mark nfs4_free_lockowner and nfs4_free_openowner as static functions Trond Myklebust
@ 2014-04-19 15:56                 ` Christoph Hellwig
  1 sibling, 0 replies; 118+ messages in thread
From: Christoph Hellwig @ 2014-04-19 15:56 UTC (permalink / raw)
  To: Trond Myklebust; +Cc: Bruce Fields, linux-nfs

> +static void
> +hash_delegation_locked(struct nfs4_delegation *dp, struct nfs4_file *fp)
> +{

This series adds a lot of _locked function.  I would really like to
see an assert_spin_locked or equivalent in each of them, to a) prove
we got the locking right, and to b) document the needed lock for new
code using them.


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

* Re: [PATCH 00/70] NFSd lock scalability patches
  2014-04-18 18:43 [PATCH 00/70] NFSd lock scalability patches Trond Myklebust
  2014-04-18 18:43 ` [PATCH 01/70] NFSd: Ensure we clear the cstate->slot in nfsd4_proc_compound Trond Myklebust
  2014-04-19 15:04 ` [PATCH 00/70] NFSd lock scalability patches Christoph Hellwig
@ 2014-04-19 20:58 ` Bruce Fields
  2014-05-07 20:29   ` Bruce Fields
  2014-04-21 15:01 ` Christoph Hellwig
  3 siblings, 1 reply; 118+ messages in thread
From: Bruce Fields @ 2014-04-19 20:58 UTC (permalink / raw)
  To: Trond Myklebust; +Cc: linux-nfs

On Fri, Apr 18, 2014 at 02:43:54PM -0400, Trond Myklebust wrote:
> In accordance with the traditional Good Friday theme of "suffering", here
> is the first draft of the NFSd lock scalability patches for your perusal.
> I've only done light testing so far, but since there is a total of 70
> patches to review, I figured you might want to start sooner rather than
> waiting for the QA folks to finish testing.

Thanks!

Yeah, this sounds like too much suffering for vacation time, but I'll at
least make a stab at merging the initial bug fixes next week, then try
to plow through these (or any revised version (thanks, Christoph, for
help reviewing!)) after I get back in a couple more weeks.

--b.

> 
> During the process, I did notice a bug or two in the existing NFSd code,
> and so the first 3 patches are bugfixes that you may want to apply
> irrespectively.
> 
> In general, what I've tried to do is add reference counting wherever
> there is a need to carry structures around outside locks, and to
> ensure that we make structures invisible to lookups before we attempt
> to free them.
> 
> There are still a few optimisations that might be worth considering in
> order to reduce the frequency of global locks that are taken. Suggestions
> include:
> 1) Caching the nfs4_client in the struct nfsd4_compound_state
> 2) Caching the current/save_stateid as references to the actual nfs4_stid in the struct nfsd4_compound_state
> 3) Converting the stateid/sessionid/clientid global table lookups to use RCU.
> 4) Converting the file_hashtbl lookups to use RCU
> 
> Cheers
>   Trond
> 
> Benny Halevy (4):
>   nfsd4: rename recall_lock to state_lock
>   nfsd4: use cl_lock to synchronize all stateid idr calls
>   nfsd4: hash deleg stateid only on successful nfs4_set_delegation
>   nfsd4: use state_lock for delegation hashing
> 
> Trond Myklebust (66):
>   NFSd: Ensure we clear the cstate->slot in nfsd4_proc_compound
>   NFSd: Move default initialisers from create_client() to alloc_client()
>   NFSd: call rpc_destroy_wait_queue() from free_client()
>   NFSd: Remove 'inline' designation for free_client()
>   NFSd: Mark nfs4_free_lockowner and nfs4_free_openowner as static
>     functions
>   NFSd: Avoid taking state_lock while holding inode lock in
>     nfsd_break_one_deleg
>   NFSd: Ensure delegation setup is safe w.r.t. break_lease()
>   NFSd: Add fine grained protection for the nfs4_file->fi_stateids list
>   NFSd: Clean up nfs4_preprocess_stateid_op
>   NFSd: Add a mutex to protect the NFSv4.0 open owner replay cache
>   NFSd: Add locking to the nfs4_file->fi_fds[] array
>   NFSd: Protect the nfs4_file delegation fields using the fi_lock
>   NFSd: Lock owners are not per open stateid
>   NFSd: Clean up helper __release_lock_stateid
>   NFSd: Allow lockowners to hold several stateids
>   NFSd: NFSv4 lock-owners are not associated to a specific file
>   NFSd: Get rid of the lockowner_ino_hashtbl
>   NFSd: Cleanup nfs4svc_encode_compoundres
>   NFSd: Don't get a session reference without a client reference
>   NFSd: Move the delegation reference counter into the struct nfs4_stid
>   NFSd: Simplify stateid management
>   NFSd: Fix delegation revocation
>   NFSd: Don't let the laundromat reap clients that are referenced
>   NFSd: Add reference counting to the lock and open stateids
>   NFSd: Add a struct nfs4_file field to struct nfs4_stid
>   NFSd: Replace delegation->dl_file with the dl_stid.sc_file
>   NFSd: Replace nfs4_ol_stateid->st_file with the st_stid.sc_file
>   NFSd: Ensure stateids remain unique until they are freed
>   NFSd: Ensure atomicity of stateid destruction and idr tree removal
>   NFSd: Fix atomicity of delegation counter
>   NFSd: Slight cleanup of find_stateid()
>   NFSd: Add reference counting to find_stateid
>   NFSd: nfs4_preprocess_seqid_op should only set *stpp on success
>   NFSd: Add reference counting to lock stateids
>   NFSd: nfsd4_locku() must reference the lock stateid
>   NFSd: Ensure that nfs4_open_delegation() references the delegation
>     stateid
>   NFSd: nfsd4_process_open2() must reference the delegation stateid
>   NFSd: nfsd4_process_open2() must reference the open stateid
>   NFSd: Prepare nfsd4_close() for open stateid referencing
>   NFSd: nfsd4_open_confirm() must reference the open stateid
>   NFSd: Add reference counting to nfs4_preprocess_confirmed_seqid_op
>   NFSd: Migrate the stateid reference into nfs4_preprocess_seqid_op
>   NFSd: Migrate the stateid reference into nfs4_lookup_stateid()
>   NFSd: Migrate the stateid reference into nfs4_find_stateid_by_type()
>   NFSd: Cleanup - Let nfsd4_lookup_stateid() take a cstate argument
>   NFSd: Use the session->se_client  in lookup_clientid()
>   NFSd: Convert nfsd4_process_open1() to work with lookup_clientid()
>   NFSd: Convert nfs4_check_open_reclaim() to work with lookup_clientid()
>   NFSd: Ensure struct nfs4_client is unhashed before we try to destroy
>     it
>   NFSd: Ensure that the laundromat unhashes the client before releasing
>     locks
>   NFSd: Don't require client_lock in free_client
>   NFSd: Move create_client() call outside the lock
>   NFSd: Protect unconfirmed client creation using client_lock
>   NFSd: Protect session creation and client confirm using client_lock
>   NFSd: Protect nfsd4_destroy_clientid using client_lock
>   NFSd: Ensure lookup_clientid() takes client_lock
>   NFSd: Remove nfs4_lock_state(): nfs4_preprocess_stateid_op()
>   NFSd: Remove nfs4_lock_state(): nfsd4_test_stateid/nfsd4_free_stateid
>   NFSd: Remove nfs4_lock_state(): nfsd4_release_lockowner
>   NFSd: Remove nfs4_lock_state(): nfsd4_lock/locku/lockt()
>   NFSd: Remove nfs4_lock_state(): nfsd4_open_downgrade + nfsd4_close
>   NFSd: Remove nfs4_lock_state(): nfsd4_delegreturn()
>   NFSd: Remove nfs4_lock_state(): nfsd4_open and nfsd4_open_confirm
>   NFSd: Remove nfs4_lock_state(): exchange_id, create/destroy_session()
>   NFSd: Remove nfs4_lock_state(): setclientid, setclientid_confirm,
>     renew
>   NFSd: Remove nfs4_lock_state(): reclaim_complete()
> 
>  fs/nfsd/netns.h        |    4 -
>  fs/nfsd/nfs4callback.c |   18 +-
>  fs/nfsd/nfs4proc.c     |   28 +-
>  fs/nfsd/nfs4state.c    | 1239 ++++++++++++++++++++++++++++++------------------
>  fs/nfsd/nfs4xdr.c      |   15 +-
>  fs/nfsd/state.h        |   46 +-
>  fs/nfsd/xdr4.h         |   21 +-
>  7 files changed, 819 insertions(+), 552 deletions(-)
> 
> -- 
> 1.9.0
> 

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

* Re: [PATCH 15/70] NFSd: Add locking to the nfs4_file->fi_fds[] array
  2014-04-19 14:35                               ` [PATCH 15/70] NFSd: Add locking to the nfs4_file->fi_fds[] array Christoph Hellwig
@ 2014-04-21 13:01                                 ` Trond Myklebust
  2014-04-21 13:14                                   ` Christoph Hellwig
  0 siblings, 1 reply; 118+ messages in thread
From: Trond Myklebust @ 2014-04-21 13:01 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: Bruce Fields, linux-nfs

Hi Christoph,

Thanks for reviewing these!

On Sat, 2014-04-19 at 07:35 -0700, Christoph Hellwig wrote:
> > +/* XXX: for first cut may fall back on returning file that doesn't work
> > + * at all? */
> 
> I think moving this code around might be a good opportunity to remove
> this confusing comment.

Will do.

> > +static struct file *find_writeable_file(struct nfs4_file *f)
> > +{
> > +	struct file *ret;
> > +
> > +	spin_lock(&f->fi_lock);
> > +	ret = __nfs4_get_fd(f, O_WRONLY);
> > +	if (!ret)
> > +		ret = __nfs4_get_fd(f, O_RDWR);
> > +	spin_unlock(&f->fi_lock);
> > +	return ret;
> > +}
> > +
> > +static struct file *find_readable_file(struct nfs4_file *f)
> > +{
> > +	struct file *ret;
> > +
> > +	spin_lock(&f->fi_lock);
> > +	ret = __nfs4_get_fd(f, O_RDONLY);
> > +	if (!ret)
> > +		ret = __nfs4_get_fd(f, O_RDWR);
> > +	spin_unlock(&f->fi_lock);
> > +	return ret;
> 
> Seems like these two functions could be easily consolidated by passing
> a single flags argument.

Yes, but we'd have to invent a new set of flags for just this function
and so I'm not sure that the end result would be more readable.
We can't reuse O_RDONLY/O_WRONLY/O_RDWR since they can't be bitwise ORed
to produce the 'read or read/write', 'write or read/write' combinations
that we need.

Cheers
  Trond

-- 
Trond Myklebust
Linux NFS client maintainer, PrimaryData
trond.myklebust@primarydata.com



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

* Re: [PATCH 21/70] NFSd: Get rid of the lockowner_ino_hashtbl
  2014-04-19 14:38                                           ` [PATCH 21/70] NFSd: Get rid of the lockowner_ino_hashtbl Christoph Hellwig
@ 2014-04-21 13:08                                             ` Trond Myklebust
  0 siblings, 0 replies; 118+ messages in thread
From: Trond Myklebust @ 2014-04-21 13:08 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: Bruce Fields, linux-nfs

On Sat, 2014-04-19 at 07:38 -0700, Christoph Hellwig wrote:
> On Fri, Apr 18, 2014 at 02:44:15PM -0400, Trond Myklebust wrote:
> > It is no longer used.
> 
> I think this should be folded into the previous patch, which is the
> reason why it is unused now.
> 

Ack and done...
-- 
Trond Myklebust
Linux NFS client maintainer, PrimaryData
trond.myklebust@primarydata.com



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

* Re: [PATCH 30/70] NFSd: Replace delegation->dl_file with the dl_stid.sc_file
  2014-04-19 14:40                                                             ` [PATCH 30/70] NFSd: Replace delegation->dl_file with the dl_stid.sc_file Christoph Hellwig
@ 2014-04-21 13:13                                                               ` Trond Myklebust
  0 siblings, 0 replies; 118+ messages in thread
From: Trond Myklebust @ 2014-04-21 13:13 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: Bruce Fields, linux-nfs

On Sat, 2014-04-19 at 07:40 -0700, Christoph Hellwig wrote:
> Instead of adding a mostly unused file field to the stid in the previous
> patch and starting to use it here I'd recommend merging the two patches.
> 
Ack and done.

-- 
Trond Myklebust
Linux NFS client maintainer, PrimaryData
trond.myklebust@primarydata.com



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

* Re: [PATCH 15/70] NFSd: Add locking to the nfs4_file->fi_fds[] array
  2014-04-21 13:01                                 ` Trond Myklebust
@ 2014-04-21 13:14                                   ` Christoph Hellwig
  2014-04-21 13:16                                     ` Christoph Hellwig
  0 siblings, 1 reply; 118+ messages in thread
From: Christoph Hellwig @ 2014-04-21 13:14 UTC (permalink / raw)
  To: Trond Myklebust; +Cc: Christoph Hellwig, Bruce Fields, linux-nfs

On Mon, Apr 21, 2014 at 09:01:37AM -0400, Trond Myklebust wrote:
> > > +static struct file *find_readable_file(struct nfs4_file *f)
> > > +{
> > > +	struct file *ret;
> > > +
> > > +	spin_lock(&f->fi_lock);
> > > +	ret = __nfs4_get_fd(f, O_RDONLY);
> > > +	if (!ret)
> > > +		ret = __nfs4_get_fd(f, O_RDWR);
> > > +	spin_unlock(&f->fi_lock);
> > > +	return ret;
> > 
> > Seems like these two functions could be easily consolidated by passing
> > a single flags argument.
> 
> Yes, but we'd have to invent a new set of flags for just this function
> and so I'm not sure that the end result would be more readable.
> We can't reuse O_RDONLY/O_WRONLY/O_RDWR since they can't be bitwise ORed
> to produce the 'read or read/write', 'write or read/write' combinations
> that we need.

One option would be:

static struct file *__nfs4_get_fd(struct nfs4_file *f, int oflag,
		int type)
{
	if ((oflag & type) && f->fi_fds[type])
		return get_file(f->fi_fds[type]);
	return NULL;
}

struct file *nfsd4_find_file(struct nfs4_file *f, unsigned int oflag)
{
	struct file *ret;

	BUG_ON(oflag & ~(O_RDONLY|O_WRONLY|O_RDWR);

	spin_lock(&f->fi_lock);
	ret = __nfs4_get_fd(f, oflag, O_RDONLY);
	if (!ret) {
		ret = __nfs4_get_fd(f, oflag, O_WRONLY);
		if (!ret) 
			ret = __nfs4_get_fd(f, oflag, O_RDWR);
	}
	spin_unlock(&f->fi_lock);
	return ret;
}

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

* Re: [PATCH 15/70] NFSd: Add locking to the nfs4_file->fi_fds[] array
  2014-04-21 13:14                                   ` Christoph Hellwig
@ 2014-04-21 13:16                                     ` Christoph Hellwig
  0 siblings, 0 replies; 118+ messages in thread
From: Christoph Hellwig @ 2014-04-21 13:16 UTC (permalink / raw)
  To: Trond Myklebust; +Cc: Christoph Hellwig, Bruce Fields, linux-nfs

On Mon, Apr 21, 2014 at 06:14:12AM -0700, Christoph Hellwig wrote:
> One option would be:

Doesn't work because O_RDONLY is defined as 0.  But if we use
FMODE_READ and FMODE_WRITE as flag it should work.


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

* Re: [PATCH 35/70] NFSd: Slight cleanup of find_stateid()
  2014-04-19 14:41                                                                       ` [PATCH 35/70] NFSd: Slight cleanup of find_stateid() Christoph Hellwig
@ 2014-04-21 13:31                                                                         ` Trond Myklebust
  0 siblings, 0 replies; 118+ messages in thread
From: Trond Myklebust @ 2014-04-21 13:31 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: Bruce Fields, linux-nfs

On Sat, 2014-04-19 at 07:41 -0700, Christoph Hellwig wrote:
> > +static struct nfs4_stid *find_stateid_locked(struct nfs4_client *cl, stateid_t *t)
> >  {
> >  	struct nfs4_stid *ret;
> >  
> > -	spin_lock(&cl->cl_lock);
> >  	ret = idr_find(&cl->cl_stateids, t->si_opaque.so_id);
> > -	spin_unlock(&cl->cl_lock);
> >  	if (!ret || !ret->sc_type)
> >  		return NULL;
> 
> Just curious, how can !ret->sc_type happen?
> 

At least for open and lock stateids, the ret->sc_type field isn't
initialised until nfsd4_process_open2() and alloc_init_lock_stateid() so
there is a small window where they are visible to the idr tree while not
being fully initialised.

-- 
Trond Myklebust
Linux NFS client maintainer, PrimaryData
trond.myklebust@primarydata.com



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

* Re: [PATCH 00/70] NFSd lock scalability patches
  2014-04-18 18:43 [PATCH 00/70] NFSd lock scalability patches Trond Myklebust
                   ` (2 preceding siblings ...)
  2014-04-19 20:58 ` Bruce Fields
@ 2014-04-21 15:01 ` Christoph Hellwig
  3 siblings, 0 replies; 118+ messages in thread
From: Christoph Hellwig @ 2014-04-21 15:01 UTC (permalink / raw)
  To: Trond Myklebust; +Cc: Bruce Fields, linux-nfs

I think the series introduces some find vs alloc races where a function
first tries to find an existing structure in a lookup structure, then
allocates a new one, but doesn't check for another allocation that could
have happened in the meantime.

 - lookup_or_create_lock_state for lock stateids
 - I can't find any protection for the creation/addition of files
   and open stateids in the whole open machinery
   (nfsd4_open, nfsd4_process_open1 and nfsd4_process_open2), but
   I also generally have trouble following that code.
 - similarly I can't find much of a protection against this sort of
   race for the various state owners.

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

* Re: [PATCH 36/70] NFSd: Add reference counting to find_stateid
  2014-04-19 14:50                                                                         ` [PATCH 36/70] NFSd: Add reference counting to find_stateid Christoph Hellwig
@ 2014-04-21 15:37                                                                           ` Trond Myklebust
  0 siblings, 0 replies; 118+ messages in thread
From: Trond Myklebust @ 2014-04-21 15:37 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: Bruce Fields, linux-nfs

On Sat, 2014-04-19 at 07:50 -0700, Christoph Hellwig wrote:
> > +static void nfs4_put_stateid(struct nfs4_stid *s)
> > +{
> > +	if (s == NULL)
> > +		return;
> > +	switch (s->sc_type) {
> > +	case NFS4_OPEN_STID:
> > +	case NFS4_LOCK_STID:
> > +	case NFS4_CLOSED_STID:
> > +		put_generic_stateid(openlockstateid(s));
> > +		break;
> > +	case NFS4_DELEG_STID:
> > +	case NFS4_REVOKED_DELEG_STID:
> > +	case NFS4_CLOSED_DELEG_STID:
> > +		nfs4_put_delegation(delegstateid(s));
> > +	}
> > +}
> 
> I really don't like the way the inheritance for the stateids works,
> a pure put operation shouldn't need this.  I think all this can be
> fixed by adding a ->free function pointer to struct nfs4_stid.  At this
> point the braindamage of passing a kmem_cache pointer to various
> function can be removed (similar to how nfs4_alloc_stid should be
> replaced with a nfs4_init_stid that takes an already allocated stid),
> and nothing in the normal refcounting path should need these switches.

Ack. I've added a free() pointer to nfs4_stid.

> > @@ -3804,26 +3823,33 @@ static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid)
> >  		return nfserr_bad_stateid;
> >  	status = check_stateid_generation(stateid, &s->sc_stateid, 1);
> >  	if (status)
> > -		return status;
> > +		goto out_put_stid;
> >  	switch (s->sc_type) {
> >  	case NFS4_DELEG_STID:
> > -		return nfs_ok;
> > +		status = nfs_ok;
> > +		break;
> >  	case NFS4_REVOKED_DELEG_STID:
> > -		return nfserr_deleg_revoked;
> > +		status = nfserr_deleg_revoked;
> > +		break;
> >  	case NFS4_OPEN_STID:
> >  	case NFS4_LOCK_STID:
> >  		ols = openlockstateid(s);
> >  		if (ols->st_stateowner->so_is_open_owner
> >  	    			&& !(openowner(ols->st_stateowner)->oo_flags
> >  						& NFS4_OO_CONFIRMED))
> > -			return nfserr_bad_stateid;
> > -		return nfs_ok;
> > +			status = nfserr_bad_stateid;
> > +		else
> > +			status = nfs_ok;
> > +		break;
> 
> Not quite as urgent as for the refcounting, but I think moving more
> of these switches on the type into proper methods would improve the
> stateid code a lot.

Agreed, but I'm leaving that as an exercise for the reader (at least as
far as this patch series is concerned).

-- 
Trond Myklebust
Linux NFS client maintainer, PrimaryData
trond.myklebust@primarydata.com



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

* Re: [PATCH 34/70] NFSd: Fix atomicity of delegation counter
  2014-04-19 15:51                                                                     ` [PATCH 34/70] NFSd: Fix atomicity of delegation counter Christoph Hellwig
@ 2014-04-21 15:58                                                                       ` Trond Myklebust
  0 siblings, 0 replies; 118+ messages in thread
From: Trond Myklebust @ 2014-04-21 15:58 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: Bruce Fields, linux-nfs

On Sat, 2014-04-19 at 08:51 -0700, Christoph Hellwig wrote:
> On Fri, Apr 18, 2014 at 02:44:28PM -0400, Trond Myklebust wrote:
> > Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
> 
> I think at this point nfs4_lock_state() is always held so it's not
> quite a fix yet.  If that's not true the patch should be moved earlier
> in the series.

Fair enough...

> 
> > -static int num_delegations;
> > +static atomic_long_t num_delegations;
> 
> Why the switch from a int to an (atomic) long here?  If that was
> intentional it should be documented in the patch description.

It is intentional. The max_delegations that we're comparing to below is
of type 'unsigned long'.

> 
> > -	if (num_delegations > max_delegations)
> > -		return NULL;
> > +	atomic_long_inc(&num_delegations);
> > +	smp_mb__after_atomic_inc();
> > +	if (atomic_long_read(&num_delegations) > max_delegations)
> > +		goto out_dec;
> 
> Just use atomic_long_inc_return here.
> 
> > +out_dec:
> > +	atomic_long_dec(&num_delegations);
> > +	smp_mb__after_atomic_dec();
> 
> I can't see any point for having these barriers.

Agreed. I can't remember why I thought they were necessary.

-- 
Trond Myklebust
Linux NFS client maintainer, PrimaryData
trond.myklebust@primarydata.com



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

* Re: [PATCH 60/70] NFSd: Ensure lookup_clientid() takes client_lock
  2014-04-18 18:44                                                                                                                       ` [PATCH 60/70] NFSd: Ensure lookup_clientid() takes client_lock Trond Myklebust
  2014-04-18 18:44                                                                                                                         ` [PATCH 61/70] NFSd: Remove nfs4_lock_state(): nfs4_preprocess_stateid_op() Trond Myklebust
@ 2014-05-05  8:53                                                                                                                         ` Christoph Hellwig
  1 sibling, 0 replies; 118+ messages in thread
From: Christoph Hellwig @ 2014-05-05  8:53 UTC (permalink / raw)
  To: Trond Myklebust; +Cc: Bruce Fields, linux-nfs

>  static __be32 nfsd4_get_session_locked(struct nfsd4_session *ses)
>  {
>  	__be32 status;
> @@ -3614,18 +3623,27 @@ static __be32 lookup_clientid(clientid_t *clid, struct nfsd4_session *session, s
>  {
>  	struct nfs4_client *found;
>  
> +	spin_lock(&nn->client_lock);
>  	if (session != NULL) {
>  		found = session->se_client;
>  		if (!same_clid(&found->cl_clientid, clid))
> -			return nfserr_stale_clientid;
> +			goto out_stale;

Do we really need the lock for the sessions case?  I don't tink
se_client can change under us.

Btw, I wonder if it makes sense to split the current lookup_clientid
into two helpers for the sessions vs non-sessions case as all but one
caller already have conditionals for 4.0 vs later anyway, so something
like:

static struct nfs4_client *client_from_session(struct nfsd4_session *session,
		clientid_t *clid)
{
	if (!same_clid(&session->se_client->cl_clientid, clid))
		return NULL;
	return session->se_client;
}

static __be32 lookup_40_client(clientid_t *clid, struct nfsd_net *nn,
	struct nfs4_client **clp)
{
	...
}


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

* Re: [PATCH 30/70] NFSd: Replace delegation->dl_file with the dl_stid.sc_file
  2014-04-18 18:44                                                           ` [PATCH 30/70] NFSd: Replace delegation->dl_file with the dl_stid.sc_file Trond Myklebust
  2014-04-18 18:44                                                             ` [PATCH 31/70] NFSd: Replace nfs4_ol_stateid->st_file with the st_stid.sc_file Trond Myklebust
  2014-04-19 14:40                                                             ` [PATCH 30/70] NFSd: Replace delegation->dl_file with the dl_stid.sc_file Christoph Hellwig
@ 2014-05-05  9:01                                                             ` Christoph Hellwig
  2 siblings, 0 replies; 118+ messages in thread
From: Christoph Hellwig @ 2014-05-05  9:01 UTC (permalink / raw)
  To: Trond Myklebust; +Cc: Bruce Fields, linux-nfs

Btw, I think it would also be useful to move the dl_perfile and
st_perfile lists into nfs4_stid, and track the file associatation in
common code.


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

* Re: [PATCH 01/70] NFSd: Ensure we clear the cstate->slot in nfsd4_proc_compound
  2014-04-18 18:43 ` [PATCH 01/70] NFSd: Ensure we clear the cstate->slot in nfsd4_proc_compound Trond Myklebust
  2014-04-18 18:43   ` [PATCH 02/70] NFSd: Move default initialisers from create_client() to alloc_client() Trond Myklebust
@ 2014-05-06 15:32   ` Bruce Fields
  2014-05-06 16:36     ` Bruce Fields
  1 sibling, 1 reply; 118+ messages in thread
From: Bruce Fields @ 2014-05-06 15:32 UTC (permalink / raw)
  To: Trond Myklebust; +Cc: linux-nfs

On Fri, Apr 18, 2014 at 02:43:55PM -0400, Trond Myklebust wrote:
> Otherwise, we may end up triggering all those nfsd4_has_session()
> tests.

Surely we'd have seen failures if this was actually not zeroed....

Right, I think the

	memset(rqstp->rq_argp, 0, procp->pc_argsize);

in svc_process_common() handles this.

But apparently the lack of an explicit assignment was confusing.  So
maybe it's better to have one.

(Or if not, to get rid of the other unnecessary assignments.)

--b.

> 
> Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
> ---
>  fs/nfsd/nfs4proc.c | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
> index d543222babf3..8eabbfb25441 100644
> --- a/fs/nfsd/nfs4proc.c
> +++ b/fs/nfsd/nfs4proc.c
> @@ -1293,6 +1293,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
>  	cstate->minorversion = args->minorversion;
>  	cstate->replay_owner = NULL;
>  	cstate->session = NULL;
> +	cstate->slot = NULL;
>  	fh_init(current_fh, NFS4_FHSIZE);
>  	fh_init(save_fh, NFS4_FHSIZE);
>  	/*
> -- 
> 1.9.0
> 

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

* Re: [PATCH 01/70] NFSd: Ensure we clear the cstate->slot in nfsd4_proc_compound
  2014-05-06 15:32   ` [PATCH 01/70] NFSd: Ensure we clear the cstate->slot in nfsd4_proc_compound Bruce Fields
@ 2014-05-06 16:36     ` Bruce Fields
  0 siblings, 0 replies; 118+ messages in thread
From: Bruce Fields @ 2014-05-06 16:36 UTC (permalink / raw)
  To: Trond Myklebust; +Cc: linux-nfs

On Tue, May 06, 2014 at 11:32:00AM -0400, Bruce Fields wrote:
> On Fri, Apr 18, 2014 at 02:43:55PM -0400, Trond Myklebust wrote:
> > Otherwise, we may end up triggering all those nfsd4_has_session()
> > tests.
> 
> Surely we'd have seen failures if this was actually not zeroed....
> 
> Right, I think the
> 
> 	memset(rqstp->rq_argp, 0, procp->pc_argsize);
> 
> in svc_process_common() handles this.
> 
> But apparently the lack of an explicit assignment was confusing.  So
> maybe it's better to have one.
> 
> (Or if not, to get rid of the other unnecessary assignments.)

(Dropping, assuming you'll resend with updated changelog if you feel
strongly about it....).

> 
> --b.
> 
> > 
> > Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
> > ---
> >  fs/nfsd/nfs4proc.c | 1 +
> >  1 file changed, 1 insertion(+)
> > 
> > diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
> > index d543222babf3..8eabbfb25441 100644
> > --- a/fs/nfsd/nfs4proc.c
> > +++ b/fs/nfsd/nfs4proc.c
> > @@ -1293,6 +1293,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
> >  	cstate->minorversion = args->minorversion;
> >  	cstate->replay_owner = NULL;
> >  	cstate->session = NULL;
> > +	cstate->slot = NULL;
> >  	fh_init(current_fh, NFS4_FHSIZE);
> >  	fh_init(save_fh, NFS4_FHSIZE);
> >  	/*
> > -- 
> > 1.9.0
> > 

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

* Re: [PATCH 02/70] NFSd: Move default initialisers from create_client() to alloc_client()
  2014-04-18 18:43   ` [PATCH 02/70] NFSd: Move default initialisers from create_client() to alloc_client() Trond Myklebust
  2014-04-18 18:43     ` [PATCH 03/70] NFSd: call rpc_destroy_wait_queue() from free_client() Trond Myklebust
@ 2014-05-06 16:37     ` Bruce Fields
  1 sibling, 0 replies; 118+ messages in thread
From: Bruce Fields @ 2014-05-06 16:37 UTC (permalink / raw)
  To: Trond Myklebust; +Cc: linux-nfs

On Fri, Apr 18, 2014 at 02:43:56PM -0400, Trond Myklebust wrote:
> Aside from making it clearer what is non-trivial in create_client(), it
> also fixes a bug whereby we can call free_client() before idr_init()
> has been called.

Thanks, applying for 3.15 and stable.

--b.

> 
> Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
> ---
>  fs/nfsd/nfs4state.c | 24 ++++++++++++------------
>  1 file changed, 12 insertions(+), 12 deletions(-)
> 
> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> index 3ba65979a3cd..230d21cb1717 100644
> --- a/fs/nfsd/nfs4state.c
> +++ b/fs/nfsd/nfs4state.c
> @@ -1078,6 +1078,18 @@ static struct nfs4_client *alloc_client(struct xdr_netobj name)
>  		return NULL;
>  	}
>  	clp->cl_name.len = name.len;
> +	INIT_LIST_HEAD(&clp->cl_sessions);
> +	idr_init(&clp->cl_stateids);
> +	atomic_set(&clp->cl_refcount, 0);
> +	clp->cl_cb_state = NFSD4_CB_UNKNOWN;
> +	INIT_LIST_HEAD(&clp->cl_idhash);
> +	INIT_LIST_HEAD(&clp->cl_openowners);
> +	INIT_LIST_HEAD(&clp->cl_delegations);
> +	INIT_LIST_HEAD(&clp->cl_lru);
> +	INIT_LIST_HEAD(&clp->cl_callbacks);
> +	INIT_LIST_HEAD(&clp->cl_revoked);
> +	spin_lock_init(&clp->cl_lock);
> +	rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table");
>  	return clp;
>  }
>  
> @@ -1347,7 +1359,6 @@ static struct nfs4_client *create_client(struct xdr_netobj name,
>  	if (clp == NULL)
>  		return NULL;
>  
> -	INIT_LIST_HEAD(&clp->cl_sessions);
>  	ret = copy_cred(&clp->cl_cred, &rqstp->rq_cred);
>  	if (ret) {
>  		spin_lock(&nn->client_lock);
> @@ -1355,20 +1366,9 @@ static struct nfs4_client *create_client(struct xdr_netobj name,
>  		spin_unlock(&nn->client_lock);
>  		return NULL;
>  	}
> -	idr_init(&clp->cl_stateids);
> -	atomic_set(&clp->cl_refcount, 0);
> -	clp->cl_cb_state = NFSD4_CB_UNKNOWN;
> -	INIT_LIST_HEAD(&clp->cl_idhash);
> -	INIT_LIST_HEAD(&clp->cl_openowners);
> -	INIT_LIST_HEAD(&clp->cl_delegations);
> -	INIT_LIST_HEAD(&clp->cl_lru);
> -	INIT_LIST_HEAD(&clp->cl_callbacks);
> -	INIT_LIST_HEAD(&clp->cl_revoked);
> -	spin_lock_init(&clp->cl_lock);
>  	nfsd4_init_callback(&clp->cl_cb_null);
>  	clp->cl_time = get_seconds();
>  	clear_bit(0, &clp->cl_cb_slot_busy);
> -	rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table");
>  	copy_verf(clp, verf);
>  	rpc_copy_addr((struct sockaddr *) &clp->cl_addr, sa);
>  	gen_confirm(clp);
> -- 
> 1.9.0
> 

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

* Re: [PATCH 03/70] NFSd: call rpc_destroy_wait_queue() from free_client()
  2014-04-18 18:43     ` [PATCH 03/70] NFSd: call rpc_destroy_wait_queue() from free_client() Trond Myklebust
  2014-04-18 18:43       ` [PATCH 04/70] NFSd: Remove 'inline' designation for free_client() Trond Myklebust
@ 2014-05-06 16:37       ` Bruce Fields
  1 sibling, 0 replies; 118+ messages in thread
From: Bruce Fields @ 2014-05-06 16:37 UTC (permalink / raw)
  To: Trond Myklebust; +Cc: linux-nfs

On Fri, Apr 18, 2014 at 02:43:57PM -0400, Trond Myklebust wrote:
> Mainly to ensure that we don't leave any hanging timers.

Thanks, applying for 3.15 and stable.

--b.

> 
> Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
> ---
>  fs/nfsd/nfs4state.c | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> index 230d21cb1717..32b699bebb9c 100644
> --- a/fs/nfsd/nfs4state.c
> +++ b/fs/nfsd/nfs4state.c
> @@ -1107,6 +1107,7 @@ free_client(struct nfs4_client *clp)
>  		WARN_ON_ONCE(atomic_read(&ses->se_ref));
>  		free_session(ses);
>  	}
> +	rpc_destroy_wait_queue(&clp->cl_cb_waitq);
>  	free_svc_cred(&clp->cl_cred);
>  	kfree(clp->cl_name.data);
>  	idr_destroy(&clp->cl_stateids);
> -- 
> 1.9.0
> 

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

* Re: [PATCH 04/70] NFSd: Remove 'inline' designation for free_client()
  2014-04-18 18:43       ` [PATCH 04/70] NFSd: Remove 'inline' designation for free_client() Trond Myklebust
  2014-04-18 18:43         ` [PATCH 05/70] nfsd4: rename recall_lock to state_lock Trond Myklebust
@ 2014-05-06 16:40         ` Bruce Fields
  1 sibling, 0 replies; 118+ messages in thread
From: Bruce Fields @ 2014-05-06 16:40 UTC (permalink / raw)
  To: Trond Myklebust; +Cc: linux-nfs

On Fri, Apr 18, 2014 at 02:43:58PM -0400, Trond Myklebust wrote:
> It is large, it is used in more than one place, and it is not performance
> critical. Let gcc figure out whether it should be inlined...

Thanks, applying for 3.16.

--b.

> 
> Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
> ---
>  fs/nfsd/nfs4state.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> index 32b699bebb9c..841495aa9170 100644
> --- a/fs/nfsd/nfs4state.c
> +++ b/fs/nfsd/nfs4state.c
> @@ -1093,7 +1093,7 @@ static struct nfs4_client *alloc_client(struct xdr_netobj name)
>  	return clp;
>  }
>  
> -static inline void
> +static void
>  free_client(struct nfs4_client *clp)
>  {
>  	struct nfsd_net __maybe_unused *nn = net_generic(clp->net, nfsd_net_id);
> -- 
> 1.9.0
> 

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

* Re: [PATCH 06/70] nfsd4: use cl_lock to synchronize all stateid idr calls
  2014-04-18 18:44           ` [PATCH 06/70] nfsd4: use cl_lock to synchronize all stateid idr calls Trond Myklebust
  2014-04-18 18:44             ` [PATCH 07/70] nfsd4: hash deleg stateid only on successful nfs4_set_delegation Trond Myklebust
@ 2014-05-06 16:48             ` Bruce Fields
  1 sibling, 0 replies; 118+ messages in thread
From: Bruce Fields @ 2014-05-06 16:48 UTC (permalink / raw)
  To: Trond Myklebust; +Cc: linux-nfs

Might be worth adding to the changelog something like "not currently
necessary, but will be once we drop the state lock here" to this and
similar patches (assuming that's accurate), just to make it clear what's
a bugfix and what isn't.

--b.

On Fri, Apr 18, 2014 at 02:44:00PM -0400, Trond Myklebust wrote:
> From: Benny Halevy <bhalevy@primarydata.com>
> 
> Signed-off-by: Benny Halevy <bhalevy@primarydata.com>
> ---
>  fs/nfsd/nfs4state.c | 15 +++++++++++++--
>  1 file changed, 13 insertions(+), 2 deletions(-)
> 
> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> index 34273ca482c3..626f310a74a8 100644
> --- a/fs/nfsd/nfs4state.c
> +++ b/fs/nfsd/nfs4state.c
> @@ -334,7 +334,11 @@ kmem_cache *slab)
>  	if (!stid)
>  		return NULL;
>  
> -	new_id = idr_alloc_cyclic(stateids, stid, 0, 0, GFP_KERNEL);
> +	idr_preload(GFP_KERNEL);
> +	spin_lock(&cl->cl_lock);
> +	new_id = idr_alloc_cyclic(stateids, stid, 0, 0, GFP_NOWAIT);
> +	spin_unlock(&cl->cl_lock);
> +	idr_preload_end();
>  	if (new_id < 0)
>  		goto out_free;
>  	stid->sc_client = cl;
> @@ -397,9 +401,12 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct sv
>  
>  static void remove_stid(struct nfs4_stid *s)
>  {
> -	struct idr *stateids = &s->sc_client->cl_stateids;
> +	struct nfs4_client *clp = s->sc_client;
> +	struct idr *stateids = &clp->cl_stateids;
>  
> +	spin_lock(&clp->cl_lock);
>  	idr_remove(stateids, s->sc_stateid.si_opaque.so_id);
> +	spin_unlock(&clp->cl_lock);
>  }
>  
>  static void nfs4_free_stid(struct kmem_cache *slab, struct nfs4_stid *s)
> @@ -1110,7 +1117,9 @@ free_client(struct nfs4_client *clp)
>  	rpc_destroy_wait_queue(&clp->cl_cb_waitq);
>  	free_svc_cred(&clp->cl_cred);
>  	kfree(clp->cl_name.data);
> +	spin_lock(&clp->cl_lock);
>  	idr_destroy(&clp->cl_stateids);
> +	spin_unlock(&clp->cl_lock);
>  	kfree(clp);
>  }
>  
> @@ -1329,7 +1338,9 @@ static struct nfs4_stid *find_stateid(struct nfs4_client *cl, stateid_t *t)
>  {
>  	struct nfs4_stid *ret;
>  
> +	spin_lock(&cl->cl_lock);
>  	ret = idr_find(&cl->cl_stateids, t->si_opaque.so_id);
> +	spin_unlock(&cl->cl_lock);
>  	if (!ret || !ret->sc_type)
>  		return NULL;
>  	return ret;
> -- 
> 1.9.0
> 

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

* Re: [PATCH 10/70] NFSd: Avoid taking state_lock while holding inode lock in nfsd_break_one_deleg
  2014-04-18 18:44                   ` [PATCH 10/70] NFSd: Avoid taking state_lock while holding inode lock in nfsd_break_one_deleg Trond Myklebust
  2014-04-18 18:44                     ` [PATCH 11/70] NFSd: Ensure delegation setup is safe w.r.t. break_lease() Trond Myklebust
@ 2014-05-06 23:40                     ` Bruce Fields
  2014-05-09  0:50                       ` Trond Myklebust
  1 sibling, 1 reply; 118+ messages in thread
From: Bruce Fields @ 2014-05-06 23:40 UTC (permalink / raw)
  To: Trond Myklebust; +Cc: linux-nfs

On Fri, Apr 18, 2014 at 02:44:04PM -0400, Trond Myklebust wrote:
> state_lock is a heavily contended global lock. We don't want to grab
> that while simultaneously holding the inode->i_lock
> Instead do the list manipulations from the work queue context prior to
> starting the rpc call.
> 
> Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
> ---
>  fs/nfsd/nfs4callback.c | 18 ++++++++++++++++--
>  fs/nfsd/nfs4state.c    | 25 +++++++++++++++----------
>  fs/nfsd/state.h        |  1 +
>  3 files changed, 32 insertions(+), 12 deletions(-)
> 
> diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
> index 39c8ef875f91..8626cd6af4d1 100644
> --- a/fs/nfsd/nfs4callback.c
> +++ b/fs/nfsd/nfs4callback.c
> @@ -1009,9 +1009,8 @@ static void nfsd4_process_cb_update(struct nfsd4_callback *cb)
>  		run_nfsd4_cb(cb);
>  }
>  
> -static void nfsd4_do_callback_rpc(struct work_struct *w)
> +static void nfsd4_run_callback_rpc(struct nfsd4_callback *cb)
>  {
> -	struct nfsd4_callback *cb = container_of(w, struct nfsd4_callback, cb_work);
>  	struct nfs4_client *clp = cb->cb_clp;
>  	struct rpc_clnt *clnt;
>  
> @@ -1029,11 +1028,25 @@ static void nfsd4_do_callback_rpc(struct work_struct *w)
>  			cb->cb_ops, cb);
>  }
>  
> +static void nfsd4_do_callback_rpc(struct work_struct *w)
> +{
> +	struct nfsd4_callback *cb = container_of(w, struct nfsd4_callback, cb_work);
> +	nfsd4_run_callback_rpc(cb);
> +}
> +
>  void nfsd4_init_callback(struct nfsd4_callback *cb)
>  {
>  	INIT_WORK(&cb->cb_work, nfsd4_do_callback_rpc);
>  }
>  
> +static void nfsd4_do_cb_recall(struct work_struct *w)
> +{
> +	struct nfsd4_callback *cb = container_of(w, struct nfsd4_callback, cb_work);
> +
> +	nfsd4_prepare_cb_recall(cb->cb_op);
> +	nfsd4_run_callback_rpc(cb);
> +}
> +
>  void nfsd4_cb_recall(struct nfs4_delegation *dp)
>  {
>  	struct nfsd4_callback *cb = &dp->dl_recall;
> @@ -1050,6 +1063,7 @@ void nfsd4_cb_recall(struct nfs4_delegation *dp)
>  
>  	INIT_LIST_HEAD(&cb->cb_per_client);
>  	cb->cb_done = true;
> +	INIT_WORK(&cb->cb_work, nfsd4_do_cb_recall);
>  
>  	run_nfsd4_cb(&dp->dl_recall);
>  }
> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> index 6d691aa2bb27..85fcbc9ebd40 100644
> --- a/fs/nfsd/nfs4state.c
> +++ b/fs/nfsd/nfs4state.c
> @@ -2743,24 +2743,31 @@ out:
>  	return ret;
>  }
>  
> -static void nfsd_break_one_deleg(struct nfs4_delegation *dp)
> +void nfsd4_prepare_cb_recall(struct nfs4_delegation *dp)
>  {
>  	struct nfs4_client *clp = dp->dl_stid.sc_client;
>  	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
>  
> -	lockdep_assert_held(&state_lock);
> +	/*
> +	 * We can't do this in nfsd_break_deleg_cb because it is
> +	 * already holding inode->i_lock
> +	 */
> +	spin_lock(&state_lock);
> +	if (list_empty(&dp->dl_recall_lru)) {
> +		dp->dl_time = get_seconds();
> +		list_add_tail(&dp->dl_recall_lru, &nn->del_recall_lru);
> +	}
> +	spin_unlock(&state_lock);
> +}
> +
> +static void nfsd_break_one_deleg(struct nfs4_delegation *dp)
> +{
>  	/* We're assuming the state code never drops its reference
>  	 * without first removing the lease.  Since we're in this lease
>  	 * callback (and since the lease code is serialized by the kernel
>  	 * lock) we know the server hasn't removed the lease yet, we know
>  	 * it's safe to take a reference: */
>  	atomic_inc(&dp->dl_count);
> -
> -	list_add_tail(&dp->dl_recall_lru, &nn->del_recall_lru);
> -
> -	/* Only place dl_time is set; protected by i_lock: */
> -	dp->dl_time = get_seconds();
> -
>  	nfsd4_cb_recall(dp);
>  }
>  
> @@ -2785,11 +2792,9 @@ static void nfsd_break_deleg_cb(struct file_lock *fl)
>  	 */
>  	fl->fl_break_time = 0;
>  
> -	spin_lock(&state_lock);
>  	fp->fi_had_conflict = true;
>  	list_for_each_entry(dp, &fp->fi_delegations, dl_perfile)
>  		nfsd_break_one_deleg(dp);
> -	spin_unlock(&state_lock);

Why do we know it's safe to traverse this list without holding
state_lock?

--b.

>  }
>  
>  static
> diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
> index 1aa22f39fc65..02c5a203c738 100644
> --- a/fs/nfsd/state.h
> +++ b/fs/nfsd/state.h
> @@ -473,6 +473,7 @@ extern void nfsd4_cb_recall(struct nfs4_delegation *dp);
>  extern int nfsd4_create_callback_queue(void);
>  extern void nfsd4_destroy_callback_queue(void);
>  extern void nfsd4_shutdown_callback(struct nfs4_client *);
> +extern void nfsd4_prepare_cb_recall(struct nfs4_delegation *dp);
>  extern void nfs4_put_delegation(struct nfs4_delegation *dp);
>  extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(const char *name,
>  							struct nfsd_net *nn);
> -- 
> 1.9.0
> 

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

* Re: [PATCH 11/70] NFSd: Ensure delegation setup is safe w.r.t. break_lease()
  2014-04-18 18:44                     ` [PATCH 11/70] NFSd: Ensure delegation setup is safe w.r.t. break_lease() Trond Myklebust
  2014-04-18 18:44                       ` [PATCH 12/70] NFSd: Add fine grained protection for the nfs4_file->fi_stateids list Trond Myklebust
@ 2014-05-06 23:41                       ` Bruce Fields
  2014-05-09  0:56                         ` Trond Myklebust
  1 sibling, 1 reply; 118+ messages in thread
From: Bruce Fields @ 2014-05-06 23:41 UTC (permalink / raw)
  To: Trond Myklebust; +Cc: linux-nfs

On Fri, Apr 18, 2014 at 02:44:05PM -0400, Trond Myklebust wrote:
> Ensure that we add/remove the dl_perfile under the inode->i_lock

Looks like maybe this addresses my question on the previous patch--in
which case it should really be merged with the previous patch for
bisectability?

--b.

> 
> Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
> ---
>  fs/nfsd/nfs4state.c | 14 +++++++++++---
>  1 file changed, 11 insertions(+), 3 deletions(-)
> 
> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> index 85fcbc9ebd40..3656980b5d19 100644
> --- a/fs/nfsd/nfs4state.c
> +++ b/fs/nfsd/nfs4state.c
> @@ -441,7 +441,9 @@ static void
>  hash_delegation_locked(struct nfs4_delegation *dp, struct nfs4_file *fp)
>  {
>  	dp->dl_stid.sc_type = NFS4_DELEG_STID;
> +	spin_lock(&fp->fi_inode->i_lock);
>  	list_add(&dp->dl_perfile, &fp->fi_delegations);
> +	spin_unlock(&fp->fi_inode->i_lock);
>  	list_add(&dp->dl_perclnt, &dp->dl_stid.sc_client->cl_delegations);
>  }
>  
> @@ -449,13 +451,19 @@ hash_delegation_locked(struct nfs4_delegation *dp, struct nfs4_file *fp)
>  static void
>  unhash_delegation(struct nfs4_delegation *dp)
>  {
> +	struct nfs4_file *fp = dp->dl_file;
> +
>  	spin_lock(&state_lock);
>  	list_del_init(&dp->dl_perclnt);
> -	list_del_init(&dp->dl_perfile);
>  	list_del_init(&dp->dl_recall_lru);
> +	if (!list_empty(&dp->dl_perfile)) {
> +		spin_lock(&fp->fi_inode->i_lock);
> +		list_del_init(&dp->dl_perfile);
> +		spin_unlock(&fp->fi_inode->i_lock);
> +	}
>  	spin_unlock(&state_lock);
> -	nfs4_put_deleg_lease(dp->dl_file);
> -	put_nfs4_file(dp->dl_file);
> +	nfs4_put_deleg_lease(fp);
> +	put_nfs4_file(fp);
>  	dp->dl_file = NULL;
>  }
>  
> -- 
> 1.9.0
> 

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

* Re: [PATCH 19/70] NFSd: Allow lockowners to hold several stateids
  2014-04-18 18:44                                     ` [PATCH 19/70] NFSd: Allow lockowners to hold several stateids Trond Myklebust
  2014-04-18 18:44                                       ` [PATCH 20/70] NFSd: NFSv4 lock-owners are not associated to a specific file Trond Myklebust
@ 2014-05-07 15:20                                       ` Bruce Fields
  2014-05-22 12:20                                         ` Jeff Layton
  1 sibling, 1 reply; 118+ messages in thread
From: Bruce Fields @ 2014-05-07 15:20 UTC (permalink / raw)
  To: Trond Myklebust; +Cc: linux-nfs

Then did "NFSd: Lock owners are not per open stateid" introduce a
temporary regression?

--b.

On Fri, Apr 18, 2014 at 02:44:13PM -0400, Trond Myklebust wrote:
> Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
> ---
>  fs/nfsd/nfs4state.c | 46 +++++++++++++++++++++++++++++-----------------
>  1 file changed, 29 insertions(+), 17 deletions(-)
> 
> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> index 0809e8355577..dad2f7b511b8 100644
> --- a/fs/nfsd/nfs4state.c
> +++ b/fs/nfsd/nfs4state.c
> @@ -4390,6 +4390,19 @@ alloc_init_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp, struct
>  	return stp;
>  }
>  
> +static struct nfs4_ol_stateid *
> +find_lock_stateid(struct nfs4_lockowner *lo, struct inode *inode)
> +{
> +	struct nfs4_ol_stateid *lst;
> +
> +	list_for_each_entry(lst, &lo->lo_owner.so_stateids, st_perstateowner) {
> +		if (lst->st_file->fi_inode == inode)
> +			return lst;
> +	}
> +	return NULL;
> +}
> +
> +
>  static int
>  check_lock_length(u64 offset, u64 length)
>  {
> @@ -4419,25 +4432,24 @@ static __be32 lookup_or_create_lock_state(struct nfsd4_compound_state *cstate, s
>  
>  	lo = find_lockowner_str(fi->fi_inode, &cl->cl_clientid,
>  				&lock->v.new.owner, nn);
> -	if (lo) {
> -		if (!cstate->minorversion)
> -			return nfserr_bad_seqid;
> -		/* XXX: a lockowner always has exactly one stateid: */
> -		*lst = list_first_entry(&lo->lo_owner.so_stateids,
> -				struct nfs4_ol_stateid, st_perstateowner);
> -		return nfs_ok;
> +	if (!lo) {
> +		strhashval = ownerstr_hashval(cl->cl_clientid.cl_id,
> +				&lock->v.new.owner);
> +		lo = alloc_init_lock_stateowner(strhashval, cl, ost, lock);
> +		if (lo == NULL)
> +			return nfserr_jukebox;
>  	}
> -	strhashval = ownerstr_hashval(cl->cl_clientid.cl_id,
> -			&lock->v.new.owner);
> -	lo = alloc_init_lock_stateowner(strhashval, cl, ost, lock);
> -	if (lo == NULL)
> -		return nfserr_jukebox;
> -	*lst = alloc_init_lock_stateid(lo, fi, ost);
> +	if (!cstate->minorversion)
> +		return nfserr_bad_seqid;
> +	*lst = find_lock_stateid(lo, fi->fi_inode);
>  	if (*lst == NULL) {
> -		release_lockowner(lo);
> -		return nfserr_jukebox;
> +		*lst = alloc_init_lock_stateid(lo, fi, ost);
> +		if (*lst == NULL) {
> +			release_lockowner_if_empty(lo);
> +			return nfserr_jukebox;
> +		}
> +		*new = true;
>  	}
> -	*new = true;
>  	return nfs_ok;
>  }
>  
> @@ -4596,7 +4608,7 @@ out:
>  	if (filp)
>  		fput(filp);
>  	if (status && new_state)
> -		release_lockowner(lock_sop);
> +		release_lockowner_if_empty(lock_sop);
>  	nfsd4_bump_seqid(cstate, status);
>  	nfs4_unlock_state();
>  	if (file_lock)
> -- 
> 1.9.0
> 

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

* Re: [PATCH 25/70] NFSd: Simplify stateid management
  2014-04-18 18:44                                                 ` [PATCH 25/70] NFSd: Simplify stateid management Trond Myklebust
  2014-04-18 18:44                                                   ` [PATCH 26/70] NFSd: Fix delegation revocation Trond Myklebust
@ 2014-05-07 16:21                                                   ` Bruce Fields
  1 sibling, 0 replies; 118+ messages in thread
From: Bruce Fields @ 2014-05-07 16:21 UTC (permalink / raw)
  To: Trond Myklebust; +Cc: linux-nfs

On Fri, Apr 18, 2014 at 02:44:19PM -0400, Trond Myklebust wrote:
> Don't allow stateids to clear the open file pointer until they are
> being destroyed.

It looks like this means the stateid will continue to reference the file
after close in the nfsv4.0 case when we keep the stateid around a little
while just to handle replays.

Ditto in the 4.1 case when we keep a revoked delegation around for
test_stateid/free_stateid.

I'd consider that a regression.  People do occasionally notice when e.g.
a large unlinked file isn't promptly deallocated on close, and there may
be other cases where this matters.

--b.

> 
> Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
> ---
>  fs/nfsd/nfs4state.c | 12 +++++-------
>  1 file changed, 5 insertions(+), 7 deletions(-)
> 
> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> index afb767319f66..51ef179339ae 100644
> --- a/fs/nfsd/nfs4state.c
> +++ b/fs/nfsd/nfs4state.c
> @@ -394,7 +394,7 @@ kmem_cache *slab)
>  	struct nfs4_stid *stid;
>  	int new_id;
>  
> -	stid = kmem_cache_alloc(slab, GFP_KERNEL);
> +	stid = kmem_cache_zalloc(slab, GFP_KERNEL);
>  	if (!stid)
>  		return NULL;
>  
> @@ -481,6 +481,8 @@ void
>  nfs4_put_delegation(struct nfs4_delegation *dp)
>  {
>  	if (atomic_dec_and_test(&dp->dl_stid.sc_count)) {
> +		if (dp->dl_file)
> +			put_nfs4_file(dp->dl_file);
>  		nfs4_free_stid(deleg_slab, &dp->dl_stid);
>  		num_delegations--;
>  	}
> @@ -528,10 +530,8 @@ unhash_delegation(struct nfs4_delegation *dp)
>  		spin_unlock(&fp->fi_inode->i_lock);
>  	}
>  	nfs4_put_deleg_lease(fp);
> -	dp->dl_file = NULL;
>  	spin_unlock(&fp->fi_lock);
>  	spin_unlock(&state_lock);
> -	put_nfs4_file(fp);
>  }
>  
>  
> @@ -701,13 +701,13 @@ static void unhash_generic_stateid(struct nfs4_ol_stateid *stp)
>  static void close_generic_stateid(struct nfs4_ol_stateid *stp)
>  {
>  	release_all_access(stp);
> -	put_nfs4_file(stp->st_file);
> -	stp->st_file = NULL;
>  }
>  
>  static void free_generic_stateid(struct nfs4_ol_stateid *stp)
>  {
>  	remove_stid(&stp->st_stid);
> +	if (stp->st_file)
> +		put_nfs4_file(stp->st_file);
>  	nfs4_free_stid(stateid_slab, &stp->st_stid);
>  }
>  
> @@ -3265,8 +3265,6 @@ unlock_and_free:
>  	spin_unlock(&fp->fi_lock);
>  	spin_unlock(&state_lock);
>  out_free:
> -	put_nfs4_file(fp);
> -	dp->dl_file = fp;
>  	return status;
>  }
>  
> -- 
> 1.9.0
> 

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

* Re: [PATCH 26/70] NFSd: Fix delegation revocation
  2014-04-18 18:44                                                   ` [PATCH 26/70] NFSd: Fix delegation revocation Trond Myklebust
  2014-04-18 18:44                                                     ` [PATCH 27/70] NFSd: Don't let the laundromat reap clients that are referenced Trond Myklebust
@ 2014-05-07 18:46                                                     ` Bruce Fields
  1 sibling, 0 replies; 118+ messages in thread
From: Bruce Fields @ 2014-05-07 18:46 UTC (permalink / raw)
  To: Trond Myklebust; +Cc: linux-nfs

On Fri, Apr 18, 2014 at 02:44:20PM -0400, Trond Myklebust wrote:
> Ensure that the delegations cannot be found by the laundromat etc once
> we add them to the various 'revoke' lists.

The current code does already attempt to do that...  I guess the point
is that there's a race in that it leaves a window after a delegation is
added to one of the local lists but before it's actually unhashed, as
here:

> @@ -3612,7 +3620,8 @@ nfs4_laundromat(struct nfsd_net *nn)
>  				test_val = u;
>  			break;
>  		}
> -		list_move(&dp->dl_recall_lru, &reaplist);
> +		unhash_delegation_locked(dp);
> +		list_add(&dp->dl_recall_lru, &reaplist);
>  	}
>  	spin_unlock(&state_lock);

where we've been dropping a lock with the thing still hashed.

OK, good, but maybe the changelog could be a little more precise about
what's being fixed.

Also it would be nice if this could be done earlier in the series as
it's a bugfix that people will probably want backported.

--b.

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

* Re: [PATCH 27/70] NFSd: Don't let the laundromat reap clients that are referenced
  2014-04-18 18:44                                                     ` [PATCH 27/70] NFSd: Don't let the laundromat reap clients that are referenced Trond Myklebust
  2014-04-18 18:44                                                       ` [PATCH 28/70] NFSd: Add reference counting to the lock and open stateids Trond Myklebust
@ 2014-05-07 19:20                                                       ` Bruce Fields
  1 sibling, 0 replies; 118+ messages in thread
From: Bruce Fields @ 2014-05-07 19:20 UTC (permalink / raw)
  To: Trond Myklebust; +Cc: linux-nfs

This looks redundant with the check just made in
mark_client_expired_locked().

--b.

On Fri, Apr 18, 2014 at 02:44:21PM -0400, Trond Myklebust wrote:
> Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
> ---
>  fs/nfsd/nfs4state.c | 3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> index 273bdddb2458..41314e493110 100644
> --- a/fs/nfsd/nfs4state.c
> +++ b/fs/nfsd/nfs4state.c
> @@ -3600,6 +3600,9 @@ nfs4_laundromat(struct nfsd_net *nn)
>  				clp->cl_clientid.cl_id);
>  			continue;
>  		}
> +		/* Hey, I'm busy with this guy! */
> +		if (atomic_read(&clp->cl_refcount) != 0)
> +			continue;
>  		list_move(&clp->cl_lru, &reaplist);
>  	}
>  	spin_unlock(&nn->client_lock);
> -- 
> 1.9.0
> 

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

* Re: [PATCH 29/70] NFSd: Add a struct nfs4_file field to struct nfs4_stid
  2014-04-18 18:44                                                         ` [PATCH 29/70] NFSd: Add a struct nfs4_file field to struct nfs4_stid Trond Myklebust
  2014-04-18 18:44                                                           ` [PATCH 30/70] NFSd: Replace delegation->dl_file with the dl_stid.sc_file Trond Myklebust
@ 2014-05-07 19:25                                                           ` Bruce Fields
  2014-05-08 19:40                                                             ` Trond Myklebust
  1 sibling, 1 reply; 118+ messages in thread
From: Bruce Fields @ 2014-05-07 19:25 UTC (permalink / raw)
  To: Trond Myklebust; +Cc: linux-nfs

We're adding a put without adding a corresponding get, so was there a
leak before this patch?

--b.

On Fri, Apr 18, 2014 at 02:44:23PM -0400, Trond Myklebust wrote:
> All stateids are associated with a nfs4_file. Let's consolidate...
> 
> Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
> ---
>  fs/nfsd/nfs4state.c | 2 ++
>  fs/nfsd/state.h     | 1 +
>  2 files changed, 3 insertions(+)
> 
> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> index 32ab3f1c83f8..5bbef4720e7c 100644
> --- a/fs/nfsd/nfs4state.c
> +++ b/fs/nfsd/nfs4state.c
> @@ -474,6 +474,8 @@ static void remove_stid(struct nfs4_stid *s)
>  
>  static void nfs4_free_stid(struct kmem_cache *slab, struct nfs4_stid *s)
>  {
> +	if (s->sc_file)
> +		put_nfs4_file(s->sc_file);
>  	kmem_cache_free(slab, s);
>  }
>  
> diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
> index 9d0088c244a8..c6deef936693 100644
> --- a/fs/nfsd/state.h
> +++ b/fs/nfsd/state.h
> @@ -85,6 +85,7 @@ struct nfs4_stid {
>  	unsigned char sc_type;
>  	stateid_t sc_stateid;
>  	struct nfs4_client *sc_client;
> +	struct nfs4_file *sc_file;
>  };
>  
>  struct nfs4_delegation {
> -- 
> 1.9.0
> 

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

* Re: [PATCH 37/70] NFSd: nfs4_preprocess_seqid_op should only set *stpp on success
  2014-04-18 18:44                                                                         ` [PATCH 37/70] NFSd: nfs4_preprocess_seqid_op should only set *stpp on success Trond Myklebust
  2014-04-18 18:44                                                                           ` [PATCH 38/70] NFSd: Add reference counting to lock stateids Trond Myklebust
@ 2014-05-07 19:58                                                                           ` Bruce Fields
  2014-05-08 19:48                                                                             ` Trond Myklebust
  1 sibling, 1 reply; 118+ messages in thread
From: Bruce Fields @ 2014-05-07 19:58 UTC (permalink / raw)
  To: Trond Myklebust; +Cc: linux-nfs

Patch-sequencing nit: I'm guessing this wasn't actually a problem until
previous patches added sequenceid reference counting, turning this case
into a reference leak.

Therefore to avoid a temporary regression we should probably make this
change before introducing the reference counting rather than after.

--b.

On Fri, Apr 18, 2014 at 02:44:31PM -0400, Trond Myklebust wrote:
> Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
> ---
>  fs/nfsd/nfs4state.c | 10 +++++++---
>  1 file changed, 7 insertions(+), 3 deletions(-)
> 
> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> index b9d6da652fb1..03a3f51d2828 100644
> --- a/fs/nfsd/nfs4state.c
> +++ b/fs/nfsd/nfs4state.c
> @@ -4068,6 +4068,7 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
>  {
>  	__be32 status;
>  	struct nfs4_stid *s;
> +	struct nfs4_ol_stateid *stp = NULL;
>  
>  	dprintk("NFSD: %s: seqid=%d stateid = " STATEID_FMT "\n", __func__,
>  		seqid, STATEID_VAL(stateid));
> @@ -4077,10 +4078,13 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
>  				      cstate->minorversion, nn);
>  	if (status)
>  		return status;
> -	*stpp = openlockstateid(s);
> -	nfsd4_cstate_assign_replay(cstate, (*stpp)->st_stateowner);
> +	stp = openlockstateid(s);
> +	nfsd4_cstate_assign_replay(cstate, stp->st_stateowner);
>  
> -	return nfs4_seqid_op_checks(cstate, stateid, seqid, *stpp);
> +	status = nfs4_seqid_op_checks(cstate, stateid, seqid, stp);
> +	if (!status)
> +		*stpp = stp;
> +	return status;
>  }
>  
>  static __be32 nfs4_preprocess_confirmed_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
> -- 
> 1.9.0
> 

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

* Re: [PATCH 50/70] NFSd: Use the session->se_client  in lookup_clientid()
  2014-04-18 18:44                                                                                                   ` [PATCH 50/70] NFSd: Use the session->se_client in lookup_clientid() Trond Myklebust
  2014-04-18 18:44                                                                                                     ` [PATCH 51/70] NFSd: Convert nfsd4_process_open1() to work with lookup_clientid() Trond Myklebust
  2014-04-19 14:56                                                                                                     ` [PATCH 50/70] NFSd: Use the session->se_client in lookup_clientid() Christoph Hellwig
@ 2014-05-07 20:18                                                                                                     ` Bruce Fields
  2014-05-07 20:21                                                                                                       ` Bruce Fields
  2 siblings, 1 reply; 118+ messages in thread
From: Bruce Fields @ 2014-05-07 20:18 UTC (permalink / raw)
  To: Trond Myklebust; +Cc: linux-nfs

On Fri, Apr 18, 2014 at 02:44:44PM -0400, Trond Myklebust wrote:
> In NFSv4.x with x>0, we want to use the session's pointer to the
> nfs4_client in order to optimise away the extra lookup of the clid.
> 
> Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
> ---
>  fs/nfsd/nfs4state.c | 25 +++++++++++++++----------
>  1 file changed, 15 insertions(+), 10 deletions(-)
> 
> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> index 888acf114e40..6e2d348d3367 100644
> --- a/fs/nfsd/nfs4state.c
> +++ b/fs/nfsd/nfs4state.c
> @@ -3571,13 +3571,19 @@ void nfsd4_cleanup_open_state(struct nfsd4_open *open, __be32 status)
>  		put_generic_stateid(open->op_stp);
>  }
>  
> -static __be32 lookup_clientid(clientid_t *clid, bool session, struct nfsd_net *nn, struct nfs4_client **clp)
> +static __be32 lookup_clientid(clientid_t *clid, struct nfsd4_session *session, struct nfsd_net *nn, struct nfs4_client **clp)
>  {
>  	struct nfs4_client *found;
>  
> -	if (STALE_CLIENTID(clid, nn))
> -		return nfserr_stale_clientid;
> -	found = find_confirmed_client(clid, session, nn);
> +	if (session != NULL) {
> +		found = session->se_client;
> +		if (!same_clid(&found->cl_clientid, clid))
> +			return nfserr_stale_clientid;

Is that the right error?  After your
a8a7c6776f8d74780348bef639581421d85a4376 "nfsd: Don't return
NFS4ERR_STALE_STATEID for NFSv4.1+", nfsd4_lookup_stateid will just
immediately map this to BAD_STATEID.  (And the other callers aren't
relevant in the minorversion > 0 case.)

--b.

> +	} else {
> +		if (STALE_CLIENTID(clid, nn))
> +			return nfserr_stale_clientid;
> +		found = find_confirmed_client(clid, false, nn);
> +	}
>  	if (clp)
>  		*clp = found;
>  	return found ? nfs_ok : nfserr_expired;
> @@ -3594,7 +3600,7 @@ nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
>  	nfs4_lock_state();
>  	dprintk("process_renew(%08x/%08x): starting\n", 
>  			clid->cl_boot, clid->cl_id);
> -	status = lookup_clientid(clid, cstate->minorversion, nn, &clp);
> +	status = lookup_clientid(clid, NULL, nn, &clp);
>  	if (status)
>  		goto out;
>  	status = nfserr_cb_path_down;
> @@ -3879,14 +3885,13 @@ static __be32 nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate,
>  {
>  	struct nfs4_client *cl;
>  	__be32 status;
> -	bool sessions = cstate->minorversion != 0;
>  
>  	if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
>  		return nfserr_bad_stateid;
> -	status = lookup_clientid(&stateid->si_opaque.so_clid, sessions,
> +	status = lookup_clientid(&stateid->si_opaque.so_clid, cstate->session,
>  							nn, &cl);
>  	if (status == nfserr_stale_clientid) {
> -		if (sessions)
> +		if (cstate->session)
>  			return nfserr_bad_stateid;
>  		return nfserr_stale_stateid;
>  	}
> @@ -4770,7 +4775,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
>  	nfs4_lock_state();
>  
>  	if (!nfsd4_has_session(cstate)) {
> -		status = lookup_clientid(&lockt->lt_clientid, false, nn, NULL);
> +		status = lookup_clientid(&lockt->lt_clientid, NULL, nn, NULL);
>  		if (status)
>  			goto out;
>  	}
> @@ -4942,7 +4947,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
>  
>  	nfs4_lock_state();
>  
> -	status = lookup_clientid(clid, cstate->minorversion, nn, NULL);
> +	status = lookup_clientid(clid, NULL, nn, NULL);
>  	if (status)
>  		goto out;
>  
> -- 
> 1.9.0
> 

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

* Re: [PATCH 50/70] NFSd: Use the session->se_client  in lookup_clientid()
  2014-05-07 20:18                                                                                                     ` Bruce Fields
@ 2014-05-07 20:21                                                                                                       ` Bruce Fields
  0 siblings, 0 replies; 118+ messages in thread
From: Bruce Fields @ 2014-05-07 20:21 UTC (permalink / raw)
  To: Trond Myklebust; +Cc: linux-nfs

On Wed, May 07, 2014 at 04:18:54PM -0400, Bruce Fields wrote:
> On Fri, Apr 18, 2014 at 02:44:44PM -0400, Trond Myklebust wrote:
> > In NFSv4.x with x>0, we want to use the session's pointer to the
> > nfs4_client in order to optimise away the extra lookup of the clid.
> > 
> > Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
> > ---
> >  fs/nfsd/nfs4state.c | 25 +++++++++++++++----------
> >  1 file changed, 15 insertions(+), 10 deletions(-)
> > 
> > diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> > index 888acf114e40..6e2d348d3367 100644
> > --- a/fs/nfsd/nfs4state.c
> > +++ b/fs/nfsd/nfs4state.c
> > @@ -3571,13 +3571,19 @@ void nfsd4_cleanup_open_state(struct nfsd4_open *open, __be32 status)
> >  		put_generic_stateid(open->op_stp);
> >  }
> >  
> > -static __be32 lookup_clientid(clientid_t *clid, bool session, struct nfsd_net *nn, struct nfs4_client **clp)
> > +static __be32 lookup_clientid(clientid_t *clid, struct nfsd4_session *session, struct nfsd_net *nn, struct nfs4_client **clp)
> >  {
> >  	struct nfs4_client *found;
> >  
> > -	if (STALE_CLIENTID(clid, nn))
> > -		return nfserr_stale_clientid;
> > -	found = find_confirmed_client(clid, session, nn);
> > +	if (session != NULL) {
> > +		found = session->se_client;
> > +		if (!same_clid(&found->cl_clientid, clid))
> > +			return nfserr_stale_clientid;
> 
> Is that the right error?  After your
> a8a7c6776f8d74780348bef639581421d85a4376 "nfsd: Don't return
> NFS4ERR_STALE_STATEID for NFSv4.1+", nfsd4_lookup_stateid will just
> immediately map this to BAD_STATEID.  (And the other callers aren't
> relevant in the minorversion > 0 case.)

(OK, never mind, I guess STALE must be the right error for the callers
added in later patches.)

--b.

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

* Re: [PATCH 00/70] NFSd lock scalability patches
  2014-04-19 20:58 ` Bruce Fields
@ 2014-05-07 20:29   ` Bruce Fields
  2014-05-08 20:16     ` Trond Myklebust
  0 siblings, 1 reply; 118+ messages in thread
From: Bruce Fields @ 2014-05-07 20:29 UTC (permalink / raw)
  To: Trond Myklebust; +Cc: linux-nfs

On Sat, Apr 19, 2014 at 04:58:15PM -0400, Bruce Fields wrote:
> On Fri, Apr 18, 2014 at 02:43:54PM -0400, Trond Myklebust wrote:
> > In accordance with the traditional Good Friday theme of "suffering", here
> > is the first draft of the NFSd lock scalability patches for your perusal.
> > I've only done light testing so far, but since there is a total of 70
> > patches to review, I figured you might want to start sooner rather than
> > waiting for the QA folks to finish testing.
> 
> Thanks!
> 
> Yeah, this sounds like too much suffering for vacation time, but I'll at
> least make a stab at merging the initial bug fixes next week, then try
> to plow through these (or any revised version (thanks, Christoph, for
> help reviewing!)) after I get back in a couple more weeks.

I've at least skimmed through them all, and that's all the suffering I
can handle for now.  I'm assuming you'll send a new version soon.

I'm applying a few of these to my for-3.16 branch, could you rebase
future versions to that to avoid resending already-reviewed patches?

How are you testing?

Thanks again for taking on this difficult and long-overdue project....

--b.

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

* Re: [PATCH 29/70] NFSd: Add a struct nfs4_file field to struct nfs4_stid
  2014-05-07 19:25                                                           ` [PATCH 29/70] NFSd: Add a struct nfs4_file field to struct nfs4_stid Bruce Fields
@ 2014-05-08 19:40                                                             ` Trond Myklebust
  2014-05-09  7:34                                                               ` Christoph Hellwig
  0 siblings, 1 reply; 118+ messages in thread
From: Trond Myklebust @ 2014-05-08 19:40 UTC (permalink / raw)
  To: Bruce Fields; +Cc: Linux NFS Mailing List

On Wed, May 7, 2014 at 3:25 PM, Bruce Fields <bfields@fieldses.org> wrote:
> We're adding a put without adding a corresponding get, so was there a
> leak before this patch?

No. The struct sc_file is added by this patch, and since the entire
stid is zeroed on allocation (through the use of kmem_cache_zalloc),
it is safe to add the put() in this patch.

>
> --b.
>
> On Fri, Apr 18, 2014 at 02:44:23PM -0400, Trond Myklebust wrote:
>> All stateids are associated with a nfs4_file. Let's consolidate...
>>
>> Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
>> ---
>>  fs/nfsd/nfs4state.c | 2 ++
>>  fs/nfsd/state.h     | 1 +
>>  2 files changed, 3 insertions(+)
>>
>> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
>> index 32ab3f1c83f8..5bbef4720e7c 100644
>> --- a/fs/nfsd/nfs4state.c
>> +++ b/fs/nfsd/nfs4state.c
>> @@ -474,6 +474,8 @@ static void remove_stid(struct nfs4_stid *s)
>>
>>  static void nfs4_free_stid(struct kmem_cache *slab, struct nfs4_stid *s)
>>  {
>> +     if (s->sc_file)
>> +             put_nfs4_file(s->sc_file);
>>       kmem_cache_free(slab, s);
>>  }
>>
>> diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
>> index 9d0088c244a8..c6deef936693 100644
>> --- a/fs/nfsd/state.h
>> +++ b/fs/nfsd/state.h
>> @@ -85,6 +85,7 @@ struct nfs4_stid {
>>       unsigned char sc_type;
>>       stateid_t sc_stateid;
>>       struct nfs4_client *sc_client;
>> +     struct nfs4_file *sc_file;
>>  };
>>
>>  struct nfs4_delegation {
>> --
>> 1.9.0
>>



-- 
Trond Myklebust

Linux NFS client maintainer, PrimaryData

trond.myklebust@primarydata.com

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

* Re: [PATCH 37/70] NFSd: nfs4_preprocess_seqid_op should only set *stpp on success
  2014-05-07 19:58                                                                           ` [PATCH 37/70] NFSd: nfs4_preprocess_seqid_op should only set *stpp on success Bruce Fields
@ 2014-05-08 19:48                                                                             ` Trond Myklebust
  0 siblings, 0 replies; 118+ messages in thread
From: Trond Myklebust @ 2014-05-08 19:48 UTC (permalink / raw)
  To: Bruce Fields; +Cc: Linux NFS Mailing List

On Wed, May 7, 2014 at 3:58 PM, Bruce Fields <bfields@fieldses.org> wrote:
> Patch-sequencing nit: I'm guessing this wasn't actually a problem until
> previous patches added sequenceid reference counting, turning this case
> into a reference leak.
>
> Therefore to avoid a temporary regression we should probably make this
> change before introducing the reference counting rather than after.

No, there should be no regression. This patch is a cleanup in
preparation for the introduction of reference counting.

> --b.
>
> On Fri, Apr 18, 2014 at 02:44:31PM -0400, Trond Myklebust wrote:
>> Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
>> ---
>>  fs/nfsd/nfs4state.c | 10 +++++++---
>>  1 file changed, 7 insertions(+), 3 deletions(-)
>>
>> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
>> index b9d6da652fb1..03a3f51d2828 100644
>> --- a/fs/nfsd/nfs4state.c
>> +++ b/fs/nfsd/nfs4state.c
>> @@ -4068,6 +4068,7 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
>>  {
>>       __be32 status;
>>       struct nfs4_stid *s;
>> +     struct nfs4_ol_stateid *stp = NULL;
>>
>>       dprintk("NFSD: %s: seqid=%d stateid = " STATEID_FMT "\n", __func__,
>>               seqid, STATEID_VAL(stateid));
>> @@ -4077,10 +4078,13 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
>>                                     cstate->minorversion, nn);
>>       if (status)
>>               return status;
>> -     *stpp = openlockstateid(s);
>> -     nfsd4_cstate_assign_replay(cstate, (*stpp)->st_stateowner);
>> +     stp = openlockstateid(s);
>> +     nfsd4_cstate_assign_replay(cstate, stp->st_stateowner);
>>
>> -     return nfs4_seqid_op_checks(cstate, stateid, seqid, *stpp);
>> +     status = nfs4_seqid_op_checks(cstate, stateid, seqid, stp);
>> +     if (!status)
>> +             *stpp = stp;
>> +     return status;
>>  }
>>
>>  static __be32 nfs4_preprocess_confirmed_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
>> --
>> 1.9.0
>>



-- 
Trond Myklebust

Linux NFS client maintainer, PrimaryData

trond.myklebust@primarydata.com

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

* Re: [PATCH 00/70] NFSd lock scalability patches
  2014-05-07 20:29   ` Bruce Fields
@ 2014-05-08 20:16     ` Trond Myklebust
  0 siblings, 0 replies; 118+ messages in thread
From: Trond Myklebust @ 2014-05-08 20:16 UTC (permalink / raw)
  To: Bruce Fields; +Cc: Linux NFS Mailing List

On Wed, May 7, 2014 at 4:29 PM, Bruce Fields <bfields@fieldses.org> wrote:
> On Sat, Apr 19, 2014 at 04:58:15PM -0400, Bruce Fields wrote:
>> On Fri, Apr 18, 2014 at 02:43:54PM -0400, Trond Myklebust wrote:
>> > In accordance with the traditional Good Friday theme of "suffering", here
>> > is the first draft of the NFSd lock scalability patches for your perusal.
>> > I've only done light testing so far, but since there is a total of 70
>> > patches to review, I figured you might want to start sooner rather than
>> > waiting for the QA folks to finish testing.
>>
>> Thanks!
>>
>> Yeah, this sounds like too much suffering for vacation time, but I'll at
>> least make a stab at merging the initial bug fixes next week, then try
>> to plow through these (or any revised version (thanks, Christoph, for
>> help reviewing!)) after I get back in a couple more weeks.

Yes. Thanks very much Christoph! I was worried that I would not get
enough reviewers for these patches.

> I've at least skimmed through them all, and that's all the suffering I
> can handle for now.  I'm assuming you'll send a new version soon.

In addition to the issues that you and Christoph have raised, I've
also had to rethink some of the open() call. I'm not seeing how to
avoid moving the open share/deny locks into do_nfsd_create() without
getting into weird races, for instance.

> I'm applying a few of these to my for-3.16 branch, could you rebase
> future versions to that to avoid resending already-reviewed patches?

OK.

> How are you testing?

Mainly through plenty of runs of Connectathon tests for now. I want to
pass the code on to our QA folks for more extensive testing when it is
ready.

> Thanks again for taking on this difficult and long-overdue project....
>
> --b.



-- 
Trond Myklebust

Linux NFS client maintainer, PrimaryData

trond.myklebust@primarydata.com

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

* Re: [PATCH 10/70] NFSd: Avoid taking state_lock while holding inode lock in nfsd_break_one_deleg
  2014-05-06 23:40                     ` [PATCH 10/70] NFSd: Avoid taking state_lock while holding inode lock in nfsd_break_one_deleg Bruce Fields
@ 2014-05-09  0:50                       ` Trond Myklebust
  2014-05-30 12:05                         ` Jeff Layton
  0 siblings, 1 reply; 118+ messages in thread
From: Trond Myklebust @ 2014-05-09  0:50 UTC (permalink / raw)
  To: Bruce Fields; +Cc: Linux NFS Mailing List

On Tue, May 6, 2014 at 7:40 PM, Bruce Fields <bfields@fieldses.org> wrote:
> On Fri, Apr 18, 2014 at 02:44:04PM -0400, Trond Myklebust wrote:
>> state_lock is a heavily contended global lock. We don't want to grab
>> that while simultaneously holding the inode->i_lock
>> Instead do the list manipulations from the work queue context prior to
>> starting the rpc call.
>>
>> Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
>> ---
>>  fs/nfsd/nfs4callback.c | 18 ++++++++++++++++--
>>  fs/nfsd/nfs4state.c    | 25 +++++++++++++++----------
>>  fs/nfsd/state.h        |  1 +
>>  3 files changed, 32 insertions(+), 12 deletions(-)
>>
>> diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
>> index 39c8ef875f91..8626cd6af4d1 100644
>> --- a/fs/nfsd/nfs4callback.c
>> +++ b/fs/nfsd/nfs4callback.c
>> @@ -1009,9 +1009,8 @@ static void nfsd4_process_cb_update(struct nfsd4_callback *cb)
>>               run_nfsd4_cb(cb);
>>  }
>>
>> -static void nfsd4_do_callback_rpc(struct work_struct *w)
>> +static void nfsd4_run_callback_rpc(struct nfsd4_callback *cb)
>>  {
>> -     struct nfsd4_callback *cb = container_of(w, struct nfsd4_callback, cb_work);
>>       struct nfs4_client *clp = cb->cb_clp;
>>       struct rpc_clnt *clnt;
>>
>> @@ -1029,11 +1028,25 @@ static void nfsd4_do_callback_rpc(struct work_struct *w)
>>                       cb->cb_ops, cb);
>>  }
>>
>> +static void nfsd4_do_callback_rpc(struct work_struct *w)
>> +{
>> +     struct nfsd4_callback *cb = container_of(w, struct nfsd4_callback, cb_work);
>> +     nfsd4_run_callback_rpc(cb);
>> +}
>> +
>>  void nfsd4_init_callback(struct nfsd4_callback *cb)
>>  {
>>       INIT_WORK(&cb->cb_work, nfsd4_do_callback_rpc);
>>  }
>>
>> +static void nfsd4_do_cb_recall(struct work_struct *w)
>> +{
>> +     struct nfsd4_callback *cb = container_of(w, struct nfsd4_callback, cb_work);
>> +
>> +     nfsd4_prepare_cb_recall(cb->cb_op);
>> +     nfsd4_run_callback_rpc(cb);
>> +}
>> +
>>  void nfsd4_cb_recall(struct nfs4_delegation *dp)
>>  {
>>       struct nfsd4_callback *cb = &dp->dl_recall;
>> @@ -1050,6 +1063,7 @@ void nfsd4_cb_recall(struct nfs4_delegation *dp)
>>
>>       INIT_LIST_HEAD(&cb->cb_per_client);
>>       cb->cb_done = true;
>> +     INIT_WORK(&cb->cb_work, nfsd4_do_cb_recall);
>>
>>       run_nfsd4_cb(&dp->dl_recall);
>>  }
>> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
>> index 6d691aa2bb27..85fcbc9ebd40 100644
>> --- a/fs/nfsd/nfs4state.c
>> +++ b/fs/nfsd/nfs4state.c
>> @@ -2743,24 +2743,31 @@ out:
>>       return ret;
>>  }
>>
>> -static void nfsd_break_one_deleg(struct nfs4_delegation *dp)
>> +void nfsd4_prepare_cb_recall(struct nfs4_delegation *dp)
>>  {
>>       struct nfs4_client *clp = dp->dl_stid.sc_client;
>>       struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
>>
>> -     lockdep_assert_held(&state_lock);
>> +     /*
>> +      * We can't do this in nfsd_break_deleg_cb because it is
>> +      * already holding inode->i_lock
>> +      */
>> +     spin_lock(&state_lock);
>> +     if (list_empty(&dp->dl_recall_lru)) {
>> +             dp->dl_time = get_seconds();
>> +             list_add_tail(&dp->dl_recall_lru, &nn->del_recall_lru);
>> +     }
>> +     spin_unlock(&state_lock);
>> +}
>> +
>> +static void nfsd_break_one_deleg(struct nfs4_delegation *dp)
>> +{
>>       /* We're assuming the state code never drops its reference
>>        * without first removing the lease.  Since we're in this lease
>>        * callback (and since the lease code is serialized by the kernel
>>        * lock) we know the server hasn't removed the lease yet, we know
>>        * it's safe to take a reference: */
>>       atomic_inc(&dp->dl_count);
>> -
>> -     list_add_tail(&dp->dl_recall_lru, &nn->del_recall_lru);
>> -
>> -     /* Only place dl_time is set; protected by i_lock: */
>> -     dp->dl_time = get_seconds();
>> -
>>       nfsd4_cb_recall(dp);
>>  }
>>
>> @@ -2785,11 +2792,9 @@ static void nfsd_break_deleg_cb(struct file_lock *fl)
>>        */
>>       fl->fl_break_time = 0;
>>
>> -     spin_lock(&state_lock);
>>       fp->fi_had_conflict = true;
>>       list_for_each_entry(dp, &fp->fi_delegations, dl_perfile)
>>               nfsd_break_one_deleg(dp);
>> -     spin_unlock(&state_lock);
>
> Why do we know it's safe to traverse this list without holding
> state_lock?

We're in a callback that is already holding the inode->i_lock, and so
this is why we need to involve inode->i_lock when hashing/unhashing
the delegation.

> --b.
>
>>  }
>>
>>  static
>> diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
>> index 1aa22f39fc65..02c5a203c738 100644
>> --- a/fs/nfsd/state.h
>> +++ b/fs/nfsd/state.h
>> @@ -473,6 +473,7 @@ extern void nfsd4_cb_recall(struct nfs4_delegation *dp);
>>  extern int nfsd4_create_callback_queue(void);
>>  extern void nfsd4_destroy_callback_queue(void);
>>  extern void nfsd4_shutdown_callback(struct nfs4_client *);
>> +extern void nfsd4_prepare_cb_recall(struct nfs4_delegation *dp);
>>  extern void nfs4_put_delegation(struct nfs4_delegation *dp);
>>  extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(const char *name,
>>                                                       struct nfsd_net *nn);
>> --
>> 1.9.0
>>



-- 
Trond Myklebust

Linux NFS client maintainer, PrimaryData

trond.myklebust@primarydata.com

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

* Re: [PATCH 11/70] NFSd: Ensure delegation setup is safe w.r.t. break_lease()
  2014-05-06 23:41                       ` [PATCH 11/70] NFSd: Ensure delegation setup is safe w.r.t. break_lease() Bruce Fields
@ 2014-05-09  0:56                         ` Trond Myklebust
  0 siblings, 0 replies; 118+ messages in thread
From: Trond Myklebust @ 2014-05-09  0:56 UTC (permalink / raw)
  To: Bruce Fields; +Cc: Linux NFS Mailing List

On Tue, May 6, 2014 at 7:41 PM, Bruce Fields <bfields@fieldses.org> wrote:
> On Fri, Apr 18, 2014 at 02:44:05PM -0400, Trond Myklebust wrote:
>> Ensure that we add/remove the dl_perfile under the inode->i_lock
>
> Looks like maybe this addresses my question on the previous patch--in
> which case it should really be merged with the previous patch for
> bisectability?
>

We could, but the client_mutex will continue to mask any conflicts. In
the case where it doesn't, it would be because the existing code is
already borken.

It really is quite non-trivial to work out all the relationships that
are at work here, and to order the patches in a sane way. I'm quite
open to suggestions for improvements, but when in doubt, I'm relying
on the 'big umbrella' being up there until it is removed...


-- 
Trond Myklebust

Linux NFS client maintainer, PrimaryData

trond.myklebust@primarydata.com

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

* Re: [PATCH 29/70] NFSd: Add a struct nfs4_file field to struct nfs4_stid
  2014-05-08 19:40                                                             ` Trond Myklebust
@ 2014-05-09  7:34                                                               ` Christoph Hellwig
  0 siblings, 0 replies; 118+ messages in thread
From: Christoph Hellwig @ 2014-05-09  7:34 UTC (permalink / raw)
  To: Trond Myklebust; +Cc: Bruce Fields, Linux NFS Mailing List

On Thu, May 08, 2014 at 03:40:49PM -0400, Trond Myklebust wrote:
> On Wed, May 7, 2014 at 3:25 PM, Bruce Fields <bfields@fieldses.org> wrote:
> > We're adding a put without adding a corresponding get, so was there a
> > leak before this patch?
> 
> No. The struct sc_file is added by this patch, and since the entire
> stid is zeroed on allocation (through the use of kmem_cache_zalloc),
> it is safe to add the put() in this patch.

It's safe, but it would still be nicer to have a single patch that just
moves the file from the delegation to the generic stateid.


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

* Re: [PATCH 58/70] NFSd: Protect session creation and client confirm using client_lock
  2014-04-18 18:44                                                                                                                   ` [PATCH 58/70] NFSd: Protect session creation and client confirm " Trond Myklebust
  2014-04-18 18:44                                                                                                                     ` [PATCH 59/70] NFSd: Protect nfsd4_destroy_clientid " Trond Myklebust
@ 2014-05-16 18:19                                                                                                                     ` Jeff Layton
  1 sibling, 0 replies; 118+ messages in thread
From: Jeff Layton @ 2014-05-16 18:19 UTC (permalink / raw)
  To: Trond Myklebust; +Cc: Bruce Fields, linux-nfs

[-- Attachment #1: Type: text/plain, Size: 6051 bytes --]

On Fri, 18 Apr 2014 14:44:52 -0400
Trond Myklebust <trond.myklebust@primarydata.com> wrote:

> In particular, we want to ensure that the move_to_confirmed() is
> protected by the nn->client_lock spin lock, so that we can use that
> when looking up the clientid etc.
> 
> Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
> ---
>  fs/nfsd/nfs4state.c | 55 ++++++++++++++++++++++++++++++-----------------------
>  1 file changed, 31 insertions(+), 24 deletions(-)
> 
> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> index 9c24031757d2..f047341678c0 100644
> --- a/fs/nfsd/nfs4state.c
> +++ b/fs/nfsd/nfs4state.c
> @@ -130,17 +130,6 @@ static __be32 mark_client_expired_locked(struct nfs4_client *clp)
>  	return nfs_ok;
>  }
>  
> -static __be32 mark_client_expired(struct nfs4_client *clp)
> -{
> -	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
> -	__be32 ret;
> -
> -	spin_lock(&nn->client_lock);
> -	ret = mark_client_expired_locked(clp);
> -	spin_unlock(&nn->client_lock);
> -	return ret;
> -}
> 

This patch breaks the build when CONFIG_NFSD_FAULT_INJECTION is enabled
as mark_client_expired is still referenced by nfsd_forget_clients. The
attached patch should do the right thing.

Trond, feel free to roll it into your patch on the next iteration.


>  static __be32 get_client_locked(struct nfs4_client *clp)
>  {
>  	if (is_client_expired(clp))
> @@ -1134,12 +1123,10 @@ static void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, stru
>  	new->se_cb_sec = cses->cb_sec;
>  	atomic_set(&new->se_ref, 0);
>  	idx = hash_sessionid(&new->se_sessionid);
> -	spin_lock(&nn->client_lock);
>  	list_add(&new->se_hash, &nn->sessionid_hashtbl[idx]);
>  	spin_lock(&clp->cl_lock);
>  	list_add(&new->se_perclnt, &clp->cl_sessions);
>  	spin_unlock(&clp->cl_lock);
> -	spin_unlock(&nn->client_lock);
>  
>  	if (cses->flags & SESSION4_BACK_CHAN) {
>  		struct sockaddr *sa = svc_addr(rqstp);
> @@ -2118,6 +2105,7 @@ nfsd4_create_session(struct svc_rqst *rqstp,
>  {
>  	struct sockaddr *sa = svc_addr(rqstp);
>  	struct nfs4_client *conf, *unconf;
> +	struct nfs4_client *old = NULL;
>  	struct nfsd4_session *new;
>  	struct nfsd4_conn *conn;
>  	struct nfsd4_clid_slot *cs_slot = NULL;
> @@ -2144,6 +2132,7 @@ nfsd4_create_session(struct svc_rqst *rqstp,
>  		goto out_free_session;
>  
>  	nfs4_lock_state();
> +	spin_lock(&nn->client_lock);
>  	unconf = find_unconfirmed_client(&cr_ses->clientid, true, nn);
>  	conf = find_confirmed_client(&cr_ses->clientid, true, nn);
>  	WARN_ON_ONCE(conf && unconf);
> @@ -2162,7 +2151,6 @@ nfsd4_create_session(struct svc_rqst *rqstp,
>  			goto out_free_conn;
>  		}
>  	} else if (unconf) {
> -		struct nfs4_client *old;
>  		if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) ||
>  		    !rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) {
>  			status = nfserr_clid_inuse;
> @@ -2180,10 +2168,10 @@ nfsd4_create_session(struct svc_rqst *rqstp,
>  		}
>  		old = find_confirmed_client_by_name(&unconf->cl_name, nn);
>  		if (old) {
> -			status = mark_client_expired(old);
> +			status = mark_client_expired_locked(old);
>  			if (status)
>  				goto out_free_conn;
> -			expire_client(old);
> +			unhash_client_locked(old);
>  		}
>  		move_to_confirmed(unconf);
>  		conf = unconf;
> @@ -2199,7 +2187,7 @@ nfsd4_create_session(struct svc_rqst *rqstp,
>  	cr_ses->flags &= ~SESSION4_RDMA;
>  
>  	init_session(rqstp, new, conf, cr_ses);
> -	nfsd4_init_conn(rqstp, conn, new);
> +	nfsd4_get_session_locked(new);
>  
>  	memcpy(cr_ses->sessionid.data, new->se_sessionid.data,
>  	       NFS4_MAX_SESSIONID_LEN);
> @@ -2208,11 +2196,20 @@ nfsd4_create_session(struct svc_rqst *rqstp,
>  
>  	/* cache solo and embedded create sessions under the state lock */
>  	nfsd4_cache_create_session(cr_ses, cs_slot, status);
> +	spin_unlock(&nn->client_lock);
> +	/* init connection and backchannel */
> +	nfsd4_init_conn(rqstp, conn, new);
> +	nfsd4_put_session(new);
>  	nfs4_unlock_state();
> +	if (old)
> +		expire_client(old);
>  	return status;
>  out_free_conn:
> +	spin_unlock(&nn->client_lock);
>  	nfs4_unlock_state();
>  	free_conn(conn);
> +	if (old)
> +		expire_client(old);
>  out_free_session:
>  	__free_session(new);
>  out_release_drc_mem:
> @@ -2657,6 +2654,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
>  			 struct nfsd4_setclientid_confirm *setclientid_confirm)
>  {
>  	struct nfs4_client *conf, *unconf;
> +	struct nfs4_client *old = NULL;
>  	nfs4_verifier confirm = setclientid_confirm->sc_confirm; 
>  	clientid_t * clid = &setclientid_confirm->sc_clientid;
>  	__be32 status;
> @@ -2666,6 +2664,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
>  		return nfserr_stale_clientid;
>  	nfs4_lock_state();
>  
> +	spin_lock(&nn->client_lock);
>  	conf = find_confirmed_client(clid, false, nn);
>  	unconf = find_unconfirmed_client(clid, false, nn);
>  	/*
> @@ -2689,21 +2688,29 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
>  	}
>  	status = nfs_ok;
>  	if (conf) { /* case 1: callback update */
> +		old = unconf;
> +		unhash_client_locked(old);
>  		nfsd4_change_callback(conf, &unconf->cl_cb_conn);
> -		nfsd4_probe_callback(conf);
> -		expire_client(unconf);
>  	} else { /* case 3: normal case; new or rebooted client */
> -		conf = find_confirmed_client_by_name(&unconf->cl_name, nn);
> -		if (conf) {
> -			status = mark_client_expired(conf);
> +		old = find_confirmed_client_by_name(&unconf->cl_name, nn);
> +		if (old) {
> +			status = mark_client_expired_locked(old);
>  			if (status)
>  				goto out;
> -			expire_client(conf);
> +			unhash_client_locked(old);
>  		}
>  		move_to_confirmed(unconf);
> -		nfsd4_probe_callback(unconf);
> +		conf = unconf;
>  	}
> +	get_client_locked(conf);
> +	spin_unlock(&nn->client_lock);
> +	nfsd4_probe_callback(conf);
> +	spin_lock(&nn->client_lock);
> +	put_client_renew_locked(conf);
>  out:
> +	spin_unlock(&nn->client_lock);
> +	if (old)
> +		expire_client(old);
>  	nfs4_unlock_state();
>  	return status;
>  }


-- 
Jeff Layton <jlayton@poochiereds.net>

[-- Attachment #2: 0001-nfsd-fix-build-when-CONFIG_NFSD_FAULT_INJECTION-is-e.patch --]
[-- Type: text/x-patch, Size: 1194 bytes --]

>From 67ed21725cee08343b25ebec364636110b904c41 Mon Sep 17 00:00:00 2001
From: Jeff Layton <jlayton@primarydata.com>
Date: Fri, 16 May 2014 14:15:04 -0400
Subject: [PATCH] nfsd: fix build when CONFIG_NFSD_FAULT_INJECTION is enabled

The patch entitled:

    NFSd: Protect session creation and client confirm using client_lock

...removes the mark_client_expired function, but doesn't fix the caller
in nfsd_forget_clients. Have that function call
mark_client_expired_locked after taking the cl_lock.

Signed-off-by: Jeff Layton <jlayton@primarydata.com>
---
 fs/nfsd/nfs4state.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index eedbbcf7be27..f5a7a08728b3 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -5435,7 +5435,13 @@ nfs4_check_open_reclaim(clientid_t *clid,
 
 u64 nfsd_forget_client(struct nfs4_client *clp, u64 max)
 {
-	if (mark_client_expired(clp))
+	int ret;
+	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
+
+	spin_lock(&nn->client_lock);
+	ret = mark_client_expired_locked(clp);
+	spin_unlock(&nn->client_lock);
+	if (ret)
 		return 0;
 	expire_client(clp);
 	return 1;
-- 
1.9.0


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

* Re: [PATCH 19/70] NFSd: Allow lockowners to hold several stateids
  2014-05-07 15:20                                       ` [PATCH 19/70] NFSd: Allow lockowners to hold several stateids Bruce Fields
@ 2014-05-22 12:20                                         ` Jeff Layton
  0 siblings, 0 replies; 118+ messages in thread
From: Jeff Layton @ 2014-05-22 12:20 UTC (permalink / raw)
  To: Bruce Fields; +Cc: Trond Myklebust, linux-nfs

On Wed, 7 May 2014 11:20:06 -0400
Bruce Fields <bfields@fieldses.org> wrote:

> Then did "NFSd: Lock owners are not per open stateid" introduce a
> temporary regression?
> 
> --b.
> 

No, I don't think it does. Even after that patch, you still only have
one lock stateid per lockowner. That patch is just adding some plumbing
that will eventually allow you to break that limitation.

That said, there are some problems with locking during the traversal of
the so_stateids list in this set that I'm looking at today.

> On Fri, Apr 18, 2014 at 02:44:13PM -0400, Trond Myklebust wrote:
> > Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
> > ---
> >  fs/nfsd/nfs4state.c | 46 +++++++++++++++++++++++++++++-----------------
> >  1 file changed, 29 insertions(+), 17 deletions(-)
> > 
> > diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> > index 0809e8355577..dad2f7b511b8 100644
> > --- a/fs/nfsd/nfs4state.c
> > +++ b/fs/nfsd/nfs4state.c
> > @@ -4390,6 +4390,19 @@ alloc_init_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp, struct
> >  	return stp;
> >  }
> >  
> > +static struct nfs4_ol_stateid *
> > +find_lock_stateid(struct nfs4_lockowner *lo, struct inode *inode)
> > +{
> > +	struct nfs4_ol_stateid *lst;
> > +
> > +	list_for_each_entry(lst, &lo->lo_owner.so_stateids, st_perstateowner) {
> > +		if (lst->st_file->fi_inode == inode)
> > +			return lst;
> > +	}
> > +	return NULL;
> > +}
> > +
> > +
> >  static int
> >  check_lock_length(u64 offset, u64 length)
> >  {
> > @@ -4419,25 +4432,24 @@ static __be32 lookup_or_create_lock_state(struct nfsd4_compound_state *cstate, s
> >  
> >  	lo = find_lockowner_str(fi->fi_inode, &cl->cl_clientid,
> >  				&lock->v.new.owner, nn);
> > -	if (lo) {
> > -		if (!cstate->minorversion)
> > -			return nfserr_bad_seqid;
> > -		/* XXX: a lockowner always has exactly one stateid: */
> > -		*lst = list_first_entry(&lo->lo_owner.so_stateids,
> > -				struct nfs4_ol_stateid, st_perstateowner);
> > -		return nfs_ok;
> > +	if (!lo) {
> > +		strhashval = ownerstr_hashval(cl->cl_clientid.cl_id,
> > +				&lock->v.new.owner);
> > +		lo = alloc_init_lock_stateowner(strhashval, cl, ost, lock);
> > +		if (lo == NULL)
> > +			return nfserr_jukebox;
> >  	}
> > -	strhashval = ownerstr_hashval(cl->cl_clientid.cl_id,
> > -			&lock->v.new.owner);
> > -	lo = alloc_init_lock_stateowner(strhashval, cl, ost, lock);
> > -	if (lo == NULL)
> > -		return nfserr_jukebox;
> > -	*lst = alloc_init_lock_stateid(lo, fi, ost);
> > +	if (!cstate->minorversion)
> > +		return nfserr_bad_seqid;
> > +	*lst = find_lock_stateid(lo, fi->fi_inode);
> >  	if (*lst == NULL) {
> > -		release_lockowner(lo);
> > -		return nfserr_jukebox;
> > +		*lst = alloc_init_lock_stateid(lo, fi, ost);
> > +		if (*lst == NULL) {
> > +			release_lockowner_if_empty(lo);
> > +			return nfserr_jukebox;
> > +		}
> > +		*new = true;
> >  	}
> > -	*new = true;
> >  	return nfs_ok;
> >  }
> >  
> > @@ -4596,7 +4608,7 @@ out:
> >  	if (filp)
> >  		fput(filp);
> >  	if (status && new_state)
> > -		release_lockowner(lock_sop);
> > +		release_lockowner_if_empty(lock_sop);
> >  	nfsd4_bump_seqid(cstate, status);
> >  	nfs4_unlock_state();
> >  	if (file_lock)
> > -- 
> > 1.9.0
> > 
> --
> 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


-- 
Jeff Layton <jlayton@poochiereds.net>

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

* Re: [PATCH 10/70] NFSd: Avoid taking state_lock while holding inode lock in nfsd_break_one_deleg
  2014-05-09  0:50                       ` Trond Myklebust
@ 2014-05-30 12:05                         ` Jeff Layton
  0 siblings, 0 replies; 118+ messages in thread
From: Jeff Layton @ 2014-05-30 12:05 UTC (permalink / raw)
  To: Trond Myklebust; +Cc: Bruce Fields, Linux NFS Mailing List

On Thu, 8 May 2014 20:50:12 -0400
Trond Myklebust <trond.myklebust@primarydata.com> wrote:

> On Tue, May 6, 2014 at 7:40 PM, Bruce Fields <bfields@fieldses.org> wrote:
> > On Fri, Apr 18, 2014 at 02:44:04PM -0400, Trond Myklebust wrote:
> >> state_lock is a heavily contended global lock. We don't want to grab
> >> that while simultaneously holding the inode->i_lock
> >> Instead do the list manipulations from the work queue context prior to
> >> starting the rpc call.
> >>
> >> Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
> >> ---
> >>  fs/nfsd/nfs4callback.c | 18 ++++++++++++++++--
> >>  fs/nfsd/nfs4state.c    | 25 +++++++++++++++----------
> >>  fs/nfsd/state.h        |  1 +
> >>  3 files changed, 32 insertions(+), 12 deletions(-)
> >>
> >> diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
> >> index 39c8ef875f91..8626cd6af4d1 100644
> >> --- a/fs/nfsd/nfs4callback.c
> >> +++ b/fs/nfsd/nfs4callback.c
> >> @@ -1009,9 +1009,8 @@ static void nfsd4_process_cb_update(struct nfsd4_callback *cb)
> >>               run_nfsd4_cb(cb);
> >>  }
> >>
> >> -static void nfsd4_do_callback_rpc(struct work_struct *w)
> >> +static void nfsd4_run_callback_rpc(struct nfsd4_callback *cb)
> >>  {
> >> -     struct nfsd4_callback *cb = container_of(w, struct nfsd4_callback, cb_work);
> >>       struct nfs4_client *clp = cb->cb_clp;
> >>       struct rpc_clnt *clnt;
> >>
> >> @@ -1029,11 +1028,25 @@ static void nfsd4_do_callback_rpc(struct work_struct *w)
> >>                       cb->cb_ops, cb);
> >>  }
> >>
> >> +static void nfsd4_do_callback_rpc(struct work_struct *w)
> >> +{
> >> +     struct nfsd4_callback *cb = container_of(w, struct nfsd4_callback, cb_work);
> >> +     nfsd4_run_callback_rpc(cb);
> >> +}
> >> +
> >>  void nfsd4_init_callback(struct nfsd4_callback *cb)
> >>  {
> >>       INIT_WORK(&cb->cb_work, nfsd4_do_callback_rpc);
> >>  }
> >>
> >> +static void nfsd4_do_cb_recall(struct work_struct *w)
> >> +{
> >> +     struct nfsd4_callback *cb = container_of(w, struct nfsd4_callback, cb_work);
> >> +
> >> +     nfsd4_prepare_cb_recall(cb->cb_op);
> >> +     nfsd4_run_callback_rpc(cb);
> >> +}
> >> +
> >>  void nfsd4_cb_recall(struct nfs4_delegation *dp)
> >>  {
> >>       struct nfsd4_callback *cb = &dp->dl_recall;
> >> @@ -1050,6 +1063,7 @@ void nfsd4_cb_recall(struct nfs4_delegation *dp)
> >>
> >>       INIT_LIST_HEAD(&cb->cb_per_client);
> >>       cb->cb_done = true;
> >> +     INIT_WORK(&cb->cb_work, nfsd4_do_cb_recall);
> >>
> >>       run_nfsd4_cb(&dp->dl_recall);
> >>  }
> >> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> >> index 6d691aa2bb27..85fcbc9ebd40 100644
> >> --- a/fs/nfsd/nfs4state.c
> >> +++ b/fs/nfsd/nfs4state.c
> >> @@ -2743,24 +2743,31 @@ out:
> >>       return ret;
> >>  }
> >>
> >> -static void nfsd_break_one_deleg(struct nfs4_delegation *dp)
> >> +void nfsd4_prepare_cb_recall(struct nfs4_delegation *dp)
> >>  {
> >>       struct nfs4_client *clp = dp->dl_stid.sc_client;
> >>       struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
> >>
> >> -     lockdep_assert_held(&state_lock);
> >> +     /*
> >> +      * We can't do this in nfsd_break_deleg_cb because it is
> >> +      * already holding inode->i_lock
> >> +      */
> >> +     spin_lock(&state_lock);
> >> +     if (list_empty(&dp->dl_recall_lru)) {
> >> +             dp->dl_time = get_seconds();
> >> +             list_add_tail(&dp->dl_recall_lru, &nn->del_recall_lru);
> >> +     }
> >> +     spin_unlock(&state_lock);
> >> +}
> >> +
> >> +static void nfsd_break_one_deleg(struct nfs4_delegation *dp)
> >> +{
> >>       /* We're assuming the state code never drops its reference
> >>        * without first removing the lease.  Since we're in this lease
> >>        * callback (and since the lease code is serialized by the kernel
> >>        * lock) we know the server hasn't removed the lease yet, we know
> >>        * it's safe to take a reference: */
> >>       atomic_inc(&dp->dl_count);
> >> -
> >> -     list_add_tail(&dp->dl_recall_lru, &nn->del_recall_lru);
> >> -
> >> -     /* Only place dl_time is set; protected by i_lock: */
> >> -     dp->dl_time = get_seconds();
> >> -
> >>       nfsd4_cb_recall(dp);
> >>  }
> >>
> >> @@ -2785,11 +2792,9 @@ static void nfsd_break_deleg_cb(struct file_lock *fl)
> >>        */
> >>       fl->fl_break_time = 0;
> >>
> >> -     spin_lock(&state_lock);
> >>       fp->fi_had_conflict = true;
> >>       list_for_each_entry(dp, &fp->fi_delegations, dl_perfile)
> >>               nfsd_break_one_deleg(dp);
> >> -     spin_unlock(&state_lock);
> >
> > Why do we know it's safe to traverse this list without holding
> > state_lock?
> 
> We're in a callback that is already holding the inode->i_lock, and so
> this is why we need to involve inode->i_lock when hashing/unhashing
> the delegation.
> 

Trond,

Yesterday on the town hall call, you mentioned that this patch would
prevent an ABBA deadlock in the existing code. I don't see that. The
existing code doesn't protect the fi_delegations list with the i_lock,
so we don't have any potential for deadlock there, AFAICT. Am I missing
something?

There *is* an existing bug in nfs4_setlease however. It adds to the
fi_delegations list without taking the recall_lock. Patch #8 in this
series fixes that.

I'll go ahead and send out that patch so we can get that fixed up, but
I'll hold off on this one though until the larger set is more ready as
it doesn't appear to be urgent.

> > --b.
> >
> >>  }
> >>
> >>  static
> >> diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
> >> index 1aa22f39fc65..02c5a203c738 100644
> >> --- a/fs/nfsd/state.h
> >> +++ b/fs/nfsd/state.h
> >> @@ -473,6 +473,7 @@ extern void nfsd4_cb_recall(struct nfs4_delegation *dp);
> >>  extern int nfsd4_create_callback_queue(void);
> >>  extern void nfsd4_destroy_callback_queue(void);
> >>  extern void nfsd4_shutdown_callback(struct nfs4_client *);
> >> +extern void nfsd4_prepare_cb_recall(struct nfs4_delegation *dp);
> >>  extern void nfs4_put_delegation(struct nfs4_delegation *dp);
> >>  extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(const char *name,
> >>                                                       struct nfsd_net *nn);
> >> --
> >> 1.9.0
> >>
> 
> 
> 


-- 
Jeff Layton <jlayton@primarydata.com>

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

end of thread, other threads:[~2014-05-30 12:05 UTC | newest]

Thread overview: 118+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-04-18 18:43 [PATCH 00/70] NFSd lock scalability patches Trond Myklebust
2014-04-18 18:43 ` [PATCH 01/70] NFSd: Ensure we clear the cstate->slot in nfsd4_proc_compound Trond Myklebust
2014-04-18 18:43   ` [PATCH 02/70] NFSd: Move default initialisers from create_client() to alloc_client() Trond Myklebust
2014-04-18 18:43     ` [PATCH 03/70] NFSd: call rpc_destroy_wait_queue() from free_client() Trond Myklebust
2014-04-18 18:43       ` [PATCH 04/70] NFSd: Remove 'inline' designation for free_client() Trond Myklebust
2014-04-18 18:43         ` [PATCH 05/70] nfsd4: rename recall_lock to state_lock Trond Myklebust
2014-04-18 18:44           ` [PATCH 06/70] nfsd4: use cl_lock to synchronize all stateid idr calls Trond Myklebust
2014-04-18 18:44             ` [PATCH 07/70] nfsd4: hash deleg stateid only on successful nfs4_set_delegation Trond Myklebust
2014-04-18 18:44               ` [PATCH 08/70] nfsd4: use state_lock for delegation hashing Trond Myklebust
2014-04-18 18:44                 ` [PATCH 09/70] NFSd: Mark nfs4_free_lockowner and nfs4_free_openowner as static functions Trond Myklebust
2014-04-18 18:44                   ` [PATCH 10/70] NFSd: Avoid taking state_lock while holding inode lock in nfsd_break_one_deleg Trond Myklebust
2014-04-18 18:44                     ` [PATCH 11/70] NFSd: Ensure delegation setup is safe w.r.t. break_lease() Trond Myklebust
2014-04-18 18:44                       ` [PATCH 12/70] NFSd: Add fine grained protection for the nfs4_file->fi_stateids list Trond Myklebust
2014-04-18 18:44                         ` [PATCH 13/70] NFSd: Clean up nfs4_preprocess_stateid_op Trond Myklebust
2014-04-18 18:44                           ` [PATCH 14/70] NFSd: Add a mutex to protect the NFSv4.0 open owner replay cache Trond Myklebust
2014-04-18 18:44                             ` [PATCH 15/70] NFSd: Add locking to the nfs4_file->fi_fds[] array Trond Myklebust
2014-04-18 18:44                               ` [PATCH 16/70] NFSd: Protect the nfs4_file delegation fields using the fi_lock Trond Myklebust
2014-04-18 18:44                                 ` [PATCH 17/70] NFSd: Lock owners are not per open stateid Trond Myklebust
2014-04-18 18:44                                   ` [PATCH 18/70] NFSd: Clean up helper __release_lock_stateid Trond Myklebust
2014-04-18 18:44                                     ` [PATCH 19/70] NFSd: Allow lockowners to hold several stateids Trond Myklebust
2014-04-18 18:44                                       ` [PATCH 20/70] NFSd: NFSv4 lock-owners are not associated to a specific file Trond Myklebust
2014-04-18 18:44                                         ` [PATCH 21/70] NFSd: Get rid of the lockowner_ino_hashtbl Trond Myklebust
2014-04-18 18:44                                           ` [PATCH 22/70] NFSd: Cleanup nfs4svc_encode_compoundres Trond Myklebust
2014-04-18 18:44                                             ` [PATCH 23/70] NFSd: Don't get a session reference without a client reference Trond Myklebust
2014-04-18 18:44                                               ` [PATCH 24/70] NFSd: Move the delegation reference counter into the struct nfs4_stid Trond Myklebust
2014-04-18 18:44                                                 ` [PATCH 25/70] NFSd: Simplify stateid management Trond Myklebust
2014-04-18 18:44                                                   ` [PATCH 26/70] NFSd: Fix delegation revocation Trond Myklebust
2014-04-18 18:44                                                     ` [PATCH 27/70] NFSd: Don't let the laundromat reap clients that are referenced Trond Myklebust
2014-04-18 18:44                                                       ` [PATCH 28/70] NFSd: Add reference counting to the lock and open stateids Trond Myklebust
2014-04-18 18:44                                                         ` [PATCH 29/70] NFSd: Add a struct nfs4_file field to struct nfs4_stid Trond Myklebust
2014-04-18 18:44                                                           ` [PATCH 30/70] NFSd: Replace delegation->dl_file with the dl_stid.sc_file Trond Myklebust
2014-04-18 18:44                                                             ` [PATCH 31/70] NFSd: Replace nfs4_ol_stateid->st_file with the st_stid.sc_file Trond Myklebust
2014-04-18 18:44                                                               ` [PATCH 32/70] NFSd: Ensure stateids remain unique until they are freed Trond Myklebust
2014-04-18 18:44                                                                 ` [PATCH 33/70] NFSd: Ensure atomicity of stateid destruction and idr tree removal Trond Myklebust
2014-04-18 18:44                                                                   ` [PATCH 34/70] NFSd: Fix atomicity of delegation counter Trond Myklebust
2014-04-18 18:44                                                                     ` [PATCH 35/70] NFSd: Slight cleanup of find_stateid() Trond Myklebust
2014-04-18 18:44                                                                       ` [PATCH 36/70] NFSd: Add reference counting to find_stateid Trond Myklebust
2014-04-18 18:44                                                                         ` [PATCH 37/70] NFSd: nfs4_preprocess_seqid_op should only set *stpp on success Trond Myklebust
2014-04-18 18:44                                                                           ` [PATCH 38/70] NFSd: Add reference counting to lock stateids Trond Myklebust
2014-04-18 18:44                                                                             ` [PATCH 39/70] NFSd: nfsd4_locku() must reference the lock stateid Trond Myklebust
2014-04-18 18:44                                                                               ` [PATCH 40/70] NFSd: Ensure that nfs4_open_delegation() references the delegation stateid Trond Myklebust
2014-04-18 18:44                                                                                 ` [PATCH 41/70] NFSd: nfsd4_process_open2() must reference " Trond Myklebust
2014-04-18 18:44                                                                                   ` [PATCH 42/70] NFSd: nfsd4_process_open2() must reference the open stateid Trond Myklebust
2014-04-18 18:44                                                                                     ` [PATCH 43/70] NFSd: Prepare nfsd4_close() for open stateid referencing Trond Myklebust
2014-04-18 18:44                                                                                       ` [PATCH 44/70] NFSd: nfsd4_open_confirm() must reference the open stateid Trond Myklebust
2014-04-18 18:44                                                                                         ` [PATCH 45/70] NFSd: Add reference counting to nfs4_preprocess_confirmed_seqid_op Trond Myklebust
2014-04-18 18:44                                                                                           ` [PATCH 46/70] NFSd: Migrate the stateid reference into nfs4_preprocess_seqid_op Trond Myklebust
2014-04-18 18:44                                                                                             ` [PATCH 47/70] NFSd: Migrate the stateid reference into nfs4_lookup_stateid() Trond Myklebust
2014-04-18 18:44                                                                                               ` [PATCH 48/70] NFSd: Migrate the stateid reference into nfs4_find_stateid_by_type() Trond Myklebust
2014-04-18 18:44                                                                                                 ` [PATCH 49/70] NFSd: Cleanup - Let nfsd4_lookup_stateid() take a cstate argument Trond Myklebust
2014-04-18 18:44                                                                                                   ` [PATCH 50/70] NFSd: Use the session->se_client in lookup_clientid() Trond Myklebust
2014-04-18 18:44                                                                                                     ` [PATCH 51/70] NFSd: Convert nfsd4_process_open1() to work with lookup_clientid() Trond Myklebust
2014-04-18 18:44                                                                                                       ` [PATCH 52/70] NFSd: Convert nfs4_check_open_reclaim() " Trond Myklebust
2014-04-18 18:44                                                                                                         ` [PATCH 53/70] NFSd: Ensure struct nfs4_client is unhashed before we try to destroy it Trond Myklebust
2014-04-18 18:44                                                                                                           ` [PATCH 54/70] NFSd: Ensure that the laundromat unhashes the client before releasing locks Trond Myklebust
2014-04-18 18:44                                                                                                             ` [PATCH 55/70] NFSd: Don't require client_lock in free_client Trond Myklebust
2014-04-18 18:44                                                                                                               ` [PATCH 56/70] NFSd: Move create_client() call outside the lock Trond Myklebust
2014-04-18 18:44                                                                                                                 ` [PATCH 57/70] NFSd: Protect unconfirmed client creation using client_lock Trond Myklebust
2014-04-18 18:44                                                                                                                   ` [PATCH 58/70] NFSd: Protect session creation and client confirm " Trond Myklebust
2014-04-18 18:44                                                                                                                     ` [PATCH 59/70] NFSd: Protect nfsd4_destroy_clientid " Trond Myklebust
2014-04-18 18:44                                                                                                                       ` [PATCH 60/70] NFSd: Ensure lookup_clientid() takes client_lock Trond Myklebust
2014-04-18 18:44                                                                                                                         ` [PATCH 61/70] NFSd: Remove nfs4_lock_state(): nfs4_preprocess_stateid_op() Trond Myklebust
2014-04-18 18:44                                                                                                                           ` [PATCH 62/70] NFSd: Remove nfs4_lock_state(): nfsd4_test_stateid/nfsd4_free_stateid Trond Myklebust
2014-04-18 18:44                                                                                                                             ` [PATCH 63/70] NFSd: Remove nfs4_lock_state(): nfsd4_release_lockowner Trond Myklebust
2014-04-18 18:44                                                                                                                               ` [PATCH 64/70] NFSd: Remove nfs4_lock_state(): nfsd4_lock/locku/lockt() Trond Myklebust
2014-04-18 18:44                                                                                                                                 ` [PATCH 65/70] NFSd: Remove nfs4_lock_state(): nfsd4_open_downgrade + nfsd4_close Trond Myklebust
2014-04-18 18:45                                                                                                                                   ` [PATCH 66/70] NFSd: Remove nfs4_lock_state(): nfsd4_delegreturn() Trond Myklebust
2014-04-18 18:45                                                                                                                                     ` [PATCH 67/70] NFSd: Remove nfs4_lock_state(): nfsd4_open and nfsd4_open_confirm Trond Myklebust
2014-04-18 18:45                                                                                                                                       ` [PATCH 68/70] NFSd: Remove nfs4_lock_state(): exchange_id, create/destroy_session() Trond Myklebust
2014-04-18 18:45                                                                                                                                         ` [PATCH 69/70] NFSd: Remove nfs4_lock_state(): setclientid, setclientid_confirm, renew Trond Myklebust
2014-04-18 18:45                                                                                                                                           ` [PATCH 70/70] NFSd: Remove nfs4_lock_state(): reclaim_complete() Trond Myklebust
2014-05-05  8:53                                                                                                                         ` [PATCH 60/70] NFSd: Ensure lookup_clientid() takes client_lock Christoph Hellwig
2014-05-16 18:19                                                                                                                     ` [PATCH 58/70] NFSd: Protect session creation and client confirm using client_lock Jeff Layton
2014-04-19 14:56                                                                                                     ` [PATCH 50/70] NFSd: Use the session->se_client in lookup_clientid() Christoph Hellwig
2014-05-07 20:18                                                                                                     ` Bruce Fields
2014-05-07 20:21                                                                                                       ` Bruce Fields
2014-05-07 19:58                                                                           ` [PATCH 37/70] NFSd: nfs4_preprocess_seqid_op should only set *stpp on success Bruce Fields
2014-05-08 19:48                                                                             ` Trond Myklebust
2014-04-19 14:50                                                                         ` [PATCH 36/70] NFSd: Add reference counting to find_stateid Christoph Hellwig
2014-04-21 15:37                                                                           ` Trond Myklebust
2014-04-19 14:41                                                                       ` [PATCH 35/70] NFSd: Slight cleanup of find_stateid() Christoph Hellwig
2014-04-21 13:31                                                                         ` Trond Myklebust
2014-04-19 15:51                                                                     ` [PATCH 34/70] NFSd: Fix atomicity of delegation counter Christoph Hellwig
2014-04-21 15:58                                                                       ` Trond Myklebust
2014-04-19 14:40                                                             ` [PATCH 30/70] NFSd: Replace delegation->dl_file with the dl_stid.sc_file Christoph Hellwig
2014-04-21 13:13                                                               ` Trond Myklebust
2014-05-05  9:01                                                             ` Christoph Hellwig
2014-05-07 19:25                                                           ` [PATCH 29/70] NFSd: Add a struct nfs4_file field to struct nfs4_stid Bruce Fields
2014-05-08 19:40                                                             ` Trond Myklebust
2014-05-09  7:34                                                               ` Christoph Hellwig
2014-05-07 19:20                                                       ` [PATCH 27/70] NFSd: Don't let the laundromat reap clients that are referenced Bruce Fields
2014-05-07 18:46                                                     ` [PATCH 26/70] NFSd: Fix delegation revocation Bruce Fields
2014-05-07 16:21                                                   ` [PATCH 25/70] NFSd: Simplify stateid management Bruce Fields
2014-04-19 14:38                                           ` [PATCH 21/70] NFSd: Get rid of the lockowner_ino_hashtbl Christoph Hellwig
2014-04-21 13:08                                             ` Trond Myklebust
2014-05-07 15:20                                       ` [PATCH 19/70] NFSd: Allow lockowners to hold several stateids Bruce Fields
2014-05-22 12:20                                         ` Jeff Layton
2014-04-19 14:35                               ` [PATCH 15/70] NFSd: Add locking to the nfs4_file->fi_fds[] array Christoph Hellwig
2014-04-21 13:01                                 ` Trond Myklebust
2014-04-21 13:14                                   ` Christoph Hellwig
2014-04-21 13:16                                     ` Christoph Hellwig
2014-05-06 23:41                       ` [PATCH 11/70] NFSd: Ensure delegation setup is safe w.r.t. break_lease() Bruce Fields
2014-05-09  0:56                         ` Trond Myklebust
2014-05-06 23:40                     ` [PATCH 10/70] NFSd: Avoid taking state_lock while holding inode lock in nfsd_break_one_deleg Bruce Fields
2014-05-09  0:50                       ` Trond Myklebust
2014-05-30 12:05                         ` Jeff Layton
2014-04-19 15:56                 ` [PATCH 08/70] nfsd4: use state_lock for delegation hashing Christoph Hellwig
2014-05-06 16:48             ` [PATCH 06/70] nfsd4: use cl_lock to synchronize all stateid idr calls Bruce Fields
2014-05-06 16:40         ` [PATCH 04/70] NFSd: Remove 'inline' designation for free_client() Bruce Fields
2014-05-06 16:37       ` [PATCH 03/70] NFSd: call rpc_destroy_wait_queue() from free_client() Bruce Fields
2014-05-06 16:37     ` [PATCH 02/70] NFSd: Move default initialisers from create_client() to alloc_client() Bruce Fields
2014-05-06 15:32   ` [PATCH 01/70] NFSd: Ensure we clear the cstate->slot in nfsd4_proc_compound Bruce Fields
2014-05-06 16:36     ` Bruce Fields
2014-04-19 15:04 ` [PATCH 00/70] NFSd lock scalability patches Christoph Hellwig
2014-04-19 20:58 ` Bruce Fields
2014-05-07 20:29   ` Bruce Fields
2014-05-08 20:16     ` Trond Myklebust
2014-04-21 15:01 ` Christoph Hellwig

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.