All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 000/117] nfsd: eliminate the client_mutex
@ 2014-06-26 19:11 Jeff Layton
  2014-06-26 19:11 ` [PATCH v2 001/117] nfsd: fix file access refcount leak when nfsd4_truncate fails Jeff Layton
                   ` (118 more replies)
  0 siblings, 119 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:11 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

v2 changes:
- rebased on top of v3.16-rc2

- fixed up checkpatch warnings (I'm really starting to hate that 80 column
  limit warning)

- fleshed out patch descriptions. Most of them should now say they are a
  necessary step toward client_mutex removal when it's not otherwise
  obvious. Also, when things touch outside of fs/nfsd, I added Cc lines
  for the appropriate maintainers.

- reordered patches to put more of the ones that don't affect locking
  near the front of the queue. This may make it easier to merge this
  piecemeal.

- I think I have addressed all of Christoph's review comments -- let me
  know if I missed any. For now, I left the Documentation/ patch intact,
  but we don't need to merge it at all if it's objectionable. I may end
  up transplanting it into comments but I ran short of time so I'll defer
  it for now.

- fix race that can occur between concurrent FREE_STATEID and CLOSE. As
  part of that fix, the cl_lock thrashing (and ensuing races) that could
  occur when a stateowner was released has also been eliminated.

- overhaul of access/deny mode handling. Christoph was correct to be
  suspicious. It didn't properly handle the case where a stateid with a
  deny mode was released or downgraded. As a bonus, the new code should be
  much more efficient when you have a long list of stateids as we no longer
  need to walk the entire list to check for deny mode conflicts. I also
  did some cleanup of the file access handling.

- ensure that dl_recall_lru list entries are dequeued before calling
  revoke_delegation (potential memory corruptor).

- Included Christophs fix for the file access leak when nfsd4_truncate
  fails. I took the liberty of adding a commit log message for it and a
  SoB line. Let me know if that's a problem and we can rework it.

For completeness' sake, I'm just re-posting my entire patch queue for
the v2 series. These are also available in my tree at samba.org:

    http://git.samba.org/?p=jlayton/linux.git;a=shortlog;h=refs/heads/nfsd-devel

I'd still like to see this merged for v3.17, so it would be ideal to
merge this into linux-next soon if possible. Bruce, please let me know
what you think the prospects are.

Original cover letter text follows:

-----------------------[snip]--------------------------

Here it is. The long awaited removal of the client_mutex from knfsd.  As
many of us are aware, one of the major bottlenecks in NFSv4 serving is
the fact that all compounds are processed while holding a single, global
mutex.

This has an obvious detrimental effect on scalability. I've heard
anecdotal reports of 10x slowdowns with v4 serving vs. v3 on the same
machine, primarily due to it.

This patchset eliminates that mutex and (hopefully!) the bottleneck that
it imposes. The basic idea is to add refcounting to most of the objects
that compounds deal with to ensure that they are pinned while in use.
Spinlocks are used to protect things like the hashtables and trees that
track the objects.

Benny started this set quite some time ago, and Trond took up the torch
early this spring. He then handed it to me to clean up the remaining
bits about a month ago.

Benny Halevy (1):
  nfsd4: use cl_lock to synchronize all stateid idr calls

Christoph Hellwig (1):
  nfsd: fix file access refcount leak when nfsd4_truncate fails

Jeff Layton (54):
  nfsd: fix return of nfs4_acl_write_who
  nfsd: add __force to opaque verifier field casts
  nfsd: clean up sparse endianness warnings in nfscache.c
  nfsd: nfsd_splice_read and nfsd_readv should return __be32
  nfsd: add appropriate __force directives to filehandle generation code
  nfsd: properly handle embedded newlines in fault_injection input
  nfsd: wait to initialize work struct just prior to using it
  nfsd: Avoid taking state_lock while holding inode lock in
    nfsd_break_one_deleg
  nfsd: Allow lockowners to hold several stateids
  nfsd: clean up nfs4_release_lockowner
  nfsd: declare v4.1+ openowners confirmed on creation
  nfsd: refactor nfs4_file_get_access and nfs4_file_put_access
  nfsd: remove nfs4_file_put_fd
  nfsd: ensure that nfs4_file_get_access enforces deny modes
  nfsd: cleanup nfs4_check_open
  locks: add file_has_lease to prevent delegation break races
  nfsd: Protect the nfs4_file delegation fields using the fi_lock
  nfsd: Ensure atomicity of stateid destruction and idr tree removal
  nfsd: Cleanup the freeing of stateids
  nfsd: do filp_close in sc_free callback for lock stateids
  nfsd: Add locking to protect the state owner lists
  nfsd: clean up races in lock stateid searching and creation
  nfsd: ensure atomicity in nfsd4_free_stateid and
    nfsd4_validate_stateid
  nfsd: clean up lockowner refcounting when finding them
  nfsd: add an operation for unhashing a stateowner
  nfsd: clean up refcounting for lockowners
  nfsd: make openstateids hold references to their openowners
  nfsd: don't allow CLOSE to proceed until refcount on stateid drops
  lockdep: add lockdep_assert_not_held
  nfsd: add locking to stateowner release
  nfsd: optimize destroy_lockowner cl_lock thrashing
  nfsd: close potential race in nfsd4_free_stateid
  nfsd: reduce cl_lock thrashing in release_openowner
  nfsd: don't thrash the cl_lock while freeing an open stateid
  nfsd: Protect session creation and client confirm using client_lock
  nfsd: protect the close_lru list and oo_last_closed_stid with
    client_lock
  nfsd: ensure that clp->cl_revoked list is protected by clp->cl_lock
  nfsd: move unhash_client_locked call into mark_client_expired_locked
  nfsd: don't destroy client if mark_client_expired_locked fails
  nfsd: don't destroy clients that are busy
  nfsd: protect clid and verifier generation with client_lock
  nfsd: abstract out the get and set routines into the fault injection
    ops
  nfsd: add a forget_clients "get" routine with proper locking
  nfsd: add a forget_client set_clnt routine
  nfsd: add nfsd_inject_forget_clients
  nfsd: add a list_head arg to nfsd_foreach_client_lock
  nfsd: add more granular locking to forget_locks fault injector
  nfsd: add more granular locking to forget_openowners fault injector
  nfsd: add more granular locking to *_delegations fault injectors
  nfsd: remove old fault injection infrastructure
  nfsd: remove nfs4_lock_state: nfs4_laundromat
  nfsd: remove nfs4_lock_state: nfs4_state_shutdown_net
  nfsd: remove the client_mutex and the nfs4_lock/unlock_state wrappers
  nfsd: add file documenting new state object model

Trond Myklebust (61):
  nfsd: Protect addition to the file_hashtbl
  nfsd: nfs4_preprocess_seqid_op should only set *stpp on success
  nfsd: Cleanup nfs4svc_encode_compoundres
  nfsd: Don't get a session reference without a client reference
  nfsd: Allow struct nfsd4_compound_state to cache the nfs4_client
  nfsd: lock owners are not per open stateid
  nfsd: NFSv4 lock-owners are not associated to a specific file
  nfsd: Cleanup - Let nfsd4_lookup_stateid() take a cstate argument
  nfsd: clean up nfsd4_close_open_stateid
  nfsd: Cache the client that was looked up in lookup_clientid()
  nfsd: Convert nfsd4_process_open1() to work with lookup_clientid()
  nfsd: Always use lookup_clientid() in nfsd4_process_open1
  nfsd: Convert nfs4_check_open_reclaim() to work with lookup_clientid()
  nfsd: Move the delegation reference counter into the struct nfs4_stid
  nfsd: Add fine grained protection for the nfs4_file->fi_stateids list
  nfsd: Add a mutex to protect the NFSv4.0 open owner replay cache
  nfsd: Add locking to the nfs4_file->fi_fds[] array
  nfsd: clean up helper __release_lock_stateid
  nfsd: Simplify stateid management
  nfsd: Fix delegation revocation
  nfsd: Add reference counting to the lock and open stateids
  nfsd: Add a struct nfs4_file field to struct nfs4_stid
  nfsd: Replace nfs4_ol_stateid->st_file with the st_stid.sc_file
  nfsd: Ensure stateids remain unique until they are freed
  nfsd: Convert delegation counter to an atomic_long_t type
  nfsd: Slight cleanup of find_stateid()
  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: Add reference counting to state owners
  nfsd: Keep a reference to the open stateid for the NFSv4.0 replay
    cache
  nfsd: Make lock stateid take a reference to the lockowner
  nfsd: Protect adding/removing open state owners using client_lock
  nfsd: Protect adding/removing lock owners using client_lock
  nfsd: Move the open owner hash table into struct nfs4_client
  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 nfsd4_destroy_clientid using client_lock
  nfsd: Ensure lookup_clientid() takes client_lock
  nfsd: Add lockdep assertions to document the nfs4_client/session
    locking
  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()

 .../filesystems/nfs/nfsd4-state-objects.txt        |  105 +
 fs/locks.c                                         |   26 +
 fs/nfsd/fault_inject.c                             |  138 +-
 fs/nfsd/netns.h                                    |   11 +-
 fs/nfsd/nfs4acl.c                                  |    2 +-
 fs/nfsd/nfs4callback.c                             |   22 +-
 fs/nfsd/nfs4proc.c                                 |   24 +-
 fs/nfsd/nfs4state.c                                | 2818 ++++++++++++++------
 fs/nfsd/nfs4xdr.c                                  |   17 +-
 fs/nfsd/nfscache.c                                 |   13 +-
 fs/nfsd/nfsfh.c                                    |   10 +-
 fs/nfsd/nfsfh.h                                    |   15 +-
 fs/nfsd/state.h                                    |   87 +-
 fs/nfsd/vfs.c                                      |    7 +-
 fs/nfsd/vfs.h                                      |    4 +-
 fs/nfsd/xdr4.h                                     |    8 +-
 include/linux/fs.h                                 |    6 +
 include/linux/lockdep.h                            |    4 +
 18 files changed, 2271 insertions(+), 1046 deletions(-)
 create mode 100644 Documentation/filesystems/nfs/nfsd4-state-objects.txt

-- 
1.9.3


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

* [PATCH v2 001/117] nfsd: fix file access refcount leak when nfsd4_truncate fails
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
@ 2014-06-26 19:11 ` Jeff Layton
  2014-06-26 19:24   ` Jeff Layton
  2014-06-26 19:11 ` [PATCH v2 002/117] nfsd: fix return of nfs4_acl_write_who Jeff Layton
                   ` (117 subsequent siblings)
  118 siblings, 1 reply; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:11 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Christoph Hellwig

From: Christoph Hellwig <hch@infradead.org>

nfsd4_process_open2 will currently will get access to the file, and then
call nfsd4_truncate to (possibly) truncate it. If that operation fails
though, then the access references will never be released as the
nfs4_ol_stateid is never initialized.

Fix by moving the nfsd4_truncate call into nfs4_get_vfs_file, ensuring
that the refcounts are properly put if the truncate fails.

Signed-off-by: Jeff Layton <jlayton@primarydata.com>
Signed-off-by: Christoph Hellwig <hch@infradead.org>
---
 fs/nfsd/nfs4state.c | 62 ++++++++++++++++++++++++++---------------------------
 1 file changed, 30 insertions(+), 32 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 2204e1fe5725..f9049516bfae 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -3042,6 +3042,21 @@ static inline int nfs4_access_to_access(u32 nfs4_access)
 	return flags;
 }
 
+static inline __be32
+nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh,
+		struct nfsd4_open *open)
+{
+	struct iattr iattr = {
+		.ia_valid = ATTR_SIZE,
+		.ia_size = 0,
+	};
+	if (!open->op_truncate)
+		return 0;
+	if (!(open->op_share_access & NFS4_SHARE_ACCESS_WRITE))
+		return nfserr_inval;
+	return nfsd_setattr(rqstp, fh, &iattr, 0, (time_t)0);
+}
+
 static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
 		struct svc_fh *cur_fh, struct nfsd4_open *open)
 {
@@ -3053,53 +3068,39 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
 		status = nfsd_open(rqstp, cur_fh, S_IFREG, access,
 			&fp->fi_fds[oflag]);
 		if (status)
-			return status;
+			goto out;
 	}
 	nfs4_file_get_access(fp, oflag);
 
+	status = nfsd4_truncate(rqstp, cur_fh, open);
+	if (status)
+		goto out_put_access;
+
 	return nfs_ok;
-}
 
-static inline __be32
-nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh,
-		struct nfsd4_open *open)
-{
-	struct iattr iattr = {
-		.ia_valid = ATTR_SIZE,
-		.ia_size = 0,
-	};
-	if (!open->op_truncate)
-		return 0;
-	if (!(open->op_share_access & NFS4_SHARE_ACCESS_WRITE))
-		return nfserr_inval;
-	return nfsd_setattr(rqstp, fh, &iattr, 0, (time_t)0);
+out_put_access:
+	nfs4_file_put_access(fp, oflag);
+out:
+	return status;
 }
 
 static __be32
 nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp, struct nfsd4_open *open)
 {
 	u32 op_share_access = open->op_share_access;
-	bool new_access;
 	__be32 status;
 
-	new_access = !test_access(op_share_access, stp);
-	if (new_access) {
+	if (!test_access(op_share_access, stp))
 		status = nfs4_get_vfs_file(rqstp, fp, cur_fh, open);
-		if (status)
-			return status;
-	}
-	status = nfsd4_truncate(rqstp, cur_fh, open);
-	if (status) {
-		if (new_access) {
-			int oflag = nfs4_access_to_omode(op_share_access);
-			nfs4_file_put_access(fp, oflag);
-		}
+	else
+		status = nfsd4_truncate(rqstp, cur_fh, open);
+
+	if (status)
 		return status;
-	}
+
 	/* remember the open */
 	set_access(op_share_access, stp);
 	set_deny(open->op_share_deny, stp);
-
 	return nfs_ok;
 }
 
@@ -3350,9 +3351,6 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
 		status = nfs4_get_vfs_file(rqstp, fp, current_fh, open);
 		if (status)
 			goto out;
-		status = nfsd4_truncate(rqstp, current_fh, open);
-		if (status)
-			goto out;
 		stp = open->op_stp;
 		open->op_stp = NULL;
 		init_open_stateid(stp, fp, open);
-- 
1.9.3


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

* [PATCH v2 002/117] nfsd: fix return of nfs4_acl_write_who
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
  2014-06-26 19:11 ` [PATCH v2 001/117] nfsd: fix file access refcount leak when nfsd4_truncate fails Jeff Layton
@ 2014-06-26 19:11 ` Jeff Layton
  2014-06-26 19:11 ` [PATCH v2 003/117] nfsd: add __force to opaque verifier field casts Jeff Layton
                   ` (116 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:11 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

AFAICT, the only way to hit this error is to pass this function a bogus
"who" value. In that case, we probably don't want to return -1 as that
could get sent back to the client. Turn this into nfserr_serverfault,
which is a more appropriate error for a server bug like this.

Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Jeff Layton <jlayton@primarydata.com>
---
 fs/nfsd/nfs4acl.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c
index d714156a19fd..b0cf00d3ee7d 100644
--- a/fs/nfsd/nfs4acl.c
+++ b/fs/nfsd/nfs4acl.c
@@ -935,5 +935,5 @@ __be32 nfs4_acl_write_who(struct xdr_stream *xdr, int who)
 		return 0;
 	}
 	WARN_ON_ONCE(1);
-	return -1;
+	return nfserr_serverfault;
 }
-- 
1.9.3


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

* [PATCH v2 003/117] nfsd: add __force to opaque verifier field casts
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
  2014-06-26 19:11 ` [PATCH v2 001/117] nfsd: fix file access refcount leak when nfsd4_truncate fails Jeff Layton
  2014-06-26 19:11 ` [PATCH v2 002/117] nfsd: fix return of nfs4_acl_write_who Jeff Layton
@ 2014-06-26 19:11 ` Jeff Layton
  2014-06-26 19:11 ` [PATCH v2 004/117] nfsd: clean up sparse endianness warnings in nfscache.c Jeff Layton
                   ` (115 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:11 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

sparse complains that we're stuffing non-byte-swapped values into
__be32's here. Since they're supposed to be opaque, it doesn't matter
much. Just add __force to make sparse happy.

Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Jeff Layton <jlayton@primarydata.com>
---
 fs/nfsd/nfs4proc.c  | 8 ++++++--
 fs/nfsd/nfs4state.c | 8 ++++++--
 2 files changed, 12 insertions(+), 4 deletions(-)

diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 6851b003f2a4..8904c9cbcb89 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -581,8 +581,12 @@ static void gen_boot_verifier(nfs4_verifier *verifier, struct net *net)
 	__be32 verf[2];
 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 
-	verf[0] = (__be32)nn->nfssvc_boot.tv_sec;
-	verf[1] = (__be32)nn->nfssvc_boot.tv_usec;
+	/*
+	 * This is opaque to client, so no need to byte-swap. Use
+	 * __force to keep sparse happy
+	 */
+	verf[0] = (__force __be32)nn->nfssvc_boot.tv_sec;
+	verf[1] = (__force __be32)nn->nfssvc_boot.tv_usec;
 	memcpy(verifier->data, verf, sizeof(verifier->data));
 }
 
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index f9049516bfae..c473bd6d52c8 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1421,8 +1421,12 @@ static void gen_confirm(struct nfs4_client *clp)
 	__be32 verf[2];
 	static u32 i;
 
-	verf[0] = (__be32)get_seconds();
-	verf[1] = (__be32)i++;
+	/*
+	 * This is opaque to client, so no need to byte-swap. Use
+	 * __force to keep sparse happy
+	 */
+	verf[0] = (__force __be32)get_seconds();
+	verf[1] = (__force __be32)i++;
 	memcpy(clp->cl_confirm.data, verf, sizeof(clp->cl_confirm.data));
 }
 
-- 
1.9.3


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

* [PATCH v2 004/117] nfsd: clean up sparse endianness warnings in nfscache.c
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (2 preceding siblings ...)
  2014-06-26 19:11 ` [PATCH v2 003/117] nfsd: add __force to opaque verifier field casts Jeff Layton
@ 2014-06-26 19:11 ` Jeff Layton
  2014-06-26 19:11 ` [PATCH v2 005/117] nfsd: nfsd_splice_read and nfsd_readv should return __be32 Jeff Layton
                   ` (114 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:11 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

We currently hash the XID to determine a hash bucket to use for the
reply cache entry, which is fed into hash_32 without byte-swapping it.
Add __force to make sparse happy, and add some comments to explain
why.

Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Jeff Layton <jlayton@primarydata.com>
---
 fs/nfsd/nfscache.c | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c
index 6040da8830ff..ff9567633245 100644
--- a/fs/nfsd/nfscache.c
+++ b/fs/nfsd/nfscache.c
@@ -221,7 +221,12 @@ static void
 hash_refile(struct svc_cacherep *rp)
 {
 	hlist_del_init(&rp->c_hash);
-	hlist_add_head(&rp->c_hash, cache_hash + hash_32(rp->c_xid, maskbits));
+	/*
+	 * No point in byte swapping c_xid since we're just using it to pick
+	 * a hash bucket.
+	 */
+	hlist_add_head(&rp->c_hash, cache_hash +
+			hash_32((__force u32)rp->c_xid, maskbits));
 }
 
 /*
@@ -356,7 +361,11 @@ nfsd_cache_search(struct svc_rqst *rqstp, __wsum csum)
 	struct hlist_head 	*rh;
 	unsigned int		entries = 0;
 
-	rh = &cache_hash[hash_32(rqstp->rq_xid, maskbits)];
+	/*
+	 * No point in byte swapping rq_xid since we're just using it to pick
+	 * a hash bucket.
+	 */
+	rh = &cache_hash[hash_32((__force u32)rqstp->rq_xid, maskbits)];
 	hlist_for_each_entry(rp, rh, c_hash) {
 		++entries;
 		if (nfsd_cache_match(rqstp, csum, rp)) {
-- 
1.9.3


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

* [PATCH v2 005/117] nfsd: nfsd_splice_read and nfsd_readv should return __be32
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (3 preceding siblings ...)
  2014-06-26 19:11 ` [PATCH v2 004/117] nfsd: clean up sparse endianness warnings in nfscache.c Jeff Layton
@ 2014-06-26 19:11 ` Jeff Layton
  2014-06-26 19:11 ` [PATCH v2 006/117] nfsd: add appropriate __force directives to filehandle generation code Jeff Layton
                   ` (113 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:11 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

The callers expect a __be32 return and the functions they call return
__be32, so having these return int is just wrong. Also, nfsd_finish_read
can be made static.

Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Jeff Layton <jlayton@primarydata.com>
---
 fs/nfsd/vfs.c | 7 ++++---
 fs/nfsd/vfs.h | 4 ++--
 2 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 140c496f612c..960f9e0bb88f 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -820,7 +820,8 @@ static int nfsd_direct_splice_actor(struct pipe_inode_info *pipe,
 	return __splice_from_pipe(pipe, sd, nfsd_splice_actor);
 }
 
-__be32 nfsd_finish_read(struct file *file, unsigned long *count, int host_err)
+static __be32
+nfsd_finish_read(struct file *file, unsigned long *count, int host_err)
 {
 	if (host_err >= 0) {
 		nfsdstats.io_read += host_err;
@@ -831,7 +832,7 @@ __be32 nfsd_finish_read(struct file *file, unsigned long *count, int host_err)
 		return nfserrno(host_err);
 }
 
-int nfsd_splice_read(struct svc_rqst *rqstp,
+__be32 nfsd_splice_read(struct svc_rqst *rqstp,
 		     struct file *file, loff_t offset, unsigned long *count)
 {
 	struct splice_desc sd = {
@@ -847,7 +848,7 @@ int nfsd_splice_read(struct svc_rqst *rqstp,
 	return nfsd_finish_read(file, count, host_err);
 }
 
-int nfsd_readv(struct file *file, loff_t offset, struct kvec *vec, int vlen,
+__be32 nfsd_readv(struct file *file, loff_t offset, struct kvec *vec, int vlen,
 		unsigned long *count)
 {
 	mm_segment_t oldfs;
diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h
index 91b6ae3f658b..b84aef50f55d 100644
--- a/fs/nfsd/vfs.h
+++ b/fs/nfsd/vfs.h
@@ -74,9 +74,9 @@ struct raparms;
 __be32		nfsd_get_tmp_read_open(struct svc_rqst *, struct svc_fh *,
 				struct file **, struct raparms **);
 void		nfsd_put_tmp_read_open(struct file *, struct raparms *);
-int		nfsd_splice_read(struct svc_rqst *,
+__be32		nfsd_splice_read(struct svc_rqst *,
 				struct file *, loff_t, unsigned long *);
-int		nfsd_readv(struct file *, loff_t, struct kvec *, int,
+__be32		nfsd_readv(struct file *, loff_t, struct kvec *, int,
 				unsigned long *);
 __be32 		nfsd_read(struct svc_rqst *, struct svc_fh *,
 				loff_t, struct kvec *, int, unsigned long *);
-- 
1.9.3


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

* [PATCH v2 006/117] nfsd: add appropriate __force directives to filehandle generation code
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (4 preceding siblings ...)
  2014-06-26 19:11 ` [PATCH v2 005/117] nfsd: nfsd_splice_read and nfsd_readv should return __be32 Jeff Layton
@ 2014-06-26 19:11 ` Jeff Layton
  2014-06-26 19:11 ` [PATCH v2 007/117] nfsd: properly handle embedded newlines in fault_injection input Jeff Layton
                   ` (112 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:11 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

The filehandle structs all use host-endian values, but will sometimes
stuff big-endian values into those fields. This is OK since these
values are opaque to the client, but it confuses sparse. Add __force to
make it clear that we are doing this intentionally.

Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Jeff Layton <jlayton@primarydata.com>
---
 fs/nfsd/nfsfh.c | 10 +++++++++-
 fs/nfsd/nfsfh.h | 15 +++++++++++----
 2 files changed, 20 insertions(+), 5 deletions(-)

diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index ec8393418154..6ae5219c478e 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -162,7 +162,15 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp)
 			/* deprecated, convert to type 3 */
 			len = key_len(FSID_ENCODE_DEV)/4;
 			fh->fh_fsid_type = FSID_ENCODE_DEV;
-			fh->fh_fsid[0] = new_encode_dev(MKDEV(ntohl(fh->fh_fsid[0]), ntohl(fh->fh_fsid[1])));
+			/*
+			 * struct knfsd_fh uses host-endian fields, which are
+			 * sometimes used to hold net-endian values. This
+			 * confuses sparse, so we must use __force here to
+			 * keep it from complaining.
+			 */
+			fh->fh_fsid[0] = new_encode_dev(
+				MKDEV(ntohl((__force __be32)fh->fh_fsid[0]),
+				      ntohl((__force __be32)fh->fh_fsid[1])));
 			fh->fh_fsid[1] = fh->fh_fsid[2];
 		}
 		data_left -= len;
diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h
index 2e89e70ac15c..08236d70c667 100644
--- a/fs/nfsd/nfsfh.h
+++ b/fs/nfsd/nfsfh.h
@@ -73,8 +73,15 @@ enum fsid_source {
 extern enum fsid_source fsid_source(struct svc_fh *fhp);
 
 
-/* This might look a little large to "inline" but in all calls except
+/*
+ * This might look a little large to "inline" but in all calls except
  * one, 'vers' is constant so moste of the function disappears.
+ *
+ * In some cases the values are considered to be host endian and in
+ * others, net endian. fsidv is always considered to be u32 as the
+ * callers don't know which it will be. So we must use __force to keep
+ * sparse from complaining. Since these values are opaque to the
+ * client, that shouldn't be a problem.
  */
 static inline void mk_fsid(int vers, u32 *fsidv, dev_t dev, ino_t ino,
 			   u32 fsid, unsigned char *uuid)
@@ -82,7 +89,7 @@ static inline void mk_fsid(int vers, u32 *fsidv, dev_t dev, ino_t ino,
 	u32 *up;
 	switch(vers) {
 	case FSID_DEV:
-		fsidv[0] = htonl((MAJOR(dev)<<16) |
+		fsidv[0] = (__force __u32)htonl((MAJOR(dev)<<16) |
 				 MINOR(dev));
 		fsidv[1] = ino_t_to_u32(ino);
 		break;
@@ -90,8 +97,8 @@ static inline void mk_fsid(int vers, u32 *fsidv, dev_t dev, ino_t ino,
 		fsidv[0] = fsid;
 		break;
 	case FSID_MAJOR_MINOR:
-		fsidv[0] = htonl(MAJOR(dev));
-		fsidv[1] = htonl(MINOR(dev));
+		fsidv[0] = (__force __u32)htonl(MAJOR(dev));
+		fsidv[1] = (__force __u32)htonl(MINOR(dev));
 		fsidv[2] = ino_t_to_u32(ino);
 		break;
 
-- 
1.9.3


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

* [PATCH v2 007/117] nfsd: properly handle embedded newlines in fault_injection input
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (5 preceding siblings ...)
  2014-06-26 19:11 ` [PATCH v2 006/117] nfsd: add appropriate __force directives to filehandle generation code Jeff Layton
@ 2014-06-26 19:11 ` Jeff Layton
  2014-06-28 11:01   ` Christoph Hellwig
  2014-06-26 19:11 ` [PATCH v2 008/117] nfsd: Protect addition to the file_hashtbl Jeff Layton
                   ` (111 subsequent siblings)
  118 siblings, 1 reply; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:11 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

Currently rpc_pton() fails to handle the case where you echo an address
into the file, as it barfs on the newline. Ensure that we NULL out the
first occurrence of any newline.

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

diff --git a/fs/nfsd/fault_inject.c b/fs/nfsd/fault_inject.c
index 2ed05c3cd43d..f1333fc35b33 100644
--- a/fs/nfsd/fault_inject.c
+++ b/fs/nfsd/fault_inject.c
@@ -115,11 +115,19 @@ static ssize_t fault_inject_write(struct file *file, const char __user *buf,
 	struct net *net = current->nsproxy->net_ns;
 	struct sockaddr_storage sa;
 	u64 val;
+	char *nl;
 
 	if (copy_from_user(write_buf, buf, size))
 		return -EFAULT;
 	write_buf[size] = '\0';
 
+	/* Deal with any embedded newlines in the string */
+	nl = strchr(write_buf, '\n');
+	if (nl) {
+		size = nl - write_buf;
+		*nl = '\0';
+	}
+
 	size = rpc_pton(net, write_buf, size, (struct sockaddr *)&sa, sizeof(sa));
 	if (size > 0)
 		nfsd_inject_set_client(file_inode(file)->i_private, &sa, size);
-- 
1.9.3


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

* [PATCH v2 008/117] nfsd: Protect addition to the file_hashtbl
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (6 preceding siblings ...)
  2014-06-26 19:11 ` [PATCH v2 007/117] nfsd: properly handle embedded newlines in fault_injection input Jeff Layton
@ 2014-06-26 19:11 ` Jeff Layton
  2014-06-26 19:11 ` [PATCH v2 009/117] nfsd: wait to initialize work struct just prior to using it Jeff Layton
                   ` (110 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:11 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

Ensure that we only can have a single struct nfs4_file per inode
in the file_hashtbl and make addition atomic with respect to lookup.

To prevent an i_lock/state_lock inversion, change nfsd4_init_file to
use ihold instead if igrab. That's also more efficient anyway as we
definitely hold a reference to the inode at that point.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Signed-off-by: Jeff Layton <jlayton@primarydata.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
 fs/nfsd/nfs4state.c | 49 +++++++++++++++++++++++++++++++++++++------------
 1 file changed, 37 insertions(+), 12 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index c473bd6d52c8..29788fd0da24 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -2611,17 +2611,18 @@ static void nfsd4_init_file(struct nfs4_file *fp, struct inode *ino)
 {
 	unsigned int hashval = file_hashval(ino);
 
+	lockdep_assert_held(&state_lock);
+
 	atomic_set(&fp->fi_ref, 1);
 	INIT_LIST_HEAD(&fp->fi_stateids);
 	INIT_LIST_HEAD(&fp->fi_delegations);
-	fp->fi_inode = igrab(ino);
+	ihold(ino);
+	fp->fi_inode = ino;
 	fp->fi_had_conflict = false;
 	fp->fi_lease = NULL;
 	memset(fp->fi_fds, 0, sizeof(fp->fi_fds));
 	memset(fp->fi_access, 0, sizeof(fp->fi_access));
-	spin_lock(&state_lock);
 	hlist_add_head(&fp->fi_hash, &file_hashtbl[hashval]);
-	spin_unlock(&state_lock);
 }
 
 void
@@ -2787,23 +2788,49 @@ find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open,
 
 /* search file_hashtbl[] for file */
 static struct nfs4_file *
-find_file(struct inode *ino)
+find_file_locked(struct inode *ino)
 {
 	unsigned int hashval = file_hashval(ino);
 	struct nfs4_file *fp;
 
-	spin_lock(&state_lock);
+	lockdep_assert_held(&state_lock);
+
 	hlist_for_each_entry(fp, &file_hashtbl[hashval], fi_hash) {
 		if (fp->fi_inode == ino) {
 			get_nfs4_file(fp);
-			spin_unlock(&state_lock);
 			return fp;
 		}
 	}
-	spin_unlock(&state_lock);
 	return NULL;
 }
 
+static struct nfs4_file *
+find_file(struct inode *ino)
+{
+	struct nfs4_file *fp;
+
+	spin_lock(&state_lock);
+	fp = find_file_locked(ino);
+	spin_unlock(&state_lock);
+	return fp;
+}
+
+static struct nfs4_file *
+find_or_add_file(struct inode *ino, struct nfs4_file *new)
+{
+	struct nfs4_file *fp;
+
+	spin_lock(&state_lock);
+	fp = find_file_locked(ino);
+	if (fp == NULL) {
+		nfsd4_init_file(new, ino);
+		fp = new;
+	}
+	spin_unlock(&state_lock);
+
+	return fp;
+}
+
 /*
  * Called to check deny when READ with all zero stateid or
  * WRITE with all zero or all one stateid
@@ -3325,21 +3352,19 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
 	 * and check for delegations in the process of being recalled.
 	 * If not found, create the nfs4_file struct
 	 */
-	fp = find_file(ino);
-	if (fp) {
+	fp = find_or_add_file(ino, open->op_file);
+	if (fp != open->op_file) {
 		if ((status = nfs4_check_open(fp, open, &stp)))
 			goto out;
 		status = nfs4_check_deleg(cl, open, &dp);
 		if (status)
 			goto out;
 	} else {
+		open->op_file = NULL;
 		status = nfserr_bad_stateid;
 		if (nfsd4_is_deleg_cur(open))
 			goto out;
 		status = nfserr_jukebox;
-		fp = open->op_file;
-		open->op_file = NULL;
-		nfsd4_init_file(fp, ino);
 	}
 
 	/*
-- 
1.9.3


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

* [PATCH v2 009/117] nfsd: wait to initialize work struct just prior to using it
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (7 preceding siblings ...)
  2014-06-26 19:11 ` [PATCH v2 008/117] nfsd: Protect addition to the file_hashtbl Jeff Layton
@ 2014-06-26 19:11 ` Jeff Layton
  2014-06-28 11:02   ` Christoph Hellwig
  2014-06-26 19:11 ` [PATCH v2 010/117] nfsd: Avoid taking state_lock while holding inode lock in nfsd_break_one_deleg Jeff Layton
                   ` (109 subsequent siblings)
  118 siblings, 1 reply; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:11 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

There's a fair chance we won't ever need this work struct, so we might
as well delay initializing it until just before we're going to use it.
In a later patch, we'll need to intialize the work with a different
function for delegation callbacks. By delaying this, we avoid having
to do it twice.

Signed-off-by: Jeff Layton <jlayton@primarydata.com>
---
 fs/nfsd/nfs4callback.c | 10 +++++-----
 fs/nfsd/nfs4state.c    |  2 --
 fs/nfsd/state.h        |  1 -
 3 files changed, 5 insertions(+), 8 deletions(-)

diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index 2c73cae9899d..00cb9b7a75f6 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -43,6 +43,7 @@
 #define NFSDDBG_FACILITY                NFSDDBG_PROC
 
 static void nfsd4_mark_cb_fault(struct nfs4_client *, int reason);
+static void nfsd4_do_callback_rpc(struct work_struct *w);
 
 #define NFSPROC4_CB_NULL 0
 #define NFSPROC4_CB_COMPOUND 1
@@ -763,6 +764,8 @@ static void do_probe_callback(struct nfs4_client *clp)
 
 	cb->cb_ops = &nfsd4_cb_probe_ops;
 
+	INIT_WORK(&cb->cb_work, nfsd4_do_callback_rpc);
+
 	run_nfsd4_cb(cb);
 }
 
@@ -1031,11 +1034,6 @@ static void nfsd4_do_callback_rpc(struct work_struct *w)
 			cb->cb_ops, cb);
 }
 
-void nfsd4_init_callback(struct nfsd4_callback *cb)
-{
-	INIT_WORK(&cb->cb_work, nfsd4_do_callback_rpc);
-}
-
 void nfsd4_cb_recall(struct nfs4_delegation *dp)
 {
 	struct nfsd4_callback *cb = &dp->dl_recall;
@@ -1053,5 +1051,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_callback_rpc);
+
 	run_nfsd4_cb(&dp->dl_recall);
 }
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 29788fd0da24..b49b46b0ce23 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -466,7 +466,6 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct sv
 	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;
 }
 
@@ -1472,7 +1471,6 @@ static struct nfs4_client *create_client(struct xdr_netobj name,
 		spin_unlock(&nn->client_lock);
 		return NULL;
 	}
-	nfsd4_init_callback(&clp->cl_cb_null);
 	clp->cl_time = get_seconds();
 	clear_bit(0, &clp->cl_cb_slot_busy);
 	copy_verf(clp, verf);
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 374c66283ac5..9447f86f2778 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -464,7 +464,6 @@ 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 int set_callback_cred(void);
-extern void nfsd4_init_callback(struct nfsd4_callback *);
 extern void nfsd4_probe_callback(struct nfs4_client *clp);
 extern void nfsd4_probe_callback_sync(struct nfs4_client *clp);
 extern void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *);
-- 
1.9.3


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

* [PATCH v2 010/117] nfsd: Avoid taking state_lock while holding inode lock in nfsd_break_one_deleg
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (8 preceding siblings ...)
  2014-06-26 19:11 ` [PATCH v2 009/117] nfsd: wait to initialize work struct just prior to using it Jeff Layton
@ 2014-06-26 19:11 ` Jeff Layton
  2014-06-28 11:06   ` Christoph Hellwig
  2014-06-26 19:11 ` [PATCH v2 011/117] nfsd: nfs4_preprocess_seqid_op should only set *stpp on success Jeff Layton
                   ` (108 subsequent siblings)
  118 siblings, 1 reply; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:11 UTC (permalink / raw)
  To: bfields; +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.

Add a new per-nfs4_file lock that we can use to protect the
per-nfs4_file delegation list. Hold that while walking the list in the
break_deleg callback and queue the workqueue job for each one.

The workqueue job can then take the state_lock and do the list
manipulations without the i_lock being held prior to starting the
rpc call.

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

diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index 00cb9b7a75f6..771323ae1b33 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -1014,9 +1014,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;
 
@@ -1034,6 +1033,22 @@ 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);
+}
+
+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,8 +1065,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_callback_rpc);
+	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 b49b46b0ce23..461229a01963 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -513,7 +513,9 @@ hash_delegation_locked(struct nfs4_delegation *dp, struct nfs4_file *fp)
 	lockdep_assert_held(&state_lock);
 
 	dp->dl_stid.sc_type = NFS4_DELEG_STID;
+	spin_lock(&fp->fi_lock);
 	list_add(&dp->dl_perfile, &fp->fi_delegations);
+	spin_unlock(&fp->fi_lock);
 	list_add(&dp->dl_perclnt, &dp->dl_stid.sc_client->cl_delegations);
 }
 
@@ -521,14 +523,18 @@ 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);
+	spin_lock(&fp->fi_lock);
+	list_del_init(&dp->dl_perfile);
+	spin_unlock(&fp->fi_lock);
 	spin_unlock(&state_lock);
-	if (dp->dl_file) {
-		nfs4_put_deleg_lease(dp->dl_file);
-		put_nfs4_file(dp->dl_file);
+	if (fp) {
+		nfs4_put_deleg_lease(fp);
+		put_nfs4_file(fp);
 		dp->dl_file = NULL;
 	}
 }
@@ -2612,6 +2618,7 @@ static void nfsd4_init_file(struct nfs4_file *fp, struct inode *ino)
 	lockdep_assert_held(&state_lock);
 
 	atomic_set(&fp->fi_ref, 1);
+	spin_lock_init(&fp->fi_lock);
 	INIT_LIST_HEAD(&fp->fi_stateids);
 	INIT_LIST_HEAD(&fp->fi_delegations);
 	ihold(ino);
@@ -2857,26 +2864,32 @@ 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();
-
 	block_delegations(&dp->dl_fh);
-
 	nfsd4_cb_recall(dp);
 }
 
@@ -2901,11 +2914,11 @@ static void nfsd_break_deleg_cb(struct file_lock *fl)
 	 */
 	fl->fl_break_time = 0;
 
-	spin_lock(&state_lock);
 	fp->fi_had_conflict = true;
+	spin_lock(&fp->fi_lock);
 	list_for_each_entry(dp, &fp->fi_delegations, dl_perfile)
 		nfsd_break_one_deleg(dp);
-	spin_unlock(&state_lock);
+	spin_unlock(&fp->fi_lock);
 }
 
 static
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 9447f86f2778..7d6ba06c1abe 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -382,6 +382,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;
@@ -471,6 +472,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.3


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

* [PATCH v2 011/117] nfsd: nfs4_preprocess_seqid_op should only set *stpp on success
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (9 preceding siblings ...)
  2014-06-26 19:11 ` [PATCH v2 010/117] nfsd: Avoid taking state_lock while holding inode lock in nfsd_break_one_deleg Jeff Layton
@ 2014-06-26 19:11 ` Jeff Layton
  2014-06-26 19:11 ` [PATCH v2 012/117] nfsd: Cleanup nfs4svc_encode_compoundres Jeff Layton
                   ` (107 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:11 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

Not technically a bugfix, since nothing tries to use the return pointer
if this function doesn't return success, but it could be a problem
with some coming changes.

Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Signed-off-by: Jeff Layton <jlayton@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 461229a01963..3ce5dc30f767 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -3964,6 +3964,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));
@@ -3973,11 +3974,14 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
 				      cstate->minorversion, nn);
 	if (status)
 		return status;
-	*stpp = openlockstateid(s);
+	stp = openlockstateid(s);
 	if (!nfsd4_has_session(cstate))
-		cstate->replay_owner = (*stpp)->st_stateowner;
+		cstate->replay_owner = 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.3


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

* [PATCH v2 012/117] nfsd: Cleanup nfs4svc_encode_compoundres
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (10 preceding siblings ...)
  2014-06-26 19:11 ` [PATCH v2 011/117] nfsd: nfs4_preprocess_seqid_op should only set *stpp on success Jeff Layton
@ 2014-06-26 19:11 ` Jeff Layton
  2014-06-26 19:11 ` [PATCH v2 013/117] nfsd: Don't get a session reference without a client reference Jeff Layton
                   ` (106 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:11 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

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

Reviewed-by: Christoph Hellwig <hch@lst.de>
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 3ce5dc30f767..ade15fcddd08 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -203,18 +203,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)
 {
@@ -1650,7 +1638,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 xdr_buf *buf = resp->xdr.buf;
@@ -2422,6 +2410,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 83baf2bfe9e9..68ea99d389ad 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -3999,7 +3999,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 xdr_buf *buf = resp->xdr.buf;
 
 	WARN_ON_ONCE(buf->len != buf->head[0].iov_len + buf->page_len +
@@ -4013,19 +4012,7 @@ nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compo
 	p += XDR_QUADLEN(resp->taglen);
 	*p++ = htonl(resp->opcnt);
 
-	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 7d6ba06c1abe..24eec922685c 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -477,7 +477,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 18cbb6d9c8a9..7d8af164523b 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -574,7 +574,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 *);
@@ -585,6 +584,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.3


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

* [PATCH v2 013/117] nfsd: Don't get a session reference without a client reference
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (11 preceding siblings ...)
  2014-06-26 19:11 ` [PATCH v2 012/117] nfsd: Cleanup nfs4svc_encode_compoundres Jeff Layton
@ 2014-06-26 19:11 ` Jeff Layton
  2014-06-26 19:11 ` [PATCH v2 014/117] nfsd: Allow struct nfsd4_compound_state to cache the nfs4_client Jeff Layton
                   ` (105 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:11 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

Preparatory patch for client_mutex removal.

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

Reviewed-by: Christoph Hellwig <hch@lst.de>
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 ade15fcddd08..73517c02d38e 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -103,12 +103,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)
@@ -117,14 +111,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)
 {
@@ -203,6 +189,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)
 {
@@ -1113,7 +1132,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;
@@ -1133,6 +1152,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)
@@ -2148,17 +2185,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;
@@ -2172,6 +2209,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;
 }
@@ -2191,7 +2230,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;
@@ -2202,14 +2242,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;
@@ -2221,7 +2259,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:
@@ -2296,7 +2334,8 @@ nfsd4_sequence(struct svc_rqst *rqstp,
 	struct nfsd4_conn *conn;
 	__be32 status;
 	int buflen;
-	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;
@@ -2310,17 +2349,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))
@@ -2404,9 +2436,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;
 }
 
@@ -2416,18 +2446,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 24eec922685c..3475a9eb11c7 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -212,8 +212,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.3


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

* [PATCH v2 014/117] nfsd: Allow struct nfsd4_compound_state to cache the nfs4_client
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (12 preceding siblings ...)
  2014-06-26 19:11 ` [PATCH v2 013/117] nfsd: Don't get a session reference without a client reference Jeff Layton
@ 2014-06-26 19:11 ` Jeff Layton
  2014-06-29 12:05   ` Christoph Hellwig
  2014-06-26 19:11 ` [PATCH v2 015/117] nfsd: lock owners are not per open stateid Jeff Layton
                   ` (104 subsequent siblings)
  118 siblings, 1 reply; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:11 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

This will be used later to accelerate lookups of the clientid.

Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/nfs4state.c | 20 +++++++++++++++++---
 fs/nfsd/xdr4.h      |  1 +
 2 files changed, 18 insertions(+), 3 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 73517c02d38e..8fe76c83583e 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -189,6 +189,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;
@@ -2382,6 +2391,7 @@ nfsd4_sequence(struct svc_rqst *rqstp,
 			goto out_put_session;
 		cstate->slot = slot;
 		cstate->session = session;
+		cstate->clp = clp;
 		/* Return the cached reply status and set cstate->status
 		 * for nfsd4_proc_compound processing */
 		status = nfsd4_replay_cache_entry(resp, seq);
@@ -2416,6 +2426,7 @@ nfsd4_sequence(struct svc_rqst *rqstp,
 
 	cstate->slot = slot;
 	cstate->session = session;
+	cstate->clp = clp;
 
 out:
 	switch (clp->cl_cb_state) {
@@ -2452,7 +2463,8 @@ nfsd4_sequence_done(struct nfsd4_compoundres *resp)
 		}
 		/* Drop session reference that was taken in nfsd4_sequence() */
 		nfsd4_put_session(cs->session);
-	}
+	} else if (cs->clp)
+		put_client_renew(cs->clp);
 }
 
 __be32
@@ -5008,8 +5020,10 @@ static u64 nfsd_foreach_client_lock(struct nfs4_client *clp, u64 max, void (*fun
 	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(stp, st_next,
+				&oop->oo_owner.so_stateids, st_perstateowner) {
+			list_for_each_entry_safe(lop, lo_next,
+					&stp->st_lockowners, lo_perstateid) {
 				if (func)
 					func(lop);
 				if (++count == max)
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
index 7d8af164523b..312f6483a48e 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -55,6 +55,7 @@ struct nfsd4_compound_state {
 	struct svc_fh		current_fh;
 	struct svc_fh		save_fh;
 	struct nfs4_stateowner	*replay_owner;
+	struct nfs4_client	*clp;
 	/* For sessions DRC */
 	struct nfsd4_session	*session;
 	struct nfsd4_slot	*slot;
-- 
1.9.3


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

* [PATCH v2 015/117] nfsd: lock owners are not per open stateid
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (13 preceding siblings ...)
  2014-06-26 19:11 ` [PATCH v2 014/117] nfsd: Allow struct nfsd4_compound_state to cache the nfs4_client Jeff Layton
@ 2014-06-26 19:11 ` Jeff Layton
  2014-06-28 11:07   ` Christoph Hellwig
  2014-06-26 19:11 ` [PATCH v2 016/117] nfsd: Allow lockowners to hold several stateids Jeff Layton
                   ` (103 subsequent siblings)
  118 siblings, 1 reply; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:11 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

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 stateids
with a list of lock stateids.

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

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 8fe76c83583e..2d7887a752db 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -728,10 +728,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);
@@ -746,12 +747,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);
 	}
 }
 
@@ -767,22 +767,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);
 }
 
@@ -2780,7 +2794,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);
 	list_add(&stp->st_perfile, &fp->fi_stateids);
 	stp->st_stateowner = &oo->oo_owner;
@@ -4380,7 +4394,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);
 }
 
 /*
@@ -4425,6 +4438,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);
 	return stp;
 }
 
@@ -5012,20 +5026,21 @@ 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;
 			}
@@ -5037,7 +5052,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 3475a9eb11c7..1bfc2482ba24 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -363,7 +363,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 */
 };
 
@@ -432,7 +431,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.3


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

* [PATCH v2 016/117] nfsd: Allow lockowners to hold several stateids
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (14 preceding siblings ...)
  2014-06-26 19:11 ` [PATCH v2 015/117] nfsd: lock owners are not per open stateid Jeff Layton
@ 2014-06-26 19:11 ` Jeff Layton
  2014-06-26 19:11 ` [PATCH v2 017/117] nfsd: NFSv4 lock-owners are not associated to a specific file Jeff Layton
                   ` (102 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:11 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

A lockowner can have more than one lock stateid. For instance, if a
process has more than one file open and has locks on both, then the same
lockowner has more than one stateid associated with it. Change it so
that this reality is better reflected by the objects that nfsd uses.

Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Signed-off-by: Jeff Layton <jlayton@primarydata.com>
---
 fs/nfsd/nfs4state.c | 55 ++++++++++++++++++++++++++++++++---------------------
 1 file changed, 33 insertions(+), 22 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 2d7887a752db..5b903761ba73 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -3913,12 +3913,7 @@ nfsd4_free_lock_stateid(struct nfs4_ol_stateid *stp)
 
 	if (check_for_locks(stp->st_file, lo))
 		return nfserr_locks_held;
-	/*
-	 * Currently there's a 1-1 lock stateid<->lockowner
-	 * correspondance, and we have to delete the lockowner when we
-	 * delete the lock stateid:
-	 */
-	release_lockowner(lo);
+	release_lockowner_if_empty(lo);
 	return nfs_ok;
 }
 
@@ -4442,6 +4437,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 nfs4_file *fp)
+{
+	struct nfs4_ol_stateid *lst;
+
+	list_for_each_entry(lst, &lo->lo_owner.so_stateids, st_perstateowner) {
+		if (lst->st_file == fp)
+			return lst;
+	}
+	return NULL;
+}
+
+
 static int
 check_lock_length(u64 offset, u64 length)
 {
@@ -4471,25 +4479,28 @@ 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)
+	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;
+	} else {
+		/* with an existing lockowner, seqids must be the same */
+		if (!cstate->minorversion &&
+		    lock->lk_new_lock_seqid != lo->lo_owner.so_seqid)
 			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;
 	}
-	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);
+
+	*lst = find_lock_stateid(lo, fi);
 	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;
 }
 
@@ -4646,7 +4657,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	}
 out:
 	if (status && new_state)
-		release_lockowner(lock_sop);
+		release_lockowner_if_empty(lock_sop);
 	nfsd4_bump_seqid(cstate, status);
 	if (!cstate->replay_owner)
 		nfs4_unlock_state();
-- 
1.9.3


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

* [PATCH v2 017/117] nfsd: NFSv4 lock-owners are not associated to a specific file
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (15 preceding siblings ...)
  2014-06-26 19:11 ` [PATCH v2 016/117] nfsd: Allow lockowners to hold several stateids Jeff Layton
@ 2014-06-26 19:11 ` Jeff Layton
  2014-06-26 19:11 ` [PATCH v2 018/117] nfsd: clean up nfs4_release_lockowner Jeff Layton
                   ` (101 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:11 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

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.

Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
---
 fs/nfsd/netns.h     |  4 ---
 fs/nfsd/nfs4state.c | 73 ++++++++++-------------------------------------------
 fs/nfsd/state.h     |  1 -
 3 files changed, 14 insertions(+), 64 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 5b903761ba73..00a1b2cda3ab 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -747,7 +747,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);
@@ -4270,8 +4269,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)
 {
@@ -4292,13 +4289,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 (file_hashval(inode) + 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
@@ -4351,46 +4341,23 @@ 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;
-	if (list_empty(&lo->lo_owner.so_stateids)) {
-		WARN_ON_ONCE(1);
-		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;
 }
 
-static void hash_lockowner(struct nfs4_lockowner *lo, unsigned int strhashval, struct nfs4_client *clp, struct nfs4_ol_stateid *open_stp)
-{
-	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]);
-}
-
 /*
  * Alloc a lock owner structure.
  * Called in nfsd4_lock - therefore, OPEN and OPEN_CONFIRM (if needed) has 
@@ -4398,10 +4365,10 @@ static void hash_lockowner(struct nfs4_lockowner *lo, unsigned int strhashval, s
  *
  * strhashval = ownerstr_hashval
  */
-
 static struct nfs4_lockowner *
 alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, struct nfs4_ol_stateid *open_stp, struct nfsd4_lock *lock) {
 	struct nfs4_lockowner *lo;
+	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
 
 	lo = alloc_stateowner(lockowner_slab, &lock->lk_new_owner, clp);
 	if (!lo)
@@ -4411,7 +4378,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);
+	list_add(&lo->lo_owner.so_strhash, &nn->ownerstr_hashtbl[strhashval]);
 	return lo;
 }
 
@@ -4477,8 +4444,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);
@@ -4692,7 +4658,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;
@@ -4715,7 +4680,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__);
@@ -4738,7 +4702,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;
@@ -5232,10 +5196,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)
@@ -5247,8 +5207,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;
@@ -5264,8 +5222,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);
@@ -5297,7 +5253,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 1bfc2482ba24..f36dd6451cbc 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -362,7 +362,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.3


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

* [PATCH v2 018/117] nfsd: clean up nfs4_release_lockowner
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (16 preceding siblings ...)
  2014-06-26 19:11 ` [PATCH v2 017/117] nfsd: NFSv4 lock-owners are not associated to a specific file Jeff Layton
@ 2014-06-26 19:11 ` Jeff Layton
  2014-06-29  6:47   ` Christoph Hellwig
  2014-06-26 19:11 ` [PATCH v2 019/117] nfsd: declare v4.1+ openowners confirmed on creation Jeff Layton
                   ` (100 subsequent siblings)
  118 siblings, 1 reply; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:11 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

Now that we know that we won't have several lockowners with the same,
owner->data, we can simplify nfs4_release_lockowner and get rid of
the lo_list in the process.

Signed-off-by: Jeff Layton <jlayton@primarydata.com>
---
 fs/nfsd/nfs4state.c | 44 ++++++++++++++++++++++----------------------
 fs/nfsd/state.h     |  1 -
 2 files changed, 22 insertions(+), 23 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 00a1b2cda3ab..a5bb96b97f09 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -4828,7 +4828,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
 			struct nfsd4_release_lockowner *rlockowner)
 {
 	clientid_t *clid = &rlockowner->rl_clientid;
-	struct nfs4_stateowner *sop;
+	struct nfs4_stateowner *sop = NULL, *tmp;
 	struct nfs4_lockowner *lo;
 	struct nfs4_ol_stateid *stp;
 	struct xdr_netobj *owner = &rlockowner->rl_owner;
@@ -4849,31 +4849,31 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
 	status = nfserr_locks_held;
 	INIT_LIST_HEAD(&matches);
 
-	list_for_each_entry(sop, &nn->ownerstr_hashtbl[hashval], so_strhash) {
-		if (sop->so_is_open_owner)
-			continue;
-		if (!same_owner_str(sop, owner, clid))
+	/* Find the matching lock stateowner */
+	list_for_each_entry(tmp, &nn->ownerstr_hashtbl[hashval], so_strhash) {
+		if (tmp->so_is_open_owner)
 			continue;
-		list_for_each_entry(stp, &sop->so_stateids,
-				st_perstateowner) {
-			lo = lockowner(sop);
-			if (check_for_locks(stp->st_file, lo))
-				goto out;
-			list_add(&lo->lo_list, &matches);
+		if (same_owner_str(tmp, owner, clid)) {
+			sop = tmp;
+			break;
 		}
 	}
-	/* Clients probably won't expect us to return with some (but not all)
-	 * of the lockowner state released; so don't release any until all
-	 * have been checked. */
-	status = nfs_ok;
-	while (!list_empty(&matches)) {
-		lo = list_entry(matches.next, struct nfs4_lockowner,
-								lo_list);
-		/* unhash_stateowner deletes so_perclient only
-		 * for openowners. */
-		list_del(&lo->lo_list);
-		release_lockowner(lo);
+
+	/* No matching owner found, maybe a replay? Just declare victory... */
+	if (!sop) {
+		status = nfs_ok;
+		goto out;
+	}
+
+	lo = lockowner(sop);
+	/* see if there are still any locks associated with it */
+	list_for_each_entry(stp, &sop->so_stateids, st_perstateowner) {
+		if (check_for_locks(stp->st_file, lo))
+			goto out;
 	}
+
+	status = nfs_ok;
+	release_lockowner(lo);
 out:
 	nfs4_unlock_state();
 	return status;
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index f36dd6451cbc..305414a083c5 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -362,7 +362,6 @@ struct nfs4_openowner {
 
 struct nfs4_lockowner {
 	struct nfs4_stateowner	lo_owner; /* must be first element */
-	struct list_head	lo_list; /* for temporary uses */
 };
 
 static inline struct nfs4_openowner * openowner(struct nfs4_stateowner *so)
-- 
1.9.3


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

* [PATCH v2 019/117] nfsd: declare v4.1+ openowners confirmed on creation
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (17 preceding siblings ...)
  2014-06-26 19:11 ` [PATCH v2 018/117] nfsd: clean up nfs4_release_lockowner Jeff Layton
@ 2014-06-26 19:11 ` Jeff Layton
  2014-06-29  6:48   ` Christoph Hellwig
  2014-06-26 19:12 ` [PATCH v2 020/117] nfsd: Cleanup - Let nfsd4_lookup_stateid() take a cstate argument Jeff Layton
                   ` (99 subsequent siblings)
  118 siblings, 1 reply; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:11 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

There's no need to confirm an openowner in v4.1 and above, so we can
go ahead and set NFS4_OO_CONFIRMED when we create openowners in
those versions. This will also be necessary when we remove the
client_mutex, as it'll be possible for two concurrent opens to race
in versions >4.0.

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

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index a5bb96b97f09..44e98e5fe44a 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -2773,7 +2773,10 @@ static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, u
 }
 
 static struct nfs4_openowner *
-alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, struct nfsd4_open *open) {
+alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp,
+			   struct nfsd4_open *open,
+			   struct nfsd4_compound_state *cstate)
+{
 	struct nfs4_openowner *oo;
 
 	oo = alloc_stateowner(openowner_slab, &open->op_owner, clp);
@@ -2782,6 +2785,8 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, str
 	oo->oo_owner.so_is_open_owner = 1;
 	oo->oo_owner.so_seqid = open->op_seqid;
 	oo->oo_flags = NFS4_OO_NEW;
+	if (nfsd4_has_session(cstate))
+		oo->oo_flags |= NFS4_OO_CONFIRMED;
 	oo->oo_time = 0;
 	oo->oo_last_closed_stid = NULL;
 	INIT_LIST_HEAD(&oo->oo_close_lru);
@@ -3047,7 +3052,7 @@ nfsd4_process_open1(struct nfsd4_compound_state *cstate,
 	clp = oo->oo_owner.so_client;
 	goto alloc_stateid;
 new_owner:
-	oo = alloc_init_open_stateowner(strhashval, clp, open);
+	oo = alloc_init_open_stateowner(strhashval, clp, open, cstate);
 	if (oo == NULL)
 		return nfserr_jukebox;
 	open->op_openowner = oo;
@@ -3457,8 +3462,6 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
 	memcpy(&open->op_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
 
 	if (nfsd4_has_session(&resp->cstate)) {
-		open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED;
-
 		if (open->op_deleg_want & NFS4_SHARE_WANT_NO_DELEG) {
 			open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT;
 			open->op_why_no_deleg = WND4_NOT_WANTED;
@@ -3852,8 +3855,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(stateid,
+				NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID,
+				&s, cstate->minorversion, nn);
 	if (status)
 		goto out;
 	status = check_stateid_generation(stateid, &s->sc_stateid, nfsd4_has_session(cstate));
-- 
1.9.3


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

* [PATCH v2 020/117] nfsd: Cleanup - Let nfsd4_lookup_stateid() take a cstate argument
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (18 preceding siblings ...)
  2014-06-26 19:11 ` [PATCH v2 019/117] nfsd: declare v4.1+ openowners confirmed on creation Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-29  6:49   ` Christoph Hellwig
  2014-06-26 19:12 ` [PATCH v2 021/117] nfsd: clean up nfsd4_close_open_stateid Jeff Layton
                   ` (98 subsequent siblings)
  118 siblings, 1 reply; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

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 | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 44e98e5fe44a..5f79625982b8 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -3804,12 +3804,14 @@ static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid)
 	}
 }
 
-static __be32 nfsd4_lookup_stateid(stateid_t *stateid, unsigned char typemask,
-				   struct nfs4_stid **s, bool sessions,
-				   struct nfsd_net *nn)
+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;
@@ -3855,9 +3857,9 @@ nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate,
 
 	nfs4_lock_state();
 
-	status = nfsd4_lookup_stateid(stateid,
+	status = nfsd4_lookup_stateid(cstate, stateid,
 				NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID,
-				&s, cstate->minorversion, nn);
+				&s, nn);
 	if (status)
 		goto out;
 	status = check_stateid_generation(stateid, &s->sc_stateid, nfsd4_has_session(cstate));
@@ -4027,8 +4029,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);
@@ -4254,8 +4255,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.3


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

* [PATCH v2 021/117] nfsd: clean up nfsd4_close_open_stateid
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (19 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 020/117] nfsd: Cleanup - Let nfsd4_lookup_stateid() take a cstate argument Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-29 12:00   ` Christoph Hellwig
  2014-06-26 19:12 ` [PATCH v2 022/117] nfsd: Cache the client that was looked up in lookup_clientid() Jeff Layton
                   ` (97 subsequent siblings)
  118 siblings, 1 reply; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

Minor cleanup that should introduce no behavioral changes.

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

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 5f79625982b8..f782ed5cad63 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -4185,8 +4185,25 @@ out:
 
 static void nfsd4_close_open_stateid(struct nfs4_ol_stateid *s)
 {
-	unhash_open_stateid(s);
+	struct nfs4_client *clp = s->st_stid.sc_client;
+	struct nfs4_openowner *oo = openowner(s->st_stateowner);
+
 	s->st_stid.sc_type = NFS4_CLOSED_STID;
+	unhash_open_stateid(s);
+
+	if (clp->cl_minorversion) {
+		free_generic_stateid(s);
+		if (list_empty(&oo->oo_owner.so_stateids))
+			release_openowner(oo);
+	} else {
+		oo->oo_last_closed_stid = s;
+		/*
+		 * In the 4.0 case we need to keep the owners around a
+		 * little while to handle CLOSE replay.
+		 */
+		if (list_empty(&oo->oo_owner.so_stateids))
+			move_to_close_lru(oo, clp->net);
+	}
 }
 
 /*
@@ -4197,7 +4214,6 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	    struct nfsd4_close *close)
 {
 	__be32 status;
-	struct nfs4_openowner *oo;
 	struct nfs4_ol_stateid *stp;
 	struct net *net = SVC_NET(rqstp);
 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
@@ -4213,28 +4229,10 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	nfsd4_bump_seqid(cstate, status);
 	if (status)
 		goto out; 
-	oo = openowner(stp->st_stateowner);
 	update_stateid(&stp->st_stid.sc_stateid);
 	memcpy(&close->cl_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
 
 	nfsd4_close_open_stateid(stp);
-
-	if (cstate->minorversion)
-		free_generic_stateid(stp);
-	else
-		oo->oo_last_closed_stid = stp;
-
-	if (list_empty(&oo->oo_owner.so_stateids)) {
-		if (cstate->minorversion)
-			release_openowner(oo);
-		else {
-			/*
-			 * In the 4.0 case we need to keep the owners around a
-			 * little while to handle CLOSE replay.
-			 */
-			move_to_close_lru(oo, SVC_NET(rqstp));
-		}
-	}
 out:
 	if (!cstate->replay_owner)
 		nfs4_unlock_state();
-- 
1.9.3


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

* [PATCH v2 022/117] nfsd: Cache the client that was looked up in lookup_clientid()
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (20 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 021/117] nfsd: clean up nfsd4_close_open_stateid Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-29 12:14   ` Christoph Hellwig
  2014-06-26 19:12 ` [PATCH v2 023/117] nfsd: Convert nfsd4_process_open1() to work with lookup_clientid() Jeff Layton
                   ` (96 subsequent siblings)
  118 siblings, 1 reply; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

We want to use the nfsd4_compound_state to cache the nfs4_client
in order to optimise away extra lookups of the clid.

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

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index f782ed5cad63..fb78d1ab2655 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -3521,15 +3521,31 @@ void nfsd4_cleanup_open_state(struct nfsd4_open *open, __be32 status)
 		free_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_compound_state *cstate,
+		struct nfsd_net *nn)
 {
 	struct nfs4_client *found;
 
-	if (STALE_CLIENTID(clid, nn))
-		return nfserr_stale_clientid;
-	found = find_confirmed_client(clid, session, nn);
-	if (clp)
-		*clp = found;
+	if (cstate->clp != NULL) {
+		found = cstate->clp;
+		if (!same_clid(&found->cl_clientid, clid))
+			return nfserr_stale_clientid;
+	} else {
+		if (STALE_CLIENTID(clid, nn))
+			return nfserr_stale_clientid;
+		/*
+		 * Usually for v4.1+ we get the client in the SEQUENCE op, so
+		 * if we don't have one cached already then we know this is for
+		 * is for v4.0 and "sessions" will be false.
+		 */
+		found = find_confirmed_client(clid, false, nn);
+		/* Cache the nfs4_client in cstate! */
+		if (found) {
+			cstate->clp = found;
+			atomic_inc(&found->cl_refcount);
+		}
+	}
 	return found ? nfs_ok : nfserr_expired;
 }
 
@@ -3544,9 +3560,10 @@ 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, cstate, nn);
 	if (status)
 		goto out;
+	clp = cstate->clp;
 	status = nfserr_cb_path_down;
 	if (!list_empty(&clp->cl_delegations)
 			&& clp->cl_cb_state != NFSD4_CB_UP)
@@ -3809,22 +3826,19 @@ 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;
-	status = lookup_clientid(&stateid->si_opaque.so_clid, sessions,
-							nn, &cl);
+	status = lookup_clientid(&stateid->si_opaque.so_clid, cstate, nn);
 	if (status == nfserr_stale_clientid) {
-		if (sessions)
+		if (cstate->session)
 			return nfserr_bad_stateid;
 		return nfserr_stale_stateid;
 	}
 	if (status)
 		return status;
-	*s = find_stateid_by_type(cl, stateid, typemask);
+	*s = find_stateid_by_type(cstate->clp, stateid, typemask);
 	if (!*s)
 		return nfserr_bad_stateid;
 	return nfs_ok;
@@ -4674,7 +4688,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, cstate, nn);
 		if (status)
 			goto out;
 	}
@@ -4844,7 +4858,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
 
 	nfs4_lock_state();
 
-	status = lookup_clientid(clid, cstate->minorversion, nn, NULL);
+	status = lookup_clientid(clid, cstate, nn);
 	if (status)
 		goto out;
 
-- 
1.9.3


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

* [PATCH v2 023/117] nfsd: Convert nfsd4_process_open1() to work with lookup_clientid()
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (21 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 022/117] nfsd: Cache the client that was looked up in lookup_clientid() Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-29 12:16   ` Christoph Hellwig
  2014-06-26 19:12 ` [PATCH v2 024/117] nfsd: Always use lookup_clientid() in nfsd4_process_open1 Jeff Layton
                   ` (95 subsequent siblings)
  118 siblings, 1 reply; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

...and have alloc_init_open_stateowner just use the cstate->clp pointer
instead of passing in a clp separately. This allows us to use the
cached nfs4_client pointer in the cstate instead of having to look it
up again.

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

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index fb78d1ab2655..ab45350fbd5a 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -71,6 +71,9 @@ 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_compound_state *cstate,
+		struct nfsd_net *nn);
 
 /* Locking: */
 
@@ -2773,10 +2776,10 @@ static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, u
 }
 
 static struct nfs4_openowner *
-alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp,
-			   struct nfsd4_open *open,
+alloc_init_open_stateowner(unsigned int strhashval, struct nfsd4_open *open,
 			   struct nfsd4_compound_state *cstate)
 {
+	struct nfs4_client *clp = cstate->clp;
 	struct nfs4_openowner *oo;
 
 	oo = alloc_stateowner(openowner_slab, &open->op_owner, clp);
@@ -3033,10 +3036,10 @@ 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, nn);
+		if (status)
+			return status;
+		clp = cstate->clp;
 		goto new_owner;
 	}
 	if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) {
@@ -3052,7 +3055,7 @@ nfsd4_process_open1(struct nfsd4_compound_state *cstate,
 	clp = oo->oo_owner.so_client;
 	goto alloc_stateid;
 new_owner:
-	oo = alloc_init_open_stateowner(strhashval, clp, open, cstate);
+	oo = alloc_init_open_stateowner(strhashval, open, cstate);
 	if (oo == NULL)
 		return nfserr_jukebox;
 	open->op_openowner = oo;
-- 
1.9.3


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

* [PATCH v2 024/117] nfsd: Always use lookup_clientid() in nfsd4_process_open1
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (22 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 023/117] nfsd: Convert nfsd4_process_open1() to work with lookup_clientid() Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-29 12:16   ` Christoph Hellwig
  2014-06-26 19:12 ` [PATCH v2 025/117] nfsd: Convert nfs4_check_open_reclaim() to work with lookup_clientid() Jeff Layton
                   ` (94 subsequent siblings)
  118 siblings, 1 reply; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

In later patches, we'll be moving the stateowner table into the
nfs4_client, and by doing this we ensure that we have a cached
nfs4_client pointer.

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

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index ab45350fbd5a..6b9dbdc52b47 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -3032,19 +3032,19 @@ nfsd4_process_open1(struct nfsd4_compound_state *cstate,
 	if (open->op_file == NULL)
 		return nfserr_jukebox;
 
+	status = lookup_clientid(clientid, cstate, nn);
+	if (status)
+		return status;
+	clp = cstate->clp;
+
 	strhashval = ownerstr_hashval(clientid->cl_id, &open->op_owner);
 	oo = find_openstateowner_str(strhashval, open, cstate->minorversion, nn);
 	open->op_openowner = oo;
 	if (!oo) {
-		status = lookup_clientid(clientid, cstate, nn);
-		if (status)
-			return status;
-		clp = cstate->clp;
 		goto new_owner;
 	}
 	if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) {
 		/* Replace unconfirmed owners without checking for replay. */
-		clp = oo->oo_owner.so_client;
 		release_openowner(oo);
 		open->op_openowner = NULL;
 		goto new_owner;
@@ -3052,7 +3052,6 @@ nfsd4_process_open1(struct nfsd4_compound_state *cstate,
 	status = nfsd4_check_seqid(cstate, &oo->oo_owner, open->op_seqid);
 	if (status)
 		return status;
-	clp = oo->oo_owner.so_client;
 	goto alloc_stateid;
 new_owner:
 	oo = alloc_init_open_stateowner(strhashval, open, cstate);
-- 
1.9.3


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

* [PATCH v2 025/117] nfsd: Convert nfs4_check_open_reclaim() to work with lookup_clientid()
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (23 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 024/117] nfsd: Always use lookup_clientid() in nfsd4_process_open1 Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-29 12:17   ` Christoph Hellwig
  2014-06-26 19:12 ` [PATCH v2 026/117] nfsd: Move the delegation reference counter into the struct nfs4_stid Jeff Layton
                   ` (93 subsequent siblings)
  118 siblings, 1 reply; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

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

diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 8904c9cbcb89..eec0737abddd 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -431,8 +431,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 			break;
 		case NFS4_OPEN_CLAIM_PREVIOUS:
 			status = nfs4_check_open_reclaim(&open->op_clientid,
-							 cstate->minorversion,
-							 nn);
+							 cstate, nn);
 			if (status)
 				goto out;
 			open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED;
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 6b9dbdc52b47..a4636aac165e 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -4981,16 +4981,19 @@ 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_compound_state *cstate,
+		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, cstate, nn);
+	if (status)
 		return nfserr_reclaim_bad;
 
-	return nfsd4_client_record_check(clp) ? nfserr_reclaim_bad : nfs_ok;
+	return nfsd4_client_record_check(cstate->clp) ?
+		nfserr_reclaim_bad : nfs_ok;
 }
 
 #ifdef CONFIG_NFSD_FAULT_INJECTION
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 305414a083c5..b2c9afce33bf 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -458,7 +458,8 @@ 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_compound_state *cstate, struct nfsd_net *nn);
 extern int set_callback_cred(void);
 extern void nfsd4_probe_callback(struct nfs4_client *clp);
 extern void nfsd4_probe_callback_sync(struct nfs4_client *clp);
-- 
1.9.3


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

* [PATCH v2 026/117] nfsd: Move the delegation reference counter into the struct nfs4_stid
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (24 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 025/117] nfsd: Convert nfs4_check_open_reclaim() to work with lookup_clientid() Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-26 19:12 ` [PATCH v2 027/117] nfsd4: use cl_lock to synchronize all stateid idr calls Jeff Layton
                   ` (92 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

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

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

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index a4636aac165e..4cb64d12c9bf 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -363,6 +363,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.
@@ -484,7 +485,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);
 	return dp;
 }
 
@@ -503,7 +503,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--;
 	}
@@ -2951,10 +2951,11 @@ 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);
+	 * callback (and since the lease code is serialized by the i_lock
+	 * we know the server hasn't removed the lease yet, we know it's
+	 * safe to take a reference.
+	 */
+	atomic_inc(&dp->dl_stid.sc_count);
 	block_delegations(&dp->dl_fh);
 	nfsd4_cb_recall(dp);
 }
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index b2c9afce33bf..9eb4fe673014 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -73,6 +73,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
@@ -90,7 +91,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.3


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

* [PATCH v2 027/117] nfsd4: use cl_lock to synchronize all stateid idr calls
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (25 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 026/117] nfsd: Move the delegation reference counter into the struct nfs4_stid Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-26 19:12 ` [PATCH v2 028/117] nfsd: Add fine grained protection for the nfs4_file->fi_stateids list Jeff Layton
                   ` (91 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Benny Halevy

From: Benny Halevy <bhalevy@primarydata.com>

Currently, this is serialized by the client_mutex, which is slated for
removal. Add finer-grained locking here.

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

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 4cb64d12c9bf..a2b4f2cbab42 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -346,7 +346,6 @@ static void nfs4_file_put_access(struct nfs4_file *fp, int oflag)
 static struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct
 kmem_cache *slab)
 {
-	struct idr *stateids = &cl->cl_stateids;
 	struct nfs4_stid *stid;
 	int new_id;
 
@@ -354,7 +353,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(&cl->cl_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;
@@ -490,9 +493,11 @@ 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;
 
-	idr_remove(stateids, s->sc_stateid.si_opaque.so_id);
+	spin_lock(&clp->cl_lock);
+	idr_remove(&clp->cl_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)
@@ -1266,7 +1271,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);
 }
 
@@ -1489,7 +1496,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.3


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

* [PATCH v2 028/117] nfsd: Add fine grained protection for the nfs4_file->fi_stateids list
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (26 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 027/117] nfsd4: use cl_lock to synchronize all stateid idr calls Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-26 19:12 ` [PATCH v2 029/117] nfsd: Add a mutex to protect the NFSv4.0 open owner replay cache Jeff Layton
                   ` (90 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

Access to this list is currently serialized by the client_mutex. Add
finer grained locking around this list in preparation for its removal.

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

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index a2b4f2cbab42..8793d9ec8311 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -719,7 +719,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);
 }
 
@@ -2812,7 +2816,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_locks);
 	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;
@@ -2821,6 +2824,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
@@ -2928,6 +2934,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))
@@ -2935,6 +2942,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;
 }
@@ -3134,6 +3142,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)
@@ -3142,9 +3151,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;
 }
 
@@ -4420,7 +4432,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);
@@ -4429,6 +4440,9 @@ alloc_init_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp, struct
 	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);
 	return stp;
 }
 
-- 
1.9.3


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

* [PATCH v2 029/117] nfsd: Add a mutex to protect the NFSv4.0 open owner replay cache
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (27 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 028/117] nfsd: Add fine grained protection for the nfs4_file->fi_stateids list Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-26 19:12 ` [PATCH v2 030/117] nfsd: Add locking to the nfs4_file->fi_fds[] array Jeff Layton
                   ` (89 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

We don't want to rely on the client_mutex 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/nfs4xdr.c   |  2 --
 fs/nfsd/state.h     |  1 +
 fs/nfsd/xdr4.h      | 21 +++++++++++++++++++++
 5 files changed, 35 insertions(+), 23 deletions(-)

diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index eec0737abddd..377f4c339cd8 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -468,11 +468,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;
 }
 
@@ -1403,10 +1403,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 8793d9ec8311..ba5408828b23 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -888,7 +888,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)
@@ -2757,6 +2757,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)
@@ -4071,8 +4072,7 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
 	if (status)
 		return status;
 	stp = openlockstateid(s);
-	if (!nfsd4_has_session(cstate))
-		cstate->replay_owner = stp->st_stateowner;
+	nfsd4_cstate_assign_replay(cstate, stp->st_stateowner);
 
 	status = nfs4_seqid_op_checks(cstate, stateid, seqid, stp);
 	if (!status)
@@ -4133,8 +4133,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;
 }
 
@@ -4216,8 +4215,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;
 }
 
@@ -4272,8 +4270,7 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 
 	nfsd4_close_open_stateid(stp);
 out:
-	if (!cstate->replay_owner)
-		nfs4_unlock_state();
+	nfs4_unlock_state();
 	return status;
 }
 
@@ -4667,8 +4664,7 @@ out:
 	if (status && new_state)
 		release_lockowner_if_empty(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)
@@ -4829,8 +4825,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/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 68ea99d389ad..4ae4a03b212d 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -3924,8 +3924,6 @@ status:
  * 
  * XDR note: do not encode rp->rp_buflen: the buffer contains the
  * previously sent already encoded operation.
- *
- * called with nfs4_lock_state() held
  */
 void
 nfsd4_encode_replay(struct xdr_stream *xdr, struct nfsd4_op *op)
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 9eb4fe673014..30ad57089896 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -327,6 +327,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 312f6483a48e..ec9674a009bd 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -74,6 +74,27 @@ 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.3


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

* [PATCH v2 030/117] nfsd: Add locking to the nfs4_file->fi_fds[] array
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (28 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 029/117] nfsd: Add a mutex to protect the NFSv4.0 open owner replay cache Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-26 19:12 ` [PATCH v2 031/117] nfsd: refactor nfs4_file_get_access and nfs4_file_put_access Jeff Layton
                   ` (88 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

Preparation for removal of the client_mutex, which currently protects
this array.

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

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index ba5408828b23..40171e2f9178 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -269,6 +269,52 @@ 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;
+}
+
+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;
 
@@ -317,20 +363,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);
 	}
 }
 
@@ -748,8 +803,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);
 }
@@ -3190,17 +3247,27 @@ nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh,
 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)
 			goto out;
+		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);
 
 	status = nfsd4_truncate(rqstp, cur_fh, open);
 	if (status)
@@ -3285,13 +3352,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;
 }
@@ -3917,6 +3986,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:
@@ -3944,7 +4014,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;
@@ -4661,6 +4731,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 		break;
 	}
 out:
+	if (filp)
+		fput(filp);
 	if (status && new_state)
 		release_lockowner_if_empty(lock_sop);
 	nfsd4_bump_seqid(cstate, status);
@@ -4800,7 +4872,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;
@@ -4822,7 +4894,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();
@@ -4832,7 +4905,7 @@ out:
 
 out_nfserr:
 	status = nfserrno(err);
-	goto out;
+	goto fput;
 }
 
 /*
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 30ad57089896..dc56ec234df7 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -399,32 +399,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.3


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

* [PATCH v2 031/117] nfsd: refactor nfs4_file_get_access and nfs4_file_put_access
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (29 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 030/117] nfsd: Add locking to the nfs4_file->fi_fds[] array Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-26 19:12 ` [PATCH v2 032/117] nfsd: remove nfs4_file_put_fd Jeff Layton
                   ` (87 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

Have them take NFS4_SHARE_ACCESS_* flags instead of an open mode. This
spares the callers from having to convert it themselves.

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

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 40171e2f9178..a6f1549a560e 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -340,6 +340,20 @@ static unsigned int ownerstr_hashval(u32 clientid, struct xdr_netobj *ownername)
 #define FILE_HASH_BITS                   8
 #define FILE_HASH_SIZE                  (1 << FILE_HASH_BITS)
 
+static int nfs4_access_to_omode(u32 access)
+{
+	switch (access & NFS4_SHARE_ACCESS_BOTH) {
+	case NFS4_SHARE_ACCESS_READ:
+		return O_RDONLY;
+	case NFS4_SHARE_ACCESS_WRITE:
+		return O_WRONLY;
+	case NFS4_SHARE_ACCESS_BOTH:
+		return O_RDWR;
+	}
+	WARN_ON_ONCE(1);
+	return O_RDONLY;
+}
+
 static unsigned int file_hashval(struct inode *ino)
 {
 	/* XXX: why are we hashing on inode pointer, anyway? */
@@ -354,8 +368,15 @@ static void __nfs4_file_get_access(struct nfs4_file *fp, int oflag)
 	atomic_inc(&fp->fi_access[oflag]);
 }
 
-static void nfs4_file_get_access(struct nfs4_file *fp, int oflag)
+static void nfs4_file_get_access(struct nfs4_file *fp, u32 access)
 {
+	int oflag = nfs4_access_to_omode(access);
+
+	/* Note: relies on NFS4_SHARE_ACCESS_BOTH == READ|WRITE */
+	access &= (NFS4_SHARE_ACCESS_READ|NFS4_SHARE_ACCESS_WRITE);
+	if (access == 0)
+		return;
+
 	if (oflag == O_RDWR) {
 		__nfs4_file_get_access(fp, O_RDONLY);
 		__nfs4_file_get_access(fp, O_WRONLY);
@@ -389,8 +410,15 @@ static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag)
 	}
 }
 
-static void nfs4_file_put_access(struct nfs4_file *fp, int oflag)
+static void nfs4_file_put_access(struct nfs4_file *fp, u32 access)
 {
+	int oflag;
+
+	access &= (NFS4_SHARE_ACCESS_READ|NFS4_SHARE_ACCESS_WRITE);
+	if (!access)
+		return;
+
+	oflag = nfs4_access_to_omode(access);
 	if (oflag == O_RDWR) {
 		__nfs4_file_put_access(fp, O_RDONLY);
 		__nfs4_file_put_access(fp, O_WRONLY);
@@ -744,20 +772,6 @@ test_deny(u32 access, struct nfs4_ol_stateid *stp)
 	return test_bit(access, &stp->st_deny_bmap);
 }
 
-static int nfs4_access_to_omode(u32 access)
-{
-	switch (access & NFS4_SHARE_ACCESS_BOTH) {
-	case NFS4_SHARE_ACCESS_READ:
-		return O_RDONLY;
-	case NFS4_SHARE_ACCESS_WRITE:
-		return O_WRONLY;
-	case NFS4_SHARE_ACCESS_BOTH:
-		return O_RDWR;
-	}
-	WARN_ON_ONCE(1);
-	return O_RDONLY;
-}
-
 /* release all access and file references for a given stateid */
 static void
 release_all_access(struct nfs4_ol_stateid *stp)
@@ -766,8 +780,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_access_to_omode(i));
+			nfs4_file_put_access(stp->st_file, i);
 		clear_access(i, stp);
 	}
 }
@@ -3264,7 +3277,7 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
 			filp = NULL;
 		}
 	}
-	nfs4_file_get_access(fp, oflag);
+	nfs4_file_get_access(fp, open->op_share_access);
 	spin_unlock(&fp->fi_lock);
 	if (filp)
 		fput(filp);
@@ -3276,7 +3289,7 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
 	return nfs_ok;
 
 out_put_access:
-	nfs4_file_put_access(fp, oflag);
+	nfs4_file_put_access(fp, open->op_share_access);
 out:
 	return status;
 }
@@ -4211,7 +4224,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_file, access);
 	clear_access(access, stp);
 }
 
@@ -4536,11 +4549,10 @@ 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;
-	int oflag = nfs4_access_to_omode(access);
 
 	if (test_access(access, lock_stp))
 		return;
-	nfs4_file_get_access(fp, oflag);
+	nfs4_file_get_access(fp, access);
 	set_access(access, lock_stp);
 }
 
-- 
1.9.3


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

* [PATCH v2 032/117] nfsd: remove nfs4_file_put_fd
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (30 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 031/117] nfsd: refactor nfs4_file_get_access and nfs4_file_put_access Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-26 19:12 ` [PATCH v2 033/117] nfsd: ensure that nfs4_file_get_access enforces deny modes Jeff Layton
                   ` (86 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

...and replace it with a simple swap call.

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

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index a6f1549a560e..0b6cd933eac6 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -384,24 +384,15 @@ static void nfs4_file_get_access(struct nfs4_file *fp, u32 access)
 		__nfs4_file_get_access(fp, oflag);
 }
 
-static struct file *nfs4_file_put_fd(struct nfs4_file *fp, int oflag)
-{
-	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_lock(&fp->fi_access[oflag], &fp->fi_lock)) {
 		struct file *f1 = NULL;
 		struct file *f2 = NULL;
 
-		f1 = nfs4_file_put_fd(fp, oflag);
+		swap(f1, fp->fi_fds[oflag]);
 		if (atomic_read(&fp->fi_access[1 - oflag]) == 0)
-			f2 = nfs4_file_put_fd(fp, O_RDWR);
+			swap(f2, fp->fi_fds[O_RDWR]);
 		spin_unlock(&fp->fi_lock);
 		if (f1)
 			fput(f1);
-- 
1.9.3


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

* [PATCH v2 033/117] nfsd: ensure that nfs4_file_get_access enforces deny modes
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (31 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 032/117] nfsd: remove nfs4_file_put_fd Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-27 19:59   ` Jeff Layton
  2014-06-26 19:12 ` [PATCH v2 034/117] nfsd: cleanup nfs4_check_open Jeff Layton
                   ` (85 subsequent siblings)
  118 siblings, 1 reply; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

The current enforcement of deny modes is both inefficient and scattered.
The former is a problem now, and the latter problem will mean races once
the client_mutex is removed.

First, we address the inefficiency. We (necessarily) track deny modes on
a per-stateid basis, but when we go to enforce them we have to walk the
entire list of stateids and check against each one. Instead of doing
that, maintain a per-nfs4_file deny mode.

When a file is opened, we simply set any deny bits in that mode that
were specified in the OPEN call. We can then use that unified deny mode
to do a simple check to see whether there are any conflicts without
needing to walk the entire stateid list.

The only time we'll need to walk the entire list of stateids is when
a stateid that has a deny mode on it is being released, or one is having
its deny mode downgraded. In that case, we must walk the entire list
and recalculate the fi_share_deny field. Since deny modes are pretty
rare today, this shouldn't happen much under normal workloads.

To address the potential for races once the client_mutex is removed, we
first check for conflicting deny modes in nfs4_file_get_access prior to
opening the file. If it turns out that we need to do a VFS layer open of
the file, then do so and recheck for conflicting deny modes afterward.
If there are any, then just put access to the file and return
nfserr_share_denied.

Finally, deal with potential races in get_lock_access. Taking an
fi_access reference must be done under the fi_lock, or that could race
with a nfs4_file_put_access call. Since we will have just dropped the
lock after finding a readable or writeable file, add some *_locked
variants of find_readable_file and find_writeable_file that we can call
while already holding the fi_lock.

Signed-off-by: Jeff Layton <jlayton@primarydata.com>
---
 fs/nfsd/nfs4state.c | 229 +++++++++++++++++++++++++++++++++++++++-------------
 fs/nfsd/state.h     |   1 +
 2 files changed, 172 insertions(+), 58 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 0b6cd933eac6..93d175661c8d 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -276,27 +276,49 @@ static struct file *__nfs4_get_fd(struct nfs4_file *f, int oflag)
 	return NULL;
 }
 
-static struct file *find_writeable_file(struct nfs4_file *f)
+static struct file *find_writeable_file_locked(struct nfs4_file *f)
 {
 	struct file *ret;
 
-	spin_lock(&f->fi_lock);
+	lockdep_assert_held(&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)
+static struct file *find_writeable_file(struct nfs4_file *f)
 {
 	struct file *ret;
 
 	spin_lock(&f->fi_lock);
+	ret = find_writeable_file_locked(f);
+	spin_unlock(&f->fi_lock);
+
+	return ret;
+}
+
+static struct file *find_readable_file_locked(struct nfs4_file *f)
+{
+	struct file *ret;
+
+	lockdep_assert_held(&f->fi_lock);
+
 	ret = __nfs4_get_fd(f, O_RDONLY);
 	if (!ret)
 		ret = __nfs4_get_fd(f, O_RDWR);
+	return ret;
+}
+
+static struct file *find_readable_file(struct nfs4_file *f)
+{
+	struct file *ret;
+
+	spin_lock(&f->fi_lock);
+	ret = find_readable_file_locked(f);
 	spin_unlock(&f->fi_lock);
+
 	return ret;
 }
 
@@ -362,26 +384,72 @@ static unsigned int file_hashval(struct inode *ino)
 
 static struct hlist_head file_hashtbl[FILE_HASH_SIZE];
 
-static void __nfs4_file_get_access(struct nfs4_file *fp, int oflag)
+static void
+__nfs4_file_get_access(struct nfs4_file *fp, u32 access)
 {
-	WARN_ON_ONCE(!(fp->fi_fds[oflag] || fp->fi_fds[O_RDWR]));
-	atomic_inc(&fp->fi_access[oflag]);
+	int oflag = nfs4_access_to_omode(access);
+
+	lockdep_assert_held(&fp->fi_lock);
+
+	if (oflag == O_RDWR) {
+		atomic_inc(&fp->fi_access[O_RDONLY]);
+		atomic_inc(&fp->fi_access[O_WRONLY]);
+	} else
+		atomic_inc(&fp->fi_access[oflag]);
 }
 
-static void nfs4_file_get_access(struct nfs4_file *fp, u32 access)
+static __be32
+nfs4_file_get_access(struct nfs4_file *fp, u32 access)
 {
-	int oflag = nfs4_access_to_omode(access);
-
 	/* Note: relies on NFS4_SHARE_ACCESS_BOTH == READ|WRITE */
-	access &= (NFS4_SHARE_ACCESS_READ|NFS4_SHARE_ACCESS_WRITE);
+	access &= NFS4_SHARE_ACCESS_BOTH;
+
+	/* Does this access mask make sense? */
 	if (access == 0)
-		return;
+		return nfserr_inval;
 
-	if (oflag == O_RDWR) {
-		__nfs4_file_get_access(fp, O_RDONLY);
-		__nfs4_file_get_access(fp, O_WRONLY);
-	} else
-		__nfs4_file_get_access(fp, oflag);
+	/* Does it conflict with a deny mode already set? */
+	if ((access & fp->fi_share_deny) != 0)
+		return nfserr_share_denied;
+
+	__nfs4_file_get_access(fp, access);
+	return nfs_ok;
+}
+
+static __be32 nfs4_file_check_deny(struct nfs4_file *fp, u32 access, u32 deny)
+{
+	int rdcnt = 0;
+	int wrcnt = 0;
+
+	lockdep_assert_held(&fp->fi_lock);
+
+	/*
+	 * We must take into account any references that were already taken
+	 * on behalf of this open attempt.
+	 */
+	switch (access) {
+	case NFS4_SHARE_ACCESS_READ:
+		++rdcnt;
+		break;
+	case NFS4_SHARE_ACCESS_WRITE:
+		++wrcnt;
+		break;
+	case NFS4_SHARE_ACCESS_BOTH:
+		++rdcnt;
+		++wrcnt;
+	}
+
+	/* Note: relies on NFS4_SHARE_DENY_BOTH == READ|WRITE */
+	deny &= NFS4_SHARE_DENY_BOTH;
+	if (deny) {
+		if ((deny & NFS4_SHARE_DENY_READ) &&
+		    (atomic_read(&fp->fi_access[O_RDONLY]) - rdcnt) > 0)
+			return nfserr_share_denied;
+		if ((deny & NFS4_SHARE_DENY_WRITE) &&
+		    (atomic_read(&fp->fi_access[O_WRONLY]) - wrcnt) > 0)
+			return nfserr_share_denied;
+	}
+	return nfs_ok;
 }
 
 static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag)
@@ -710,17 +778,6 @@ bmap_to_share_mode(unsigned long bmap) {
 	return access;
 }
 
-static bool
-test_share(struct nfs4_ol_stateid *stp, struct nfsd4_open *open) {
-	unsigned int access, deny;
-
-	access = bmap_to_share_mode(stp->st_access_bmap);
-	deny = bmap_to_share_mode(stp->st_deny_bmap);
-	if ((access & open->op_share_deny) || (deny & open->op_share_access))
-		return false;
-	return true;
-}
-
 /* set share access for a given stateid */
 static inline void
 set_access(u32 access, struct nfs4_ol_stateid *stp)
@@ -763,11 +820,31 @@ test_deny(u32 access, struct nfs4_ol_stateid *stp)
 	return test_bit(access, &stp->st_deny_bmap);
 }
 
+/*
+ * A stateid that had a deny mode associated with it is being released
+ * or downgraded. Recalculate the deny mode on the file.
+ */
+static void
+recalculate_deny_mode(struct nfs4_file *fp)
+{
+	struct nfs4_ol_stateid *stp;
+
+	spin_lock(&fp->fi_lock);
+	fp->fi_share_deny = 0;
+	list_for_each_entry(stp, &fp->fi_stateids, st_perfile)
+		fp->fi_share_deny |= bmap_to_share_mode(stp->st_deny_bmap);
+	spin_unlock(&fp->fi_lock);
+}
+
 /* release all access and file references for a given stateid */
 static void
 release_all_access(struct nfs4_ol_stateid *stp)
 {
 	int i;
+	struct nfs4_file *fp = stp->st_file;
+
+	if (fp && stp->st_deny_bmap != 0)
+		recalculate_deny_mode(fp);
 
 	for (i = 1; i < 4; i++) {
 		if (test_access(i, stp))
@@ -2760,6 +2837,7 @@ static void nfsd4_init_file(struct nfs4_file *fp, struct inode *ino)
 	fp->fi_inode = ino;
 	fp->fi_had_conflict = false;
 	fp->fi_lease = NULL;
+	fp->fi_share_deny = 0;
 	memset(fp->fi_fds, 0, sizeof(fp->fi_fds));
 	memset(fp->fi_access, 0, sizeof(fp->fi_access));
 	hlist_add_head(&fp->fi_hash, &file_hashtbl[hashval]);
@@ -2988,22 +3066,15 @@ nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type)
 {
 	struct inode *ino = current_fh->fh_dentry->d_inode;
 	struct nfs4_file *fp;
-	struct nfs4_ol_stateid *stp;
-	__be32 ret;
+	__be32 ret = nfs_ok;
 
 	fp = find_file(ino);
 	if (!fp)
-		return nfs_ok;
-	ret = nfserr_locked;
-	/* Search for conflicting share reservations */
+		return ret;
+	/* Check 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))
-			goto out;
-	}
-	ret = nfs_ok;
-out:
+	if (fp->fi_share_deny & deny_type)
+		ret = nfserr_locked;
 	spin_unlock(&fp->fi_lock);
 	put_nfs4_file(fp);
 	return ret;
@@ -3204,21 +3275,18 @@ 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);
+	lockdep_assert_held(&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)
 			continue;
 		/* remember if we have seen this open owner */
-		if (local->st_stateowner == &oo->oo_owner)
+		if (local->st_stateowner == &oo->oo_owner) {
 			*stpp = local;
-		/* check for conflicting share reservations */
-		if (!test_share(local, open)) {
-			spin_unlock(&fp->fi_lock);
-			return nfserr_share_denied;
+			break;
 		}
 	}
-	spin_unlock(&fp->fi_lock);
 	return nfs_ok;
 }
 
@@ -3257,18 +3325,46 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
 	int access = nfs4_access_to_access(open->op_share_access);
 
 	spin_lock(&fp->fi_lock);
+	/* Are we trying to set a deny mode that would conflict? */
+	status = nfs4_file_check_deny(fp, 0, open->op_share_deny);
+	if (status != nfs_ok) {
+		spin_unlock(&fp->fi_lock);
+		goto out;
+	}
+
+	/* Set access to the file */
+	status = nfs4_file_get_access(fp, open->op_share_access);
+	if (status != nfs_ok) {
+		spin_unlock(&fp->fi_lock);
+		goto out;
+	}
+
 	if (!fp->fi_fds[oflag]) {
 		spin_unlock(&fp->fi_lock);
 		status = nfsd_open(rqstp, cur_fh, S_IFREG, access, &filp);
 		if (status)
-			goto out;
+			goto out_put_access;
 		spin_lock(&fp->fi_lock);
 		if (!fp->fi_fds[oflag]) {
 			fp->fi_fds[oflag] = filp;
 			filp = NULL;
 		}
+
+		/*
+		 * Recheck: did someone race in and open the file in a way that
+		 *	    would conflict with our deny bits?
+		 */
+		if (nfs4_file_check_deny(fp, open->op_share_access,
+					 open->op_share_deny)) {
+			spin_unlock(&fp->fi_lock);
+			status = nfserr_share_denied;
+			goto out_put_access;
+		}
+
+		/* Set any new deny bits */
+		fp->fi_share_deny |= (open->op_share_deny &
+					NFS4_SHARE_DENY_BOTH);
 	}
-	nfs4_file_get_access(fp, open->op_share_access);
 	spin_unlock(&fp->fi_lock);
 	if (filp)
 		fput(filp);
@@ -3276,13 +3372,11 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
 	status = nfsd4_truncate(rqstp, cur_fh, open);
 	if (status)
 		goto out_put_access;
-
-	return nfs_ok;
-
-out_put_access:
-	nfs4_file_put_access(fp, open->op_share_access);
 out:
 	return status;
+out_put_access:
+	nfs4_file_put_access(fp, open->op_share_access);
+	goto out;
 }
 
 static __be32
@@ -3526,7 +3620,12 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
 	 */
 	fp = find_or_add_file(ino, open->op_file);
 	if (fp != open->op_file) {
-		if ((status = nfs4_check_open(fp, open, &stp)))
+		spin_lock(&fp->fi_lock);
+		status = nfs4_file_check_deny(fp, 0, open->op_share_deny);
+		if (status == nfs_ok)
+			status = nfs4_check_open(fp, open, &stp);
+		spin_unlock(&fp->fi_lock);
+		if (status)
 			goto out;
 		status = nfs4_check_deleg(cl, open, &dp);
 		if (status)
@@ -4241,10 +4340,16 @@ static void
 reset_union_bmap_deny(unsigned long deny, struct nfs4_ol_stateid *stp)
 {
 	int i;
+	u32 prev_deny = bmap_to_share_mode(stp->st_deny_bmap);
+
 	for (i = 0; i < 4; i++) {
 		if ((i & deny) != i)
 			clear_deny(i, stp);
 	}
+
+	/* Downgrade per-file deny mode if this one changed */
+	if (prev_deny != deny)
+		recalculate_deny_mode(stp->st_file);
 }
 
 __be32
@@ -4541,9 +4646,11 @@ static void get_lock_access(struct nfs4_ol_stateid *lock_stp, u32 access)
 {
 	struct nfs4_file *fp = lock_stp->st_file;
 
+	lockdep_assert_held(&fp->fi_lock);
+
 	if (test_access(access, lock_stp))
 		return;
-	nfs4_file_get_access(fp, access);
+	__nfs4_file_get_access(fp, access);
 	set_access(access, lock_stp);
 }
 
@@ -4595,6 +4702,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	struct file *filp = NULL;
 	struct file_lock *file_lock = NULL;
 	struct file_lock *conflock = NULL;
+	struct nfs4_file *fp;
 	__be32 status = 0;
 	bool new_state = false;
 	int lkflg;
@@ -4672,20 +4780,25 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 		goto out;
 	}
 
+	fp = lock_stp->st_file;
 	locks_init_lock(file_lock);
 	switch (lock->lk_type) {
 		case NFS4_READ_LT:
 		case NFS4_READW_LT:
-			filp = find_readable_file(lock_stp->st_file);
+			spin_lock(&fp->fi_lock);
+			filp = find_readable_file_locked(fp);
 			if (filp)
 				get_lock_access(lock_stp, NFS4_SHARE_ACCESS_READ);
+			spin_unlock(&fp->fi_lock);
 			file_lock->fl_type = F_RDLCK;
 			break;
 		case NFS4_WRITE_LT:
 		case NFS4_WRITEW_LT:
-			filp = find_writeable_file(lock_stp->st_file);
+			spin_lock(&fp->fi_lock);
+			filp = find_writeable_file_locked(fp);
 			if (filp)
 				get_lock_access(lock_stp, NFS4_SHARE_ACCESS_WRITE);
+			spin_unlock(&fp->fi_lock);
 			file_lock->fl_type = F_WRLCK;
 			break;
 		default:
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index dc56ec234df7..561b94181751 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -392,6 +392,7 @@ struct nfs4_file {
 	 *   + 1 to both of the above if NFS4_SHARE_ACCESS_BOTH is set.
 	 */
 	atomic_t		fi_access[2];
+	u32			fi_share_deny;
 	struct file		*fi_deleg_file;
 	struct file_lock	*fi_lease;
 	atomic_t		fi_delegees;
-- 
1.9.3


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

* [PATCH v2 034/117] nfsd: cleanup nfs4_check_open
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (32 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 033/117] nfsd: ensure that nfs4_file_get_access enforces deny modes Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-26 19:12 ` [PATCH v2 035/117] locks: add file_has_lease to prevent delegation break races Jeff Layton
                   ` (84 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

Rename it to better describe what it does, and have it just return the
stateid instead of a __be32 (which is now always nfs_ok).

Signed-off-by: Jeff Layton <jlayton@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 93d175661c8d..e75cb6da1e64 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -3269,10 +3269,10 @@ out:
 	return nfs_ok;
 }
 
-static __be32
-nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_ol_stateid **stpp)
+static struct nfs4_ol_stateid *
+nfsd4_find_existing_open(struct nfs4_file *fp, struct nfsd4_open *open)
 {
-	struct nfs4_ol_stateid *local;
+	struct nfs4_ol_stateid *local, *ret = NULL;
 	struct nfs4_openowner *oo = open->op_openowner;
 
 	lockdep_assert_held(&fp->fi_lock);
@@ -3283,11 +3283,11 @@ 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;
 			break;
 		}
 	}
-	return nfs_ok;
+	return ret;
 }
 
 static inline int nfs4_access_to_access(u32 nfs4_access)
@@ -3623,7 +3623,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
 		spin_lock(&fp->fi_lock);
 		status = nfs4_file_check_deny(fp, 0, open->op_share_deny);
 		if (status == nfs_ok)
-			status = nfs4_check_open(fp, open, &stp);
+			stp = nfsd4_find_existing_open(fp, open);
 		spin_unlock(&fp->fi_lock);
 		if (status)
 			goto out;
-- 
1.9.3


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

* [PATCH v2 035/117] locks: add file_has_lease to prevent delegation break races
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (33 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 034/117] nfsd: cleanup nfs4_check_open Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-26 19:12 ` [PATCH v2 036/117] nfsd: Protect the nfs4_file delegation fields using the fi_lock Jeff Layton
                   ` (83 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

Once we remove the client_mutex, we'll have a potential race between
setting a lease on a file and breaking the delegation. We may set the
lease, but by the time we go to hash it, it may have already been
broken. Currently, we know that this won't happen as the nfs4_laundromat
takes the client_mutex, but we want to remove that.

As part of that fix, add a function that can tell us whether a
particular file has a lease set on it. In a later nfsd patch, we'll use
that to close the potential race window.

Signed-off-by: Jeff Layton <jlayton@primarydata.com>
---
 fs/locks.c         | 26 ++++++++++++++++++++++++++
 include/linux/fs.h |  6 ++++++
 2 files changed, 32 insertions(+)

diff --git a/fs/locks.c b/fs/locks.c
index 717fbc404e6b..005cc86927e3 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -1308,6 +1308,32 @@ static bool leases_conflict(struct file_lock *lease, struct file_lock *breaker)
 }
 
 /**
+ * file_has_lease - does the given file have a lease set on it?
+ * @file: struct file on which we want to check the lease
+ *
+ * Returns true if a lease was is set on the given file description,
+ * false otherwise.
+ */
+bool
+file_has_lease(struct file *file)
+{
+	bool ret = false;
+	struct inode *inode = file_inode(file);
+	struct file_lock *fl;
+
+	spin_lock(&inode->i_lock);
+	for (fl = inode->i_flock; fl && IS_LEASE(fl); fl = fl->fl_next) {
+		if (fl->fl_file == file) {
+			ret = true;
+			break;
+		}
+	}
+	spin_unlock(&inode->i_lock);
+	return ret;
+}
+EXPORT_SYMBOL(file_has_lease);
+
+/**
  *	__break_lease	-	revoke all outstanding leases on file
  *	@inode: the inode of the file to return
  *	@mode: O_RDONLY: break only write leases; O_WRONLY or O_RDWR:
diff --git a/include/linux/fs.h b/include/linux/fs.h
index e11d60cc867b..7ae6f4869669 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -953,6 +953,7 @@ extern int vfs_test_lock(struct file *, struct file_lock *);
 extern int vfs_lock_file(struct file *, unsigned int, struct file_lock *, struct file_lock *);
 extern int vfs_cancel_lock(struct file *filp, struct file_lock *fl);
 extern int flock_lock_file_wait(struct file *filp, struct file_lock *fl);
+extern bool file_has_lease(struct file *file);
 extern int __break_lease(struct inode *inode, unsigned int flags, unsigned int type);
 extern void lease_get_mtime(struct inode *, struct timespec *time);
 extern int generic_setlease(struct file *, long, struct file_lock **);
@@ -1064,6 +1065,11 @@ static inline int flock_lock_file_wait(struct file *filp,
 	return -ENOLCK;
 }
 
+static inline bool file_has_lease(struct file *file)
+{
+	return false;
+}
+
 static inline int __break_lease(struct inode *inode, unsigned int mode, unsigned int type)
 {
 	return 0;
-- 
1.9.3


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

* [PATCH v2 036/117] nfsd: Protect the nfs4_file delegation fields using the fi_lock
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (34 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 035/117] locks: add file_has_lease to prevent delegation break races Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-26 19:12 ` [PATCH v2 037/117] nfsd: clean up helper __release_lock_stateid Jeff Layton
                   ` (82 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

Move more of the delegation fields to be protected by the fi_lock. It's
more granular than the state_lock and in later patches we'll want to
be able to rely on it in addition to the state_lock.

Also, the current code in nfs4_setlease calls vfs_setlease and uses the
client_mutex to ensure that it doesn't disappear before we can hash the
delegation. With the client_mutex gone, we'll have a potential race
condition.

It's possible that the delegation could be recalled after we acquire the
lease but before we ever get around to hashing it. If that happens, then
we'd have a nfs4_file that *thinks* it has a delegation, when it
actually has none.

Attempt to acquire a delegation. If that succeeds, take the state_lock
and recheck to make sure the lease is still there. If it is, then take
the fi_lock and set up the rest of the delegation fields. This prevents
the race because the delegation break workqueue job must also take the
state_lock.

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

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index e75cb6da1e64..01970b3cf593 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -658,6 +658,8 @@ nfs4_put_delegation(struct nfs4_delegation *dp)
 
 static void nfs4_put_deleg_lease(struct nfs4_file *fp)
 {
+	lockdep_assert_held(&state_lock);
+
 	if (!fp->fi_lease)
 		return;
 	if (atomic_dec_and_test(&fp->fi_delegees)) {
@@ -677,11 +679,10 @@ static void
 hash_delegation_locked(struct nfs4_delegation *dp, struct nfs4_file *fp)
 {
 	lockdep_assert_held(&state_lock);
+	lockdep_assert_held(&fp->fi_lock);
 
 	dp->dl_stid.sc_type = NFS4_DELEG_STID;
-	spin_lock(&fp->fi_lock);
 	list_add(&dp->dl_perfile, &fp->fi_delegations);
-	spin_unlock(&fp->fi_lock);
 	list_add(&dp->dl_perclnt, &dp->dl_stid.sc_client->cl_delegations);
 }
 
@@ -692,17 +693,17 @@ 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);
-	spin_lock(&fp->fi_lock);
 	list_del_init(&dp->dl_perfile);
 	spin_unlock(&fp->fi_lock);
-	spin_unlock(&state_lock);
 	if (fp) {
 		nfs4_put_deleg_lease(fp);
-		put_nfs4_file(fp);
 		dp->dl_file = NULL;
 	}
+	spin_unlock(&state_lock);
+	put_nfs4_file(fp);
 }
 
 
@@ -3440,7 +3441,7 @@ 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)
@@ -3448,15 +3449,31 @@ static int nfs4_setlease(struct nfs4_delegation *dp)
 	fl->fl_file = find_readable_file(fp);
 	status = vfs_setlease(fl->fl_file, fl->fl_type, &fl);
 	if (status)
-		goto out_free;
+		goto out_fput;
+	spin_lock(&state_lock);
+	/* Did the lease get broken before we took the lock? */
+	status = -EAGAIN;
+	if (!file_has_lease(fl->fl_file))
+		goto out_unlock;
+	spin_lock(&fp->fi_lock);
+	/* Race breaker */
+	if (fp->fi_lease) {
+		status = 0;
+		atomic_inc(&fp->fi_delegees);
+		hash_delegation_locked(dp, fp);
+		spin_unlock(&fp->fi_lock);
+		goto out_unlock;
+	}
 	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:
+out_unlock:
+	spin_unlock(&state_lock);
+out_fput:
 	if (fl->fl_file)
 		fput(fl->fl_file);
 	locks_free_lock(fl);
@@ -3465,19 +3482,27 @@ out_free:
 
 static int nfs4_set_delegation(struct nfs4_delegation *dp, struct nfs4_file *fp)
 {
+	int status = 0;
+
 	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)
+	if (!fp->fi_lease) {
+		spin_unlock(&fp->fi_lock);
+		spin_unlock(&state_lock);
 		return nfs4_setlease(dp);
-	spin_lock(&state_lock);
+	}
 	atomic_inc(&fp->fi_delegees);
 	if (fp->fi_had_conflict) {
-		spin_unlock(&state_lock);
-		return -EAGAIN;
+		status = -EAGAIN;
+		goto out_unlock;
 	}
 	hash_delegation_locked(dp, fp);
+out_unlock:
+	spin_unlock(&fp->fi_lock);
 	spin_unlock(&state_lock);
 	return 0;
 }
-- 
1.9.3


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

* [PATCH v2 037/117] nfsd: clean up helper __release_lock_stateid
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (35 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 036/117] nfsd: Protect the nfs4_file delegation fields using the fi_lock Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-30 10:40   ` Christoph Hellwig
  2014-06-26 19:12 ` [PATCH v2 038/117] nfsd: Simplify stateid management Jeff Layton
                   ` (81 subsequent siblings)
  118 siblings, 1 reply; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

Use filp_close instead of open coding. filp_close does a bit more than
just release the locks and put the filp. It also calls ->flush and
dnotify_flush, both of which should be done here anyway.

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

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 01970b3cf593..0e42cca6192c 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -885,10 +885,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)lockowner(stp->st_stateowner));
 	close_generic_stateid(stp);
 	free_generic_stateid(stp);
 }
-- 
1.9.3


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

* [PATCH v2 038/117] nfsd: Simplify stateid management
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (36 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 037/117] nfsd: clean up helper __release_lock_stateid Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-26 19:12 ` [PATCH v2 039/117] nfsd: Fix delegation revocation Jeff Layton
                   ` (80 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

Don't allow stateids to clear the open file pointer until they are
being destroyed. Also, move to kzalloc and get rid of explicit
zeroing of fields.

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

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 0e42cca6192c..deddd51f3680 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -491,7 +491,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;
 
@@ -503,11 +503,9 @@ kmem_cache *slab)
 	if (new_id < 0)
 		goto out_free;
 	stid->sc_client = cl;
-	stid->sc_type = 0;
 	stid->sc_stateid.si_opaque.so_id = new_id;
 	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);
 
 	/*
@@ -626,10 +624,8 @@ 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;
 	return dp;
 }
 
@@ -651,6 +647,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--;
 	}
@@ -698,12 +696,9 @@ unhash_delegation(struct nfs4_delegation *dp)
 	list_del_init(&dp->dl_recall_lru);
 	list_del_init(&dp->dl_perfile);
 	spin_unlock(&fp->fi_lock);
-	if (fp) {
+	if (fp)
 		nfs4_put_deleg_lease(fp);
-		dp->dl_file = NULL;
-	}
 	spin_unlock(&state_lock);
-	put_nfs4_file(fp);
 }
 
 
@@ -867,13 +862,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);
 }
 
@@ -4434,6 +4429,10 @@ static void nfsd4_close_open_stateid(struct nfs4_ol_stateid *s)
 		if (list_empty(&oo->oo_owner.so_stateids))
 			release_openowner(oo);
 	} else {
+		if (s->st_file) {
+			put_nfs4_file(s->st_file);
+			s->st_file = NULL;
+		}
 		oo->oo_last_closed_stid = s;
 		/*
 		 * In the 4.0 case we need to keep the owners around a
-- 
1.9.3


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

* [PATCH v2 039/117] nfsd: Fix delegation revocation
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (37 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 038/117] nfsd: Simplify stateid management Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-26 19:12 ` [PATCH v2 040/117] nfsd: Add reference counting to the lock and open stateids Jeff Layton
                   ` (79 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

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 | 56 +++++++++++++++++++++++++++++++++--------------------
 1 file changed, 35 insertions(+), 21 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index deddd51f3680..78b90880d291 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -684,13 +684,13 @@ hash_delegation_locked(struct nfs4_delegation *dp, struct nfs4_file *fp)
 	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)
+unhash_delegation_locked(struct nfs4_delegation *dp)
 {
 	struct nfs4_file *fp = dp->dl_file;
 
-	spin_lock(&state_lock);
+	lockdep_assert_held(&state_lock);
+
 	spin_lock(&fp->fi_lock);
 	list_del_init(&dp->dl_perclnt);
 	list_del_init(&dp->dl_recall_lru);
@@ -698,23 +698,32 @@ unhash_delegation(struct nfs4_delegation *dp)
 	spin_unlock(&fp->fi_lock);
 	if (fp)
 		nfs4_put_deleg_lease(fp);
-	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)
@@ -722,11 +731,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);
 	}
 }
 
@@ -1438,12 +1446,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);
@@ -3584,7 +3593,7 @@ nfs4_open_delegation(struct net *net, struct svc_fh *fh,
 	open->op_delegate_type = NFS4_OPEN_DELEGATE_READ;
 	return;
 out_free:
-	destroy_delegation(dp);
+	unhash_and_destroy_delegation(dp);
 out_no_deleg:
 	open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE;
 	if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS &&
@@ -3855,7 +3864,8 @@ nfs4_laundromat(struct nfsd_net *nn)
 			new_timeo = min(new_timeo, t);
 			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) {
@@ -4497,7 +4507,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();
 
@@ -5323,8 +5333,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;
 	}
@@ -5573,11 +5585,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.3


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

* [PATCH v2 040/117] nfsd: Add reference counting to the lock and open stateids
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (38 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 039/117] nfsd: Fix delegation revocation Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-26 19:12 ` [PATCH v2 041/117] nfsd: Add a struct nfs4_file field to struct nfs4_stid Jeff Layton
                   ` (78 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

When we remove the client_mutex, we'll need to be able to ensure that
these objects aren't destroyed while we're not holding locks.

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 78b90880d291..cad93b38f20b 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -872,8 +872,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);
@@ -891,7 +893,7 @@ static void __release_lock_stateid(struct nfs4_ol_stateid *stp)
 	if (file)
 		filp_close(file, (fl_owner_t)lockowner(stp->st_stateowner));
 	close_generic_stateid(stp);
-	free_generic_stateid(stp);
+	put_generic_stateid(stp);
 }
 
 static void unhash_lockowner(struct nfs4_lockowner *lo)
@@ -954,7 +956,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)
@@ -975,7 +977,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;
 	}
 }
@@ -3742,7 +3744,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,
@@ -4435,9 +4437,9 @@ static void nfsd4_close_open_stateid(struct nfs4_ol_stateid *s)
 	unhash_open_stateid(s);
 
 	if (clp->cl_minorversion) {
-		free_generic_stateid(s);
 		if (list_empty(&oo->oo_owner.so_stateids))
 			release_openowner(oo);
+		put_generic_stateid(s);
 	} else {
 		if (s->st_file) {
 			put_nfs4_file(s->st_file);
-- 
1.9.3


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

* [PATCH v2 041/117] nfsd: Add a struct nfs4_file field to struct nfs4_stid
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (39 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 040/117] nfsd: Add reference counting to the lock and open stateids Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-26 19:12 ` [PATCH v2 042/117] nfsd: Replace nfs4_ol_stateid->st_file with the st_stid.sc_file Jeff Layton
                   ` (77 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

All stateids are associated with a nfs4_file. Let's consolidate.
Start by replacing delegation->dl_file with the dl_stid.sc_file

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

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index cad93b38f20b..40cce9303d46 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -640,6 +640,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);
 }
 
@@ -647,8 +649,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--;
 	}
@@ -687,7 +687,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;
 
 	lockdep_assert_held(&state_lock);
 
@@ -3087,8 +3087,8 @@ nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type)
 
 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);
+	struct nfsd_net *nn = net_generic(dp->dl_stid.sc_client->net,
+					  nfsd_net_id);
 
 	/*
 	 * We can't do this in nfsd_break_deleg_cb because it is
@@ -3436,14 +3436,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;
 
@@ -3493,7 +3493,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);
@@ -4113,7 +4113,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 561b94181751..46ac2d6a9d7a 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -84,6 +84,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 {
@@ -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 */
-	struct nfs4_file	*dl_file;
 	u32			dl_type;
 	time_t			dl_time;
 /* For recall: */
-- 
1.9.3


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

* [PATCH v2 042/117] nfsd: Replace nfs4_ol_stateid->st_file with the st_stid.sc_file
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (40 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 041/117] nfsd: Add a struct nfs4_file field to struct nfs4_stid Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-26 19:12 ` [PATCH v2 043/117] nfsd: Ensure stateids remain unique until they are freed Jeff Layton
                   ` (76 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

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

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 40cce9303d46..a02a5892f839 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -845,21 +845,21 @@ static void
 release_all_access(struct nfs4_ol_stateid *stp)
 {
 	int i;
-	struct nfs4_file *fp = stp->st_file;
+	struct nfs4_file *fp = stp->st_stid.sc_file;
 
 	if (fp && stp->st_deny_bmap != 0)
 		recalculate_deny_mode(fp);
 
 	for (i = 1; i < 4; i++) {
 		if (test_access(i, stp))
-			nfs4_file_put_access(stp->st_file, i);
+			nfs4_file_put_access(stp->st_stid.sc_file, i);
 		clear_access(i, 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);
@@ -877,8 +877,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);
 }
 
@@ -889,7 +887,7 @@ static void __release_lock_stateid(struct nfs4_ol_stateid *stp)
 	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)lockowner(stp->st_stateowner));
 	close_generic_stateid(stp);
@@ -2963,7 +2961,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);
@@ -3584,7 +3582,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;
 
@@ -3907,7 +3905,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;
 }
@@ -4135,10 +4133,12 @@ nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate,
 		if (status)
 			goto out;
 		if (filpp) {
+			struct nfs4_file *fp = stp->st_stid.sc_file;
+
 			if (flags & RD_STATE)
-				file = find_readable_file(stp->st_file);
+				file = find_readable_file(fp);
 			else
-				file = find_writeable_file(stp->st_file);
+				file = find_writeable_file(fp);
 		}
 		break;
 	default:
@@ -4158,7 +4158,7 @@ nfsd4_free_lock_stateid(struct nfs4_ol_stateid *stp)
 {
 	struct nfs4_lockowner *lo = lockowner(stp->st_stateowner);
 
-	if (check_for_locks(stp->st_file, lo))
+	if (check_for_locks(stp->st_stid.sc_file, lo))
 		return nfserr_locks_held;
 	release_lockowner_if_empty(lo);
 	return nfs_ok;
@@ -4344,7 +4344,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, access);
+	nfs4_file_put_access(stp->st_stid.sc_file, access);
 	clear_access(access, stp);
 }
 
@@ -4379,7 +4379,7 @@ reset_union_bmap_deny(unsigned long deny, struct nfs4_ol_stateid *stp)
 
 	/* Downgrade per-file deny mode if this one changed */
 	if (prev_deny != deny)
-		recalculate_deny_mode(stp->st_file);
+		recalculate_deny_mode(stp->st_stid.sc_file);
 }
 
 __be32
@@ -4441,9 +4441,9 @@ static void nfsd4_close_open_stateid(struct nfs4_ol_stateid *s)
 			release_openowner(oo);
 		put_generic_stateid(s);
 	} else {
-		if (s->st_file) {
-			put_nfs4_file(s->st_file);
-			s->st_file = NULL;
+		if (s->st_stid.sc_file) {
+			put_nfs4_file(s->st_stid.sc_file);
+			s->st_stid.sc_file = NULL;
 		}
 		oo->oo_last_closed_stid = s;
 		/*
@@ -4645,7 +4645,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;
@@ -4662,7 +4662,7 @@ find_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp)
 	struct nfs4_ol_stateid *lst;
 
 	list_for_each_entry(lst, &lo->lo_owner.so_stateids, st_perstateowner) {
-		if (lst->st_file == fp)
+		if (lst->st_stid.sc_file == fp)
 			return lst;
 	}
 	return NULL;
@@ -4678,7 +4678,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;
 
 	lockdep_assert_held(&fp->fi_lock);
 
@@ -4690,7 +4690,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;
@@ -4814,7 +4814,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 		goto out;
 	}
 
-	fp = lock_stp->st_file;
+	fp = lock_stp->st_stid.sc_file;
 	locks_init_lock(file_lock);
 	switch (lock->lk_type) {
 		case NFS4_READ_LT:
@@ -5013,7 +5013,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;
@@ -5128,7 +5128,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
 	lo = lockowner(sop);
 	/* see if there are still any locks associated with it */
 	list_for_each_entry(stp, &sop->so_stateids, st_perstateowner) {
-		if (check_for_locks(stp->st_file, lo))
+		if (check_for_locks(stp->st_stid.sc_file, lo))
 			goto out;
 	}
 
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 46ac2d6a9d7a..fc71ad61238d 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -407,7 +407,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.3


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

* [PATCH v2 043/117] nfsd: Ensure stateids remain unique until they are freed
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (41 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 042/117] nfsd: Replace nfs4_ol_stateid->st_file with the st_stid.sc_file Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-26 19:12 ` [PATCH v2 044/117] nfsd: Ensure atomicity of stateid destruction and idr tree removal Jeff Layton
                   ` (75 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

Add an extra delegation state to allow the stateid to remain in the idr
tree until the last reference has been released. This will be necessary
to ensure uniqueness once the client_mutex is removed.

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

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index a02a5892f839..2aa21a263510 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -640,6 +640,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);
@@ -710,7 +711,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);
 }
 
@@ -723,7 +724,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)
@@ -876,7 +877,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);
 }
 
@@ -4041,7 +4041,9 @@ static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid)
 		return nfs_ok;
 	default:
 		printk("unknown stateid type %x\n", s->sc_type);
+		/* Fallthrough */
 	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 fc71ad61238d..7aaf6e74504c 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -81,6 +81,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.3


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

* [PATCH v2 044/117] nfsd: Ensure atomicity of stateid destruction and idr tree removal
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (42 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 043/117] nfsd: Ensure stateids remain unique until they are freed Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-26 19:12 ` [PATCH v2 045/117] nfsd: Cleanup the freeing of stateids Jeff Layton
                   ` (74 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

Preparation for removal of the client_mutex. Ensure that they are done
while holding the clp->cl_lock.

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

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 2aa21a263510..d3e845fa419a 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -629,30 +629,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;
+	lockdep_assert_held(&clp->cl_lock);
 
-	spin_lock(&clp->cl_lock);
 	idr_remove(&clp->cl_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--;
-	}
 }
 
 static void nfs4_put_deleg_lease(struct nfs4_file *fp)
@@ -875,9 +882,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_ol_stateid *stp)
-- 
1.9.3


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

* [PATCH v2 045/117] nfsd: Cleanup the freeing of stateids
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (43 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 044/117] nfsd: Ensure atomicity of stateid destruction and idr tree removal Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-26 19:12 ` [PATCH v2 046/117] nfsd: do filp_close in sc_free callback for lock stateids Jeff Layton
                   ` (73 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

Add a ->free() callback to the struct nfs4_stid, so that we can
release a reference to the stid without caring about the contents.

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

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index d3e845fa419a..b56ff136039d 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -71,6 +71,7 @@ static u64 current_sessionid = 1;
 
 /* forward declarations */
 static int check_for_locks(struct nfs4_file *filp, struct nfs4_lockowner *lowner);
+static void nfs4_free_generic_stateid(struct nfs4_stid *stid);
 static __be32 lookup_clientid(clientid_t *clid,
 		struct nfsd4_compound_state *cstate,
 		struct nfsd_net *nn);
@@ -485,8 +486,15 @@ static void nfs4_file_put_access(struct nfs4_file *fp, u32 access)
 		__nfs4_file_put_access(fp, oflag);
 }
 
-static struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct
-kmem_cache *slab)
+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);
+}
+
+static struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl,
+					 struct kmem_cache *slab)
 {
 	struct nfs4_stid *stid;
 	int new_id;
@@ -525,7 +533,22 @@ out_free:
 
 static struct nfs4_ol_stateid * nfs4_alloc_stateid(struct nfs4_client *clp)
 {
-	return openlockstateid(nfs4_alloc_stid(clp, stateid_slab));
+	struct nfs4_stid *stid;
+	struct nfs4_ol_stateid *stp;
+
+	stid = nfs4_alloc_stid(clp, stateid_slab);
+	if (!stid)
+		return NULL;
+
+	stp = openlockstateid(stid);
+	stp->st_stid.sc_free = nfs4_free_generic_stateid;
+	return stp;
+}
+
+static void nfs4_free_deleg(struct nfs4_stid *stid)
+{
+	nfs4_free_stid(deleg_slab, stid);
+	num_delegations--;
 }
 
 /*
@@ -614,6 +637,8 @@ 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_free = nfs4_free_deleg;
 	/*
 	 * delegation seqid's are never incremented.  The 4.1 special
 	 * meaning of seqid 0 isn't meaningful, really, but let's avoid
@@ -636,30 +661,21 @@ static void remove_stid_locked(struct nfs4_client *clp, struct nfs4_stid *s)
 	idr_remove(&clp->cl_stateids, s->sc_stateid.si_opaque.so_id);
 }
 
-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);
-}
-
-static bool nfs4_put_stid(struct kmem_cache *slab, struct nfs4_stid *s)
+static void nfs4_put_stid(struct nfs4_stid *s)
 {
 	struct nfs4_client *clp = s->sc_client;
 
 	if (!atomic_dec_and_lock(&s->sc_count, &clp->cl_lock))
-		return false;
+		return;
 	remove_stid_locked(clp, s);
 	spin_unlock(&clp->cl_lock);
-	nfs4_free_stid(slab, s);
-	return true;
+	s->sc_free(s);
 }
 
 void
 nfs4_put_delegation(struct nfs4_delegation *dp)
 {
-	if (nfs4_put_stid(deleg_slab, &dp->dl_stid))
-		num_delegations--;
+	nfs4_put_stid(&dp->dl_stid);
 }
 
 static void nfs4_put_deleg_lease(struct nfs4_file *fp)
@@ -875,14 +891,17 @@ static void unhash_generic_stateid(struct nfs4_ol_stateid *stp)
 	list_del(&stp->st_perstateowner);
 }
 
-static void close_generic_stateid(struct nfs4_ol_stateid *stp)
+static void nfs4_free_generic_stateid(struct nfs4_stid *stid)
 {
+	struct nfs4_ol_stateid *stp = openlockstateid(stid);
+
 	release_all_access(stp);
+	nfs4_free_stid(stateid_slab, stid);
 }
 
 static void put_generic_stateid(struct nfs4_ol_stateid *stp)
 {
-	nfs4_put_stid(stateid_slab, &stp->st_stid);
+	nfs4_put_stid(&stp->st_stid);
 }
 
 static void __release_lock_stateid(struct nfs4_ol_stateid *stp)
@@ -895,7 +914,6 @@ static void __release_lock_stateid(struct nfs4_ol_stateid *stp)
 	file = find_any_file(stp->st_stid.sc_file);
 	if (file)
 		filp_close(file, (fl_owner_t)lockowner(stp->st_stateowner));
-	close_generic_stateid(stp);
 	put_generic_stateid(stp);
 }
 
@@ -953,7 +971,6 @@ static void unhash_open_stateid(struct nfs4_ol_stateid *stp)
 {
 	unhash_generic_stateid(stp);
 	release_open_stateid_locks(stp);
-	close_generic_stateid(stp);
 }
 
 static void release_open_stateid(struct nfs4_ol_stateid *stp)
@@ -4455,8 +4472,11 @@ static void nfsd4_close_open_stateid(struct nfs4_ol_stateid *s)
 		oo->oo_last_closed_stid = s;
 		/*
 		 * In the 4.0 case we need to keep the owners around a
-		 * little while to handle CLOSE replay.
+		 * little while to handle CLOSE replay. We still do need
+		 * to release any file access that is held by them
+		 * before returning however.
 		 */
+		release_all_access(s);
 		if (list_empty(&oo->oo_owner.so_stateids))
 			move_to_close_lru(oo, clp->net);
 	}
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 7aaf6e74504c..700ea964fe54 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -86,6 +86,8 @@ struct nfs4_stid {
 	stateid_t sc_stateid;
 	struct nfs4_client *sc_client;
 	struct nfs4_file *sc_file;
+
+	void (*sc_free)(struct nfs4_stid *);
 };
 
 struct nfs4_delegation {
-- 
1.9.3


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

* [PATCH v2 046/117] nfsd: do filp_close in sc_free callback for lock stateids
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (44 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 045/117] nfsd: Cleanup the freeing of stateids Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-26 19:12 ` [PATCH v2 047/117] nfsd: Add locking to protect the state owner lists Jeff Layton
                   ` (72 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

Releasing locks when we unhash the stateid instead of doing so only when
the stateid is actually released is problematic and will complicate some
later changes.

Signed-off-by: Jeff Layton <jlayton@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 b56ff136039d..93876dc366cc 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -899,6 +899,18 @@ static void nfs4_free_generic_stateid(struct nfs4_stid *stid)
 	nfs4_free_stid(stateid_slab, stid);
 }
 
+static void nfs4_free_lock_stateid(struct nfs4_stid *stid)
+{
+	struct nfs4_ol_stateid *stp = openlockstateid(stid);
+	struct nfs4_lockowner *lo = lockowner(stp->st_stateowner);
+	struct file *file;
+
+	file = find_any_file(stp->st_stid.sc_file);
+	if (file)
+		filp_close(file, (fl_owner_t)lo);
+	nfs4_free_generic_stateid(stid);
+}
+
 static void put_generic_stateid(struct nfs4_ol_stateid *stp)
 {
 	nfs4_put_stid(&stp->st_stid);
@@ -906,14 +918,9 @@ static void put_generic_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_stid.sc_file);
-	if (file)
-		filp_close(file, (fl_owner_t)lockowner(stp->st_stateowner));
 	put_generic_stateid(stp);
 }
 
@@ -4673,6 +4680,7 @@ alloc_init_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp, struct
 	stp->st_stateowner = &lo->lo_owner;
 	get_nfs4_file(fp);
 	stp->st_stid.sc_file = fp;
+	stp->st_stid.sc_free = nfs4_free_lock_stateid;
 	stp->st_access_bmap = 0;
 	stp->st_deny_bmap = open_stp->st_deny_bmap;
 	stp->st_openstp = open_stp;
-- 
1.9.3


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

* [PATCH v2 047/117] nfsd: Add locking to protect the state owner lists
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (45 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 046/117] nfsd: do filp_close in sc_free callback for lock stateids Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-26 19:12 ` [PATCH v2 048/117] nfsd: clean up races in lock stateid searching and creation Jeff Layton
                   ` (71 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

Change to using the clp->cl_lock for this. For now, there's a lot of
cl_lock thrashing, but in later patches we'll eliminate that and close
the potential races that can occur when releasing the cl_lock while
walking the lists. For now, the client_mutex prevents those races.

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

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 93876dc366cc..a3413cb4ac46 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -885,6 +885,8 @@ static void unhash_generic_stateid(struct nfs4_ol_stateid *stp)
 {
 	struct nfs4_file *fp = stp->st_stid.sc_file;
 
+	lockdep_assert_held(&stp->st_stateowner->so_client->cl_lock);
+
 	spin_lock(&fp->fi_lock);
 	list_del(&stp->st_perfile);
 	spin_unlock(&fp->fi_lock);
@@ -918,9 +920,13 @@ static void put_generic_stateid(struct nfs4_ol_stateid *stp)
 
 static void __release_lock_stateid(struct nfs4_ol_stateid *stp)
 {
+	struct nfs4_openowner *oo = openowner(stp->st_openstp->st_stateowner);
+
+	spin_lock(&oo->oo_owner.so_client->cl_lock);
 	list_del(&stp->st_locks);
 	unhash_generic_stateid(stp);
 	unhash_stid(&stp->st_stid);
+	spin_unlock(&oo->oo_owner.so_client->cl_lock);
 	put_generic_stateid(stp);
 }
 
@@ -964,20 +970,26 @@ static void release_lock_stateid(struct nfs4_ol_stateid *stp)
 }
 
 static void release_open_stateid_locks(struct nfs4_ol_stateid *open_stp)
+	__releases(&open_stp->st_stateowner->so_client->cl_lock)
+	__acquires(&open_stp->st_stateowner->so_client->cl_lock)
 {
 	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);
+		spin_unlock(&open_stp->st_stateowner->so_client->cl_lock);
 		release_lock_stateid(stp);
+		spin_lock(&open_stp->st_stateowner->so_client->cl_lock);
 	}
 }
 
 static void unhash_open_stateid(struct nfs4_ol_stateid *stp)
 {
+	spin_lock(&stp->st_stateowner->so_client->cl_lock);
 	unhash_generic_stateid(stp);
 	release_open_stateid_locks(stp);
+	spin_unlock(&stp->st_stateowner->so_client->cl_lock);
 }
 
 static void release_open_stateid(struct nfs4_ol_stateid *stp)
@@ -2987,7 +2999,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_locks);
-	list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids);
 	stp->st_stateowner = &oo->oo_owner;
 	get_nfs4_file(fp);
 	stp->st_stid.sc_file = fp;
@@ -2996,9 +3007,12 @@ 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(&oo->oo_owner.so_client->cl_lock);
+	list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids);
 	spin_lock(&fp->fi_lock);
 	list_add(&stp->st_perfile, &fp->fi_stateids);
 	spin_unlock(&fp->fi_lock);
+	spin_unlock(&oo->oo_owner.so_client->cl_lock);
 }
 
 static void
@@ -4669,6 +4683,7 @@ alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, str
 static struct nfs4_ol_stateid *
 alloc_init_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp, struct nfs4_ol_stateid *open_stp)
 {
+	struct nfs4_openowner *oo = openowner(open_stp->st_stateowner);
 	struct nfs4_ol_stateid *stp;
 	struct nfs4_client *clp = lo->lo_owner.so_client;
 
@@ -4676,7 +4691,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_perstateowner, &lo->lo_owner.so_stateids);
 	stp->st_stateowner = &lo->lo_owner;
 	get_nfs4_file(fp);
 	stp->st_stid.sc_file = fp;
@@ -4684,10 +4698,13 @@ 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(&oo->oo_owner.so_client->cl_lock);
 	list_add(&stp->st_locks, &open_stp->st_locks);
+	list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids);
 	spin_lock(&fp->fi_lock);
 	list_add(&stp->st_perfile, &fp->fi_stateids);
 	spin_unlock(&fp->fi_lock);
+	spin_unlock(&oo->oo_owner.so_client->cl_lock);
 	return stp;
 }
 
-- 
1.9.3


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

* [PATCH v2 048/117] nfsd: clean up races in lock stateid searching and creation
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (46 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 047/117] nfsd: Add locking to protect the state owner lists Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-26 19:12 ` [PATCH v2 049/117] nfsd: Convert delegation counter to an atomic_long_t type Jeff Layton
                   ` (70 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

Preparation for removal of the client_mutex.

Currently, no lock aside from the client_mutex is held when calling
find_lock_state. Ensure that the cl_lock is held by adding a lockdep
assertion.

Once we remove the client_mutex, it'll be possible for another thread to
race in and insert a lock state for the same file after we search but
before we insert a new one. Ensure that doesn't happen by redoing the
search after allocating a new stid that we plan to insert. If one is
found just put the one we just allocated.

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

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index a3413cb4ac46..6e918aa0829c 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -4680,16 +4680,14 @@ alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, str
 	return lo;
 }
 
-static struct nfs4_ol_stateid *
-alloc_init_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp, struct nfs4_ol_stateid *open_stp)
+static void
+init_lock_stateid(struct nfs4_ol_stateid *stp, struct nfs4_lockowner *lo,
+		  struct nfs4_file *fp, struct nfs4_ol_stateid *open_stp)
 {
-	struct nfs4_openowner *oo = openowner(open_stp->st_stateowner);
-	struct nfs4_ol_stateid *stp;
 	struct nfs4_client *clp = lo->lo_owner.so_client;
 
-	stp = nfs4_alloc_stateid(clp);
-	if (stp == NULL)
-		return NULL;
+	lockdep_assert_held(&clp->cl_lock);
+
 	stp->st_stid.sc_type = NFS4_LOCK_STID;
 	stp->st_stateowner = &lo->lo_owner;
 	get_nfs4_file(fp);
@@ -4698,20 +4696,20 @@ 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(&oo->oo_owner.so_client->cl_lock);
 	list_add(&stp->st_locks, &open_stp->st_locks);
 	list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids);
 	spin_lock(&fp->fi_lock);
 	list_add(&stp->st_perfile, &fp->fi_stateids);
 	spin_unlock(&fp->fi_lock);
-	spin_unlock(&oo->oo_owner.so_client->cl_lock);
-	return stp;
 }
 
 static struct nfs4_ol_stateid *
 find_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp)
 {
 	struct nfs4_ol_stateid *lst;
+	struct nfs4_client *clp = lo->lo_owner.so_client;
+
+	lockdep_assert_held(&clp->cl_lock);
 
 	list_for_each_entry(lst, &lo->lo_owner.so_stateids, st_perstateowner) {
 		if (lst->st_stid.sc_file == fp)
@@ -4720,6 +4718,36 @@ find_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp)
 	return NULL;
 }
 
+static struct nfs4_ol_stateid *
+find_or_create_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fi,
+			    struct nfs4_ol_stateid *ost, bool *new)
+{
+	struct nfs4_ol_stateid *lst, *nst = NULL;
+	struct nfs4_openowner *oo = openowner(ost->st_stateowner);
+	struct nfs4_client *clp = oo->oo_owner.so_client;
+
+	spin_lock(&clp->cl_lock);
+	lst = find_lock_stateid(lo, fi);
+	if (lst == NULL) {
+		spin_unlock(&clp->cl_lock);
+		nst = nfs4_alloc_stateid(clp);
+		if (nst == NULL)
+			return NULL;
+
+		spin_lock(&clp->cl_lock);
+		lst = find_lock_stateid(lo, fi);
+		if (likely(!lst)) {
+			init_lock_stateid(nst, lo, fi, ost);
+			lst = nst;
+			nst = NULL;
+			*new = true;
+		}
+	}
+	spin_unlock(&clp->cl_lock);
+	if (nst)
+		put_generic_stateid(nst);
+	return lst;
+}
 
 static int
 check_lock_length(u64 offset, u64 length)
@@ -4763,14 +4791,10 @@ static __be32 lookup_or_create_lock_state(struct nfsd4_compound_state *cstate, s
 			return nfserr_bad_seqid;
 	}
 
-	*lst = find_lock_stateid(lo, fi);
+	*lst = find_or_create_lock_stateid(lo, fi, ost, new);
 	if (*lst == NULL) {
-		*lst = alloc_init_lock_stateid(lo, fi, ost);
-		if (*lst == NULL) {
-			release_lockowner_if_empty(lo);
-			return nfserr_jukebox;
-		}
-		*new = true;
+		release_lockowner_if_empty(lo);
+		return nfserr_jukebox;
 	}
 	return nfs_ok;
 }
-- 
1.9.3


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

* [PATCH v2 049/117] nfsd: Convert delegation counter to an atomic_long_t type
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (47 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 048/117] nfsd: clean up races in lock stateid searching and creation Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-26 19:12 ` [PATCH v2 050/117] nfsd: Slight cleanup of find_stateid() Jeff Layton
                   ` (69 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

We want to convert to an atomic type so that we don't need to lock
across the call to alloc_init_deleg(). Then convert to a long type so
that we match the size of 'max_delegations'.

None of this is a problem today, but it will be once we remove
client_mutex protection.

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

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 6e918aa0829c..714273b942ce 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -338,7 +338,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;
 
 /*
@@ -548,7 +548,7 @@ static struct nfs4_ol_stateid * nfs4_alloc_stateid(struct nfs4_client *clp)
 static void nfs4_free_deleg(struct nfs4_stid *stid)
 {
 	nfs4_free_stid(deleg_slab, stid);
-	num_delegations--;
+	atomic_long_dec(&num_delegations);
 }
 
 /*
@@ -628,15 +628,17 @@ static struct nfs4_delegation *
 alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct svc_fh *current_fh)
 {
 	struct nfs4_delegation *dp;
+	long n;
 
 	dprintk("NFSD alloc_init_deleg\n");
-	if (num_delegations > max_delegations)
-		return NULL;
+	n = atomic_long_inc_return(&num_delegations);
+	if (n < 0 || n > max_delegations)
+		goto out_dec;
 	if (delegation_blocked(&current_fh->fh_handle))
-		return NULL;
+		goto out_dec;
 	dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab));
 	if (dp == NULL)
-		return dp;
+		goto out_dec;
 
 	dp->dl_stid.sc_free = nfs4_free_deleg;
 	/*
@@ -645,13 +647,15 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct sv
 	 * 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);
 	dp->dl_type = NFS4_OPEN_DELEGATE_READ;
 	fh_copy_shallow(&dp->dl_fh, &current_fh->fh_handle);
 	return dp;
+out_dec:
+	atomic_long_dec(&num_delegations);
+	return NULL;
 }
 
 static void remove_stid_locked(struct nfs4_client *clp, struct nfs4_stid *s)
-- 
1.9.3


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

* [PATCH v2 050/117] nfsd: Slight cleanup of find_stateid()
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (48 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 049/117] nfsd: Convert delegation counter to an atomic_long_t type Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-26 19:12 ` [PATCH v2 051/117] nfsd: ensure atomicity in nfsd4_free_stateid and nfsd4_validate_stateid Jeff Layton
                   ` (68 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

In preparation of reference counting.

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

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 714273b942ce..b188a40f6416 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1682,28 +1682,37 @@ 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.3


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

* [PATCH v2 051/117] nfsd: ensure atomicity in nfsd4_free_stateid and nfsd4_validate_stateid
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (49 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 050/117] nfsd: Slight cleanup of find_stateid() Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-26 19:12 ` [PATCH v2 052/117] nfsd: Add reference counting to lock stateids Jeff Layton
                   ` (67 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

Hold the cl_lock over the bulk of these functions. In addition to
ensuring that they aren't freed prematurely, this will also help prevent
a potential race that could be introduced later. Once we remove the
client_mutex, it'll be possible for FREE_STATEID and CLOSE to race and
for both to try to put the "persistent" reference to the stateid.

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

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index b188a40f6416..42fea991ae0b 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1693,16 +1693,6 @@ find_stateid_locked(struct nfs4_client *cl, stateid_t *t)
 	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;
@@ -4063,10 +4053,10 @@ static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid)
 {
 	struct nfs4_stid *s;
 	struct nfs4_ol_stateid *ols;
-	__be32 status;
+	__be32 status = nfserr_bad_stateid;
 
 	if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
-		return nfserr_bad_stateid;
+		return status;
 	/* Client debugging aid. */
 	if (!same_clid(&stateid->si_opaque.so_clid, &cl->cl_clientid)) {
 		char addr_str[INET6_ADDRSTRLEN];
@@ -4074,34 +4064,42 @@ static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid)
 				 sizeof(addr_str));
 		pr_warn_ratelimited("NFSD: client %s testing state ID "
 					"with incorrect client ID\n", addr_str);
-		return nfserr_bad_stateid;
+		return status;
 	}
-	s = find_stateid(cl, stateid);
+	spin_lock(&cl->cl_lock);
+	s = find_stateid_locked(cl, stateid);
 	if (!s)
-		return nfserr_bad_stateid;
+		goto out_unlock;
 	status = check_stateid_generation(stateid, &s->sc_stateid, 1);
 	if (status)
-		return status;
+		goto out_unlock;
 	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);
 		/* Fallthrough */
 	case NFS4_CLOSED_STID:
 	case NFS4_CLOSED_DELEG_STID:
-		return nfserr_bad_stateid;
+		status = nfserr_bad_stateid;
 	}
+out_unlock:
+	spin_unlock(&cl->cl_lock);
+	return status;
 }
 
 static __be32
@@ -4252,31 +4250,36 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	__be32 ret = nfserr_bad_stateid;
 
 	nfs4_lock_state();
-	s = find_stateid(cl, stateid);
+	spin_lock(&cl->cl_lock);
+	s = find_stateid_locked(cl, stateid);
 	if (!s)
-		goto out;
+		goto out_unlock;
 	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;
-		if (s->sc_type == NFS4_LOCK_STID)
-			ret = nfsd4_free_lock_stateid(openlockstateid(s));
-		else
+			break;
+		if (s->sc_type != NFS4_LOCK_STID) {
 			ret = nfserr_locks_held;
-		break;
+			break;
+		}
+		spin_unlock(&cl->cl_lock);
+		ret = nfsd4_free_lock_stateid(openlockstateid(s));
+		goto out;
 	case NFS4_REVOKED_DELEG_STID:
+		spin_unlock(&cl->cl_lock);
 		dp = delegstateid(s);
 		destroy_revoked_delegation(dp);
 		ret = nfs_ok;
-		break;
-	default:
-		ret = nfserr_bad_stateid;
+		goto out;
+	/* Default falls through and returns nfserr_bad_stateid */
 	}
+out_unlock:
+	spin_unlock(&cl->cl_lock);
 out:
 	nfs4_unlock_state();
 	return ret;
-- 
1.9.3


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

* [PATCH v2 052/117] nfsd: Add reference counting to lock stateids
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (50 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 051/117] nfsd: ensure atomicity in nfsd4_free_stateid and nfsd4_validate_stateid Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-26 19:12 ` [PATCH v2 053/117] nfsd: nfsd4_locku() must reference the lock stateid Jeff Layton
                   ` (66 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

Ensure that nfsd4_lock() references the lock stateid while it is
manipulating it. Not currently necessary, but will be once the
client_mutex is removed.

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 42fea991ae0b..29b31a6d749b 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -4704,6 +4704,7 @@ init_lock_stateid(struct nfs4_ol_stateid *stp, struct nfs4_lockowner *lo,
 
 	lockdep_assert_held(&clp->cl_lock);
 
+	atomic_inc(&stp->st_stid.sc_count);
 	stp->st_stid.sc_type = NFS4_LOCK_STID;
 	stp->st_stateowner = &lo->lo_owner;
 	get_nfs4_file(fp);
@@ -4728,8 +4729,10 @@ find_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp)
 	lockdep_assert_held(&clp->cl_lock);
 
 	list_for_each_entry(lst, &lo->lo_owner.so_stateids, st_perstateowner) {
-		if (lst->st_stid.sc_file == fp)
+		if (lst->st_stid.sc_file == fp) {
+			atomic_inc(&lst->st_stid.sc_count);
 			return lst;
+		}
 	}
 	return NULL;
 }
@@ -4824,7 +4827,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;
@@ -4878,11 +4881,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);
@@ -4975,6 +4982,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.3


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

* [PATCH v2 053/117] nfsd: nfsd4_locku() must reference the lock stateid
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (51 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 052/117] nfsd: Add reference counting to lock stateids Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-26 19:12 ` [PATCH v2 054/117] nfsd: Ensure that nfs4_open_delegation() references the delegation stateid Jeff Layton
                   ` (65 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

Ensure that nfsd4_locku() keeps a reference to the lock stateid
until it is done working with it. Necessary step toward client_mutex
removal.

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 29b31a6d749b..0c9f707c8470 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -5114,10 +5114,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) {
@@ -5147,6 +5149,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.3


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

* [PATCH v2 054/117] nfsd: Ensure that nfs4_open_delegation() references the delegation stateid
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (52 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 053/117] nfsd: nfsd4_locku() must reference the lock stateid Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-26 19:12 ` [PATCH v2 055/117] nfsd: nfsd4_process_open2() must reference " Jeff Layton
                   ` (64 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

Ensure that nfs4_open_delegation() keeps a reference to the delegation
stateid until it is done working with it. Necessary step toward
client_mutex removal.

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 0c9f707c8470..ed5091e0abec 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -707,6 +707,7 @@ hash_delegation_locked(struct nfs4_delegation *dp, struct nfs4_file *fp)
 	lockdep_assert_held(&state_lock);
 	lockdep_assert_held(&fp->fi_lock);
 
+	atomic_inc(&dp->dl_stid.sc_count);
 	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);
@@ -3637,6 +3638,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:
 	unhash_and_destroy_delegation(dp);
-- 
1.9.3


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

* [PATCH v2 055/117] nfsd: nfsd4_process_open2() must reference the delegation stateid
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (53 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 054/117] nfsd: Ensure that nfs4_open_delegation() references the delegation stateid Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-26 19:12 ` [PATCH v2 056/117] nfsd: nfsd4_process_open2() must reference the open stateid Jeff Layton
                   ` (63 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

Ensure that nfsd4_process_open2() keeps a reference to the delegation
stateid until it is done working with it. Necessary step toward
client_mutex removal.

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 ed5091e0abec..5b88cb314b99 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -3287,6 +3287,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);
 }
 
@@ -3302,14 +3304,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;
@@ -3768,6 +3774,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.3


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

* [PATCH v2 056/117] nfsd: nfsd4_process_open2() must reference the open stateid
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (54 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 055/117] nfsd: nfsd4_process_open2() must reference " Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-26 19:12 ` [PATCH v2 057/117] nfsd: Prepare nfsd4_close() for open stateid referencing Jeff Layton
                   ` (62 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

Ensure that nfsd4_process_open2() keeps a reference to the open
stateid until it is done working with it. Necessary step toward
client_mutex removal.

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

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 5b88cb314b99..bb0676051b6b 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -3001,6 +3001,7 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfsd4_open *open,
 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);
 	stp->st_stateowner = &oo->oo_owner;
@@ -3340,6 +3341,7 @@ nfsd4_find_existing_open(struct nfs4_file *fp, struct nfsd4_open *open)
 		/* remember if we have seen this open owner */
 		if (local->st_stateowner == &oo->oo_owner) {
 			ret = local;
+			atomic_inc(&ret->st_stid.sc_count);
 			break;
 		}
 	}
@@ -3776,6 +3778,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.3


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

* [PATCH v2 057/117] nfsd: Prepare nfsd4_close() for open stateid referencing
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (55 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 056/117] nfsd: nfsd4_process_open2() must reference the open stateid Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-26 19:12 ` [PATCH v2 058/117] nfsd: nfsd4_open_confirm() must reference the open stateid Jeff Layton
                   ` (61 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

Prepare nfsd4_close for a future where nfs4_preprocess_seqid_op()
hands it a fully referenced open stateid. Necessary step toward
client_mutex removal.

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 bb0676051b6b..828205fabd3e 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -4556,10 +4556,15 @@ 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);
 	update_stateid(&stp->st_stid.sc_stateid);
 	memcpy(&close->cl_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
 
 	nfsd4_close_open_stateid(stp);
+
+	/* put reference from nfs4_preprocess_seqid_op */
+	put_generic_stateid(stp);
 out:
 	nfs4_unlock_state();
 	return status;
-- 
1.9.3


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

* [PATCH v2 058/117] nfsd: nfsd4_open_confirm() must reference the open stateid
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (56 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 057/117] nfsd: Prepare nfsd4_close() for open stateid referencing Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-26 19:12 ` [PATCH v2 059/117] nfsd: Add reference counting to nfs4_preprocess_confirmed_seqid_op Jeff Layton
                   ` (60 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

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

Necessary step toward client_mutex removal.

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 828205fabd3e..32d0238cb0bf 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -4397,10 +4397,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));
@@ -4409,6 +4411,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.3


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

* [PATCH v2 059/117] nfsd: Add reference counting to nfs4_preprocess_confirmed_seqid_op
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (57 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 058/117] nfsd: nfsd4_open_confirm() must reference the open stateid Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-26 19:12 ` [PATCH v2 060/117] nfsd: Migrate the stateid reference into nfs4_preprocess_seqid_op Jeff Layton
                   ` (59 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

Ensure that all the callers put the open stateid after use.
Necessary step toward client_mutex removal.

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 32d0238cb0bf..b810be1ce2f7 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -4368,6 +4368,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;
@@ -4487,12 +4489,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);
 
@@ -4501,6 +4503,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();
@@ -4851,6 +4855,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;
@@ -4878,8 +4883,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,
@@ -5007,6 +5010,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.3


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

* [PATCH v2 060/117] nfsd: Migrate the stateid reference into nfs4_preprocess_seqid_op
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (58 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 059/117] nfsd: Add reference counting to nfs4_preprocess_confirmed_seqid_op Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-26 19:12 ` [PATCH v2 061/117] nfsd: Migrate the stateid reference into nfs4_lookup_stateid() Jeff Layton
                   ` (58 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

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 b810be1ce2f7..0eb74ffb8db5 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -4353,8 +4353,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;
 }
 
@@ -4363,16 +4366,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;
 }
 
@@ -4399,8 +4404,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)
@@ -4564,8 +4567,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);
 	update_stateid(&stp->st_stid.sc_stateid);
 	memcpy(&close->cl_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
 
@@ -4912,9 +4913,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;
@@ -5142,8 +5140,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.3


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

* [PATCH v2 061/117] nfsd: Migrate the stateid reference into nfs4_lookup_stateid()
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (59 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 060/117] nfsd: Migrate the stateid reference into nfs4_preprocess_seqid_op Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-26 19:12 ` [PATCH v2 062/117] nfsd: Migrate the stateid reference into nfs4_find_stateid_by_type() Jeff Layton
                   ` (57 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

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 0eb74ffb8db5..e0f140c7c5a4 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -4136,6 +4136,8 @@ nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate,
 	*s = find_stateid_by_type(cstate->clp, stateid, typemask);
 	if (!*s)
 		return nfserr_bad_stateid;
+	/* FIXME: move into find_stateid_by_type */
+	atomic_inc(&(*s)->sc_count);
 	return nfs_ok;
 }
 
@@ -4170,7 +4172,7 @@ nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate,
 				NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID,
 				&s, nn);
 	if (status)
-		goto out;
+		goto unlock_state;
 	status = check_stateid_generation(stateid, &s->sc_stateid, nfsd4_has_session(cstate));
 	if (status)
 		goto out;
@@ -4219,6 +4221,8 @@ nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate,
 	if (file)
 		*filpp = file;
 out:
+	nfs4_put_stid(s);
+unlock_state:
 	nfs4_unlock_state();
 	return status;
 }
@@ -4353,11 +4357,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;
 }
 
@@ -4599,9 +4602,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.3


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

* [PATCH v2 062/117] nfsd: Migrate the stateid reference into nfs4_find_stateid_by_type()
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (60 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 061/117] nfsd: Migrate the stateid reference into nfs4_lookup_stateid() Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-26 19:12 ` [PATCH v2 063/117] nfsd: Add reference counting to state owners Jeff Layton
                   ` (56 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

Allow nfs4_find_stateid_by_type to take the stateid reference, while
still holding the &cl->cl_lock. Necessary step toward client_mutex
removal.

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 e0f140c7c5a4..c5058683877d 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1700,8 +1700,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;
 }
@@ -3288,8 +3292,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);
 }
 
@@ -4136,8 +4138,6 @@ nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate,
 	*s = find_stateid_by_type(cstate->clp, 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.3


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

* [PATCH v2 063/117] nfsd: Add reference counting to state owners
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (61 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 062/117] nfsd: Migrate the stateid reference into nfs4_find_stateid_by_type() Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-26 19:12 ` [PATCH v2 064/117] nfsd: Keep a reference to the open stateid for the NFSv4.0 replay cache Jeff Layton
                   ` (55 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

The way stateowners are managed today is somewhat awkward. They need to
be explicitly destroyed, even though the stateids reference them. This
will be particularly problematic when we remove the client_mutex.

We may create a new stateowner and attempt to open a file or set a lock,
and have that fail. In the meantime, another RPC may come in that uses
that same stateowner and succeed. We can't have the first task tearing
down the stateowner in that situation.

To fix this, we need to change how stateowners are tracked altogether.
Refcount them and only destroy them once all stateids that reference
them have been destroyed. This patch starts by adding the refcounting
necessary to do that.

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

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index c5058683877d..53b11ede4675 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -72,6 +72,7 @@ static u64 current_sessionid = 1;
 /* forward declarations */
 static int check_for_locks(struct nfs4_file *filp, struct nfs4_lockowner *lowner);
 static void nfs4_free_generic_stateid(struct nfs4_stid *stid);
+static void nfs4_put_stateowner(struct nfs4_stateowner *sop);
 static __be32 lookup_clientid(clientid_t *clid,
 		struct nfsd4_compound_state *cstate,
 		struct nfsd_net *nn);
@@ -947,16 +948,10 @@ 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);
-	nfs4_free_lockowner(lo);
+	nfs4_put_stateowner(&lo->lo_owner);
 }
 
 static void release_lockowner_if_empty(struct nfs4_lockowner *lo)
@@ -1026,18 +1021,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);
 	list_del(&oo->oo_close_lru);
 	release_last_closed_stateid(oo);
-	nfs4_free_openowner(oo);
+	nfs4_put_stateowner(&oo->oo_owner);
 }
 
 static inline int
@@ -2969,9 +2958,17 @@ static inline void *alloc_stateowner(struct kmem_cache *slab, struct xdr_netobj
 	INIT_LIST_HEAD(&sop->so_stateids);
 	sop->so_client = clp;
 	init_nfs4_replay(&sop->so_replay);
+	atomic_set(&sop->so_count, 1);
 	return sop;
 }
 
+static void nfs4_put_stateowner(struct nfs4_stateowner *sop)
+{
+	if (!atomic_dec_and_test(&sop->so_count))
+		return;
+	sop->so_free(sop);
+}
+
 static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, unsigned int strhashval)
 {
 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
@@ -2980,6 +2977,14 @@ static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, u
 	list_add(&oo->oo_perclient, &clp->cl_openowners);
 }
 
+static void nfs4_free_openowner(struct nfs4_stateowner *so)
+{
+	struct nfs4_openowner *oo = openowner(so);
+
+	kfree(oo->oo_owner.so_owner.data);
+	kmem_cache_free(openowner_slab, oo);
+}
+
 static struct nfs4_openowner *
 alloc_init_open_stateowner(unsigned int strhashval, struct nfsd4_open *open,
 			   struct nfsd4_compound_state *cstate)
@@ -2990,6 +2995,7 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfsd4_open *open,
 	oo = alloc_stateowner(openowner_slab, &open->op_owner, clp);
 	if (!oo)
 		return NULL;
+	oo->oo_owner.so_free = nfs4_free_openowner;
 	oo->oo_owner.so_is_open_owner = 1;
 	oo->oo_owner.so_seqid = open->op_seqid;
 	oo->oo_flags = NFS4_OO_NEW;
@@ -4705,6 +4711,14 @@ find_lockowner_str(clientid_t *clid, struct xdr_netobj *owner,
 	return NULL;
 }
 
+static void nfs4_free_lockowner(struct nfs4_stateowner *sop)
+{
+	struct nfs4_lockowner *lo = lockowner(sop);
+
+	kfree(lo->lo_owner.so_owner.data);
+	kmem_cache_free(lockowner_slab, lo);
+}
+
 /*
  * Alloc a lock owner structure.
  * Called in nfsd4_lock - therefore, OPEN and OPEN_CONFIRM (if needed) has 
@@ -4725,6 +4739,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;
+	lo->lo_owner.so_free = nfs4_free_lockowner;
 	list_add(&lo->lo_owner.so_strhash, &nn->ownerstr_hashtbl[strhashval]);
 	return lo;
 }
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 700ea964fe54..e8a9bd8c3c61 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -340,10 +340,13 @@ struct nfs4_stateowner {
 	struct nfs4_client *    so_client;
 	/* after increment in ENCODE_SEQID_OP_TAIL, represents the next
 	 * sequence id expected from the client: */
+	atomic_t		so_count;
 	u32                     so_seqid;
 	struct xdr_netobj       so_owner;     /* open owner name */
 	struct nfs4_replay	so_replay;
 	bool			so_is_open_owner;
+
+	void (*so_free)(struct nfs4_stateowner *);
 };
 
 struct nfs4_openowner {
-- 
1.9.3


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

* [PATCH v2 064/117] nfsd: Keep a reference to the open stateid for the NFSv4.0 replay cache
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (62 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 063/117] nfsd: Add reference counting to state owners Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-26 19:12 ` [PATCH v2 065/117] nfsd: clean up lockowner refcounting when finding them Jeff Layton
                   ` (54 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

Ensure that nfsd4_cstate_assign_replay/nfsd4_cstate_clear_replay take
a reference to the stateowner when they are using it for NFSv4.0
open and lock replay caching.

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

diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 377f4c339cd8..833c753e4775 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -467,10 +467,7 @@ out:
 		fh_put(resfh);
 		kfree(resfh);
 	}
-	nfsd4_cleanup_open_state(open, status);
-	if (open->op_openowner)
-		nfsd4_cstate_assign_replay(cstate,
-				&open->op_openowner->oo_owner);
+	nfsd4_cleanup_open_state(cstate, open, status);
 	nfsd4_bump_seqid(cstate, status);
 	nfs4_unlock_state();
 	return status;
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 53b11ede4675..b10551901d03 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -2940,6 +2940,27 @@ static void init_nfs4_replay(struct nfs4_replay *rp)
 	mutex_init(&rp->rp_mutex);
 }
 
+static 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;
+		atomic_inc(&so->so_count);
+	}
+}
+
+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);
+		nfs4_put_stateowner(so);
+	}
+}
+
 static inline void *alloc_stateowner(struct kmem_cache *slab, struct xdr_netobj *owner, struct nfs4_client *clp)
 {
 	struct nfs4_stateowner *sop;
@@ -3792,7 +3813,8 @@ out:
 	return status;
 }
 
-void nfsd4_cleanup_open_state(struct nfsd4_open *open, __be32 status)
+void nfsd4_cleanup_open_state(struct nfsd4_compound_state *cstate,
+			      struct nfsd4_open *open, __be32 status)
 {
 	if (open->op_openowner) {
 		struct nfs4_openowner *oo = open->op_openowner;
@@ -3806,6 +3828,8 @@ void nfsd4_cleanup_open_state(struct nfsd4_open *open, __be32 status)
 			} else
 				oo->oo_flags &= ~NFS4_OO_NEW;
 		}
+		if (open->op_openowner)
+			nfsd4_cstate_assign_replay(cstate, &oo->oo_owner);
 	}
 	if (open->op_file)
 		nfsd4_free_file(open->op_file);
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
index ec9674a009bd..634e016f50d3 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -74,27 +74,6 @@ 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;
@@ -616,7 +595,9 @@ extern __be32 nfsd4_process_open1(struct nfsd4_compound_state *,
 		struct nfsd4_open *open, struct nfsd_net *nn);
 extern __be32 nfsd4_process_open2(struct svc_rqst *rqstp,
 		struct svc_fh *current_fh, struct nfsd4_open *open);
-extern void nfsd4_cleanup_open_state(struct nfsd4_open *open, __be32 status);
+extern void nfsd4_cstate_clear_replay(struct nfsd4_compound_state *cstate);
+extern void nfsd4_cleanup_open_state(struct nfsd4_compound_state *cstate,
+		struct nfsd4_open *open, __be32 status);
 extern __be32 nfsd4_open_confirm(struct svc_rqst *rqstp,
 		struct nfsd4_compound_state *, struct nfsd4_open_confirm *oc);
 extern __be32 nfsd4_close(struct svc_rqst *rqstp,
@@ -647,6 +628,7 @@ extern __be32 nfsd4_test_stateid(struct svc_rqst *rqstp,
 extern __be32 nfsd4_free_stateid(struct svc_rqst *rqstp,
 		struct nfsd4_compound_state *, struct nfsd4_free_stateid *free_stateid);
 extern void nfsd4_bump_seqid(struct nfsd4_compound_state *, __be32 nfserr);
+
 #endif
 
 /*
-- 
1.9.3


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

* [PATCH v2 065/117] nfsd: clean up lockowner refcounting when finding them
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (63 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 064/117] nfsd: Keep a reference to the open stateid for the NFSv4.0 replay cache Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-26 19:12 ` [PATCH v2 066/117] nfsd: add an operation for unhashing a stateowner Jeff Layton
                   ` (53 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

Ensure that when finding or creating a lockowner, that we get a
reference to it. For now, we also take an extra reference when a
lockowner is created that can be put when release_lockowner is called,
but we'll remove that in a later patch once we change how references are
held.

Since we no longer destroy lockowners in the event of an error in
nfsd4_lock, we must change how the seqid gets bumped in the lk_is_new
case. Instead of doing so on creation, do it manually in nfsd4_lock.

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

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index b10551901d03..28d42aaf9745 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -4730,6 +4730,7 @@ find_lockowner_str(clientid_t *clid, struct xdr_netobj *owner,
 			continue;
 		if (!same_owner_str(so, owner, clid))
 			continue;
+		atomic_inc(&so->so_count);
 		return lockowner(so);
 	}
 	return NULL;
@@ -4760,9 +4761,7 @@ alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, str
 		return NULL;
 	INIT_LIST_HEAD(&lo->lo_owner.so_stateids);
 	lo->lo_owner.so_is_open_owner = 0;
-	/* 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;
+	lo->lo_owner.so_seqid = lock->lk_new_lock_seqid;
 	lo->lo_owner.so_free = nfs4_free_lockowner;
 	list_add(&lo->lo_owner.so_strhash, &nn->ownerstr_hashtbl[strhashval]);
 	return lo;
@@ -4859,8 +4858,13 @@ static void get_lock_access(struct nfs4_ol_stateid *lock_stp, u32 access)
 	set_access(access, lock_stp);
 }
 
-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)
+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)
 {
+	__be32 status;
 	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;
@@ -4875,19 +4879,26 @@ static __be32 lookup_or_create_lock_state(struct nfsd4_compound_state *cstate, s
 		lo = alloc_init_lock_stateowner(strhashval, cl, ost, lock);
 		if (lo == NULL)
 			return nfserr_jukebox;
+		/* FIXME: extra reference for new lockowners for the client */
+		atomic_inc(&lo->lo_owner.so_count);
 	} else {
 		/* with an existing lockowner, seqids must be the same */
+		status = nfserr_bad_seqid;
 		if (!cstate->minorversion &&
 		    lock->lk_new_lock_seqid != lo->lo_owner.so_seqid)
-			return nfserr_bad_seqid;
+			goto out;
 	}
 
 	*lst = find_or_create_lock_stateid(lo, fi, ost, new);
 	if (*lst == NULL) {
 		release_lockowner_if_empty(lo);
-		return nfserr_jukebox;
+		status = nfserr_jukebox;
+		goto out;
 	}
-	return nfs_ok;
+	status = nfs_ok;
+out:
+	nfs4_put_stateowner(&lo->lo_owner);
+	return status;
 }
 
 /*
@@ -4906,9 +4917,9 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	struct file_lock *conflock = NULL;
 	struct nfs4_file *fp;
 	__be32 status = 0;
-	bool new_state = false;
 	int lkflg;
 	int err;
+	bool new = false;
 	struct net *net = SVC_NET(rqstp);
 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 
@@ -4951,7 +4962,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 						&lock->v.new.clientid))
 			goto out;
 		status = lookup_or_create_lock_state(cstate, open_stp, lock,
-							&lock_stp, &new_state);
+							&lock_stp, &new);
 	} else {
 		status = nfs4_preprocess_seqid_op(cstate,
 				       lock->lk_old_lock_seqid,
@@ -5050,12 +5061,24 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 out:
 	if (filp)
 		fput(filp);
-	if (lock_stp)
+	if (lock_stp) {
+		/* Bump seqid manually if the 4.0 replay owner is openowner */
+		if (cstate->replay_owner &&
+		    cstate->replay_owner != &lock_sop->lo_owner &&
+		    seqid_mutating_err(ntohl(status)))
+			lock_sop->lo_owner.so_seqid++;
+
+		/*
+		 * If this is a new, never-before-used stateid, and we are
+		 * returning an error, then just go ahead and release it.
+		 */
+		if (status && new)
+			release_lock_stateid(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);
 	nfs4_unlock_state();
 	if (file_lock)
@@ -5090,7 +5113,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	    struct nfsd4_lockt *lockt)
 {
 	struct file_lock *file_lock = NULL;
-	struct nfs4_lockowner *lo;
+	struct nfs4_lockowner *lo = NULL;
 	__be32 status;
 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
 
@@ -5153,6 +5176,8 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 		nfs4_set_lock_denied(file_lock, &lockt->lt_denied);
 	}
 out:
+	if (lo)
+		nfs4_put_stateowner(&lo->lo_owner);
 	nfs4_unlock_state();
 	if (file_lock)
 		locks_free_lock(file_lock);
-- 
1.9.3


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

* [PATCH v2 066/117] nfsd: add an operation for unhashing a stateowner
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (64 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 065/117] nfsd: clean up lockowner refcounting when finding them Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-26 19:12 ` [PATCH v2 067/117] nfsd: Make lock stateid take a reference to the lockowner Jeff Layton
                   ` (52 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

Allow stateowners to be unhashed and destroyed when the last reference
is put. The unhashing must be idempotent. In a future patch, we'll add
some locking around it, but for now it's only protected by the
client_mutex.

Signed-off-by: Jeff Layton <jlayton@primarydata.com>
---
 fs/nfsd/nfs4state.c | 45 +++++++++++++++++++++++++++++++++++----------
 fs/nfsd/state.h     |  1 +
 2 files changed, 36 insertions(+), 10 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 28d42aaf9745..3ae5a3b56a85 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -938,9 +938,13 @@ static void __release_lock_stateid(struct nfs4_ol_stateid *stp)
 
 static void unhash_lockowner(struct nfs4_lockowner *lo)
 {
+	list_del_init(&lo->lo_owner.so_strhash);
+}
+
+static void release_lockowner_stateids(struct nfs4_lockowner *lo)
+{
 	struct nfs4_ol_stateid *stp;
 
-	list_del(&lo->lo_owner.so_strhash);
 	while (!list_empty(&lo->lo_owner.so_stateids)) {
 		stp = list_first_entry(&lo->lo_owner.so_stateids,
 				struct nfs4_ol_stateid, st_perstateowner);
@@ -951,6 +955,7 @@ static void unhash_lockowner(struct nfs4_lockowner *lo)
 static void release_lockowner(struct nfs4_lockowner *lo)
 {
 	unhash_lockowner(lo);
+	release_lockowner_stateids(lo);
 	nfs4_put_stateowner(&lo->lo_owner);
 }
 
@@ -1000,15 +1005,8 @@ static void release_open_stateid(struct nfs4_ol_stateid *stp)
 
 static void unhash_openowner(struct nfs4_openowner *oo)
 {
-	struct nfs4_ol_stateid *stp;
-
-	list_del(&oo->oo_owner.so_strhash);
-	list_del(&oo->oo_perclient);
-	while (!list_empty(&oo->oo_owner.so_stateids)) {
-		stp = list_first_entry(&oo->oo_owner.so_stateids,
-				struct nfs4_ol_stateid, st_perstateowner);
-		release_open_stateid(stp);
-	}
+	list_del_init(&oo->oo_owner.so_strhash);
+	list_del_init(&oo->oo_perclient);
 }
 
 static void release_last_closed_stateid(struct nfs4_openowner *oo)
@@ -1021,9 +1019,21 @@ static void release_last_closed_stateid(struct nfs4_openowner *oo)
 	}
 }
 
+static void release_openowner_stateids(struct nfs4_openowner *oo)
+{
+	struct nfs4_ol_stateid *stp;
+
+	while (!list_empty(&oo->oo_owner.so_stateids)) {
+		stp = list_first_entry(&oo->oo_owner.so_stateids,
+				struct nfs4_ol_stateid, st_perstateowner);
+		release_open_stateid(stp);
+	}
+}
+
 static void release_openowner(struct nfs4_openowner *oo)
 {
 	unhash_openowner(oo);
+	release_openowner_stateids(oo);
 	list_del(&oo->oo_close_lru);
 	release_last_closed_stateid(oo);
 	nfs4_put_stateowner(&oo->oo_owner);
@@ -2987,6 +2997,7 @@ static void nfs4_put_stateowner(struct nfs4_stateowner *sop)
 {
 	if (!atomic_dec_and_test(&sop->so_count))
 		return;
+	sop->so_unhash(sop);
 	sop->so_free(sop);
 }
 
@@ -2998,6 +3009,13 @@ static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, u
 	list_add(&oo->oo_perclient, &clp->cl_openowners);
 }
 
+static void nfs4_unhash_openowner(struct nfs4_stateowner *so)
+{
+	struct nfs4_openowner *oo = openowner(so);
+
+	unhash_openowner(oo);
+}
+
 static void nfs4_free_openowner(struct nfs4_stateowner *so)
 {
 	struct nfs4_openowner *oo = openowner(so);
@@ -3017,6 +3035,7 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfsd4_open *open,
 	if (!oo)
 		return NULL;
 	oo->oo_owner.so_free = nfs4_free_openowner;
+	oo->oo_owner.so_unhash = nfs4_unhash_openowner;
 	oo->oo_owner.so_is_open_owner = 1;
 	oo->oo_owner.so_seqid = open->op_seqid;
 	oo->oo_flags = NFS4_OO_NEW;
@@ -4736,6 +4755,11 @@ find_lockowner_str(clientid_t *clid, struct xdr_netobj *owner,
 	return NULL;
 }
 
+static void nfs4_unhash_lockowner(struct nfs4_stateowner *sop)
+{
+	unhash_lockowner(lockowner(sop));
+}
+
 static void nfs4_free_lockowner(struct nfs4_stateowner *sop)
 {
 	struct nfs4_lockowner *lo = lockowner(sop);
@@ -4763,6 +4787,7 @@ alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, str
 	lo->lo_owner.so_is_open_owner = 0;
 	lo->lo_owner.so_seqid = lock->lk_new_lock_seqid;
 	lo->lo_owner.so_free = nfs4_free_lockowner;
+	lo->lo_owner.so_unhash = nfs4_unhash_lockowner;
 	list_add(&lo->lo_owner.so_strhash, &nn->ownerstr_hashtbl[strhashval]);
 	return lo;
 }
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index e8a9bd8c3c61..e318fc29dd68 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -347,6 +347,7 @@ struct nfs4_stateowner {
 	bool			so_is_open_owner;
 
 	void (*so_free)(struct nfs4_stateowner *);
+	void (*so_unhash)(struct nfs4_stateowner *);
 };
 
 struct nfs4_openowner {
-- 
1.9.3


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

* [PATCH v2 067/117] nfsd: Make lock stateid take a reference to the lockowner
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (65 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 066/117] nfsd: add an operation for unhashing a stateowner Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-26 19:12 ` [PATCH v2 068/117] nfsd: clean up refcounting for lockowners Jeff Layton
                   ` (51 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

A necessary step toward client_mutex removal.

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 3ae5a3b56a85..649b2e829981 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -904,6 +904,8 @@ static void nfs4_free_generic_stateid(struct nfs4_stid *stid)
 	struct nfs4_ol_stateid *stp = openlockstateid(stid);
 
 	release_all_access(stp);
+	if (stp->st_stateowner && stid->sc_type == NFS4_LOCK_STID)
+		nfs4_put_stateowner(stp->st_stateowner);
 	nfs4_free_stid(stateid_slab, stid);
 }
 
@@ -4803,6 +4805,7 @@ init_lock_stateid(struct nfs4_ol_stateid *stp, struct nfs4_lockowner *lo,
 	atomic_inc(&stp->st_stid.sc_count);
 	stp->st_stid.sc_type = NFS4_LOCK_STID;
 	stp->st_stateowner = &lo->lo_owner;
+	atomic_inc(&lo->lo_owner.so_count);
 	get_nfs4_file(fp);
 	stp->st_stid.sc_file = fp;
 	stp->st_stid.sc_free = nfs4_free_lock_stateid;
-- 
1.9.3


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

* [PATCH v2 068/117] nfsd: clean up refcounting for lockowners
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (66 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 067/117] nfsd: Make lock stateid take a reference to the lockowner Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-26 19:12 ` [PATCH v2 069/117] nfsd: make openstateids hold references to their openowners Jeff Layton
                   ` (50 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

Ensure that lockowner references are only held by lockstateids and
operations that are in-progress. With this, we can get rid of
release_lockowner_if_empty, which will be racy once we remove
client_mutex protection.

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

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 649b2e829981..d8de65e0a457 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -926,7 +926,7 @@ static void put_generic_stateid(struct nfs4_ol_stateid *stp)
 	nfs4_put_stid(&stp->st_stid);
 }
 
-static void __release_lock_stateid(struct nfs4_ol_stateid *stp)
+static void release_lock_stateid(struct nfs4_ol_stateid *stp)
 {
 	struct nfs4_openowner *oo = openowner(stp->st_openstp->st_stateowner);
 
@@ -950,7 +950,7 @@ static void release_lockowner_stateids(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(stp);
 	}
 }
 
@@ -961,21 +961,6 @@ static void release_lockowner(struct nfs4_lockowner *lo)
 	nfs4_put_stateowner(&lo->lo_owner);
 }
 
-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;
-
-	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)
 	__releases(&open_stp->st_stateowner->so_client->cl_lock)
 	__acquires(&open_stp->st_stateowner->so_client->cl_lock)
@@ -4285,7 +4270,7 @@ nfsd4_free_lock_stateid(struct nfs4_ol_stateid *stp)
 
 	if (check_for_locks(stp->st_stid.sc_file, lo))
 		return nfserr_locks_held;
-	release_lockowner_if_empty(lo);
+	release_lock_stateid(stp);
 	return nfs_ok;
 }
 
@@ -4907,8 +4892,6 @@ static __be32 lookup_or_create_lock_state(struct nfsd4_compound_state *cstate,
 		lo = alloc_init_lock_stateowner(strhashval, cl, ost, lock);
 		if (lo == NULL)
 			return nfserr_jukebox;
-		/* FIXME: extra reference for new lockowners for the client */
-		atomic_inc(&lo->lo_owner.so_count);
 	} else {
 		/* with an existing lockowner, seqids must be the same */
 		status = nfserr_bad_seqid;
@@ -4919,7 +4902,6 @@ static __be32 lookup_or_create_lock_state(struct nfsd4_compound_state *cstate,
 
 	*lst = find_or_create_lock_stateid(lo, fi, ost, new);
 	if (*lst == NULL) {
-		release_lockowner_if_empty(lo);
 		status = nfserr_jukebox;
 		goto out;
 	}
@@ -5341,6 +5323,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
 			continue;
 		if (same_owner_str(tmp, owner, clid)) {
 			sop = tmp;
+			atomic_inc(&sop->so_count);
 			break;
 		}
 	}
@@ -5354,8 +5337,10 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
 	lo = lockowner(sop);
 	/* see if there are still any locks associated with it */
 	list_for_each_entry(stp, &sop->so_stateids, st_perstateowner) {
-		if (check_for_locks(stp->st_stid.sc_file, lo))
+		if (check_for_locks(stp->st_stid.sc_file, lo)) {
+			nfs4_put_stateowner(sop);
 			goto out;
+		}
 	}
 
 	status = nfs_ok;
-- 
1.9.3


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

* [PATCH v2 069/117] nfsd: make openstateids hold references to their openowners
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (67 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 068/117] nfsd: clean up refcounting for lockowners Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-26 19:12 ` [PATCH v2 070/117] nfsd: don't allow CLOSE to proceed until refcount on stateid drops Jeff Layton
                   ` (49 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

Change it so that only openstateids hold persistent references to
openowners. References can still be held by compounds in progress.

With this, we can get rid of NFS4_OO_NEW. It's possible that we
will create a new openowner in the process of doing the open, but
something later fails. In the meantime, another task could find
that openowner and start using it on a successful open. If that
occurs we don't necessarily want to tear it down, just put the
reference that the failing compound holds.

Signed-off-by: Jeff Layton <jlayton@primarydata.com>
---
 fs/nfsd/nfs4state.c | 71 +++++++++++++++++++++++------------------------------
 fs/nfsd/state.h     |  1 -
 2 files changed, 31 insertions(+), 41 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index d8de65e0a457..d1b55d61ae6f 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -904,7 +904,7 @@ static void nfs4_free_generic_stateid(struct nfs4_stid *stid)
 	struct nfs4_ol_stateid *stp = openlockstateid(stid);
 
 	release_all_access(stp);
-	if (stp->st_stateowner && stid->sc_type == NFS4_LOCK_STID)
+	if (stp->st_stateowner)
 		nfs4_put_stateowner(stp->st_stateowner);
 	nfs4_free_stid(stateid_slab, stid);
 }
@@ -1001,8 +1001,9 @@ static void release_last_closed_stateid(struct nfs4_openowner *oo)
 	struct nfs4_ol_stateid *s = oo->oo_last_closed_stid;
 
 	if (s) {
-		put_generic_stateid(s);
+		list_del_init(&oo->oo_close_lru);
 		oo->oo_last_closed_stid = NULL;
+		put_generic_stateid(s);
 	}
 }
 
@@ -1021,7 +1022,6 @@ static void release_openowner(struct nfs4_openowner *oo)
 {
 	unhash_openowner(oo);
 	release_openowner_stateids(oo);
-	list_del(&oo->oo_close_lru);
 	release_last_closed_stateid(oo);
 	nfs4_put_stateowner(&oo->oo_owner);
 }
@@ -1494,6 +1494,7 @@ destroy_client(struct nfs4_client *clp)
 	}
 	while (!list_empty(&clp->cl_openowners)) {
 		oo = list_entry(clp->cl_openowners.next, struct nfs4_openowner, oo_perclient);
+		atomic_inc(&oo->oo_owner.so_count);
 		release_openowner(oo);
 	}
 	nfsd4_shutdown_callback(clp);
@@ -3025,7 +3026,7 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfsd4_open *open,
 	oo->oo_owner.so_unhash = nfs4_unhash_openowner;
 	oo->oo_owner.so_is_open_owner = 1;
 	oo->oo_owner.so_seqid = open->op_seqid;
-	oo->oo_flags = NFS4_OO_NEW;
+	oo->oo_flags = 0;
 	if (nfsd4_has_session(cstate))
 		oo->oo_flags |= NFS4_OO_CONFIRMED;
 	oo->oo_time = 0;
@@ -3042,6 +3043,7 @@ 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_locks);
 	stp->st_stateowner = &oo->oo_owner;
+	atomic_inc(&stp->st_stateowner->so_count);
 	get_nfs4_file(fp);
 	stp->st_stid.sc_file = fp;
 	stp->st_access_bmap = 0;
@@ -3057,13 +3059,27 @@ static void init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp,
 	spin_unlock(&oo->oo_owner.so_client->cl_lock);
 }
 
+/*
+ * In the 4.0 case we need to keep the owners around a little while to handle
+ * CLOSE replay. We still do need to release any file access that is held by
+ * them before returning however.
+ */
 static void
-move_to_close_lru(struct nfs4_openowner *oo, struct net *net)
+move_to_close_lru(struct nfs4_ol_stateid *s, struct net *net)
 {
-	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+	struct nfs4_openowner *oo = openowner(s->st_stateowner);
+	struct nfsd_net *nn = net_generic(s->st_stid.sc_client->net,
+						nfsd_net_id);
 
 	dprintk("NFSD: move_to_close_lru nfs4_openowner %p\n", oo);
 
+	release_all_access(s);
+	if (s->st_stid.sc_file) {
+		put_nfs4_file(s->st_stid.sc_file);
+		s->st_stid.sc_file = NULL;
+	}
+	release_last_closed_stateid(oo);
+	oo->oo_last_closed_stid = s;
 	list_move_tail(&oo->oo_close_lru, &nn->close_lru);
 	oo->oo_time = get_seconds();
 }
@@ -3094,6 +3110,7 @@ find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open,
 			if ((bool)clp->cl_minorversion != sessions)
 				return NULL;
 			renew_client(oo->oo_owner.so_client);
+			atomic_inc(&oo->oo_owner.so_count);
 			return oo;
 		}
 	}
@@ -3823,19 +3840,10 @@ void nfsd4_cleanup_open_state(struct nfsd4_compound_state *cstate,
 			      struct nfsd4_open *open, __be32 status)
 {
 	if (open->op_openowner) {
-		struct nfs4_openowner *oo = open->op_openowner;
-
-		if (!list_empty(&oo->oo_owner.so_stateids))
-			list_del_init(&oo->oo_close_lru);
-		if (oo->oo_flags & NFS4_OO_NEW) {
-			if (status) {
-				release_openowner(oo);
-				open->op_openowner = NULL;
-			} else
-				oo->oo_flags &= ~NFS4_OO_NEW;
-		}
-		if (open->op_openowner)
-			nfsd4_cstate_assign_replay(cstate, &oo->oo_owner);
+		struct nfs4_stateowner *so = &open->op_openowner->oo_owner;
+
+		nfsd4_cstate_assign_replay(cstate, so);
+		nfs4_put_stateowner(so);
 	}
 	if (open->op_file)
 		nfsd4_free_file(open->op_file);
@@ -3977,7 +3985,7 @@ nfs4_laundromat(struct nfsd_net *nn)
 			new_timeo = min(new_timeo, t);
 			break;
 		}
-		release_openowner(oo);
+		release_last_closed_stateid(oo);
 	}
 	new_timeo = max_t(time_t, new_timeo, NFSD_LAUNDROMAT_MINTIMEOUT);
 	nfs4_unlock_state();
@@ -4556,31 +4564,14 @@ out:
 static void nfsd4_close_open_stateid(struct nfs4_ol_stateid *s)
 {
 	struct nfs4_client *clp = s->st_stid.sc_client;
-	struct nfs4_openowner *oo = openowner(s->st_stateowner);
 
 	s->st_stid.sc_type = NFS4_CLOSED_STID;
 	unhash_open_stateid(s);
 
-	if (clp->cl_minorversion) {
-		if (list_empty(&oo->oo_owner.so_stateids))
-			release_openowner(oo);
+	if (clp->cl_minorversion)
 		put_generic_stateid(s);
-	} else {
-		if (s->st_stid.sc_file) {
-			put_nfs4_file(s->st_stid.sc_file);
-			s->st_stid.sc_file = NULL;
-		}
-		oo->oo_last_closed_stid = s;
-		/*
-		 * In the 4.0 case we need to keep the owners around a
-		 * little while to handle CLOSE replay. We still do need
-		 * to release any file access that is held by them
-		 * before returning however.
-		 */
-		release_all_access(s);
-		if (list_empty(&oo->oo_owner.so_stateids))
-			move_to_close_lru(oo, clp->net);
-	}
+	else
+		move_to_close_lru(s, clp->net);
 }
 
 /*
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index e318fc29dd68..89d43c3b5078 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -364,7 +364,6 @@ struct nfs4_openowner {
 	struct nfs4_ol_stateid *oo_last_closed_stid;
 	time_t			oo_time; /* time of placement on so_close_lru */
 #define NFS4_OO_CONFIRMED   1
-#define NFS4_OO_NEW         4
 	unsigned char		oo_flags;
 };
 
-- 
1.9.3


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

* [PATCH v2 070/117] nfsd: don't allow CLOSE to proceed until refcount on stateid drops
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (68 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 069/117] nfsd: make openstateids hold references to their openowners Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-26 19:12 ` [PATCH v2 071/117] nfsd: Protect adding/removing open state owners using client_lock Jeff Layton
                   ` (48 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

Once we remove client_mutex protection, it'll be possible to have an
in-flight operation using an openstateid when a CLOSE call comes in.
If that happens, we can't just put the sc_file reference and clear its
pointer without risking an oops.

Fix this by ensuring that v4.0 CLOSE operations wait for the refcount
to drop before proceeding to do so.

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

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index d1b55d61ae6f..029e41b4de84 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -89,6 +89,12 @@ static DEFINE_MUTEX(client_mutex);
  */
 static DEFINE_SPINLOCK(state_lock);
 
+/*
+ * A waitqueue for all in-progress 4.0 CLOSE operations that are waiting for
+ * the refcount on the open stateid to drop.
+ */
+static DECLARE_WAIT_QUEUE_HEAD(close_wq);
+
 static struct kmem_cache *openowner_slab;
 static struct kmem_cache *lockowner_slab;
 static struct kmem_cache *file_slab;
@@ -670,8 +676,10 @@ static void nfs4_put_stid(struct nfs4_stid *s)
 {
 	struct nfs4_client *clp = s->sc_client;
 
-	if (!atomic_dec_and_lock(&s->sc_count, &clp->cl_lock))
+	if (!atomic_dec_and_lock(&s->sc_count, &clp->cl_lock)) {
+		wake_up_all(&close_wq);
 		return;
+	}
 	remove_stid_locked(clp, s);
 	spin_unlock(&clp->cl_lock);
 	s->sc_free(s);
@@ -3073,11 +3081,23 @@ move_to_close_lru(struct nfs4_ol_stateid *s, struct net *net)
 
 	dprintk("NFSD: move_to_close_lru nfs4_openowner %p\n", oo);
 
+	/*
+	 * We know that we hold one reference via nfsd4_close, and another
+	 * "persistent" reference for the client. If the refcount is higher
+	 * than 2, then there are still calls in progress that are using this
+	 * stateid. We can't put the sc_file reference until they are finished.
+	 * Wait for the refcount to drop to 2. Since it has been unhashed,
+	 * there should be no danger of the refcount going back up again at
+	 * this point.
+	 */
+	wait_event(close_wq, atomic_read(&s->st_stid.sc_count) == 2);
+
 	release_all_access(s);
 	if (s->st_stid.sc_file) {
 		put_nfs4_file(s->st_stid.sc_file);
 		s->st_stid.sc_file = NULL;
 	}
+
 	release_last_closed_stateid(oo);
 	oo->oo_last_closed_stid = s;
 	list_move_tail(&oo->oo_close_lru, &nn->close_lru);
-- 
1.9.3


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

* [PATCH v2 071/117] nfsd: Protect adding/removing open state owners using client_lock
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (69 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 070/117] nfsd: don't allow CLOSE to proceed until refcount on stateid drops Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-26 19:12 ` [PATCH v2 072/117] nfsd: Protect adding/removing lock " Jeff Layton
                   ` (47 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

Once we remove client mutex protection, we'll need to ensure that
stateowner lookup and creation are atomic between concurrent compounds.
Ensure that alloc_init_open_stateowner checks the hashtable under the
client_lock before adding a new element.

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

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 029e41b4de84..4285bc405736 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -72,6 +72,9 @@ static u64 current_sessionid = 1;
 /* forward declarations */
 static int check_for_locks(struct nfs4_file *filp, struct nfs4_lockowner *lowner);
 static void nfs4_free_generic_stateid(struct nfs4_stid *stid);
+static struct nfs4_openowner *find_openstateowner_str_locked(
+		unsigned int hashval, struct nfsd4_open *open,
+		bool sessions, struct nfsd_net *nn);
 static void nfs4_put_stateowner(struct nfs4_stateowner *sop);
 static __be32 lookup_clientid(clientid_t *clid,
 		struct nfsd4_compound_state *cstate,
@@ -998,8 +1001,13 @@ static void release_open_stateid(struct nfs4_ol_stateid *stp)
 	put_generic_stateid(stp);
 }
 
-static void unhash_openowner(struct nfs4_openowner *oo)
+static void unhash_openowner_locked(struct nfs4_openowner *oo)
 {
+	struct nfsd_net *nn = net_generic(oo->oo_owner.so_client->net,
+						nfsd_net_id);
+
+	lockdep_assert_held(&nn->client_lock);
+
 	list_del_init(&oo->oo_owner.so_strhash);
 	list_del_init(&oo->oo_perclient);
 }
@@ -1018,18 +1026,29 @@ static void release_last_closed_stateid(struct nfs4_openowner *oo)
 static void release_openowner_stateids(struct nfs4_openowner *oo)
 {
 	struct nfs4_ol_stateid *stp;
+	struct nfsd_net *nn = net_generic(oo->oo_owner.so_client->net,
+						nfsd_net_id);
+
+	lockdep_assert_held(&nn->client_lock);
 
 	while (!list_empty(&oo->oo_owner.so_stateids)) {
 		stp = list_first_entry(&oo->oo_owner.so_stateids,
 				struct nfs4_ol_stateid, st_perstateowner);
+		spin_unlock(&nn->client_lock);
 		release_open_stateid(stp);
+		spin_lock(&nn->client_lock);
 	}
 }
 
 static void release_openowner(struct nfs4_openowner *oo)
 {
-	unhash_openowner(oo);
+	struct nfsd_net *nn = net_generic(oo->oo_owner.so_client->net,
+						nfsd_net_id);
+
+	spin_lock(&nn->client_lock);
+	unhash_openowner_locked(oo);
 	release_openowner_stateids(oo);
+	spin_unlock(&nn->client_lock);
 	release_last_closed_stateid(oo);
 	nfs4_put_stateowner(&oo->oo_owner);
 }
@@ -3008,8 +3027,11 @@ static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, u
 static void nfs4_unhash_openowner(struct nfs4_stateowner *so)
 {
 	struct nfs4_openowner *oo = openowner(so);
+	struct nfsd_net *nn = net_generic(so->so_client->net, nfsd_net_id);
 
-	unhash_openowner(oo);
+	spin_lock(&nn->client_lock);
+	unhash_openowner_locked(oo);
+	spin_unlock(&nn->client_lock);
 }
 
 static void nfs4_free_openowner(struct nfs4_stateowner *so)
@@ -3025,7 +3047,8 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfsd4_open *open,
 			   struct nfsd4_compound_state *cstate)
 {
 	struct nfs4_client *clp = cstate->clp;
-	struct nfs4_openowner *oo;
+	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
+	struct nfs4_openowner *oo, *ret;
 
 	oo = alloc_stateowner(openowner_slab, &open->op_owner, clp);
 	if (!oo)
@@ -3040,7 +3063,15 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfsd4_open *open,
 	oo->oo_time = 0;
 	oo->oo_last_closed_stid = NULL;
 	INIT_LIST_HEAD(&oo->oo_close_lru);
-	hash_openowner(oo, clp, strhashval);
+	spin_lock(&nn->client_lock);
+	ret = find_openstateowner_str_locked(strhashval,
+			open, clp->cl_minorversion, nn);
+	if (ret == NULL) {
+		hash_openowner(oo, clp, strhashval);
+		ret = oo;
+	} else
+		nfs4_free_openowner(&oo->oo_owner);
+	spin_unlock(&nn->client_lock);
 	return oo;
 }
 
@@ -3114,13 +3145,15 @@ same_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner,
 }
 
 static struct nfs4_openowner *
-find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open,
+find_openstateowner_str_locked(unsigned int hashval, struct nfsd4_open *open,
 			bool sessions, struct nfsd_net *nn)
 {
 	struct nfs4_stateowner *so;
 	struct nfs4_openowner *oo;
 	struct nfs4_client *clp;
 
+	lockdep_assert_held(&nn->client_lock);
+
 	list_for_each_entry(so, &nn->ownerstr_hashtbl[hashval], so_strhash) {
 		if (!so->so_is_open_owner)
 			continue;
@@ -3128,15 +3161,27 @@ find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open,
 			oo = openowner(so);
 			clp = oo->oo_owner.so_client;
 			if ((bool)clp->cl_minorversion != sessions)
-				return NULL;
-			renew_client(oo->oo_owner.so_client);
-			atomic_inc(&oo->oo_owner.so_count);
+				break;
+			renew_client_locked(clp);
+			atomic_inc(&so->so_count);
 			return oo;
 		}
 	}
 	return NULL;
 }
 
+static struct nfs4_openowner *
+find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open,
+			bool sessions, struct nfsd_net *nn)
+{
+	struct nfs4_openowner *oo;
+
+	spin_lock(&nn->client_lock);
+	oo = find_openstateowner_str_locked(hashval, open, sessions, nn);
+	spin_unlock(&nn->client_lock);
+	return oo;
+}
+
 /* search file_hashtbl[] for file */
 static struct nfs4_file *
 find_file_locked(struct inode *ino)
-- 
1.9.3


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

* [PATCH v2 072/117] nfsd: Protect adding/removing lock owners using client_lock
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (70 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 071/117] nfsd: Protect adding/removing open state owners using client_lock Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-26 19:12 ` [PATCH v2 073/117] nfsd: Move the open owner hash table into struct nfs4_client Jeff Layton
                   ` (46 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

Once we remove client mutex protection, we'll need to ensure that
stateowner lookup and creation are atomic between concurrent compounds.
Ensure that alloc_init_lock_stateowner checks the hashtable under the
client_lock before adding a new element.

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

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 4285bc405736..54aa5fbcb927 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -949,26 +949,42 @@ static void release_lock_stateid(struct nfs4_ol_stateid *stp)
 	put_generic_stateid(stp);
 }
 
-static void unhash_lockowner(struct nfs4_lockowner *lo)
+static void unhash_lockowner_locked(struct nfs4_lockowner *lo)
 {
+	struct nfsd_net *nn = net_generic(lo->lo_owner.so_client->net,
+						nfsd_net_id);
+
+	lockdep_assert_held(&nn->client_lock);
+
 	list_del_init(&lo->lo_owner.so_strhash);
 }
 
 static void release_lockowner_stateids(struct nfs4_lockowner *lo)
 {
+	struct nfsd_net *nn = net_generic(lo->lo_owner.so_client->net,
+						nfsd_net_id);
 	struct nfs4_ol_stateid *stp;
 
+	lockdep_assert_held(&nn->client_lock);
+
 	while (!list_empty(&lo->lo_owner.so_stateids)) {
 		stp = list_first_entry(&lo->lo_owner.so_stateids,
 				struct nfs4_ol_stateid, st_perstateowner);
+		spin_unlock(&nn->client_lock);
 		release_lock_stateid(stp);
+		spin_lock(&nn->client_lock);
 	}
 }
 
 static void release_lockowner(struct nfs4_lockowner *lo)
 {
-	unhash_lockowner(lo);
+	struct nfsd_net *nn = net_generic(lo->lo_owner.so_client->net,
+						nfsd_net_id);
+
+	spin_lock(&nn->client_lock);
+	unhash_lockowner_locked(lo);
 	release_lockowner_stateids(lo);
+	spin_unlock(&nn->client_lock);
 	nfs4_put_stateowner(&lo->lo_owner);
 }
 
@@ -4781,7 +4797,7 @@ nevermind:
 }
 
 static struct nfs4_lockowner *
-find_lockowner_str(clientid_t *clid, struct xdr_netobj *owner,
+find_lockowner_str_locked(clientid_t *clid, struct xdr_netobj *owner,
 		struct nfsd_net *nn)
 {
 	unsigned int strhashval = ownerstr_hashval(clid->cl_id, owner);
@@ -4798,9 +4814,25 @@ find_lockowner_str(clientid_t *clid, struct xdr_netobj *owner,
 	return NULL;
 }
 
+static struct nfs4_lockowner *
+find_lockowner_str(clientid_t *clid, struct xdr_netobj *owner,
+		struct nfsd_net *nn)
+{
+	struct nfs4_lockowner *lo;
+
+	spin_lock(&nn->client_lock);
+	lo = find_lockowner_str_locked(clid, owner, nn);
+	spin_unlock(&nn->client_lock);
+	return lo;
+}
+
 static void nfs4_unhash_lockowner(struct nfs4_stateowner *sop)
 {
-	unhash_lockowner(lockowner(sop));
+	struct nfsd_net *nn = net_generic(sop->so_client->net, nfsd_net_id);
+
+	spin_lock(&nn->client_lock);
+	unhash_lockowner_locked(lockowner(sop));
+	spin_unlock(&nn->client_lock);
 }
 
 static void nfs4_free_lockowner(struct nfs4_stateowner *sop)
@@ -4819,9 +4851,12 @@ static void nfs4_free_lockowner(struct nfs4_stateowner *sop)
  * strhashval = ownerstr_hashval
  */
 static struct nfs4_lockowner *
-alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, struct nfs4_ol_stateid *open_stp, struct nfsd4_lock *lock) {
-	struct nfs4_lockowner *lo;
+alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp,
+			   struct nfs4_ol_stateid *open_stp,
+			   struct nfsd4_lock *lock)
+{
 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
+	struct nfs4_lockowner *lo, *ret;
 
 	lo = alloc_stateowner(lockowner_slab, &lock->lk_new_owner, clp);
 	if (!lo)
@@ -4831,7 +4866,16 @@ alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, str
 	lo->lo_owner.so_seqid = lock->lk_new_lock_seqid;
 	lo->lo_owner.so_free = nfs4_free_lockowner;
 	lo->lo_owner.so_unhash = nfs4_unhash_lockowner;
-	list_add(&lo->lo_owner.so_strhash, &nn->ownerstr_hashtbl[strhashval]);
+	spin_lock(&nn->client_lock);
+	ret = find_lockowner_str_locked(&clp->cl_clientid,
+			&lock->lk_new_owner, nn);
+	if (ret == NULL) {
+		list_add(&lo->lo_owner.so_strhash,
+			 &nn->ownerstr_hashtbl[strhashval]);
+		ret = lo;
+	} else
+		nfs4_free_lockowner(&lo->lo_owner);
+	spin_unlock(&nn->client_lock);
 	return lo;
 }
 
@@ -5360,6 +5404,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
 	unsigned int hashval = ownerstr_hashval(clid->cl_id, owner);
 	__be32 status;
 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
+	struct nfs4_client *clp;
 
 	dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n",
 		clid->cl_boot, clid->cl_id);
@@ -5374,6 +5419,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
 	INIT_LIST_HEAD(&matches);
 
 	/* Find the matching lock stateowner */
+	spin_lock(&nn->client_lock);
 	list_for_each_entry(tmp, &nn->ownerstr_hashtbl[hashval], so_strhash) {
 		if (tmp->so_is_open_owner)
 			continue;
@@ -5383,6 +5429,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
 			break;
 		}
 	}
+	spin_unlock(&nn->client_lock);
 
 	/* No matching owner found, maybe a replay? Just declare victory... */
 	if (!sop) {
@@ -5392,16 +5439,22 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
 
 	lo = lockowner(sop);
 	/* see if there are still any locks associated with it */
+	clp = cstate->clp;
+	spin_lock(&clp->cl_lock);
 	list_for_each_entry(stp, &sop->so_stateids, st_perstateowner) {
 		if (check_for_locks(stp->st_stid.sc_file, lo)) {
-			nfs4_put_stateowner(sop);
+			spin_unlock(&clp->cl_lock);
 			goto out;
 		}
 	}
+	spin_unlock(&clp->cl_lock);
 
 	status = nfs_ok;
+	sop = NULL;
 	release_lockowner(lo);
 out:
+	if (sop)
+		nfs4_put_stateowner(sop);
 	nfs4_unlock_state();
 	return status;
 }
-- 
1.9.3


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

* [PATCH v2 073/117] nfsd: Move the open owner hash table into struct nfs4_client
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (71 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 072/117] nfsd: Protect adding/removing lock " Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-26 19:12 ` [PATCH v2 074/117] lockdep: add lockdep_assert_not_held Jeff Layton
                   ` (45 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

Preparation for removing the client_mutex.

Convert the open owner hash table into a per-client table and protect it
using the nfs4_client->cl_lock spin lock.

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

diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h
index beaceac90ad3..f89042ae0056 100644
--- a/fs/nfsd/netns.h
+++ b/fs/nfsd/netns.h
@@ -63,7 +63,6 @@ struct nfsd_net {
 	struct rb_root conf_name_tree;
 	struct list_head *unconf_id_hashtbl;
 	struct rb_root unconf_name_tree;
-	struct list_head *ownerstr_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 54aa5fbcb927..503beb3faa6c 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -74,7 +74,7 @@ static int check_for_locks(struct nfs4_file *filp, struct nfs4_lockowner *lowner
 static void nfs4_free_generic_stateid(struct nfs4_stid *stid);
 static struct nfs4_openowner *find_openstateowner_str_locked(
 		unsigned int hashval, struct nfsd4_open *open,
-		bool sessions, struct nfsd_net *nn);
+		struct nfs4_client *clp);
 static void nfs4_put_stateowner(struct nfs4_stateowner *sop);
 static __be32 lookup_clientid(clientid_t *clid,
 		struct nfsd4_compound_state *cstate,
@@ -360,12 +360,11 @@ unsigned long max_delegations;
 #define OWNER_HASH_SIZE             (1 << OWNER_HASH_BITS)
 #define OWNER_HASH_MASK             (OWNER_HASH_SIZE - 1)
 
-static unsigned int ownerstr_hashval(u32 clientid, struct xdr_netobj *ownername)
+static unsigned int ownerstr_hashval(struct xdr_netobj *ownername)
 {
 	unsigned int ret;
 
 	ret = opaque_hashval(ownername->data, ownername->len);
-	ret += clientid;
 	return ret & OWNER_HASH_MASK;
 }
 
@@ -951,40 +950,37 @@ static void release_lock_stateid(struct nfs4_ol_stateid *stp)
 
 static void unhash_lockowner_locked(struct nfs4_lockowner *lo)
 {
-	struct nfsd_net *nn = net_generic(lo->lo_owner.so_client->net,
-						nfsd_net_id);
+	struct nfs4_client *clp = lo->lo_owner.so_client;
 
-	lockdep_assert_held(&nn->client_lock);
+	lockdep_assert_held(&clp->cl_lock);
 
 	list_del_init(&lo->lo_owner.so_strhash);
 }
 
 static void release_lockowner_stateids(struct nfs4_lockowner *lo)
 {
-	struct nfsd_net *nn = net_generic(lo->lo_owner.so_client->net,
-						nfsd_net_id);
+	struct nfs4_client *clp = lo->lo_owner.so_client;
 	struct nfs4_ol_stateid *stp;
 
-	lockdep_assert_held(&nn->client_lock);
+	lockdep_assert_held(&clp->cl_lock);
 
 	while (!list_empty(&lo->lo_owner.so_stateids)) {
 		stp = list_first_entry(&lo->lo_owner.so_stateids,
 				struct nfs4_ol_stateid, st_perstateowner);
-		spin_unlock(&nn->client_lock);
+		spin_unlock(&clp->cl_lock);
 		release_lock_stateid(stp);
-		spin_lock(&nn->client_lock);
+		spin_lock(&clp->cl_lock);
 	}
 }
 
 static void release_lockowner(struct nfs4_lockowner *lo)
 {
-	struct nfsd_net *nn = net_generic(lo->lo_owner.so_client->net,
-						nfsd_net_id);
+	struct nfs4_client *clp = lo->lo_owner.so_client;
 
-	spin_lock(&nn->client_lock);
+	spin_lock(&clp->cl_lock);
 	unhash_lockowner_locked(lo);
 	release_lockowner_stateids(lo);
-	spin_unlock(&nn->client_lock);
+	spin_unlock(&clp->cl_lock);
 	nfs4_put_stateowner(&lo->lo_owner);
 }
 
@@ -1019,10 +1015,9 @@ static void release_open_stateid(struct nfs4_ol_stateid *stp)
 
 static void unhash_openowner_locked(struct nfs4_openowner *oo)
 {
-	struct nfsd_net *nn = net_generic(oo->oo_owner.so_client->net,
-						nfsd_net_id);
+	struct nfs4_client *clp = oo->oo_owner.so_client;
 
-	lockdep_assert_held(&nn->client_lock);
+	lockdep_assert_held(&clp->cl_lock);
 
 	list_del_init(&oo->oo_owner.so_strhash);
 	list_del_init(&oo->oo_perclient);
@@ -1042,29 +1037,27 @@ static void release_last_closed_stateid(struct nfs4_openowner *oo)
 static void release_openowner_stateids(struct nfs4_openowner *oo)
 {
 	struct nfs4_ol_stateid *stp;
-	struct nfsd_net *nn = net_generic(oo->oo_owner.so_client->net,
-						nfsd_net_id);
+	struct nfs4_client *clp = oo->oo_owner.so_client;
 
-	lockdep_assert_held(&nn->client_lock);
+	lockdep_assert_held(&clp->cl_lock);
 
 	while (!list_empty(&oo->oo_owner.so_stateids)) {
 		stp = list_first_entry(&oo->oo_owner.so_stateids,
 				struct nfs4_ol_stateid, st_perstateowner);
-		spin_unlock(&nn->client_lock);
+		spin_unlock(&clp->cl_lock);
 		release_open_stateid(stp);
-		spin_lock(&nn->client_lock);
+		spin_lock(&clp->cl_lock);
 	}
 }
 
 static void release_openowner(struct nfs4_openowner *oo)
 {
-	struct nfsd_net *nn = net_generic(oo->oo_owner.so_client->net,
-						nfsd_net_id);
+	struct nfs4_client *clp = oo->oo_owner.so_client;
 
-	spin_lock(&nn->client_lock);
+	spin_lock(&clp->cl_lock);
 	unhash_openowner_locked(oo);
 	release_openowner_stateids(oo);
-	spin_unlock(&nn->client_lock);
+	spin_unlock(&clp->cl_lock);
 	release_last_closed_stateid(oo);
 	nfs4_put_stateowner(&oo->oo_owner);
 }
@@ -1448,15 +1441,20 @@ STALE_CLIENTID(clientid_t *clid, struct nfsd_net *nn)
 static struct nfs4_client *alloc_client(struct xdr_netobj name)
 {
 	struct nfs4_client *clp;
+	int i;
 
 	clp = kzalloc(sizeof(struct nfs4_client), GFP_KERNEL);
 	if (clp == NULL)
 		return NULL;
 	clp->cl_name.data = kmemdup(name.data, name.len, GFP_KERNEL);
-	if (clp->cl_name.data == NULL) {
-		kfree(clp);
-		return NULL;
-	}
+	if (clp->cl_name.data == NULL)
+		goto err_no_name;
+	clp->cl_ownerstr_hashtbl = kmalloc(sizeof(struct list_head) *
+			OWNER_HASH_SIZE, GFP_KERNEL);
+	if (!clp->cl_ownerstr_hashtbl)
+		goto err_no_hashtbl;
+	for (i = 0; i < OWNER_HASH_SIZE; i++)
+		INIT_LIST_HEAD(&clp->cl_ownerstr_hashtbl[i]);
 	clp->cl_name.len = name.len;
 	INIT_LIST_HEAD(&clp->cl_sessions);
 	idr_init(&clp->cl_stateids);
@@ -1471,6 +1469,11 @@ static struct nfs4_client *alloc_client(struct xdr_netobj name)
 	spin_lock_init(&clp->cl_lock);
 	rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table");
 	return clp;
+err_no_hashtbl:
+	kfree(clp->cl_name.data);
+err_no_name:
+	kfree(clp);
+	return NULL;
 }
 
 static void
@@ -1489,6 +1492,7 @@ free_client(struct nfs4_client *clp)
 	}
 	rpc_destroy_wait_queue(&clp->cl_cb_waitq);
 	free_svc_cred(&clp->cl_cred);
+	kfree(clp->cl_ownerstr_hashtbl);
 	kfree(clp->cl_name.data);
 	spin_lock(&clp->cl_lock);
 	idr_destroy(&clp->cl_stateids);
@@ -3034,20 +3038,20 @@ static void nfs4_put_stateowner(struct nfs4_stateowner *sop)
 
 static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, unsigned int strhashval)
 {
-	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
+	lockdep_assert_held(&clp->cl_lock);
 
-	list_add(&oo->oo_owner.so_strhash, &nn->ownerstr_hashtbl[strhashval]);
+	list_add(&oo->oo_owner.so_strhash,
+		 &clp->cl_ownerstr_hashtbl[strhashval]);
 	list_add(&oo->oo_perclient, &clp->cl_openowners);
 }
 
 static void nfs4_unhash_openowner(struct nfs4_stateowner *so)
 {
-	struct nfs4_openowner *oo = openowner(so);
-	struct nfsd_net *nn = net_generic(so->so_client->net, nfsd_net_id);
+	struct nfs4_client *clp = so->so_client;
 
-	spin_lock(&nn->client_lock);
-	unhash_openowner_locked(oo);
-	spin_unlock(&nn->client_lock);
+	spin_lock(&clp->cl_lock);
+	unhash_openowner_locked(openowner(so));
+	spin_unlock(&clp->cl_lock);
 }
 
 static void nfs4_free_openowner(struct nfs4_stateowner *so)
@@ -3063,7 +3067,6 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfsd4_open *open,
 			   struct nfsd4_compound_state *cstate)
 {
 	struct nfs4_client *clp = cstate->clp;
-	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
 	struct nfs4_openowner *oo, *ret;
 
 	oo = alloc_stateowner(openowner_slab, &open->op_owner, clp);
@@ -3079,15 +3082,14 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfsd4_open *open,
 	oo->oo_time = 0;
 	oo->oo_last_closed_stid = NULL;
 	INIT_LIST_HEAD(&oo->oo_close_lru);
-	spin_lock(&nn->client_lock);
-	ret = find_openstateowner_str_locked(strhashval,
-			open, clp->cl_minorversion, nn);
+	spin_lock(&clp->cl_lock);
+	ret = find_openstateowner_str_locked(strhashval, open, clp);
 	if (ret == NULL) {
 		hash_openowner(oo, clp, strhashval);
 		ret = oo;
 	} else
 		nfs4_free_openowner(&oo->oo_owner);
-	spin_unlock(&nn->client_lock);
+	spin_unlock(&clp->cl_lock);
 	return oo;
 }
 
@@ -3152,35 +3154,27 @@ move_to_close_lru(struct nfs4_ol_stateid *s, struct net *net)
 }
 
 static int
-same_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner,
-							clientid_t *clid)
+same_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner)
 {
 	return (sop->so_owner.len == owner->len) &&
-		0 == memcmp(sop->so_owner.data, owner->data, owner->len) &&
-		(sop->so_client->cl_clientid.cl_id == clid->cl_id);
+		0 == memcmp(sop->so_owner.data, owner->data, owner->len);
 }
 
 static struct nfs4_openowner *
 find_openstateowner_str_locked(unsigned int hashval, struct nfsd4_open *open,
-			bool sessions, struct nfsd_net *nn)
+			struct nfs4_client *clp)
 {
 	struct nfs4_stateowner *so;
-	struct nfs4_openowner *oo;
-	struct nfs4_client *clp;
 
-	lockdep_assert_held(&nn->client_lock);
+	lockdep_assert_held(&clp->cl_lock);
 
-	list_for_each_entry(so, &nn->ownerstr_hashtbl[hashval], so_strhash) {
+	list_for_each_entry(so, &clp->cl_ownerstr_hashtbl[hashval],
+			    so_strhash) {
 		if (!so->so_is_open_owner)
 			continue;
-		if (same_owner_str(so, &open->op_owner, &open->op_clientid)) {
-			oo = openowner(so);
-			clp = oo->oo_owner.so_client;
-			if ((bool)clp->cl_minorversion != sessions)
-				break;
-			renew_client_locked(clp);
+		if (same_owner_str(so, &open->op_owner)) {
 			atomic_inc(&so->so_count);
-			return oo;
+			return openowner(so);
 		}
 	}
 	return NULL;
@@ -3188,13 +3182,13 @@ find_openstateowner_str_locked(unsigned int hashval, struct nfsd4_open *open,
 
 static struct nfs4_openowner *
 find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open,
-			bool sessions, struct nfsd_net *nn)
+			struct nfs4_client *clp)
 {
 	struct nfs4_openowner *oo;
 
-	spin_lock(&nn->client_lock);
-	oo = find_openstateowner_str_locked(hashval, open, sessions, nn);
-	spin_unlock(&nn->client_lock);
+	spin_lock(&clp->cl_lock);
+	oo = find_openstateowner_str_locked(hashval, open, clp);
+	spin_unlock(&clp->cl_lock);
 	return oo;
 }
 
@@ -3374,8 +3368,8 @@ nfsd4_process_open1(struct nfsd4_compound_state *cstate,
 		return status;
 	clp = cstate->clp;
 
-	strhashval = ownerstr_hashval(clientid->cl_id, &open->op_owner);
-	oo = find_openstateowner_str(strhashval, open, cstate->minorversion, nn);
+	strhashval = ownerstr_hashval(&open->op_owner);
+	oo = find_openstateowner_str(strhashval, open, clp);
 	open->op_openowner = oo;
 	if (!oo) {
 		goto new_owner;
@@ -4798,15 +4792,16 @@ nevermind:
 
 static struct nfs4_lockowner *
 find_lockowner_str_locked(clientid_t *clid, struct xdr_netobj *owner,
-		struct nfsd_net *nn)
+		struct nfs4_client *clp)
 {
-	unsigned int strhashval = ownerstr_hashval(clid->cl_id, owner);
+	unsigned int strhashval = ownerstr_hashval(owner);
 	struct nfs4_stateowner *so;
 
-	list_for_each_entry(so, &nn->ownerstr_hashtbl[strhashval], so_strhash) {
+	list_for_each_entry(so, &clp->cl_ownerstr_hashtbl[strhashval],
+			    so_strhash) {
 		if (so->so_is_open_owner)
 			continue;
-		if (!same_owner_str(so, owner, clid))
+		if (!same_owner_str(so, owner))
 			continue;
 		atomic_inc(&so->so_count);
 		return lockowner(so);
@@ -4816,23 +4811,23 @@ find_lockowner_str_locked(clientid_t *clid, struct xdr_netobj *owner,
 
 static struct nfs4_lockowner *
 find_lockowner_str(clientid_t *clid, struct xdr_netobj *owner,
-		struct nfsd_net *nn)
+		struct nfs4_client *clp)
 {
 	struct nfs4_lockowner *lo;
 
-	spin_lock(&nn->client_lock);
-	lo = find_lockowner_str_locked(clid, owner, nn);
-	spin_unlock(&nn->client_lock);
+	spin_lock(&clp->cl_lock);
+	lo = find_lockowner_str_locked(clid, owner, clp);
+	spin_unlock(&clp->cl_lock);
 	return lo;
 }
 
 static void nfs4_unhash_lockowner(struct nfs4_stateowner *sop)
 {
-	struct nfsd_net *nn = net_generic(sop->so_client->net, nfsd_net_id);
+	struct nfs4_client *clp = sop->so_client;
 
-	spin_lock(&nn->client_lock);
+	spin_lock(&clp->cl_lock);
 	unhash_lockowner_locked(lockowner(sop));
-	spin_unlock(&nn->client_lock);
+	spin_unlock(&clp->cl_lock);
 }
 
 static void nfs4_free_lockowner(struct nfs4_stateowner *sop)
@@ -4855,7 +4850,6 @@ alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp,
 			   struct nfs4_ol_stateid *open_stp,
 			   struct nfsd4_lock *lock)
 {
-	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
 	struct nfs4_lockowner *lo, *ret;
 
 	lo = alloc_stateowner(lockowner_slab, &lock->lk_new_owner, clp);
@@ -4866,16 +4860,16 @@ alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp,
 	lo->lo_owner.so_seqid = lock->lk_new_lock_seqid;
 	lo->lo_owner.so_free = nfs4_free_lockowner;
 	lo->lo_owner.so_unhash = nfs4_unhash_lockowner;
-	spin_lock(&nn->client_lock);
+	spin_lock(&clp->cl_lock);
 	ret = find_lockowner_str_locked(&clp->cl_clientid,
-			&lock->lk_new_owner, nn);
+			&lock->lk_new_owner, clp);
 	if (ret == NULL) {
 		list_add(&lo->lo_owner.so_strhash,
-			 &nn->ownerstr_hashtbl[strhashval]);
+			 &clp->cl_ownerstr_hashtbl[strhashval]);
 		ret = lo;
 	} else
 		nfs4_free_lockowner(&lo->lo_owner);
-	spin_unlock(&nn->client_lock);
+	spin_unlock(&clp->cl_lock);
 	return lo;
 }
 
@@ -4983,12 +4977,10 @@ static __be32 lookup_or_create_lock_state(struct nfsd4_compound_state *cstate,
 	struct nfs4_client *cl = oo->oo_owner.so_client;
 	struct nfs4_lockowner *lo;
 	unsigned int strhashval;
-	struct nfsd_net *nn = net_generic(cl->net, nfsd_net_id);
 
-	lo = find_lockowner_str(&cl->cl_clientid, &lock->v.new.owner, nn);
+	lo = find_lockowner_str(&cl->cl_clientid, &lock->v.new.owner, cl);
 	if (!lo) {
-		strhashval = ownerstr_hashval(cl->cl_clientid.cl_id,
-				&lock->v.new.owner);
+		strhashval = ownerstr_hashval(&lock->v.new.owner);
 		lo = alloc_init_lock_stateowner(strhashval, cl, ost, lock);
 		if (lo == NULL)
 			return nfserr_jukebox;
@@ -5266,7 +5258,8 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 		goto out;
 	}
 
-	lo = find_lockowner_str(&lockt->lt_clientid, &lockt->lt_owner, nn);
+	lo = find_lockowner_str(&lockt->lt_clientid, &lockt->lt_owner,
+				cstate->clp);
 	if (lo)
 		file_lock->fl_owner = (fl_owner_t)lo;
 	file_lock->fl_pid = current->tgid;
@@ -5401,7 +5394,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
 	struct nfs4_ol_stateid *stp;
 	struct xdr_netobj *owner = &rlockowner->rl_owner;
 	struct list_head matches;
-	unsigned int hashval = ownerstr_hashval(clid->cl_id, owner);
+	unsigned int hashval = ownerstr_hashval(owner);
 	__be32 status;
 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
 	struct nfs4_client *clp;
@@ -5418,29 +5411,29 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
 	status = nfserr_locks_held;
 	INIT_LIST_HEAD(&matches);
 
+	clp = cstate->clp;
 	/* Find the matching lock stateowner */
-	spin_lock(&nn->client_lock);
-	list_for_each_entry(tmp, &nn->ownerstr_hashtbl[hashval], so_strhash) {
+	spin_lock(&clp->cl_lock);
+	list_for_each_entry(tmp, &clp->cl_ownerstr_hashtbl[hashval],
+			    so_strhash) {
 		if (tmp->so_is_open_owner)
 			continue;
-		if (same_owner_str(tmp, owner, clid)) {
+		if (same_owner_str(tmp, owner)) {
 			sop = tmp;
 			atomic_inc(&sop->so_count);
 			break;
 		}
 	}
-	spin_unlock(&nn->client_lock);
 
 	/* No matching owner found, maybe a replay? Just declare victory... */
 	if (!sop) {
+		spin_unlock(&clp->cl_lock);
 		status = nfs_ok;
 		goto out;
 	}
 
 	lo = lockowner(sop);
 	/* see if there are still any locks associated with it */
-	clp = cstate->clp;
-	spin_lock(&clp->cl_lock);
 	list_for_each_entry(stp, &sop->so_stateids, st_perstateowner) {
 		if (check_for_locks(stp->st_stid.sc_file, lo)) {
 			spin_unlock(&clp->cl_lock);
@@ -5777,10 +5770,6 @@ static int nfs4_state_create_net(struct net *net)
 			CLIENT_HASH_SIZE, GFP_KERNEL);
 	if (!nn->unconf_id_hashtbl)
 		goto err_unconf_id;
-	nn->ownerstr_hashtbl = kmalloc(sizeof(struct list_head) *
-			OWNER_HASH_SIZE, GFP_KERNEL);
-	if (!nn->ownerstr_hashtbl)
-		goto err_ownerstr;
 	nn->sessionid_hashtbl = kmalloc(sizeof(struct list_head) *
 			SESSION_HASH_SIZE, GFP_KERNEL);
 	if (!nn->sessionid_hashtbl)
@@ -5790,8 +5779,6 @@ static int nfs4_state_create_net(struct net *net)
 		INIT_LIST_HEAD(&nn->conf_id_hashtbl[i]);
 		INIT_LIST_HEAD(&nn->unconf_id_hashtbl[i]);
 	}
-	for (i = 0; i < OWNER_HASH_SIZE; i++)
-		INIT_LIST_HEAD(&nn->ownerstr_hashtbl[i]);
 	for (i = 0; i < SESSION_HASH_SIZE; i++)
 		INIT_LIST_HEAD(&nn->sessionid_hashtbl[i]);
 	nn->conf_name_tree = RB_ROOT;
@@ -5807,8 +5794,6 @@ static int nfs4_state_create_net(struct net *net)
 	return 0;
 
 err_sessionid:
-	kfree(nn->ownerstr_hashtbl);
-err_ownerstr:
 	kfree(nn->unconf_id_hashtbl);
 err_unconf_id:
 	kfree(nn->conf_id_hashtbl);
@@ -5838,7 +5823,6 @@ nfs4_state_destroy_net(struct net *net)
 	}
 
 	kfree(nn->sessionid_hashtbl);
-	kfree(nn->ownerstr_hashtbl);
 	kfree(nn->unconf_id_hashtbl);
 	kfree(nn->conf_id_hashtbl);
 	put_net(net);
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 89d43c3b5078..a09a72fdb5a6 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -237,6 +237,7 @@ struct nfsd4_sessionid {
 struct nfs4_client {
 	struct list_head	cl_idhash; 	/* hash by cl_clientid.id */
 	struct rb_node		cl_namenode;	/* link into by-name trees */
+	struct list_head	*cl_ownerstr_hashtbl;
 	struct list_head	cl_openowners;
 	struct idr		cl_stateids;	/* stateid lookup */
 	struct list_head	cl_delegations;
-- 
1.9.3


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

* [PATCH v2 074/117] lockdep: add lockdep_assert_not_held
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (72 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 073/117] nfsd: Move the open owner hash table into struct nfs4_client Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-26 19:12 ` [PATCH v2 075/117] nfsd: add locking to stateowner release Jeff Layton
                   ` (44 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Peter Zijlstra, Ingo Molnar

We currently have the ability to call lockdep_assert_held to throw a
warning when a spinlock isn't held in a codepath. There are also times
when we'd like to throw a warning when a lock is held (i.e. when there
is the potential for deadlock with atomic_dec_and_lock or similar).

Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Ingo Molnar <mingo@redhat.com>
Signed-off-by: Jeff Layton <jlayton@primarydata.com>
---
 include/linux/lockdep.h | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h
index 008388f920d7..1e5f1d544029 100644
--- a/include/linux/lockdep.h
+++ b/include/linux/lockdep.h
@@ -362,6 +362,8 @@ extern void lockdep_trace_alloc(gfp_t mask);
 		WARN_ON(debug_locks && !lockdep_is_held(l));	\
 	} while (0)
 
+#define lockdep_assert_not_held(l) WARN_ON(debug_locks && lockdep_is_held(l))
+
 #define lockdep_recursing(tsk)	((tsk)->lockdep_recursion)
 
 #else /* !CONFIG_LOCKDEP */
@@ -413,6 +415,8 @@ struct lock_class_key { };
 
 #define lockdep_assert_held(l)			do { (void)(l); } while (0)
 
+#define lockdep_assert_not_held(l)		(void)(l)
+
 #define lockdep_recursing(tsk)			(0)
 
 #endif /* !LOCKDEP */
-- 
1.9.3


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

* [PATCH v2 075/117] nfsd: add locking to stateowner release
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (73 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 074/117] lockdep: add lockdep_assert_not_held Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-26 19:12 ` [PATCH v2 076/117] nfsd: optimize destroy_lockowner cl_lock thrashing Jeff Layton
                   ` (43 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

Once we remove the client_mutex, we'll need to properly protect
the stateowner reference counts using the cl_lock.

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

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 503beb3faa6c..92680d6531e7 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -678,6 +678,8 @@ static void nfs4_put_stid(struct nfs4_stid *s)
 {
 	struct nfs4_client *clp = s->sc_client;
 
+	lockdep_assert_not_held(&clp->cl_lock);
+
 	if (!atomic_dec_and_lock(&s->sc_count, &clp->cl_lock)) {
 		wake_up_all(&close_wq);
 		return;
@@ -3030,9 +3032,14 @@ static inline void *alloc_stateowner(struct kmem_cache *slab, struct xdr_netobj
 
 static void nfs4_put_stateowner(struct nfs4_stateowner *sop)
 {
-	if (!atomic_dec_and_test(&sop->so_count))
+	struct nfs4_client *clp = sop->so_client;
+
+	lockdep_assert_not_held(&clp->cl_lock);
+
+	if (!atomic_dec_and_lock(&sop->so_count, &clp->cl_lock))
 		return;
 	sop->so_unhash(sop);
+	spin_unlock(&clp->cl_lock);
 	sop->so_free(sop);
 }
 
@@ -3047,11 +3054,7 @@ static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, u
 
 static void nfs4_unhash_openowner(struct nfs4_stateowner *so)
 {
-	struct nfs4_client *clp = so->so_client;
-
-	spin_lock(&clp->cl_lock);
 	unhash_openowner_locked(openowner(so));
-	spin_unlock(&clp->cl_lock);
 }
 
 static void nfs4_free_openowner(struct nfs4_stateowner *so)
@@ -4823,11 +4826,7 @@ find_lockowner_str(clientid_t *clid, struct xdr_netobj *owner,
 
 static void nfs4_unhash_lockowner(struct nfs4_stateowner *sop)
 {
-	struct nfs4_client *clp = sop->so_client;
-
-	spin_lock(&clp->cl_lock);
 	unhash_lockowner_locked(lockowner(sop));
-	spin_unlock(&clp->cl_lock);
 }
 
 static void nfs4_free_lockowner(struct nfs4_stateowner *sop)
-- 
1.9.3


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

* [PATCH v2 076/117] nfsd: optimize destroy_lockowner cl_lock thrashing
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (74 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 075/117] nfsd: add locking to stateowner release Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-26 19:12 ` [PATCH v2 077/117] nfsd: close potential race in nfsd4_free_stateid Jeff Layton
                   ` (42 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

Reduce the cl_lock trashing in destroy_lockowner. Unhash all of the
lockstateids on the lockowner's list. Put the reference under the lock
and see if it was the last one. If so, then add it to a private list
to be destroyed after we drop the lock.

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

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 92680d6531e7..790ff7dacbfb 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -938,14 +938,23 @@ static void put_generic_stateid(struct nfs4_ol_stateid *stp)
 	nfs4_put_stid(&stp->st_stid);
 }
 
-static void release_lock_stateid(struct nfs4_ol_stateid *stp)
+static void unhash_lock_stateid(struct nfs4_ol_stateid *stp)
 {
 	struct nfs4_openowner *oo = openowner(stp->st_openstp->st_stateowner);
 
-	spin_lock(&oo->oo_owner.so_client->cl_lock);
-	list_del(&stp->st_locks);
+	lockdep_assert_held(&oo->oo_owner.so_client->cl_lock);
+
+	list_del_init(&stp->st_locks);
 	unhash_generic_stateid(stp);
 	unhash_stid(&stp->st_stid);
+}
+
+static void release_lock_stateid(struct nfs4_ol_stateid *stp)
+{
+	struct nfs4_openowner *oo = openowner(stp->st_openstp->st_stateowner);
+
+	spin_lock(&oo->oo_owner.so_client->cl_lock);
+	unhash_lock_stateid(stp);
 	spin_unlock(&oo->oo_owner.so_client->cl_lock);
 	put_generic_stateid(stp);
 }
@@ -959,30 +968,37 @@ static void unhash_lockowner_locked(struct nfs4_lockowner *lo)
 	list_del_init(&lo->lo_owner.so_strhash);
 }
 
-static void release_lockowner_stateids(struct nfs4_lockowner *lo)
+static void release_lockowner(struct nfs4_lockowner *lo)
 {
 	struct nfs4_client *clp = lo->lo_owner.so_client;
 	struct nfs4_ol_stateid *stp;
+	struct list_head reaplist;
 
-	lockdep_assert_held(&clp->cl_lock);
+	INIT_LIST_HEAD(&reaplist);
 
+	spin_lock(&clp->cl_lock);
+	unhash_lockowner_locked(lo);
 	while (!list_empty(&lo->lo_owner.so_stateids)) {
 		stp = list_first_entry(&lo->lo_owner.so_stateids,
 				struct nfs4_ol_stateid, st_perstateowner);
-		spin_unlock(&clp->cl_lock);
-		release_lock_stateid(stp);
-		spin_lock(&clp->cl_lock);
+		unhash_lock_stateid(stp);
+		/*
+		 * We now know that no new references can be added to the
+		 * stateid. If ours is the last one, finish the unhashing
+		 * and put it on the list to be reaped.
+		 */
+		if (atomic_dec_and_test(&stp->st_stid.sc_count)) {
+			remove_stid_locked(clp, &stp->st_stid);
+			list_add(&stp->st_locks, &reaplist);
+		}
 	}
-}
-
-static void release_lockowner(struct nfs4_lockowner *lo)
-{
-	struct nfs4_client *clp = lo->lo_owner.so_client;
-
-	spin_lock(&clp->cl_lock);
-	unhash_lockowner_locked(lo);
-	release_lockowner_stateids(lo);
 	spin_unlock(&clp->cl_lock);
+	while (!list_empty(&reaplist)) {
+		stp = list_first_entry(&reaplist, struct nfs4_ol_stateid,
+					st_locks);
+		list_del(&stp->st_locks);
+		stp->st_stid.sc_free(&stp->st_stid);
+	}
 	nfs4_put_stateowner(&lo->lo_owner);
 }
 
-- 
1.9.3


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

* [PATCH v2 077/117] nfsd: close potential race in nfsd4_free_stateid
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (75 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 076/117] nfsd: optimize destroy_lockowner cl_lock thrashing Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-26 19:12 ` [PATCH v2 078/117] nfsd: reduce cl_lock thrashing in release_openowner Jeff Layton
                   ` (41 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

Once we remove the client_mutex, it'll be possible for the sc_type of a
lock stateid to change after it's found and checked, but before we can
go to destroy it. If that happens, we can end up putting the persistent
reference to the stateid more than once, and unhash it more than once.

Fix this by unhashing the lock stateid prior to dropping the cl_lock but
after finding it.

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

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 790ff7dacbfb..207120f721e3 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -4365,17 +4365,6 @@ unlock_state:
 	return status;
 }
 
-static __be32
-nfsd4_free_lock_stateid(struct nfs4_ol_stateid *stp)
-{
-	struct nfs4_lockowner *lo = lockowner(stp->st_stateowner);
-
-	if (check_for_locks(stp->st_stid.sc_file, lo))
-		return nfserr_locks_held;
-	release_lock_stateid(stp);
-	return nfs_ok;
-}
-
 /*
  * Test if the stateid is valid
  */
@@ -4402,6 +4391,7 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	stateid_t *stateid = &free_stateid->fr_stateid;
 	struct nfs4_stid *s;
 	struct nfs4_delegation *dp;
+	struct nfs4_ol_stateid *stp;
 	struct nfs4_client *cl = cstate->session->se_client;
 	__be32 ret = nfserr_bad_stateid;
 
@@ -4419,12 +4409,16 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 		ret = check_stateid_generation(stateid, &s->sc_stateid, 1);
 		if (ret)
 			break;
-		if (s->sc_type != NFS4_LOCK_STID) {
-			ret = nfserr_locks_held;
+		stp = openlockstateid(s);
+		ret = nfserr_locks_held;
+		if (s->sc_type == NFS4_OPEN_STID ||
+		    check_for_locks(s->sc_file,
+				    lockowner(stp->st_stateowner)))
 			break;
-		}
+		unhash_lock_stateid(stp);
 		spin_unlock(&cl->cl_lock);
-		ret = nfsd4_free_lock_stateid(openlockstateid(s));
+		put_generic_stateid(stp);
+		ret = nfs_ok;
 		goto out;
 	case NFS4_REVOKED_DELEG_STID:
 		spin_unlock(&cl->cl_lock);
-- 
1.9.3


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

* [PATCH v2 078/117] nfsd: reduce cl_lock thrashing in release_openowner
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (76 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 077/117] nfsd: close potential race in nfsd4_free_stateid Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-26 19:12 ` [PATCH v2 079/117] nfsd: don't thrash the cl_lock while freeing an open stateid Jeff Layton
                   ` (40 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

Releasing an openowner is a bit inefficient as it can potentially thrash
the cl_lock if you have a lot of stateids attached to it. Once we remove
the client_mutex, it'll also potentially be dangerous to do this.

Add some functions to make it easier to defer the part of putting a
generic stateid reference that needs to be done outside the cl_lock while
doing the parts that must be done while holding it under a single lock.

First we unhash each open stateid. Then we call
put_generic_stateid_locked which will put the reference to an
nfs4_ol_stateid. If it turns out to be the last reference, it'll go
ahead and remove the stid from the IDR tree and put it onto the reaplist
using the st_locks list_head.

Then, after dropping the lock we'll call free_stateid_reaplist to walk
the list of stateids that are fully unhashed and ready to be freed, and
free each of them. This function can sleep, so it must be done outside
any spinlocks.

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

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 207120f721e3..60dc6b4921dd 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -938,6 +938,30 @@ static void put_generic_stateid(struct nfs4_ol_stateid *stp)
 	nfs4_put_stid(&stp->st_stid);
 }
 
+/*
+ * Put the persistent reference to an already unhashed generic stateid, while
+ * holding the cl_lock. If it's the last reference, then put it onto the
+ * reaplist for later destruction.
+ */
+static void put_generic_stateid_locked(struct nfs4_ol_stateid *stp,
+				       struct list_head *reaplist)
+{
+	struct nfs4_stid *s = &stp->st_stid;
+	struct nfs4_client *clp = s->sc_client;
+
+	lockdep_assert_held(&clp->cl_lock);
+
+	WARN_ON_ONCE(!list_empty(&stp->st_locks));
+
+	if (!atomic_dec_and_test(&s->sc_count)) {
+		wake_up_all(&close_wq);
+		return;
+	}
+
+	remove_stid_locked(clp, s);
+	list_add(&stp->st_locks, reaplist);
+}
+
 static void unhash_lock_stateid(struct nfs4_ol_stateid *stp)
 {
 	struct nfs4_openowner *oo = openowner(stp->st_openstp->st_stateowner);
@@ -968,6 +992,25 @@ static void unhash_lockowner_locked(struct nfs4_lockowner *lo)
 	list_del_init(&lo->lo_owner.so_strhash);
 }
 
+/*
+ * Free a list of generic stateids that were collected earlier after being
+ * fully unhashed.
+ */
+static void
+free_stateid_reaplist(struct list_head *reaplist)
+{
+	struct nfs4_ol_stateid *stp;
+
+	might_sleep();
+
+	while (!list_empty(reaplist)) {
+		stp = list_first_entry(reaplist, struct nfs4_ol_stateid,
+				       st_locks);
+		list_del(&stp->st_locks);
+		stp->st_stid.sc_free(&stp->st_stid);
+	}
+}
+
 static void release_lockowner(struct nfs4_lockowner *lo)
 {
 	struct nfs4_client *clp = lo->lo_owner.so_client;
@@ -982,23 +1025,10 @@ static void release_lockowner(struct nfs4_lockowner *lo)
 		stp = list_first_entry(&lo->lo_owner.so_stateids,
 				struct nfs4_ol_stateid, st_perstateowner);
 		unhash_lock_stateid(stp);
-		/*
-		 * We now know that no new references can be added to the
-		 * stateid. If ours is the last one, finish the unhashing
-		 * and put it on the list to be reaped.
-		 */
-		if (atomic_dec_and_test(&stp->st_stid.sc_count)) {
-			remove_stid_locked(clp, &stp->st_stid);
-			list_add(&stp->st_locks, &reaplist);
-		}
+		put_generic_stateid_locked(stp, &reaplist);
 	}
 	spin_unlock(&clp->cl_lock);
-	while (!list_empty(&reaplist)) {
-		stp = list_first_entry(&reaplist, struct nfs4_ol_stateid,
-					st_locks);
-		list_del(&stp->st_locks);
-		stp->st_stid.sc_free(&stp->st_stid);
-	}
+	free_stateid_reaplist(&reaplist);
 	nfs4_put_stateowner(&lo->lo_owner);
 }
 
@@ -1019,16 +1049,10 @@ static void release_open_stateid_locks(struct nfs4_ol_stateid *open_stp)
 
 static void unhash_open_stateid(struct nfs4_ol_stateid *stp)
 {
-	spin_lock(&stp->st_stateowner->so_client->cl_lock);
+	lockdep_assert_held(&stp->st_stateowner->so_client->cl_lock);
+
 	unhash_generic_stateid(stp);
 	release_open_stateid_locks(stp);
-	spin_unlock(&stp->st_stateowner->so_client->cl_lock);
-}
-
-static void release_open_stateid(struct nfs4_ol_stateid *stp)
-{
-	unhash_open_stateid(stp);
-	put_generic_stateid(stp);
 }
 
 static void unhash_openowner_locked(struct nfs4_openowner *oo)
@@ -1052,30 +1076,24 @@ static void release_last_closed_stateid(struct nfs4_openowner *oo)
 	}
 }
 
-static void release_openowner_stateids(struct nfs4_openowner *oo)
+static void release_openowner(struct nfs4_openowner *oo)
 {
 	struct nfs4_ol_stateid *stp;
 	struct nfs4_client *clp = oo->oo_owner.so_client;
+	struct list_head reaplist;
 
-	lockdep_assert_held(&clp->cl_lock);
+	INIT_LIST_HEAD(&reaplist);
 
+	spin_lock(&clp->cl_lock);
+	unhash_openowner_locked(oo);
 	while (!list_empty(&oo->oo_owner.so_stateids)) {
 		stp = list_first_entry(&oo->oo_owner.so_stateids,
 				struct nfs4_ol_stateid, st_perstateowner);
-		spin_unlock(&clp->cl_lock);
-		release_open_stateid(stp);
-		spin_lock(&clp->cl_lock);
+		unhash_open_stateid(stp);
+		put_generic_stateid_locked(stp, &reaplist);
 	}
-}
-
-static void release_openowner(struct nfs4_openowner *oo)
-{
-	struct nfs4_client *clp = oo->oo_owner.so_client;
-
-	spin_lock(&clp->cl_lock);
-	unhash_openowner_locked(oo);
-	release_openowner_stateids(oo);
 	spin_unlock(&clp->cl_lock);
+	free_stateid_reaplist(&reaplist);
 	release_last_closed_stateid(oo);
 	nfs4_put_stateowner(&oo->oo_owner);
 }
@@ -4654,7 +4672,9 @@ static void nfsd4_close_open_stateid(struct nfs4_ol_stateid *s)
 	struct nfs4_client *clp = s->st_stid.sc_client;
 
 	s->st_stid.sc_type = NFS4_CLOSED_STID;
+	spin_lock(&clp->cl_lock);
 	unhash_open_stateid(s);
+	spin_unlock(&clp->cl_lock);
 
 	if (clp->cl_minorversion)
 		put_generic_stateid(s);
-- 
1.9.3


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

* [PATCH v2 079/117] nfsd: don't thrash the cl_lock while freeing an open stateid
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (77 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 078/117] nfsd: reduce cl_lock thrashing in release_openowner Jeff Layton
@ 2014-06-26 19:12 ` Jeff Layton
  2014-06-26 19:13 ` [PATCH v2 080/117] nfsd: Ensure struct nfs4_client is unhashed before we try to destroy it Jeff Layton
                   ` (39 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:12 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

When we remove the client_mutex, we'll have a potential race between
FREE_STATEID and CLOSE.

The root of the problem is that we are walking the st_locks list,
dropping the spinlock and then trying to release the persistent
reference to the lockstateid. In between, a FREE_STATEID call can come
along and take the lock, find the stateid and then try to put the
reference. That leads to a double put.

Fix this by not releasing the cl_lock in order to release each lock
stateid. Use put_generic_stateid_locked to unhash them and gather
them onto a list, and free_stateid_reaplist to free any that end up
on the list.

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

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 60dc6b4921dd..ca87362b9a17 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1032,27 +1032,26 @@ static void release_lockowner(struct nfs4_lockowner *lo)
 	nfs4_put_stateowner(&lo->lo_owner);
 }
 
-static void release_open_stateid_locks(struct nfs4_ol_stateid *open_stp)
-	__releases(&open_stp->st_stateowner->so_client->cl_lock)
-	__acquires(&open_stp->st_stateowner->so_client->cl_lock)
+static void release_open_stateid_locks(struct nfs4_ol_stateid *open_stp,
+				       struct list_head *reaplist)
 {
 	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);
-		spin_unlock(&open_stp->st_stateowner->so_client->cl_lock);
-		release_lock_stateid(stp);
-		spin_lock(&open_stp->st_stateowner->so_client->cl_lock);
+		unhash_lock_stateid(stp);
+		put_generic_stateid_locked(stp, reaplist);
 	}
 }
 
-static void unhash_open_stateid(struct nfs4_ol_stateid *stp)
+static void unhash_open_stateid(struct nfs4_ol_stateid *stp,
+				struct list_head *reaplist)
 {
 	lockdep_assert_held(&stp->st_stateowner->so_client->cl_lock);
 
 	unhash_generic_stateid(stp);
-	release_open_stateid_locks(stp);
+	release_open_stateid_locks(stp, reaplist);
 }
 
 static void unhash_openowner_locked(struct nfs4_openowner *oo)
@@ -1089,7 +1088,7 @@ static void release_openowner(struct nfs4_openowner *oo)
 	while (!list_empty(&oo->oo_owner.so_stateids)) {
 		stp = list_first_entry(&oo->oo_owner.so_stateids,
 				struct nfs4_ol_stateid, st_perstateowner);
-		unhash_open_stateid(stp);
+		unhash_open_stateid(stp, &reaplist);
 		put_generic_stateid_locked(stp, &reaplist);
 	}
 	spin_unlock(&clp->cl_lock);
@@ -4670,16 +4669,21 @@ out:
 static void nfsd4_close_open_stateid(struct nfs4_ol_stateid *s)
 {
 	struct nfs4_client *clp = s->st_stid.sc_client;
+	LIST_HEAD(reaplist);
 
 	s->st_stid.sc_type = NFS4_CLOSED_STID;
 	spin_lock(&clp->cl_lock);
-	unhash_open_stateid(s);
-	spin_unlock(&clp->cl_lock);
+	unhash_open_stateid(s, &reaplist);
 
-	if (clp->cl_minorversion)
-		put_generic_stateid(s);
-	else
+	if (clp->cl_minorversion) {
+		put_generic_stateid_locked(s, &reaplist);
+		spin_unlock(&clp->cl_lock);
+		free_stateid_reaplist(&reaplist);
+	} else {
+		spin_unlock(&clp->cl_lock);
+		free_stateid_reaplist(&reaplist);
 		move_to_close_lru(s, clp->net);
+	}
 }
 
 /*
-- 
1.9.3


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

* [PATCH v2 080/117] nfsd: Ensure struct nfs4_client is unhashed before we try to destroy it
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (78 preceding siblings ...)
  2014-06-26 19:12 ` [PATCH v2 079/117] nfsd: don't thrash the cl_lock while freeing an open stateid Jeff Layton
@ 2014-06-26 19:13 ` Jeff Layton
  2014-06-26 19:13 ` [PATCH v2 081/117] nfsd: Ensure that the laundromat unhashes the client before releasing locks Jeff Layton
                   ` (38 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:13 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

When we remove the client_mutex 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 ca87362b9a17..8a973601718e 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1536,12 +1536,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);
@@ -1549,7 +1560,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;
@@ -1582,22 +1603,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.3


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

* [PATCH v2 081/117] nfsd: Ensure that the laundromat unhashes the client before releasing locks
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (79 preceding siblings ...)
  2014-06-26 19:13 ` [PATCH v2 080/117] nfsd: Ensure struct nfs4_client is unhashed before we try to destroy it Jeff Layton
@ 2014-06-26 19:13 ` Jeff Layton
  2014-06-26 19:13 ` [PATCH v2 082/117] nfsd: Don't require client_lock in free_client Jeff Layton
                   ` (37 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:13 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

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 8a973601718e..889854591557 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -4085,13 +4085,15 @@ nfs4_laundromat(struct nfsd_net *nn)
 				clp->cl_clientid.cl_id);
 			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.3


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

* [PATCH v2 082/117] nfsd: Don't require client_lock in free_client
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (80 preceding siblings ...)
  2014-06-26 19:13 ` [PATCH v2 081/117] nfsd: Ensure that the laundromat unhashes the client before releasing locks Jeff Layton
@ 2014-06-26 19:13 ` Jeff Layton
  2014-06-26 19:13 ` [PATCH v2 083/117] nfsd: Move create_client() call outside the lock Jeff Layton
                   ` (36 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:13 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

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 | 13 -------------
 1 file changed, 13 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 889854591557..461e6d5c6af1 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1362,9 +1362,6 @@ static void __free_session(struct nfsd4_session *ses)
 
 static void free_session(struct nfsd4_session *ses)
 {
-	struct nfsd_net *nn = net_generic(ses->se_client->net, nfsd_net_id);
-
-	lockdep_assert_held(&nn->client_lock);
 	nfsd4_del_conns(ses);
 	nfsd4_put_drc_mem(&ses->se_fchannel);
 	__free_session(ses);
@@ -1514,9 +1511,6 @@ err_no_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,
@@ -1575,7 +1569,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);
@@ -1603,10 +1596,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
@@ -1809,7 +1799,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)
@@ -1817,9 +1806,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;
 	}
 	clp->cl_time = get_seconds();
-- 
1.9.3


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

* [PATCH v2 083/117] nfsd: Move create_client() call outside the lock
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (81 preceding siblings ...)
  2014-06-26 19:13 ` [PATCH v2 082/117] nfsd: Don't require client_lock in free_client Jeff Layton
@ 2014-06-26 19:13 ` Jeff Layton
  2014-06-26 19:20 ` [PATCH v2 084/117] nfsd: Protect unconfirmed client creation using client_lock Jeff Layton
                   ` (35 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:13 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

For efficiency reasons, and because we want to use spin locks instead
of relying on the client_mutex.

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 461e6d5c6af1..974617538a49 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -2127,6 +2127,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);
@@ -2153,7 +2157,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 */
@@ -2166,7 +2169,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 */
@@ -2184,29 +2186,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;
 }
 
@@ -2849,6 +2850,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);
@@ -2869,10 +2873,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);
@@ -2884,9 +2884,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.3


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

* [PATCH v2 084/117] nfsd: Protect unconfirmed client creation using client_lock
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (82 preceding siblings ...)
  2014-06-26 19:13 ` [PATCH v2 083/117] nfsd: Move create_client() call outside the lock Jeff Layton
@ 2014-06-26 19:20 ` Jeff Layton
  2014-06-26 19:20 ` [PATCH v2 085/117] nfsd: Protect session creation and client confirm " Jeff Layton
                   ` (34 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:20 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

...instead of relying on the client_mutex.

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

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 974617538a49..f1a11b57d7e0 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1869,7 +1869,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
@@ -1883,7 +1883,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 *
@@ -1896,7 +1896,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;
 		}
 	}
@@ -2098,7 +2098,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;
@@ -2133,6 +2134,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);
@@ -2164,7 +2166,6 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
 				status = nfserr_clid_inuse;
 				goto out;
 			}
-			expire_client(conf);
 			goto out_new;
 		}
 		if (verfs_match) { /* case 2 */
@@ -2172,6 +2173,7 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
 			goto out_copy;
 		}
 		/* case 5, client reboot */
+		conf = NULL;
 		goto out_new;
 	}
 
@@ -2182,17 +2184,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;
@@ -2205,9 +2208,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;
 }
 
@@ -2846,7 +2852,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);
 
@@ -2855,6 +2862,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: */
@@ -2872,7 +2880,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);
@@ -2887,9 +2895,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.3


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

* [PATCH v2 085/117] nfsd: Protect session creation and client confirm using client_lock
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (83 preceding siblings ...)
  2014-06-26 19:20 ` [PATCH v2 084/117] nfsd: Protect unconfirmed client creation using client_lock Jeff Layton
@ 2014-06-26 19:20 ` Jeff Layton
  2014-06-26 19:20 ` [PATCH v2 086/117] nfsd: Protect nfsd4_destroy_clientid " Jeff Layton
                   ` (33 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:20 UTC (permalink / raw)
  To: bfields; +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. instead of relying on the client_mutex.

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

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index f1a11b57d7e0..ba853aa0bfa0 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -144,17 +144,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))
@@ -1383,12 +1372,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);
@@ -2357,6 +2344,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;
@@ -2383,6 +2371,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);
@@ -2401,7 +2390,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;
@@ -2419,10 +2407,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;
@@ -2438,20 +2426,29 @@ 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);
 	cs_slot->sl_seqid++;
 	cr_ses->seqid = cs_slot->sl_seqid;
 
-	/* cache solo and embedded create sessions under the state lock */
+	/* cache solo and embedded create sessions under the client_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:
@@ -2911,6 +2908,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;
@@ -2920,6 +2918,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);
 	/*
@@ -2943,21 +2942,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;
 }
@@ -5614,7 +5621,13 @@ nfs4_check_open_reclaim(clientid_t *clid,
 
 u64 nfsd_forget_client(struct nfs4_client *clp, u64 max)
 {
-	if (mark_client_expired(clp))
+	__be32 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 != nfs_ok)
 		return 0;
 	expire_client(clp);
 	return 1;
-- 
1.9.3


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

* [PATCH v2 086/117] nfsd: Protect nfsd4_destroy_clientid using client_lock
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (84 preceding siblings ...)
  2014-06-26 19:20 ` [PATCH v2 085/117] nfsd: Protect session creation and client confirm " Jeff Layton
@ 2014-06-26 19:20 ` Jeff Layton
  2014-06-26 19:20 ` [PATCH v2 087/117] nfsd: Ensure lookup_clientid() takes client_lock Jeff Layton
                   ` (32 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:20 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

...instead of relying on the client_mutex.

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 ba853aa0bfa0..77e4e24c920d 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -2772,22 +2772,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 {
@@ -2795,12 +2796,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.3


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

* [PATCH v2 087/117] nfsd: Ensure lookup_clientid() takes client_lock
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (85 preceding siblings ...)
  2014-06-26 19:20 ` [PATCH v2 086/117] nfsd: Protect nfsd4_destroy_clientid " Jeff Layton
@ 2014-06-26 19:20 ` Jeff Layton
  2014-06-26 19:20 ` [PATCH v2 088/117] nfsd: Add lockdep assertions to document the nfs4_client/session locking Jeff Layton
                   ` (31 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:20 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

Ensure that the client lookup is done safely under the client_lock, so
we're not relying on the client_mutex.

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 77e4e24c920d..e81c97435f7f 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -4016,12 +4016,14 @@ static __be32 lookup_clientid(clientid_t *clid,
 		 * if we don't have one cached already then we know this is for
 		 * is for v4.0 and "sessions" will be false.
 		 */
+		spin_lock(&nn->client_lock);
 		found = find_confirmed_client(clid, false, nn);
 		/* Cache the nfs4_client in cstate! */
 		if (found) {
 			cstate->clp = found;
 			atomic_inc(&found->cl_refcount);
 		}
+		spin_unlock(&nn->client_lock);
 	}
 	return found ? nfs_ok : nfserr_expired;
 }
-- 
1.9.3


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

* [PATCH v2 088/117] nfsd: Add lockdep assertions to document the nfs4_client/session locking
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (86 preceding siblings ...)
  2014-06-26 19:20 ` [PATCH v2 087/117] nfsd: Ensure lookup_clientid() takes client_lock Jeff Layton
@ 2014-06-26 19:20 ` Jeff Layton
  2014-06-26 19:20 ` [PATCH v2 089/117] nfsd: protect the close_lru list and oo_last_closed_stid with client_lock Jeff Layton
                   ` (30 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:20 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

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

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index e81c97435f7f..f49def48464d 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -146,6 +146,10 @@ static __be32 mark_client_expired_locked(struct nfs4_client *clp)
 
 static __be32 get_client_locked(struct nfs4_client *clp)
 {
+	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
+
+	lockdep_assert_held(&nn->client_lock);
+
 	if (is_client_expired(clp))
 		return nfserr_expired;
 	atomic_inc(&clp->cl_refcount);
@@ -186,6 +190,10 @@ renew_client(struct nfs4_client *clp)
 
 static void put_client_renew_locked(struct nfs4_client *clp)
 {
+	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
+
+	lockdep_assert_held(&nn->client_lock);
+
 	if (!atomic_dec_and_test(&clp->cl_refcount))
 		return;
 	if (!is_client_expired(clp))
@@ -217,6 +225,9 @@ static __be32 nfsd4_get_session_locked(struct nfsd4_session *ses)
 static void nfsd4_put_session_locked(struct nfsd4_session *ses)
 {
 	struct nfs4_client *clp = ses->se_client;
+	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
+
+	lockdep_assert_held(&nn->client_lock);
 
 	if (atomic_dec_and_test(&ses->se_ref) && is_session_dead(ses))
 		free_session(ses);
@@ -1399,6 +1410,8 @@ __find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid, struct net *net)
 	int idx;
 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 
+	lockdep_assert_held(&nn->client_lock);
+
 	dump_sessionid(__func__, sessionid);
 	idx = hash_sessionid(sessionid);
 	/* Search in the appropriate list */
@@ -1435,6 +1448,11 @@ out:
 static void
 unhash_session(struct nfsd4_session *ses)
 {
+	struct nfs4_client *clp = ses->se_client;
+	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
+
+	lockdep_assert_held(&nn->client_lock);
+
 	list_del(&ses->se_hash);
 	spin_lock(&ses->se_client->cl_lock);
 	list_del(&ses->se_perclnt);
@@ -1523,6 +1541,8 @@ unhash_client_locked(struct nfs4_client *clp)
 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
 	struct nfsd4_session *ses;
 
+	lockdep_assert_held(&nn->client_lock);
+
 	/* Mark the client as expired! */
 	clp->cl_time = 0;
 	/* Make it invisible */
@@ -1852,6 +1872,8 @@ add_to_unconfirmed(struct nfs4_client *clp)
 	unsigned int idhashval;
 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
 
+	lockdep_assert_held(&nn->client_lock);
+
 	clear_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags);
 	add_clp_to_name_tree(clp, &nn->unconf_name_tree);
 	idhashval = clientid_hashval(clp->cl_clientid.cl_id);
@@ -1865,6 +1887,8 @@ move_to_confirmed(struct nfs4_client *clp)
 	unsigned int idhashval = clientid_hashval(clp->cl_clientid.cl_id);
 	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
 
+	lockdep_assert_held(&nn->client_lock);
+
 	dprintk("NFSD: move_to_confirm nfs4_client %p\n", clp);
 	list_move(&clp->cl_idhash, &nn->conf_id_hashtbl[idhashval]);
 	rb_erase(&clp->cl_namenode, &nn->unconf_name_tree);
@@ -1895,6 +1919,7 @@ find_confirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn)
 {
 	struct list_head *tbl = nn->conf_id_hashtbl;
 
+	lockdep_assert_held(&nn->client_lock);
 	return find_client_in_id_table(tbl, clid, sessions);
 }
 
@@ -1903,6 +1928,7 @@ find_unconfirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn)
 {
 	struct list_head *tbl = nn->unconf_id_hashtbl;
 
+	lockdep_assert_held(&nn->client_lock);
 	return find_client_in_id_table(tbl, clid, sessions);
 }
 
@@ -1914,12 +1940,14 @@ static bool clp_used_exchangeid(struct nfs4_client *clp)
 static struct nfs4_client *
 find_confirmed_client_by_name(struct xdr_netobj *name, struct nfsd_net *nn)
 {
+	lockdep_assert_held(&nn->client_lock);
 	return find_clp_in_name_tree(name, &nn->conf_name_tree);
 }
 
 static struct nfs4_client *
 find_unconfirmed_client_by_name(struct xdr_netobj *name, struct nfsd_net *nn)
 {
+	lockdep_assert_held(&nn->client_lock);
 	return find_clp_in_name_tree(name, &nn->unconf_name_tree);
 }
 
@@ -4874,6 +4902,8 @@ find_lockowner_str_locked(clientid_t *clid, struct xdr_netobj *owner,
 	unsigned int strhashval = ownerstr_hashval(owner);
 	struct nfs4_stateowner *so;
 
+	lockdep_assert_held(&clp->cl_lock);
+
 	list_for_each_entry(so, &clp->cl_ownerstr_hashtbl[strhashval],
 			    so_strhash) {
 		if (so->so_is_open_owner)
-- 
1.9.3


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

* [PATCH v2 089/117] nfsd: protect the close_lru list and oo_last_closed_stid with client_lock
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (87 preceding siblings ...)
  2014-06-26 19:20 ` [PATCH v2 088/117] nfsd: Add lockdep assertions to document the nfs4_client/session locking Jeff Layton
@ 2014-06-26 19:20 ` Jeff Layton
  2014-06-26 19:20 ` [PATCH v2 090/117] nfsd: ensure that clp->cl_revoked list is protected by clp->cl_lock Jeff Layton
                   ` (29 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:20 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

Currently, it's protected by the client_mutex. Move it so that the list
and the fields in the openowner are protected by the client_lock.

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

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index f49def48464d..73eb34901bf2 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1066,13 +1066,19 @@ static void unhash_openowner_locked(struct nfs4_openowner *oo)
 
 static void release_last_closed_stateid(struct nfs4_openowner *oo)
 {
-	struct nfs4_ol_stateid *s = oo->oo_last_closed_stid;
+	struct nfsd_net *nn = net_generic(oo->oo_owner.so_client->net,
+					  nfsd_net_id);
+	struct nfs4_ol_stateid *s;
 
+	spin_lock(&nn->client_lock);
+	s = oo->oo_last_closed_stid;
 	if (s) {
 		list_del_init(&oo->oo_close_lru);
 		oo->oo_last_closed_stid = NULL;
-		put_generic_stateid(s);
 	}
+	spin_unlock(&nn->client_lock);
+	if (s)
+		put_generic_stateid(s);
 }
 
 static void release_openowner(struct nfs4_openowner *oo)
@@ -3224,6 +3230,7 @@ static void init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp,
 static void
 move_to_close_lru(struct nfs4_ol_stateid *s, struct net *net)
 {
+	struct nfs4_ol_stateid *last;
 	struct nfs4_openowner *oo = openowner(s->st_stateowner);
 	struct nfsd_net *nn = net_generic(s->st_stid.sc_client->net,
 						nfsd_net_id);
@@ -3247,10 +3254,14 @@ move_to_close_lru(struct nfs4_ol_stateid *s, struct net *net)
 		s->st_stid.sc_file = NULL;
 	}
 
-	release_last_closed_stateid(oo);
+	spin_lock(&nn->client_lock);
+	last = oo->oo_last_closed_stid;
 	oo->oo_last_closed_stid = s;
 	list_move_tail(&oo->oo_close_lru, &nn->close_lru);
 	oo->oo_time = get_seconds();
+	spin_unlock(&nn->client_lock);
+	if (last)
+		put_generic_stateid(last);
 }
 
 static int
@@ -4106,6 +4117,7 @@ nfs4_laundromat(struct nfsd_net *nn)
 	struct nfs4_client *clp;
 	struct nfs4_openowner *oo;
 	struct nfs4_delegation *dp;
+	struct nfs4_ol_stateid *stp;
 	struct list_head *pos, *next, reaplist;
 	time_t cutoff = get_seconds() - nn->nfsd4_lease;
 	time_t t, new_timeo = nn->nfsd4_lease;
@@ -4157,15 +4169,26 @@ nfs4_laundromat(struct nfsd_net *nn)
 		dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
 		revoke_delegation(dp);
 	}
-	list_for_each_safe(pos, next, &nn->close_lru) {
-		oo = container_of(pos, struct nfs4_openowner, oo_close_lru);
-		if (time_after((unsigned long)oo->oo_time, (unsigned long)cutoff)) {
+
+	spin_lock(&nn->client_lock);
+	while (!list_empty(&nn->close_lru)) {
+		oo = list_first_entry(&nn->close_lru, struct nfs4_openowner,
+					oo_close_lru);
+		if (time_after((unsigned long)oo->oo_time,
+			       (unsigned long)cutoff)) {
 			t = oo->oo_time - cutoff;
 			new_timeo = min(new_timeo, t);
 			break;
 		}
-		release_last_closed_stateid(oo);
+		list_del_init(&oo->oo_close_lru);
+		stp = oo->oo_last_closed_stid;
+		oo->oo_last_closed_stid = NULL;
+		spin_unlock(&nn->client_lock);
+		put_generic_stateid(stp);
+		spin_lock(&nn->client_lock);
 	}
+	spin_unlock(&nn->client_lock);
+
 	new_timeo = max_t(time_t, new_timeo, NFSD_LAUNDROMAT_MINTIMEOUT);
 	nfs4_unlock_state();
 	return new_timeo;
-- 
1.9.3


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

* [PATCH v2 090/117] nfsd: ensure that clp->cl_revoked list is protected by clp->cl_lock
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (88 preceding siblings ...)
  2014-06-26 19:20 ` [PATCH v2 089/117] nfsd: protect the close_lru list and oo_last_closed_stid with client_lock Jeff Layton
@ 2014-06-26 19:20 ` Jeff Layton
  2014-06-26 19:20 ` [PATCH v2 091/117] nfsd: move unhash_client_locked call into mark_client_expired_locked Jeff Layton
                   ` (28 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:20 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

Currently, both destroy_revoked_delegation and revoke_delegation
manipulate the cl_revoked list without any locking aside from the
client_mutex. Ensure that the clp->cl_lock is held when manipulating it,
except for the list walking in destroy_client. At that point, the client
should no longer be in use, and so it should be safe to walk the list
without any locking. That also means that we don't need to do the
list_splice_init there either.

Also, the fact that destroy_revoked_delegation and revoke_delegation
delete dl_recall_lru without any locking makes it difficult to know
whether they're doing so safely in all cases. Move the list_del_init
calls into the callers, and add WARN_ONs in the event that these calls
are passed a delegation that has a non-empty list_head.

Signed-off-by: Jeff Layton <jlayton@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 73eb34901bf2..e9daa2649275 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -764,7 +764,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);
+	WARN_ON(!list_empty(&dp->dl_recall_lru));
 	nfs4_put_delegation(dp);
 }
 
@@ -772,11 +772,15 @@ static void revoke_delegation(struct nfs4_delegation *dp)
 {
 	struct nfs4_client *clp = dp->dl_stid.sc_client;
 
+	WARN_ON(!list_empty(&dp->dl_recall_lru));
+
 	if (clp->cl_minorversion == 0)
 		destroy_revoked_delegation(dp);
 	else {
 		dp->dl_stid.sc_type = NFS4_REVOKED_DELEG_STID;
-		list_move(&dp->dl_recall_lru, &clp->cl_revoked);
+		spin_lock(&clp->cl_lock);
+		list_add(&dp->dl_recall_lru, &clp->cl_revoked);
+		spin_unlock(&clp->cl_lock);
 	}
 }
 
@@ -1596,9 +1600,9 @@ __destroy_client(struct nfs4_client *clp)
 		list_del_init(&dp->dl_recall_lru);
 		destroy_delegation(dp);
 	}
-	list_splice_init(&clp->cl_revoked, &reaplist);
-	while (!list_empty(&reaplist)) {
+	while (!list_empty(&clp->cl_revoked)) {
 		dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru);
+		list_del_init(&dp->dl_recall_lru);
 		destroy_revoked_delegation(dp);
 	}
 	while (!list_empty(&clp->cl_openowners)) {
@@ -4165,8 +4169,10 @@ nfs4_laundromat(struct nfsd_net *nn)
 		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);
+	while (!list_empty(&reaplist)) {
+		dp = list_first_entry(&reaplist, struct nfs4_delegation,
+					dl_recall_lru);
+		list_del_init(&dp->dl_recall_lru);
 		revoke_delegation(dp);
 	}
 
@@ -4529,8 +4535,9 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 		ret = nfs_ok;
 		goto out;
 	case NFS4_REVOKED_DELEG_STID:
-		spin_unlock(&cl->cl_lock);
 		dp = delegstateid(s);
+		list_del_init(&dp->dl_recall_lru);
+		spin_unlock(&cl->cl_lock);
 		destroy_revoked_delegation(dp);
 		ret = nfs_ok;
 		goto out;
-- 
1.9.3


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

* [PATCH v2 091/117] nfsd: move unhash_client_locked call into mark_client_expired_locked
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (89 preceding siblings ...)
  2014-06-26 19:20 ` [PATCH v2 090/117] nfsd: ensure that clp->cl_revoked list is protected by clp->cl_lock Jeff Layton
@ 2014-06-26 19:20 ` Jeff Layton
  2014-06-26 19:21 ` [PATCH v2 092/117] nfsd: don't destroy client if mark_client_expired_locked fails Jeff Layton
                   ` (27 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:20 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

All the callers except for the fault injection code call it directly
afterward, and in the fault injection case it won't hurt to do so
anyway.

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

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index e9daa2649275..3bd24d5b973e 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -70,6 +70,7 @@ static u64 current_sessionid = 1;
 #define CURRENT_STATEID(stateid) (!memcmp((stateid), &currentstateid, sizeof(stateid_t)))
 
 /* forward declarations */
+static void unhash_client_locked(struct nfs4_client *clp);
 static int check_for_locks(struct nfs4_file *filp, struct nfs4_lockowner *lowner);
 static void nfs4_free_generic_stateid(struct nfs4_stid *stid);
 static struct nfs4_openowner *find_openstateowner_str_locked(
@@ -140,7 +141,7 @@ static __be32 mark_client_expired_locked(struct nfs4_client *clp)
 {
 	if (atomic_read(&clp->cl_refcount))
 		return nfserr_jukebox;
-	clp->cl_time = 0;
+	unhash_client_locked(clp);
 	return nfs_ok;
 }
 
@@ -2448,7 +2449,6 @@ nfsd4_create_session(struct svc_rqst *rqstp,
 			status = mark_client_expired_locked(old);
 			if (status)
 				goto out_free_conn;
-			unhash_client_locked(old);
 		}
 		move_to_confirmed(unconf);
 		conf = unconf;
@@ -2994,7 +2994,6 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
 			status = mark_client_expired_locked(old);
 			if (status)
 				goto out;
-			unhash_client_locked(old);
 		}
 		move_to_confirmed(unconf);
 		conf = unconf;
@@ -4144,7 +4143,6 @@ nfs4_laundromat(struct nfsd_net *nn)
 				clp->cl_clientid.cl_id);
 			continue;
 		}
-		unhash_client_locked(clp);
 		list_add(&clp->cl_lru, &reaplist);
 	}
 	spin_unlock(&nn->client_lock);
-- 
1.9.3


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

* [PATCH v2 092/117] nfsd: don't destroy client if mark_client_expired_locked fails
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (90 preceding siblings ...)
  2014-06-26 19:20 ` [PATCH v2 091/117] nfsd: move unhash_client_locked call into mark_client_expired_locked Jeff Layton
@ 2014-06-26 19:21 ` Jeff Layton
  2014-06-26 19:21 ` [PATCH v2 093/117] nfsd: don't destroy clients that are busy Jeff Layton
                   ` (26 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:21 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

If it fails, it means that the client is in use and so destroying it
would be bad. Currently, the client_mutex prevents this from happening
but once we remove it, we won't be able to do this.

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

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 3bd24d5b973e..014849dfaa4b 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -2447,8 +2447,10 @@ nfsd4_create_session(struct svc_rqst *rqstp,
 		old = find_confirmed_client_by_name(&unconf->cl_name, nn);
 		if (old) {
 			status = mark_client_expired_locked(old);
-			if (status)
+			if (status) {
+				old = NULL;
 				goto out_free_conn;
+			}
 		}
 		move_to_confirmed(unconf);
 		conf = unconf;
@@ -2992,8 +2994,10 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
 		old = find_confirmed_client_by_name(&unconf->cl_name, nn);
 		if (old) {
 			status = mark_client_expired_locked(old);
-			if (status)
+			if (status) {
+				old = NULL;
 				goto out;
+			}
 		}
 		move_to_confirmed(unconf);
 		conf = unconf;
-- 
1.9.3


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

* [PATCH v2 093/117] nfsd: don't destroy clients that are busy
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (91 preceding siblings ...)
  2014-06-26 19:21 ` [PATCH v2 092/117] nfsd: don't destroy client if mark_client_expired_locked fails Jeff Layton
@ 2014-06-26 19:21 ` Jeff Layton
  2014-06-26 19:21 ` [PATCH v2 094/117] nfsd: protect clid and verifier generation with client_lock Jeff Layton
                   ` (25 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:21 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

It's possible that we'll have an in-progress call on some of the clients
while a rogue EXCHANGE_ID or DESTROY_CLIENTID call comes in. Be sure to
try and mark the client expired first, so that the refcount is
respected.

This will only be a problem once the client_mutex is removed.

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

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 014849dfaa4b..02cb3f4e27d5 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -2214,8 +2214,11 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
 
 	/* case 1 (normal case) */
 out_new:
-	if (conf)
-		unhash_client_locked(conf);
+	if (conf) {
+		status = mark_client_expired_locked(conf);
+		if (status)
+			goto out;
+	}
 	new->cl_minorversion = cstate->minorversion;
 	new->cl_mach_cred = (exid->spa_how == SP4_MACH_CRED);
 
@@ -2828,6 +2831,9 @@ nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *csta
 			status = nfserr_clientid_busy;
 			goto out;
 		}
+		status = mark_client_expired_locked(conf);
+		if (status)
+			goto out;
 		clp = conf;
 	} else if (unconf)
 		clp = unconf;
-- 
1.9.3


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

* [PATCH v2 094/117] nfsd: protect clid and verifier generation with client_lock
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (92 preceding siblings ...)
  2014-06-26 19:21 ` [PATCH v2 093/117] nfsd: don't destroy clients that are busy Jeff Layton
@ 2014-06-26 19:21 ` Jeff Layton
  2014-06-26 19:21 ` [PATCH v2 095/117] nfsd: abstract out the get and set routines into the fault injection ops Jeff Layton
                   ` (24 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:21 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

The clid counter is a global counter currently. Move it to be a per-net
property so that it can be properly protected by the nn->client_lock
instead of relying on the client_mutex.

The verifier generator is also potentially racy if there are two
simultaneous callers. Generate the verifier when we generate the clid
value, so it's also created under the client_lock. With this, there's
no need to keep two counters as they'd always be in sync anyway, so
just use the clientid_counter for both.

As Trond points out, what would be best is to eventually move this
code to use IDR instead of the hash tables. That would also help ensure
uniqueness, but that's probably best done as a separate project.

Signed-off-by: Jeff Layton <jlayton@primarydata.com>
---
 fs/nfsd/netns.h     |  6 +++---
 fs/nfsd/nfs4state.c | 21 +++++++++------------
 2 files changed, 12 insertions(+), 15 deletions(-)

diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h
index f89042ae0056..831abbdc6c52 100644
--- a/fs/nfsd/netns.h
+++ b/fs/nfsd/netns.h
@@ -92,11 +92,11 @@ struct nfsd_net {
 	bool nfsd_net_up;
 	bool lockd_up;
 
-	/*
-	 * Time of server startup
-	 */
+	/* Time of server startup */
 	struct timeval nfssvc_boot;
 
+	u32 clientid_counter;
+
 	struct svc_serv *nfsd_serv;
 };
 
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 02cb3f4e27d5..a0b1a727c415 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1761,28 +1761,26 @@ static bool mach_creds_match(struct nfs4_client *cl, struct svc_rqst *rqstp)
 	return 0 == strcmp(cl->cl_cred.cr_principal, cr->cr_principal);
 }
 
-static void gen_clid(struct nfs4_client *clp, struct nfsd_net *nn)
-{
-	static u32 current_clientid = 1;
-
-	clp->cl_clientid.cl_boot = nn->boot_time;
-	clp->cl_clientid.cl_id = current_clientid++; 
-}
-
-static void gen_confirm(struct nfs4_client *clp)
+static void gen_confirm(struct nfs4_client *clp, struct nfsd_net *nn)
 {
 	__be32 verf[2];
-	static u32 i;
 
 	/*
 	 * This is opaque to client, so no need to byte-swap. Use
 	 * __force to keep sparse happy
 	 */
 	verf[0] = (__force __be32)get_seconds();
-	verf[1] = (__force __be32)i++;
+	verf[1] = (__force __be32)nn->clientid_counter;
 	memcpy(clp->cl_confirm.data, verf, sizeof(clp->cl_confirm.data));
 }
 
+static void gen_clid(struct nfs4_client *clp, struct nfsd_net *nn)
+{
+	clp->cl_clientid.cl_boot = nn->boot_time;
+	clp->cl_clientid.cl_id = nn->clientid_counter++;
+	gen_confirm(clp, nn);
+}
+
 static struct nfs4_stid *
 find_stateid_locked(struct nfs4_client *cl, stateid_t *t)
 {
@@ -1831,7 +1829,6 @@ static struct nfs4_client *create_client(struct xdr_netobj name,
 	clear_bit(0, &clp->cl_cb_slot_busy);
 	copy_verf(clp, verf);
 	rpc_copy_addr((struct sockaddr *) &clp->cl_addr, sa);
-	gen_confirm(clp);
 	clp->cl_cb_session = NULL;
 	clp->net = net;
 	return clp;
-- 
1.9.3


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

* [PATCH v2 095/117] nfsd: abstract out the get and set routines into the fault injection ops
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (93 preceding siblings ...)
  2014-06-26 19:21 ` [PATCH v2 094/117] nfsd: protect clid and verifier generation with client_lock Jeff Layton
@ 2014-06-26 19:21 ` Jeff Layton
  2014-06-26 19:21 ` [PATCH v2 096/117] nfsd: add a forget_clients "get" routine with proper locking Jeff Layton
                   ` (23 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:21 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

Now that we've added more granular locking in other places, it's time
to address the fault injection code. This code is currently quite
reliant on the client_mutex for protection. Start to change this by
adding a new set of fault injection op vectors.

For now they all use the legacy ones. In later patches we'll add new
routines that can deal with more granular locking.

Also, move some of the printk routines into the callers to make the
results of the operations more uniform.

Signed-off-by: Jeff Layton <jlayton@primarydata.com>
---
 fs/nfsd/fault_inject.c | 129 ++++++++++++++++++++++++++++++-------------------
 1 file changed, 78 insertions(+), 51 deletions(-)

diff --git a/fs/nfsd/fault_inject.c b/fs/nfsd/fault_inject.c
index f1333fc35b33..b1159900d934 100644
--- a/fs/nfsd/fault_inject.c
+++ b/fs/nfsd/fault_inject.c
@@ -17,79 +17,50 @@
 
 struct nfsd_fault_inject_op {
 	char *file;
+	u64 (*get)(struct nfsd_fault_inject_op *);
+	u64 (*set_val)(struct nfsd_fault_inject_op *, u64);
+	u64 (*set_clnt)(struct nfsd_fault_inject_op *,
+			struct sockaddr_storage *, size_t);
 	u64 (*forget)(struct nfs4_client *, u64);
 	u64 (*print)(struct nfs4_client *, u64);
 };
 
-static struct nfsd_fault_inject_op inject_ops[] = {
-	{
-		.file   = "forget_clients",
-		.forget = nfsd_forget_client,
-		.print  = nfsd_print_client,
-	},
-	{
-		.file   = "forget_locks",
-		.forget = nfsd_forget_client_locks,
-		.print  = nfsd_print_client_locks,
-	},
-	{
-		.file   = "forget_openowners",
-		.forget = nfsd_forget_client_openowners,
-		.print  = nfsd_print_client_openowners,
-	},
-	{
-		.file   = "forget_delegations",
-		.forget = nfsd_forget_client_delegations,
-		.print  = nfsd_print_client_delegations,
-	},
-	{
-		.file   = "recall_delegations",
-		.forget = nfsd_recall_client_delegations,
-		.print  = nfsd_print_client_delegations,
-	},
-};
-
-static long int NUM_INJECT_OPS = sizeof(inject_ops) / sizeof(struct nfsd_fault_inject_op);
 static struct dentry *debug_dir;
 
-static void nfsd_inject_set(struct nfsd_fault_inject_op *op, u64 val)
+static u64 nfsd_inject_set(struct nfsd_fault_inject_op *op, u64 val)
 {
-	u64 count = 0;
-
-	if (val == 0)
-		printk(KERN_INFO "NFSD Fault Injection: %s (all)", op->file);
-	else
-		printk(KERN_INFO "NFSD Fault Injection: %s (n = %llu)", op->file, val);
+	u64 count;
 
 	nfs4_lock_state();
 	count = nfsd_for_n_state(val, op->forget);
 	nfs4_unlock_state();
-	printk(KERN_INFO "NFSD: %s: found %llu", op->file, count);
+	return count;
 }
 
-static void nfsd_inject_set_client(struct nfsd_fault_inject_op *op,
+static u64 nfsd_inject_set_client(struct nfsd_fault_inject_op *op,
 				   struct sockaddr_storage *addr,
 				   size_t addr_size)
 {
-	char buf[INET6_ADDRSTRLEN];
 	struct nfs4_client *clp;
-	u64 count;
+	u64 count = 0;
 
 	nfs4_lock_state();
 	clp = nfsd_find_client(addr, addr_size);
-	if (clp) {
+	if (clp)
 		count = op->forget(clp, 0);
-		rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf));
-		printk(KERN_INFO "NFSD [%s]: Client %s had %llu state object(s)\n", op->file, buf, count);
-	}
 	nfs4_unlock_state();
+	return count;
 }
 
-static void nfsd_inject_get(struct nfsd_fault_inject_op *op, u64 *val)
+static u64 nfsd_inject_get(struct nfsd_fault_inject_op *op)
 {
+	u64 count;
+
 	nfs4_lock_state();
-	*val = nfsd_for_n_state(0, op->print);
+	count = nfsd_for_n_state(0, op->print);
 	nfs4_unlock_state();
+
+	return count;
 }
 
 static ssize_t fault_inject_read(struct file *file, char __user *buf,
@@ -99,9 +70,10 @@ static ssize_t fault_inject_read(struct file *file, char __user *buf,
 	char read_buf[25];
 	size_t size;
 	loff_t pos = *ppos;
+	struct nfsd_fault_inject_op *op = file_inode(file)->i_private;
 
 	if (!pos)
-		nfsd_inject_get(file_inode(file)->i_private, &val);
+		val = op->get(op);
 	size = scnprintf(read_buf, sizeof(read_buf), "%llu\n", val);
 
 	return simple_read_from_buffer(buf, len, ppos, read_buf, size);
@@ -114,6 +86,7 @@ static ssize_t fault_inject_write(struct file *file, const char __user *buf,
 	size_t size = min(sizeof(write_buf) - 1, len);
 	struct net *net = current->nsproxy->net_ns;
 	struct sockaddr_storage sa;
+	struct nfsd_fault_inject_op *op = file_inode(file)->i_private;
 	u64 val;
 	char *nl;
 
@@ -129,11 +102,20 @@ static ssize_t fault_inject_write(struct file *file, const char __user *buf,
 	}
 
 	size = rpc_pton(net, write_buf, size, (struct sockaddr *)&sa, sizeof(sa));
-	if (size > 0)
-		nfsd_inject_set_client(file_inode(file)->i_private, &sa, size);
-	else {
+	if (size > 0) {
+		val = op->set_clnt(op, &sa, size);
+		if (val)
+			pr_info("NFSD [%s]: Client %s had %llu state object(s)\n",
+				op->file, write_buf, val);
+	} else {
 		val = simple_strtoll(write_buf, NULL, 0);
-		nfsd_inject_set(file_inode(file)->i_private, val);
+		if (val == 0)
+			pr_info("NFSD Fault Injection: %s (all)", op->file);
+		else
+			pr_info("NFSD Fault Injection: %s (n = %llu)",
+				op->file, val);
+		val = op->set_val(op, val);
+		pr_info("NFSD: %s: found %llu", op->file, val);
 	}
 	return len; /* on success, claim we got the whole input */
 }
@@ -149,6 +131,51 @@ void nfsd_fault_inject_cleanup(void)
 	debugfs_remove_recursive(debug_dir);
 }
 
+static struct nfsd_fault_inject_op inject_ops[] = {
+	{
+		.file     = "forget_clients",
+		.get	  = nfsd_inject_get,
+		.set_val  = nfsd_inject_set,
+		.set_clnt = nfsd_inject_set_client,
+		.forget   = nfsd_forget_client,
+		.print    = nfsd_print_client,
+	},
+	{
+		.file     = "forget_locks",
+		.get	  = nfsd_inject_get,
+		.set_val  = nfsd_inject_set,
+		.set_clnt = nfsd_inject_set_client,
+		.forget   = nfsd_forget_client_locks,
+		.print    = nfsd_print_client_locks,
+	},
+	{
+		.file     = "forget_openowners",
+		.get	  = nfsd_inject_get,
+		.set_val  = nfsd_inject_set,
+		.set_clnt = nfsd_inject_set_client,
+		.forget   = nfsd_forget_client_openowners,
+		.print    = nfsd_print_client_openowners,
+	},
+	{
+		.file     = "forget_delegations",
+		.get	  = nfsd_inject_get,
+		.set_val  = nfsd_inject_set,
+		.set_clnt = nfsd_inject_set_client,
+		.forget   = nfsd_forget_client_delegations,
+		.print    = nfsd_print_client_delegations,
+	},
+	{
+		.file     = "recall_delegations",
+		.get	  = nfsd_inject_get,
+		.set_val  = nfsd_inject_set,
+		.set_clnt = nfsd_inject_set_client,
+		.forget   = nfsd_recall_client_delegations,
+		.print    = nfsd_print_client_delegations,
+	},
+};
+
+#define NUM_INJECT_OPS (sizeof(inject_ops)/sizeof(struct nfsd_fault_inject_op))
+
 int nfsd_fault_inject_init(void)
 {
 	unsigned int i;
-- 
1.9.3


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

* [PATCH v2 096/117] nfsd: add a forget_clients "get" routine with proper locking
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (94 preceding siblings ...)
  2014-06-26 19:21 ` [PATCH v2 095/117] nfsd: abstract out the get and set routines into the fault injection ops Jeff Layton
@ 2014-06-26 19:21 ` Jeff Layton
  2014-06-26 19:21 ` [PATCH v2 097/117] nfsd: add a forget_client set_clnt routine Jeff Layton
                   ` (22 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:21 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

Add a new "get" routine for forget_clients that relies on the
client_lock instead of the client_mutex.

Signed-off-by: Jeff Layton <jlayton@primarydata.com>
---
 fs/nfsd/fault_inject.c |  3 +--
 fs/nfsd/nfs4state.c    | 30 ++++++++++++++++++++++--------
 fs/nfsd/state.h        |  4 +++-
 3 files changed, 26 insertions(+), 11 deletions(-)

diff --git a/fs/nfsd/fault_inject.c b/fs/nfsd/fault_inject.c
index b1159900d934..a0387fd47e14 100644
--- a/fs/nfsd/fault_inject.c
+++ b/fs/nfsd/fault_inject.c
@@ -134,11 +134,10 @@ void nfsd_fault_inject_cleanup(void)
 static struct nfsd_fault_inject_op inject_ops[] = {
 	{
 		.file     = "forget_clients",
-		.get	  = nfsd_inject_get,
+		.get	  = nfsd_inject_print_clients,
 		.set_val  = nfsd_inject_set,
 		.set_clnt = nfsd_inject_set_client,
 		.forget   = nfsd_forget_client,
-		.print    = nfsd_print_client,
 	},
 	{
 		.file     = "forget_locks",
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index a0b1a727c415..eee87cca8430 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -5690,6 +5690,28 @@ nfs4_check_open_reclaim(clientid_t *clid,
 }
 
 #ifdef CONFIG_NFSD_FAULT_INJECTION
+u64
+nfsd_inject_print_clients(struct nfsd_fault_inject_op *op)
+{
+	struct nfs4_client *clp;
+	u64 count = 0;
+	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
+					  nfsd_net_id);
+	char buf[INET6_ADDRSTRLEN];
+
+	if (!nfsd_netns_ready(nn))
+		return 0;
+
+	spin_lock(&nn->client_lock);
+	list_for_each_entry(clp, &nn->client_lru, cl_lru) {
+		rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf));
+		pr_info("NFS Client: %s\n", buf);
+		++count;
+	}
+	spin_unlock(&nn->client_lock);
+
+	return count;
+}
 
 u64 nfsd_forget_client(struct nfs4_client *clp, u64 max)
 {
@@ -5705,14 +5727,6 @@ u64 nfsd_forget_client(struct nfs4_client *clp, u64 max)
 	return 1;
 }
 
-u64 nfsd_print_client(struct nfs4_client *clp, u64 num)
-{
-	char buf[INET6_ADDRSTRLEN];
-	rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf));
-	printk(KERN_INFO "NFS Client: %s\n", buf);
-	return 1;
-}
-
 static void nfsd_print_count(struct nfs4_client *clp, unsigned int count,
 			     const char *type)
 {
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index a09a72fdb5a6..61f42e1783d6 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -466,18 +466,20 @@ extern void nfsd4_record_grace_done(struct nfsd_net *nn, time_t boot_time);
 
 /* nfs fault injection functions */
 #ifdef CONFIG_NFSD_FAULT_INJECTION
+struct nfsd_fault_inject_op;
+
 int nfsd_fault_inject_init(void);
 void nfsd_fault_inject_cleanup(void);
 u64 nfsd_for_n_state(u64, u64 (*)(struct nfs4_client *, u64));
 struct nfs4_client *nfsd_find_client(struct sockaddr_storage *, size_t);
 
+u64 nfsd_inject_print_clients(struct nfsd_fault_inject_op *op);
 u64 nfsd_forget_client(struct nfs4_client *, u64);
 u64 nfsd_forget_client_locks(struct nfs4_client*, u64);
 u64 nfsd_forget_client_openowners(struct nfs4_client *, u64);
 u64 nfsd_forget_client_delegations(struct nfs4_client *, u64);
 u64 nfsd_recall_client_delegations(struct nfs4_client *, u64);
 
-u64 nfsd_print_client(struct nfs4_client *, u64);
 u64 nfsd_print_client_locks(struct nfs4_client *, u64);
 u64 nfsd_print_client_openowners(struct nfs4_client *, u64);
 u64 nfsd_print_client_delegations(struct nfs4_client *, u64);
-- 
1.9.3


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

* [PATCH v2 097/117] nfsd: add a forget_client set_clnt routine
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (95 preceding siblings ...)
  2014-06-26 19:21 ` [PATCH v2 096/117] nfsd: add a forget_clients "get" routine with proper locking Jeff Layton
@ 2014-06-26 19:21 ` Jeff Layton
  2014-06-26 19:21 ` [PATCH v2 098/117] nfsd: add nfsd_inject_forget_clients Jeff Layton
                   ` (21 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:21 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

...that relies on the client_lock instead of client_mutex.

Signed-off-by: Jeff Layton <jlayton@primarydata.com>
---
 fs/nfsd/fault_inject.c |  2 +-
 fs/nfsd/nfs4state.c    | 28 ++++++++++++++++++++++++++++
 fs/nfsd/state.h        |  3 +++
 3 files changed, 32 insertions(+), 1 deletion(-)

diff --git a/fs/nfsd/fault_inject.c b/fs/nfsd/fault_inject.c
index a0387fd47e14..5f3ead0c72fb 100644
--- a/fs/nfsd/fault_inject.c
+++ b/fs/nfsd/fault_inject.c
@@ -136,7 +136,7 @@ static struct nfsd_fault_inject_op inject_ops[] = {
 		.file     = "forget_clients",
 		.get	  = nfsd_inject_print_clients,
 		.set_val  = nfsd_inject_set,
-		.set_clnt = nfsd_inject_set_client,
+		.set_clnt = nfsd_inject_forget_client,
 		.forget   = nfsd_forget_client,
 	},
 	{
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index eee87cca8430..b12a36e71fee 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -5727,6 +5727,34 @@ u64 nfsd_forget_client(struct nfs4_client *clp, u64 max)
 	return 1;
 }
 
+u64
+nfsd_inject_forget_client(struct nfsd_fault_inject_op *op,
+			  struct sockaddr_storage *addr, size_t addr_size)
+{
+	u64 count = 0;
+	struct nfs4_client *clp;
+	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
+					  nfsd_net_id);
+
+	if (!nfsd_netns_ready(nn))
+		return count;
+
+	spin_lock(&nn->client_lock);
+	clp = nfsd_find_client(addr, addr_size);
+	if (clp) {
+		if (mark_client_expired_locked(clp) == nfs_ok)
+			++count;
+		else
+			clp = NULL;
+	}
+	spin_unlock(&nn->client_lock);
+
+	if (clp)
+		expire_client(clp);
+
+	return count;
+}
+
 static void nfsd_print_count(struct nfs4_client *clp, unsigned int count,
 			     const char *type)
 {
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 61f42e1783d6..a644a9f628d6 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -475,6 +475,9 @@ struct nfs4_client *nfsd_find_client(struct sockaddr_storage *, size_t);
 
 u64 nfsd_inject_print_clients(struct nfsd_fault_inject_op *op);
 u64 nfsd_forget_client(struct nfs4_client *, u64);
+u64 nfsd_inject_forget_client(struct nfsd_fault_inject_op *,
+			      struct sockaddr_storage *, size_t);
+
 u64 nfsd_forget_client_locks(struct nfs4_client*, u64);
 u64 nfsd_forget_client_openowners(struct nfs4_client *, u64);
 u64 nfsd_forget_client_delegations(struct nfs4_client *, u64);
-- 
1.9.3


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

* [PATCH v2 098/117] nfsd: add nfsd_inject_forget_clients
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (96 preceding siblings ...)
  2014-06-26 19:21 ` [PATCH v2 097/117] nfsd: add a forget_client set_clnt routine Jeff Layton
@ 2014-06-26 19:21 ` Jeff Layton
  2014-06-26 19:21 ` [PATCH v2 099/117] nfsd: add a list_head arg to nfsd_foreach_client_lock Jeff Layton
                   ` (20 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:21 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

...which uses the client_lock for protection instead of client_mutex.
Also remove nfsd_forget_client as there are no more callers.

Signed-off-by: Jeff Layton <jlayton@primarydata.com>
---
 fs/nfsd/fault_inject.c |  3 +--
 fs/nfsd/nfs4state.c    | 42 ++++++++++++++++++++++++++++--------------
 fs/nfsd/state.h        |  2 +-
 3 files changed, 30 insertions(+), 17 deletions(-)

diff --git a/fs/nfsd/fault_inject.c b/fs/nfsd/fault_inject.c
index 5f3ead0c72fb..76ecdff37ea2 100644
--- a/fs/nfsd/fault_inject.c
+++ b/fs/nfsd/fault_inject.c
@@ -135,9 +135,8 @@ static struct nfsd_fault_inject_op inject_ops[] = {
 	{
 		.file     = "forget_clients",
 		.get	  = nfsd_inject_print_clients,
-		.set_val  = nfsd_inject_set,
+		.set_val  = nfsd_inject_forget_clients,
 		.set_clnt = nfsd_inject_forget_client,
-		.forget   = nfsd_forget_client,
 	},
 	{
 		.file     = "forget_locks",
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index b12a36e71fee..9feb219e8699 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -5713,20 +5713,6 @@ nfsd_inject_print_clients(struct nfsd_fault_inject_op *op)
 	return count;
 }
 
-u64 nfsd_forget_client(struct nfs4_client *clp, u64 max)
-{
-	__be32 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 != nfs_ok)
-		return 0;
-	expire_client(clp);
-	return 1;
-}
-
 u64
 nfsd_inject_forget_client(struct nfsd_fault_inject_op *op,
 			  struct sockaddr_storage *addr, size_t addr_size)
@@ -5755,6 +5741,34 @@ nfsd_inject_forget_client(struct nfsd_fault_inject_op *op,
 	return count;
 }
 
+u64
+nfsd_inject_forget_clients(struct nfsd_fault_inject_op *op, u64 max)
+{
+	u64 count = 0;
+	struct nfs4_client *clp, *next;
+	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
+						nfsd_net_id);
+	LIST_HEAD(reaplist);
+
+	if (!nfsd_netns_ready(nn))
+		return count;
+
+	spin_lock(&nn->client_lock);
+	list_for_each_entry_safe(clp, next, &nn->client_lru, cl_lru) {
+		if (mark_client_expired_locked(clp) == nfs_ok) {
+			list_add(&clp->cl_lru, &reaplist);
+			if (max != 0 && ++count >= max)
+				break;
+		}
+	}
+	spin_unlock(&nn->client_lock);
+
+	list_for_each_entry_safe(clp, next, &reaplist, cl_lru)
+		expire_client(clp);
+
+	return count;
+}
+
 static void nfsd_print_count(struct nfs4_client *clp, unsigned int count,
 			     const char *type)
 {
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index a644a9f628d6..4fe973bbb68f 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -474,9 +474,9 @@ u64 nfsd_for_n_state(u64, u64 (*)(struct nfs4_client *, u64));
 struct nfs4_client *nfsd_find_client(struct sockaddr_storage *, size_t);
 
 u64 nfsd_inject_print_clients(struct nfsd_fault_inject_op *op);
-u64 nfsd_forget_client(struct nfs4_client *, u64);
 u64 nfsd_inject_forget_client(struct nfsd_fault_inject_op *,
 			      struct sockaddr_storage *, size_t);
+u64 nfsd_inject_forget_clients(struct nfsd_fault_inject_op *, u64);
 
 u64 nfsd_forget_client_locks(struct nfs4_client*, u64);
 u64 nfsd_forget_client_openowners(struct nfs4_client *, u64);
-- 
1.9.3


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

* [PATCH v2 099/117] nfsd: add a list_head arg to nfsd_foreach_client_lock
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (97 preceding siblings ...)
  2014-06-26 19:21 ` [PATCH v2 098/117] nfsd: add nfsd_inject_forget_clients Jeff Layton
@ 2014-06-26 19:21 ` Jeff Layton
  2014-06-26 19:21 ` [PATCH v2 100/117] nfsd: add more granular locking to forget_locks fault injector Jeff Layton
                   ` (19 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:21 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

In a later patch, we'll want to collect the locks onto a list for later
destruction. If "func" is defined and "collect" is defined, then we'll
add the lock stateid to the list.

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

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 9feb219e8699..c26ecd4ad3b2 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -5778,6 +5778,7 @@ static void nfsd_print_count(struct nfs4_client *clp, unsigned int count,
 }
 
 static u64 nfsd_foreach_client_lock(struct nfs4_client *clp, u64 max,
+				    struct list_head *collect,
 				    void (*func)(struct nfs4_ol_stateid *))
 {
 	struct nfs4_openowner *oop;
@@ -5790,8 +5791,12 @@ static u64 nfsd_foreach_client_lock(struct nfs4_client *clp, u64 max,
 				&oop->oo_owner.so_stateids, st_perstateowner) {
 			list_for_each_entry_safe(lst, lst_next,
 					&stp->st_locks, st_locks) {
-				if (func)
+				if (func) {
 					func(lst);
+					if (collect)
+						list_add(&lst->st_locks,
+							 collect);
+				}
 				if (++count == max)
 					return count;
 			}
@@ -5803,12 +5808,12 @@ static u64 nfsd_foreach_client_lock(struct nfs4_client *clp, u64 max,
 
 u64 nfsd_forget_client_locks(struct nfs4_client *clp, u64 max)
 {
-	return nfsd_foreach_client_lock(clp, max, release_lock_stateid);
+	return nfsd_foreach_client_lock(clp, max, NULL, release_lock_stateid);
 }
 
 u64 nfsd_print_client_locks(struct nfs4_client *clp, u64 max)
 {
-	u64 count = nfsd_foreach_client_lock(clp, max, NULL);
+	u64 count = nfsd_foreach_client_lock(clp, max, NULL, NULL);
 	nfsd_print_count(clp, count, "locked files");
 	return count;
 }
-- 
1.9.3


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

* [PATCH v2 100/117] nfsd: add more granular locking to forget_locks fault injector
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (98 preceding siblings ...)
  2014-06-26 19:21 ` [PATCH v2 099/117] nfsd: add a list_head arg to nfsd_foreach_client_lock Jeff Layton
@ 2014-06-26 19:21 ` Jeff Layton
  2014-06-26 19:21 ` [PATCH v2 101/117] nfsd: add more granular locking to forget_openowners " Jeff Layton
                   ` (18 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:21 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

...instead of relying on the client_mutex.

Signed-off-by: Jeff Layton <jlayton@primarydata.com>
---
 fs/nfsd/fault_inject.c |   8 ++-
 fs/nfsd/nfs4state.c    | 136 +++++++++++++++++++++++++++++++++++++++++++++----
 fs/nfsd/state.h        |   7 ++-
 3 files changed, 135 insertions(+), 16 deletions(-)

diff --git a/fs/nfsd/fault_inject.c b/fs/nfsd/fault_inject.c
index 76ecdff37ea2..a444d821d2a5 100644
--- a/fs/nfsd/fault_inject.c
+++ b/fs/nfsd/fault_inject.c
@@ -140,11 +140,9 @@ static struct nfsd_fault_inject_op inject_ops[] = {
 	},
 	{
 		.file     = "forget_locks",
-		.get	  = nfsd_inject_get,
-		.set_val  = nfsd_inject_set,
-		.set_clnt = nfsd_inject_set_client,
-		.forget   = nfsd_forget_client_locks,
-		.print    = nfsd_print_client_locks,
+		.get	  = nfsd_inject_print_locks,
+		.set_val  = nfsd_inject_forget_locks,
+		.set_clnt = nfsd_inject_forget_client_locks,
 	},
 	{
 		.file     = "forget_openowners",
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index c26ecd4ad3b2..ab5858e272b8 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -5690,6 +5690,16 @@ nfs4_check_open_reclaim(clientid_t *clid,
 }
 
 #ifdef CONFIG_NFSD_FAULT_INJECTION
+static void
+put_client(struct nfs4_client *clp)
+{
+	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
+
+	spin_lock(&nn->client_lock);
+	atomic_dec(&clp->cl_refcount);
+	spin_unlock(&nn->client_lock);
+}
+
 u64
 nfsd_inject_print_clients(struct nfsd_fault_inject_op *op)
 {
@@ -5777,6 +5787,22 @@ 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 void
+nfsd_inject_add_lock_to_list(struct nfs4_ol_stateid *lst,
+			     struct list_head *collect)
+{
+	struct nfs4_client *clp = lst->st_stid.sc_client;
+	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
+					  nfsd_net_id);
+
+	if (!collect)
+		return;
+
+	lockdep_assert_held(&nn->client_lock);
+	atomic_inc(&clp->cl_refcount);
+	list_add(&lst->st_locks, collect);
+}
+
 static u64 nfsd_foreach_client_lock(struct nfs4_client *clp, u64 max,
 				    struct list_head *collect,
 				    void (*func)(struct nfs4_ol_stateid *))
@@ -5786,6 +5812,7 @@ static u64 nfsd_foreach_client_lock(struct nfs4_client *clp, u64 max,
 	struct nfs4_ol_stateid *lst, *lst_next;
 	u64 count = 0;
 
+	spin_lock(&clp->cl_lock);
 	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) {
@@ -5793,31 +5820,122 @@ static u64 nfsd_foreach_client_lock(struct nfs4_client *clp, u64 max,
 					&stp->st_locks, st_locks) {
 				if (func) {
 					func(lst);
-					if (collect)
-						list_add(&lst->st_locks,
-							 collect);
+					nfsd_inject_add_lock_to_list(lst,
+								collect);
 				}
-				if (++count == max)
-					return count;
+				++count;
+				/*
+				 * Despite the fact that these functions deal
+				 * with 64-bit integers for "count", we must
+				 * ensure that it doesn't blow up the
+				 * clp->cl_refcount. Throw a warning if we
+				 * start to approach INT_MAX here.
+				 */
+				WARN_ON_ONCE(count == (INT_MAX / 2));
+				if (count == max)
+					goto out;
 			}
 		}
 	}
+out:
+	spin_unlock(&clp->cl_lock);
 
 	return count;
 }
 
-u64 nfsd_forget_client_locks(struct nfs4_client *clp, u64 max)
+static u64
+nfsd_collect_client_locks(struct nfs4_client *clp, struct list_head *collect,
+			  u64 max)
 {
-	return nfsd_foreach_client_lock(clp, max, NULL, release_lock_stateid);
+	return nfsd_foreach_client_lock(clp, max, collect, unhash_lock_stateid);
 }
 
-u64 nfsd_print_client_locks(struct nfs4_client *clp, u64 max)
+static u64
+nfsd_print_client_locks(struct nfs4_client *clp)
 {
-	u64 count = nfsd_foreach_client_lock(clp, max, NULL, NULL);
+	u64 count = nfsd_foreach_client_lock(clp, 0, NULL, NULL);
 	nfsd_print_count(clp, count, "locked files");
 	return count;
 }
 
+u64
+nfsd_inject_print_locks(struct nfsd_fault_inject_op *op)
+{
+	struct nfs4_client *clp;
+	u64 count = 0;
+	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
+						nfsd_net_id);
+
+	if (!nfsd_netns_ready(nn))
+		return 0;
+
+	spin_lock(&nn->client_lock);
+	list_for_each_entry(clp, &nn->client_lru, cl_lru)
+		count += nfsd_print_client_locks(clp);
+	spin_unlock(&nn->client_lock);
+
+	return count;
+}
+
+static void
+nfsd_reap_locks(struct list_head *reaplist)
+{
+	struct nfs4_client *clp;
+	struct nfs4_ol_stateid *stp, *next;
+
+	list_for_each_entry_safe(stp, next, reaplist, st_locks) {
+		list_del_init(&stp->st_locks);
+		clp = stp->st_stid.sc_client;
+		put_generic_stateid(stp);
+		put_client(clp);
+	}
+}
+
+u64
+nfsd_inject_forget_client_locks(struct nfsd_fault_inject_op *op,
+				struct sockaddr_storage *addr, size_t addr_size)
+{
+	unsigned int count = 0;
+	struct nfs4_client *clp;
+	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
+						nfsd_net_id);
+	LIST_HEAD(reaplist);
+
+	if (!nfsd_netns_ready(nn))
+		return count;
+
+	spin_lock(&nn->client_lock);
+	clp = nfsd_find_client(addr, addr_size);
+	if (clp)
+		count = nfsd_collect_client_locks(clp, &reaplist, 0);
+	spin_unlock(&nn->client_lock);
+	nfsd_reap_locks(&reaplist);
+	return count;
+}
+
+u64
+nfsd_inject_forget_locks(struct nfsd_fault_inject_op *op, u64 max)
+{
+	u64 count = 0;
+	struct nfs4_client *clp;
+	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
+						nfsd_net_id);
+	LIST_HEAD(reaplist);
+
+	if (!nfsd_netns_ready(nn))
+		return count;
+
+	spin_lock(&nn->client_lock);
+	list_for_each_entry(clp, &nn->client_lru, cl_lru) {
+		count += nfsd_collect_client_locks(clp, &reaplist, max - count);
+		if (max != 0 && count >= max)
+			break;
+	}
+	spin_unlock(&nn->client_lock);
+	nfsd_reap_locks(&reaplist);
+	return count;
+}
+
 static u64 nfsd_foreach_client_open(struct nfs4_client *clp, u64 max, void (*func)(struct nfs4_openowner *))
 {
 	struct nfs4_openowner *oop, *next;
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 4fe973bbb68f..12ffe33662f1 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -478,12 +478,15 @@ u64 nfsd_inject_forget_client(struct nfsd_fault_inject_op *,
 			      struct sockaddr_storage *, size_t);
 u64 nfsd_inject_forget_clients(struct nfsd_fault_inject_op *, u64);
 
-u64 nfsd_forget_client_locks(struct nfs4_client*, u64);
+u64 nfsd_inject_print_locks(struct nfsd_fault_inject_op *);
+u64 nfsd_inject_forget_client_locks(struct nfsd_fault_inject_op *,
+				    struct sockaddr_storage *, size_t);
+u64 nfsd_inject_forget_locks(struct nfsd_fault_inject_op *, u64);
+
 u64 nfsd_forget_client_openowners(struct nfs4_client *, u64);
 u64 nfsd_forget_client_delegations(struct nfs4_client *, u64);
 u64 nfsd_recall_client_delegations(struct nfs4_client *, u64);
 
-u64 nfsd_print_client_locks(struct nfs4_client *, u64);
 u64 nfsd_print_client_openowners(struct nfs4_client *, u64);
 u64 nfsd_print_client_delegations(struct nfs4_client *, u64);
 #else /* CONFIG_NFSD_FAULT_INJECTION */
-- 
1.9.3


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

* [PATCH v2 101/117] nfsd: add more granular locking to forget_openowners fault injector
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (99 preceding siblings ...)
  2014-06-26 19:21 ` [PATCH v2 100/117] nfsd: add more granular locking to forget_locks fault injector Jeff Layton
@ 2014-06-26 19:21 ` Jeff Layton
  2014-06-26 19:21 ` [PATCH v2 102/117] nfsd: add more granular locking to *_delegations fault injectors Jeff Layton
                   ` (17 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:21 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

...instead of relying on the client_mutex.

Also, fix up the printk output that is generated when the file is read.
It currently says that it's reporting the number of open files, but
it's actually reporting the number of openowners.

Signed-off-by: Jeff Layton <jlayton@primarydata.com>
---
 fs/nfsd/fault_inject.c |   8 ++--
 fs/nfsd/nfs4state.c    | 122 +++++++++++++++++++++++++++++++++++++++++++++----
 fs/nfsd/state.h        |   7 ++-
 3 files changed, 122 insertions(+), 15 deletions(-)

diff --git a/fs/nfsd/fault_inject.c b/fs/nfsd/fault_inject.c
index a444d821d2a5..d4472cd19807 100644
--- a/fs/nfsd/fault_inject.c
+++ b/fs/nfsd/fault_inject.c
@@ -146,11 +146,9 @@ static struct nfsd_fault_inject_op inject_ops[] = {
 	},
 	{
 		.file     = "forget_openowners",
-		.get	  = nfsd_inject_get,
-		.set_val  = nfsd_inject_set,
-		.set_clnt = nfsd_inject_set_client,
-		.forget   = nfsd_forget_client_openowners,
-		.print    = nfsd_print_client_openowners,
+		.get	  = nfsd_inject_print_openowners,
+		.set_val  = nfsd_inject_forget_openowners,
+		.set_clnt = nfsd_inject_forget_client_openowners,
 	},
 	{
 		.file     = "forget_delegations",
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index ab5858e272b8..123b7d1eda1c 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -5936,30 +5936,136 @@ nfsd_inject_forget_locks(struct nfsd_fault_inject_op *op, u64 max)
 	return count;
 }
 
-static u64 nfsd_foreach_client_open(struct nfs4_client *clp, u64 max, void (*func)(struct nfs4_openowner *))
+static u64
+nfsd_foreach_client_openowner(struct nfs4_client *clp, u64 max,
+			      struct list_head *collect,
+			      void (*func)(struct nfs4_openowner *))
 {
 	struct nfs4_openowner *oop, *next;
+	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
+						nfsd_net_id);
 	u64 count = 0;
 
+	lockdep_assert_held(&nn->client_lock);
+
+	spin_lock(&clp->cl_lock);
 	list_for_each_entry_safe(oop, next, &clp->cl_openowners, oo_perclient) {
-		if (func)
+		if (func) {
 			func(oop);
-		if (++count == max)
+			if (collect) {
+				atomic_inc(&clp->cl_refcount);
+				list_add(&oop->oo_perclient, collect);
+			}
+		}
+		++count;
+		/*
+		 * Despite the fact that these functions deal with
+		 * 64-bit integers for "count", we must ensure that
+		 * it doesn't blow up the clp->cl_refcount. Throw a
+		 * warning if we start to approach INT_MAX here.
+		 */
+		WARN_ON_ONCE(count == (INT_MAX / 2));
+		if (count == max)
 			break;
 	}
+	spin_unlock(&clp->cl_lock);
+
+	return count;
+}
 
+static u64
+nfsd_print_client_openowners(struct nfs4_client *clp)
+{
+	u64 count = nfsd_foreach_client_openowner(clp, 0, NULL, NULL);
+
+	nfsd_print_count(clp, count, "openowners");
 	return count;
 }
 
-u64 nfsd_forget_client_openowners(struct nfs4_client *clp, u64 max)
+static u64
+nfsd_collect_client_openowners(struct nfs4_client *clp,
+			       struct list_head *collect, u64 max)
 {
-	return nfsd_foreach_client_open(clp, max, release_openowner);
+	return nfsd_foreach_client_openowner(clp, max, collect,
+						unhash_openowner_locked);
 }
 
-u64 nfsd_print_client_openowners(struct nfs4_client *clp, u64 max)
+u64
+nfsd_inject_print_openowners(struct nfsd_fault_inject_op *op)
 {
-	u64 count = nfsd_foreach_client_open(clp, max, NULL);
-	nfsd_print_count(clp, count, "open files");
+	struct nfs4_client *clp;
+	u64 count = 0;
+	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
+						nfsd_net_id);
+
+	if (!nfsd_netns_ready(nn))
+		return 0;
+
+	spin_lock(&nn->client_lock);
+	list_for_each_entry(clp, &nn->client_lru, cl_lru)
+		count += nfsd_print_client_openowners(clp);
+	spin_unlock(&nn->client_lock);
+
+	return count;
+}
+
+static void
+nfsd_reap_openowners(struct list_head *reaplist)
+{
+	struct nfs4_client *clp;
+	struct nfs4_openowner *oop, *next;
+
+	list_for_each_entry_safe(oop, next, reaplist, oo_perclient) {
+		list_del_init(&oop->oo_perclient);
+		clp = oop->oo_owner.so_client;
+		release_openowner(oop);
+		put_client(clp);
+	}
+}
+
+u64
+nfsd_inject_forget_client_openowners(struct nfsd_fault_inject_op *op,
+				struct sockaddr_storage *addr, size_t addr_size)
+{
+	unsigned int count = 0;
+	struct nfs4_client *clp;
+	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
+						nfsd_net_id);
+	LIST_HEAD(reaplist);
+
+	if (!nfsd_netns_ready(nn))
+		return count;
+
+	spin_lock(&nn->client_lock);
+	clp = nfsd_find_client(addr, addr_size);
+	if (clp)
+		count = nfsd_collect_client_openowners(clp, &reaplist, 0);
+	spin_unlock(&nn->client_lock);
+	nfsd_reap_openowners(&reaplist);
+	return count;
+}
+
+u64
+nfsd_inject_forget_openowners(struct nfsd_fault_inject_op *op, u64 max)
+{
+	u64 count = 0;
+	struct nfs4_client *clp;
+	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
+						nfsd_net_id);
+	LIST_HEAD(reaplist);
+
+	if (!nfsd_netns_ready(nn))
+		return count;
+
+	spin_lock(&nn->client_lock);
+	list_for_each_entry(clp, &nn->client_lru, cl_lru) {
+		count += nfsd_collect_client_openowners(clp, &reaplist,
+							max - count);
+		if (max != 0 && count >= max)
+			break;
+	}
+	spin_unlock(&nn->client_lock);
+	nfsd_reap_openowners(&reaplist);
 	return count;
 }
 
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 12ffe33662f1..9b35e84e8d81 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -483,11 +483,14 @@ u64 nfsd_inject_forget_client_locks(struct nfsd_fault_inject_op *,
 				    struct sockaddr_storage *, size_t);
 u64 nfsd_inject_forget_locks(struct nfsd_fault_inject_op *, u64);
 
-u64 nfsd_forget_client_openowners(struct nfs4_client *, u64);
+u64 nfsd_inject_print_openowners(struct nfsd_fault_inject_op *);
+u64 nfsd_inject_forget_client_openowners(struct nfsd_fault_inject_op *,
+					 struct sockaddr_storage *, size_t);
+u64 nfsd_inject_forget_openowners(struct nfsd_fault_inject_op *, u64);
+
 u64 nfsd_forget_client_delegations(struct nfs4_client *, u64);
 u64 nfsd_recall_client_delegations(struct nfs4_client *, u64);
 
-u64 nfsd_print_client_openowners(struct nfs4_client *, u64);
 u64 nfsd_print_client_delegations(struct nfs4_client *, u64);
 #else /* CONFIG_NFSD_FAULT_INJECTION */
 static inline int nfsd_fault_inject_init(void) { return 0; }
-- 
1.9.3


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

* [PATCH v2 102/117] nfsd: add more granular locking to *_delegations fault injectors
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (100 preceding siblings ...)
  2014-06-26 19:21 ` [PATCH v2 101/117] nfsd: add more granular locking to forget_openowners " Jeff Layton
@ 2014-06-26 19:21 ` Jeff Layton
  2014-06-26 19:21 ` [PATCH v2 103/117] nfsd: remove old fault injection infrastructure Jeff Layton
                   ` (16 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:21 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

...instead of relying on the client_mutex.

Signed-off-by: Jeff Layton <jlayton@primarydata.com>
---
 fs/nfsd/fault_inject.c |  16 ++---
 fs/nfsd/nfs4state.c    | 167 ++++++++++++++++++++++++++++++++++++++++++-------
 fs/nfsd/state.h        |  11 ++--
 3 files changed, 157 insertions(+), 37 deletions(-)

diff --git a/fs/nfsd/fault_inject.c b/fs/nfsd/fault_inject.c
index d4472cd19807..2479dba71c3c 100644
--- a/fs/nfsd/fault_inject.c
+++ b/fs/nfsd/fault_inject.c
@@ -152,19 +152,15 @@ static struct nfsd_fault_inject_op inject_ops[] = {
 	},
 	{
 		.file     = "forget_delegations",
-		.get	  = nfsd_inject_get,
-		.set_val  = nfsd_inject_set,
-		.set_clnt = nfsd_inject_set_client,
-		.forget   = nfsd_forget_client_delegations,
-		.print    = nfsd_print_client_delegations,
+		.get	  = nfsd_inject_print_delegations,
+		.set_val  = nfsd_inject_forget_delegations,
+		.set_clnt = nfsd_inject_forget_client_delegations,
 	},
 	{
 		.file     = "recall_delegations",
-		.get	  = nfsd_inject_get,
-		.set_val  = nfsd_inject_set,
-		.set_clnt = nfsd_inject_set_client,
-		.forget   = nfsd_recall_client_delegations,
-		.print    = nfsd_print_client_delegations,
+		.get	  = nfsd_inject_print_delegations,
+		.set_val  = nfsd_inject_recall_delegations,
+		.set_clnt = nfsd_inject_recall_client_delegations,
 	},
 };
 
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 123b7d1eda1c..0577d221f602 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -6073,60 +6073,180 @@ static u64 nfsd_find_all_delegations(struct nfs4_client *clp, u64 max,
 				     struct list_head *victims)
 {
 	struct nfs4_delegation *dp, *next;
+	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
+						nfsd_net_id);
 	u64 count = 0;
 
-	lockdep_assert_held(&state_lock);
+	lockdep_assert_held(&nn->client_lock);
+
+	spin_lock(&state_lock);
 	list_for_each_entry_safe(dp, next, &clp->cl_delegations, dl_perclnt) {
 		if (victims) {
+			atomic_inc(&clp->cl_refcount);
 			unhash_delegation_locked(dp);
 			list_add(&dp->dl_recall_lru, victims);
 		}
-		if (++count == max)
+		++count;
+		/*
+		 * Despite the fact that these functions deal with
+		 * 64-bit integers for "count", we must ensure that
+		 * it doesn't blow up the clp->cl_refcount. Throw a
+		 * warning if we start to approach INT_MAX here.
+		 */
+		WARN_ON_ONCE(count == (INT_MAX / 2));
+		if (count == max)
 			break;
 	}
+	spin_unlock(&state_lock);
 	return count;
 }
 
-u64 nfsd_forget_client_delegations(struct nfs4_client *clp, u64 max)
+static u64
+nfsd_print_client_delegations(struct nfs4_client *clp)
 {
-	struct nfs4_delegation *dp, *next;
-	LIST_HEAD(victims);
-	u64 count;
+	u64 count = nfsd_find_all_delegations(clp, 0, NULL);
 
-	spin_lock(&state_lock);
-	count = nfsd_find_all_delegations(clp, max, &victims);
-	spin_unlock(&state_lock);
+	nfsd_print_count(clp, count, "delegations");
+	return count;
+}
+
+u64
+nfsd_inject_print_delegations(struct nfsd_fault_inject_op *op)
+{
+	struct nfs4_client *clp;
+	u64 count = 0;
+	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
+						nfsd_net_id);
+
+	if (!nfsd_netns_ready(nn))
+		return 0;
+
+	spin_lock(&nn->client_lock);
+	list_for_each_entry(clp, &nn->client_lru, cl_lru)
+		count += nfsd_print_client_delegations(clp);
+	spin_unlock(&nn->client_lock);
+
+	return count;
+}
 
-	list_for_each_entry_safe(dp, next, &victims, dl_recall_lru)
+static void
+nfsd_forget_delegations(struct list_head *reaplist)
+{
+	struct nfs4_client *clp;
+	struct nfs4_delegation *dp, *next;
+
+	list_for_each_entry_safe(dp, next, reaplist, dl_recall_lru) {
+		list_del_init(&dp->dl_recall_lru);
+		clp = dp->dl_stid.sc_client;
 		revoke_delegation(dp);
+		put_client(clp);
+	}
+}
+
+u64
+nfsd_inject_forget_client_delegations(struct nfsd_fault_inject_op *op,
+				struct sockaddr_storage *addr, size_t addr_size)
+{
+	u64 count = 0;
+	struct nfs4_client *clp;
+	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
+						nfsd_net_id);
+	LIST_HEAD(reaplist);
+
+	if (!nfsd_netns_ready(nn))
+		return count;
+
+	spin_lock(&nn->client_lock);
+	clp = nfsd_find_client(addr, addr_size);
+	if (clp)
+		count = nfsd_find_all_delegations(clp, 0, &reaplist);
+	spin_unlock(&nn->client_lock);
+
+	nfsd_forget_delegations(&reaplist);
+	return count;
+}
+
+u64
+nfsd_inject_forget_delegations(struct nfsd_fault_inject_op *op, u64 max)
+{
+	u64 count = 0;
+	struct nfs4_client *clp;
+	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
+						nfsd_net_id);
+	LIST_HEAD(reaplist);
+
+	if (!nfsd_netns_ready(nn))
+		return count;
 
+	spin_lock(&nn->client_lock);
+	list_for_each_entry(clp, &nn->client_lru, cl_lru) {
+		count += nfsd_find_all_delegations(clp, max - count, &reaplist);
+		if (max != 0 && count >= max)
+			break;
+	}
+	spin_unlock(&nn->client_lock);
+	nfsd_forget_delegations(&reaplist);
 	return count;
 }
 
-u64 nfsd_recall_client_delegations(struct nfs4_client *clp, u64 max)
+static void
+nfsd_recall_delegations(struct list_head *reaplist)
 {
+	struct nfs4_client *clp;
 	struct nfs4_delegation *dp, *next;
-	LIST_HEAD(victims);
-	u64 count;
 
-	spin_lock(&state_lock);
-	count = nfsd_find_all_delegations(clp, max, &victims);
-	list_for_each_entry_safe(dp, next, &victims, dl_recall_lru)
+	list_for_each_entry_safe(dp, next, reaplist, dl_recall_lru) {
+		list_del_init(&dp->dl_recall_lru);
+		clp = dp->dl_stid.sc_client;
 		nfsd_break_one_deleg(dp);
-	spin_unlock(&state_lock);
+		put_client(clp);
+	}
+}
+
+u64
+nfsd_inject_recall_client_delegations(struct nfsd_fault_inject_op *op,
+				      struct sockaddr_storage *addr,
+				      size_t addr_size)
+{
+	u64 count = 0;
+	struct nfs4_client *clp;
+	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
+						nfsd_net_id);
+	LIST_HEAD(reaplist);
+
+	if (!nfsd_netns_ready(nn))
+		return count;
+
+	spin_lock(&nn->client_lock);
+	clp = nfsd_find_client(addr, addr_size);
+	if (clp)
+		count = nfsd_find_all_delegations(clp, 0, &reaplist);
+	spin_unlock(&nn->client_lock);
 
+	nfsd_recall_delegations(&reaplist);
 	return count;
 }
 
-u64 nfsd_print_client_delegations(struct nfs4_client *clp, u64 max)
+u64
+nfsd_inject_recall_delegations(struct nfsd_fault_inject_op *op, u64 max)
 {
 	u64 count = 0;
+	struct nfs4_client *clp, *next;
+	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
+						nfsd_net_id);
+	LIST_HEAD(reaplist);
 
-	spin_lock(&state_lock);
-	count = nfsd_find_all_delegations(clp, max, NULL);
-	spin_unlock(&state_lock);
+	if (!nfsd_netns_ready(nn))
+		return count;
 
-	nfsd_print_count(clp, count, "delegations");
+	spin_lock(&nn->client_lock);
+	list_for_each_entry_safe(clp, next, &nn->client_lru, cl_lru) {
+		count += nfsd_find_all_delegations(clp, max - count, &reaplist);
+		if (max != 0 && ++count >= max)
+			break;
+	}
+	spin_unlock(&nn->client_lock);
+	nfsd_recall_delegations(&reaplist);
 	return count;
 }
 
@@ -6134,7 +6254,8 @@ u64 nfsd_for_n_state(u64 max, u64 (*func)(struct nfs4_client *, u64))
 {
 	struct nfs4_client *clp, *next;
 	u64 count = 0;
-	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, nfsd_net_id);
+	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
+						nfsd_net_id);
 
 	if (!nfsd_netns_ready(nn))
 		return 0;
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 9b35e84e8d81..5bfa7823fa48 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -488,10 +488,13 @@ u64 nfsd_inject_forget_client_openowners(struct nfsd_fault_inject_op *,
 					 struct sockaddr_storage *, size_t);
 u64 nfsd_inject_forget_openowners(struct nfsd_fault_inject_op *, u64);
 
-u64 nfsd_forget_client_delegations(struct nfs4_client *, u64);
-u64 nfsd_recall_client_delegations(struct nfs4_client *, u64);
-
-u64 nfsd_print_client_delegations(struct nfs4_client *, u64);
+u64 nfsd_inject_print_delegations(struct nfsd_fault_inject_op *);
+u64 nfsd_inject_forget_client_delegations(struct nfsd_fault_inject_op *,
+					  struct sockaddr_storage *, size_t);
+u64 nfsd_inject_forget_delegations(struct nfsd_fault_inject_op *, u64);
+u64 nfsd_inject_recall_client_delegations(struct nfsd_fault_inject_op *,
+					  struct sockaddr_storage *, size_t);
+u64 nfsd_inject_recall_delegations(struct nfsd_fault_inject_op *, u64);
 #else /* CONFIG_NFSD_FAULT_INJECTION */
 static inline int nfsd_fault_inject_init(void) { return 0; }
 static inline void nfsd_fault_inject_cleanup(void) {}
-- 
1.9.3


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

* [PATCH v2 103/117] nfsd: remove old fault injection infrastructure
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (101 preceding siblings ...)
  2014-06-26 19:21 ` [PATCH v2 102/117] nfsd: add more granular locking to *_delegations fault injectors Jeff Layton
@ 2014-06-26 19:21 ` Jeff Layton
  2014-06-26 19:21 ` [PATCH v2 104/117] nfsd: Remove nfs4_lock_state(): nfs4_preprocess_stateid_op() Jeff Layton
                   ` (15 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:21 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

Remove the old nfsd_for_n_state function and move nfsd_find_client
higher up into the file to get rid of forward declaration. Remove
the struct nfsd_fault_inject_op arguments from the operations as
they are no longer needed by any of them.

Finally, remove the old "standard" get and set routines, which
also eliminates the client_mutex from this code.

Signed-off-by: Jeff Layton <jlayton@primarydata.com>
---
 fs/nfsd/fault_inject.c | 51 ++++-------------------------
 fs/nfsd/nfs4state.c    | 87 +++++++++++++++++++-------------------------------
 fs/nfsd/state.h        | 45 +++++++++++---------------
 3 files changed, 57 insertions(+), 126 deletions(-)

diff --git a/fs/nfsd/fault_inject.c b/fs/nfsd/fault_inject.c
index 2479dba71c3c..c16bf5af6831 100644
--- a/fs/nfsd/fault_inject.c
+++ b/fs/nfsd/fault_inject.c
@@ -17,52 +17,13 @@
 
 struct nfsd_fault_inject_op {
 	char *file;
-	u64 (*get)(struct nfsd_fault_inject_op *);
-	u64 (*set_val)(struct nfsd_fault_inject_op *, u64);
-	u64 (*set_clnt)(struct nfsd_fault_inject_op *,
-			struct sockaddr_storage *, size_t);
-	u64 (*forget)(struct nfs4_client *, u64);
-	u64 (*print)(struct nfs4_client *, u64);
+	u64 (*get)(void);
+	u64 (*set_val)(u64);
+	u64 (*set_clnt)(struct sockaddr_storage *, size_t);
 };
 
 static struct dentry *debug_dir;
 
-static u64 nfsd_inject_set(struct nfsd_fault_inject_op *op, u64 val)
-{
-	u64 count;
-
-	nfs4_lock_state();
-	count = nfsd_for_n_state(val, op->forget);
-	nfs4_unlock_state();
-	return count;
-}
-
-static u64 nfsd_inject_set_client(struct nfsd_fault_inject_op *op,
-				   struct sockaddr_storage *addr,
-				   size_t addr_size)
-{
-	struct nfs4_client *clp;
-	u64 count = 0;
-
-	nfs4_lock_state();
-	clp = nfsd_find_client(addr, addr_size);
-	if (clp)
-		count = op->forget(clp, 0);
-	nfs4_unlock_state();
-	return count;
-}
-
-static u64 nfsd_inject_get(struct nfsd_fault_inject_op *op)
-{
-	u64 count;
-
-	nfs4_lock_state();
-	count = nfsd_for_n_state(0, op->print);
-	nfs4_unlock_state();
-
-	return count;
-}
-
 static ssize_t fault_inject_read(struct file *file, char __user *buf,
 				 size_t len, loff_t *ppos)
 {
@@ -73,7 +34,7 @@ static ssize_t fault_inject_read(struct file *file, char __user *buf,
 	struct nfsd_fault_inject_op *op = file_inode(file)->i_private;
 
 	if (!pos)
-		val = op->get(op);
+		val = op->get();
 	size = scnprintf(read_buf, sizeof(read_buf), "%llu\n", val);
 
 	return simple_read_from_buffer(buf, len, ppos, read_buf, size);
@@ -103,7 +64,7 @@ static ssize_t fault_inject_write(struct file *file, const char __user *buf,
 
 	size = rpc_pton(net, write_buf, size, (struct sockaddr *)&sa, sizeof(sa));
 	if (size > 0) {
-		val = op->set_clnt(op, &sa, size);
+		val = op->set_clnt(&sa, size);
 		if (val)
 			pr_info("NFSD [%s]: Client %s had %llu state object(s)\n",
 				op->file, write_buf, val);
@@ -114,7 +75,7 @@ static ssize_t fault_inject_write(struct file *file, const char __user *buf,
 		else
 			pr_info("NFSD Fault Injection: %s (n = %llu)",
 				op->file, val);
-		val = op->set_val(op, val);
+		val = op->set_val(val);
 		pr_info("NFSD: %s: found %llu", op->file, val);
 	}
 	return len; /* on success, claim we got the whole input */
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 0577d221f602..16269a54b689 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -5700,8 +5700,25 @@ put_client(struct nfs4_client *clp)
 	spin_unlock(&nn->client_lock);
 }
 
+static struct nfs4_client *
+nfsd_find_client(struct sockaddr_storage *addr, size_t addr_size)
+{
+	struct nfs4_client *clp;
+	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
+					  nfsd_net_id);
+
+	if (!nfsd_netns_ready(nn))
+		return NULL;
+
+	list_for_each_entry(clp, &nn->client_lru, cl_lru) {
+		if (memcmp(&clp->cl_addr, addr, addr_size) == 0)
+			return clp;
+	}
+	return NULL;
+}
+
 u64
-nfsd_inject_print_clients(struct nfsd_fault_inject_op *op)
+nfsd_inject_print_clients(void)
 {
 	struct nfs4_client *clp;
 	u64 count = 0;
@@ -5724,8 +5741,7 @@ nfsd_inject_print_clients(struct nfsd_fault_inject_op *op)
 }
 
 u64
-nfsd_inject_forget_client(struct nfsd_fault_inject_op *op,
-			  struct sockaddr_storage *addr, size_t addr_size)
+nfsd_inject_forget_client(struct sockaddr_storage *addr, size_t addr_size)
 {
 	u64 count = 0;
 	struct nfs4_client *clp;
@@ -5752,7 +5768,7 @@ nfsd_inject_forget_client(struct nfsd_fault_inject_op *op,
 }
 
 u64
-nfsd_inject_forget_clients(struct nfsd_fault_inject_op *op, u64 max)
+nfsd_inject_forget_clients(u64 max)
 {
 	u64 count = 0;
 	struct nfs4_client *clp, *next;
@@ -5859,7 +5875,7 @@ nfsd_print_client_locks(struct nfs4_client *clp)
 }
 
 u64
-nfsd_inject_print_locks(struct nfsd_fault_inject_op *op)
+nfsd_inject_print_locks(void)
 {
 	struct nfs4_client *clp;
 	u64 count = 0;
@@ -5892,8 +5908,7 @@ nfsd_reap_locks(struct list_head *reaplist)
 }
 
 u64
-nfsd_inject_forget_client_locks(struct nfsd_fault_inject_op *op,
-				struct sockaddr_storage *addr, size_t addr_size)
+nfsd_inject_forget_client_locks(struct sockaddr_storage *addr, size_t addr_size)
 {
 	unsigned int count = 0;
 	struct nfs4_client *clp;
@@ -5914,7 +5929,7 @@ nfsd_inject_forget_client_locks(struct nfsd_fault_inject_op *op,
 }
 
 u64
-nfsd_inject_forget_locks(struct nfsd_fault_inject_op *op, u64 max)
+nfsd_inject_forget_locks(u64 max)
 {
 	u64 count = 0;
 	struct nfs4_client *clp;
@@ -5991,7 +6006,7 @@ nfsd_collect_client_openowners(struct nfs4_client *clp,
 }
 
 u64
-nfsd_inject_print_openowners(struct nfsd_fault_inject_op *op)
+nfsd_inject_print_openowners(void)
 {
 	struct nfs4_client *clp;
 	u64 count = 0;
@@ -6024,8 +6039,8 @@ nfsd_reap_openowners(struct list_head *reaplist)
 }
 
 u64
-nfsd_inject_forget_client_openowners(struct nfsd_fault_inject_op *op,
-				struct sockaddr_storage *addr, size_t addr_size)
+nfsd_inject_forget_client_openowners(struct sockaddr_storage *addr,
+				     size_t addr_size)
 {
 	unsigned int count = 0;
 	struct nfs4_client *clp;
@@ -6046,7 +6061,7 @@ nfsd_inject_forget_client_openowners(struct nfsd_fault_inject_op *op,
 }
 
 u64
-nfsd_inject_forget_openowners(struct nfsd_fault_inject_op *op, u64 max)
+nfsd_inject_forget_openowners(u64 max)
 {
 	u64 count = 0;
 	struct nfs4_client *clp;
@@ -6111,7 +6126,7 @@ nfsd_print_client_delegations(struct nfs4_client *clp)
 }
 
 u64
-nfsd_inject_print_delegations(struct nfsd_fault_inject_op *op)
+nfsd_inject_print_delegations(void)
 {
 	struct nfs4_client *clp;
 	u64 count = 0;
@@ -6144,8 +6159,8 @@ nfsd_forget_delegations(struct list_head *reaplist)
 }
 
 u64
-nfsd_inject_forget_client_delegations(struct nfsd_fault_inject_op *op,
-				struct sockaddr_storage *addr, size_t addr_size)
+nfsd_inject_forget_client_delegations(struct sockaddr_storage *addr,
+				      size_t addr_size)
 {
 	u64 count = 0;
 	struct nfs4_client *clp;
@@ -6167,7 +6182,7 @@ nfsd_inject_forget_client_delegations(struct nfsd_fault_inject_op *op,
 }
 
 u64
-nfsd_inject_forget_delegations(struct nfsd_fault_inject_op *op, u64 max)
+nfsd_inject_forget_delegations(u64 max)
 {
 	u64 count = 0;
 	struct nfs4_client *clp;
@@ -6204,8 +6219,7 @@ nfsd_recall_delegations(struct list_head *reaplist)
 }
 
 u64
-nfsd_inject_recall_client_delegations(struct nfsd_fault_inject_op *op,
-				      struct sockaddr_storage *addr,
+nfsd_inject_recall_client_delegations(struct sockaddr_storage *addr,
 				      size_t addr_size)
 {
 	u64 count = 0;
@@ -6228,7 +6242,7 @@ nfsd_inject_recall_client_delegations(struct nfsd_fault_inject_op *op,
 }
 
 u64
-nfsd_inject_recall_delegations(struct nfsd_fault_inject_op *op, u64 max)
+nfsd_inject_recall_delegations(u64 max)
 {
 	u64 count = 0;
 	struct nfs4_client *clp, *next;
@@ -6249,41 +6263,6 @@ nfsd_inject_recall_delegations(struct nfsd_fault_inject_op *op, u64 max)
 	nfsd_recall_delegations(&reaplist);
 	return count;
 }
-
-u64 nfsd_for_n_state(u64 max, u64 (*func)(struct nfs4_client *, u64))
-{
-	struct nfs4_client *clp, *next;
-	u64 count = 0;
-	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
-						nfsd_net_id);
-
-	if (!nfsd_netns_ready(nn))
-		return 0;
-
-	list_for_each_entry_safe(clp, next, &nn->client_lru, cl_lru) {
-		count += func(clp, max - count);
-		if ((max != 0) && (count >= max))
-			break;
-	}
-
-	return count;
-}
-
-struct nfs4_client *nfsd_find_client(struct sockaddr_storage *addr, size_t addr_size)
-{
-	struct nfs4_client *clp;
-	struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, nfsd_net_id);
-
-	if (!nfsd_netns_ready(nn))
-		return NULL;
-
-	list_for_each_entry(clp, &nn->client_lru, cl_lru) {
-		if (memcmp(&clp->cl_addr, addr, addr_size) == 0)
-			return clp;
-	}
-	return NULL;
-}
-
 #endif /* CONFIG_NFSD_FAULT_INJECTION */
 
 /*
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 5bfa7823fa48..375a715116fd 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -466,35 +466,26 @@ extern void nfsd4_record_grace_done(struct nfsd_net *nn, time_t boot_time);
 
 /* nfs fault injection functions */
 #ifdef CONFIG_NFSD_FAULT_INJECTION
-struct nfsd_fault_inject_op;
-
 int nfsd_fault_inject_init(void);
 void nfsd_fault_inject_cleanup(void);
-u64 nfsd_for_n_state(u64, u64 (*)(struct nfs4_client *, u64));
-struct nfs4_client *nfsd_find_client(struct sockaddr_storage *, size_t);
-
-u64 nfsd_inject_print_clients(struct nfsd_fault_inject_op *op);
-u64 nfsd_inject_forget_client(struct nfsd_fault_inject_op *,
-			      struct sockaddr_storage *, size_t);
-u64 nfsd_inject_forget_clients(struct nfsd_fault_inject_op *, u64);
-
-u64 nfsd_inject_print_locks(struct nfsd_fault_inject_op *);
-u64 nfsd_inject_forget_client_locks(struct nfsd_fault_inject_op *,
-				    struct sockaddr_storage *, size_t);
-u64 nfsd_inject_forget_locks(struct nfsd_fault_inject_op *, u64);
-
-u64 nfsd_inject_print_openowners(struct nfsd_fault_inject_op *);
-u64 nfsd_inject_forget_client_openowners(struct nfsd_fault_inject_op *,
-					 struct sockaddr_storage *, size_t);
-u64 nfsd_inject_forget_openowners(struct nfsd_fault_inject_op *, u64);
-
-u64 nfsd_inject_print_delegations(struct nfsd_fault_inject_op *);
-u64 nfsd_inject_forget_client_delegations(struct nfsd_fault_inject_op *,
-					  struct sockaddr_storage *, size_t);
-u64 nfsd_inject_forget_delegations(struct nfsd_fault_inject_op *, u64);
-u64 nfsd_inject_recall_client_delegations(struct nfsd_fault_inject_op *,
-					  struct sockaddr_storage *, size_t);
-u64 nfsd_inject_recall_delegations(struct nfsd_fault_inject_op *, u64);
+
+u64 nfsd_inject_print_clients(void);
+u64 nfsd_inject_forget_client(struct sockaddr_storage *, size_t);
+u64 nfsd_inject_forget_clients(u64);
+
+u64 nfsd_inject_print_locks(void);
+u64 nfsd_inject_forget_client_locks(struct sockaddr_storage *, size_t);
+u64 nfsd_inject_forget_locks(u64);
+
+u64 nfsd_inject_print_openowners(void);
+u64 nfsd_inject_forget_client_openowners(struct sockaddr_storage *, size_t);
+u64 nfsd_inject_forget_openowners(u64);
+
+u64 nfsd_inject_print_delegations(void);
+u64 nfsd_inject_forget_client_delegations(struct sockaddr_storage *, size_t);
+u64 nfsd_inject_forget_delegations(u64);
+u64 nfsd_inject_recall_client_delegations(struct sockaddr_storage *, size_t);
+u64 nfsd_inject_recall_delegations(u64);
 #else /* CONFIG_NFSD_FAULT_INJECTION */
 static inline int nfsd_fault_inject_init(void) { return 0; }
 static inline void nfsd_fault_inject_cleanup(void) {}
-- 
1.9.3


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

* [PATCH v2 104/117] nfsd: Remove nfs4_lock_state(): nfs4_preprocess_stateid_op()
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (102 preceding siblings ...)
  2014-06-26 19:21 ` [PATCH v2 103/117] nfsd: remove old fault injection infrastructure Jeff Layton
@ 2014-06-26 19:21 ` Jeff Layton
  2014-06-26 19:21 ` [PATCH v2 105/117] nfsd: Remove nfs4_lock_state(): nfsd4_test_stateid/nfsd4_free_stateid Jeff Layton
                   ` (14 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:21 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

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 16269a54b689..658863ed1c35 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -4423,13 +4423,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;
@@ -4479,8 +4477,6 @@ nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate,
 		*filpp = file;
 out:
 	nfs4_put_stid(s);
-unlock_state:
-	nfs4_unlock_state();
 	return status;
 }
 
-- 
1.9.3


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

* [PATCH v2 105/117] nfsd: Remove nfs4_lock_state(): nfsd4_test_stateid/nfsd4_free_stateid
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (103 preceding siblings ...)
  2014-06-26 19:21 ` [PATCH v2 104/117] nfsd: Remove nfs4_lock_state(): nfs4_preprocess_stateid_op() Jeff Layton
@ 2014-06-26 19:21 ` Jeff Layton
  2014-06-26 19:21 ` [PATCH v2 106/117] nfsd: Remove nfs4_lock_state(): nfsd4_release_lockowner Jeff Layton
                   ` (13 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:21 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

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 658863ed1c35..e5b7b8bbc609 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -4490,11 +4490,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;
 }
@@ -4510,7 +4508,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();
 	spin_lock(&cl->cl_lock);
 	s = find_stateid_locked(cl, stateid);
 	if (!s)
@@ -4547,7 +4544,6 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 out_unlock:
 	spin_unlock(&cl->cl_lock);
 out:
-	nfs4_unlock_state();
 	return ret;
 }
 
-- 
1.9.3


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

* [PATCH v2 106/117] nfsd: Remove nfs4_lock_state(): nfsd4_release_lockowner
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (104 preceding siblings ...)
  2014-06-26 19:21 ` [PATCH v2 105/117] nfsd: Remove nfs4_lock_state(): nfsd4_test_stateid/nfsd4_free_stateid Jeff Layton
@ 2014-06-26 19:21 ` Jeff Layton
  2014-06-26 19:21 ` [PATCH v2 107/117] nfsd: Remove nfs4_lock_state(): nfsd4_lock/locku/lockt() Jeff Layton
                   ` (12 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:21 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

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

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index e5b7b8bbc609..2be356341929 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -5532,11 +5532,9 @@ 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, cstate, nn);
 	if (status)
-		goto out;
+		return status;
 
 	status = nfserr_locks_held;
 	INIT_LIST_HEAD(&matches);
@@ -5578,7 +5576,6 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
 out:
 	if (sop)
 		nfs4_put_stateowner(sop);
-	nfs4_unlock_state();
 	return status;
 }
 
-- 
1.9.3


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

* [PATCH v2 107/117] nfsd: Remove nfs4_lock_state(): nfsd4_lock/locku/lockt()
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (105 preceding siblings ...)
  2014-06-26 19:21 ` [PATCH v2 106/117] nfsd: Remove nfs4_lock_state(): nfsd4_release_lockowner Jeff Layton
@ 2014-06-26 19:21 ` Jeff Layton
  2014-06-26 19:21 ` [PATCH v2 108/117] nfsd: Remove nfs4_lock_state(): nfsd4_open_downgrade + nfsd4_close Jeff Layton
                   ` (11 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:21 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

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 2be356341929..3d5ea785652b 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -5168,8 +5168,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: */
@@ -5312,7 +5310,6 @@ out:
 	if (open_stp)
 		put_generic_stateid(open_stp);
 	nfsd4_bump_seqid(cstate, status);
-	nfs4_unlock_state();
 	if (file_lock)
 		locks_free_lock(file_lock);
 	if (conflock)
@@ -5355,8 +5352,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, cstate, nn);
 		if (status)
@@ -5411,7 +5406,6 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 out:
 	if (lo)
 		nfs4_put_stateowner(&lo->lo_owner);
-	nfs4_unlock_state();
 	if (file_lock)
 		locks_free_lock(file_lock);
 	return status;
@@ -5435,8 +5429,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);
@@ -5479,7 +5471,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.3


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

* [PATCH v2 108/117] nfsd: Remove nfs4_lock_state(): nfsd4_open_downgrade + nfsd4_close
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (106 preceding siblings ...)
  2014-06-26 19:21 ` [PATCH v2 107/117] nfsd: Remove nfs4_lock_state(): nfsd4_lock/locku/lockt() Jeff Layton
@ 2014-06-26 19:21 ` Jeff Layton
  2014-06-26 19:21 ` [PATCH v2 109/117] nfsd: Remove nfs4_lock_state(): nfsd4_delegreturn() Jeff Layton
                   ` (10 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:21 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

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 3d5ea785652b..2d67dd5268e8 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -4667,7 +4667,6 @@ put_stateid:
 	put_generic_stateid(stp);
 out:
 	nfsd4_bump_seqid(cstate, status);
-	nfs4_unlock_state();
 	return status;
 }
 
@@ -4730,7 +4729,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)
@@ -4796,7 +4794,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,
@@ -4812,7 +4809,6 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 	/* put reference from nfs4_preprocess_seqid_op */
 	put_generic_stateid(stp);
 out:
-	nfs4_unlock_state();
 	return status;
 }
 
-- 
1.9.3


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

* [PATCH v2 109/117] nfsd: Remove nfs4_lock_state(): nfsd4_delegreturn()
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (107 preceding siblings ...)
  2014-06-26 19:21 ` [PATCH v2 108/117] nfsd: Remove nfs4_lock_state(): nfsd4_open_downgrade + nfsd4_close Jeff Layton
@ 2014-06-26 19:21 ` Jeff Layton
  2014-06-26 19:21 ` [PATCH v2 110/117] nfsd: Remove nfs4_lock_state(): nfsd4_open and nfsd4_open_confirm Jeff Layton
                   ` (9 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:21 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

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 2d67dd5268e8..8734847f7e49 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -4825,7 +4825,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;
@@ -4838,8 +4837,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.3


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

* [PATCH v2 110/117] nfsd: Remove nfs4_lock_state(): nfsd4_open and nfsd4_open_confirm
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (108 preceding siblings ...)
  2014-06-26 19:21 ` [PATCH v2 109/117] nfsd: Remove nfs4_lock_state(): nfsd4_delegreturn() Jeff Layton
@ 2014-06-26 19:21 ` Jeff Layton
  2014-06-26 19:21 ` [PATCH v2 111/117] nfsd: Remove nfs4_lock_state(): exchange_id, create/destroy_session() Jeff Layton
                   ` (8 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:21 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

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 833c753e4775..0b718f545785 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);
@@ -469,7 +467,6 @@ out:
 	}
 	nfsd4_cleanup_open_state(cstate, open, status);
 	nfsd4_bump_seqid(cstate, status);
-	nfs4_unlock_state();
 	return status;
 }
 
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 8734847f7e49..879328c70e4b 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -3930,9 +3930,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)
 {
@@ -4644,8 +4641,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);
@@ -4755,7 +4750,6 @@ put_stateid:
 	put_generic_stateid(stp);
 out:
 	nfsd4_bump_seqid(cstate, status);
-	nfs4_unlock_state();
 	return status;
 }
 
-- 
1.9.3


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

* [PATCH v2 111/117] nfsd: Remove nfs4_lock_state(): exchange_id, create/destroy_session()
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (109 preceding siblings ...)
  2014-06-26 19:21 ` [PATCH v2 110/117] nfsd: Remove nfs4_lock_state(): nfsd4_open and nfsd4_open_confirm Jeff Layton
@ 2014-06-26 19:21 ` Jeff Layton
  2014-06-26 19:21 ` [PATCH v2 112/117] nfsd: Remove nfs4_lock_state(): setclientid, setclientid_confirm, renew Jeff Layton
                   ` (7 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:21 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

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 879328c70e4b..7e9dc3356d53 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -2156,7 +2156,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) {
@@ -2235,7 +2234,6 @@ out_copy:
 
 out:
 	spin_unlock(&nn->client_lock);
-	nfs4_unlock_state();
 	if (new)
 		expire_client(new);
 	if (unconf)
@@ -2409,7 +2407,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);
@@ -2479,13 +2476,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);
@@ -2541,7 +2536,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);
@@ -2562,7 +2556,6 @@ __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp,
 out:
 	nfsd4_put_session(session);
 out_no_session:
-	nfs4_unlock_state();
 	return status;
 }
 
@@ -2584,7 +2577,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))
@@ -2614,7 +2606,6 @@ out_put_session:
 out_client_lock:
 	spin_unlock(&nn->client_lock);
 out:
-	nfs4_unlock_state();
 	return status;
 }
 
@@ -2817,7 +2808,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);
@@ -2846,7 +2836,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.3


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

* [PATCH v2 112/117] nfsd: Remove nfs4_lock_state(): setclientid, setclientid_confirm, renew
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (110 preceding siblings ...)
  2014-06-26 19:21 ` [PATCH v2 111/117] nfsd: Remove nfs4_lock_state(): exchange_id, create/destroy_session() Jeff Layton
@ 2014-06-26 19:21 ` Jeff Layton
  2014-06-26 19:21 ` [PATCH v2 113/117] nfsd: Remove nfs4_lock_state(): reclaim_complete() Jeff Layton
                   ` (6 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:21 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

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 7e9dc3356d53..9d963037eaa2 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -2895,7 +2895,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) {
@@ -2930,7 +2929,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)
@@ -2953,7 +2951,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);
@@ -3003,7 +3000,6 @@ out:
 	spin_unlock(&nn->client_lock);
 	if (old)
 		expire_client(old);
-	nfs4_unlock_state();
 	return status;
 }
 
@@ -4071,7 +4067,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, cstate, nn);
@@ -4084,7 +4079,6 @@ nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 		goto out;
 	status = nfs_ok;
 out:
-	nfs4_unlock_state();
 	return status;
 }
 
-- 
1.9.3


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

* [PATCH v2 113/117] nfsd: Remove nfs4_lock_state(): reclaim_complete()
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (111 preceding siblings ...)
  2014-06-26 19:21 ` [PATCH v2 112/117] nfsd: Remove nfs4_lock_state(): setclientid, setclientid_confirm, renew Jeff Layton
@ 2014-06-26 19:21 ` Jeff Layton
  2014-06-26 19:21 ` [PATCH v2 114/117] nfsd: remove nfs4_lock_state: nfs4_laundromat Jeff Layton
                   ` (5 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:21 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs, Trond Myklebust

From: Trond Myklebust <trond.myklebust@primarydata.com>

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 9d963037eaa2..ccf6bb390fbb 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -2856,7 +2856,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))
@@ -2876,7 +2875,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.3


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

* [PATCH v2 114/117] nfsd: remove nfs4_lock_state: nfs4_laundromat
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (112 preceding siblings ...)
  2014-06-26 19:21 ` [PATCH v2 113/117] nfsd: Remove nfs4_lock_state(): reclaim_complete() Jeff Layton
@ 2014-06-26 19:21 ` Jeff Layton
  2014-06-26 19:21 ` [PATCH v2 115/117] nfsd: remove nfs4_lock_state: nfs4_state_shutdown_net Jeff Layton
                   ` (4 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:21 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

Signed-off-by: Jeff Layton <jlayton@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 ccf6bb390fbb..b49c43c40832 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -4110,8 +4110,6 @@ nfs4_laundromat(struct nfsd_net *nn)
 	time_t cutoff = get_seconds() - nn->nfsd4_lease;
 	time_t t, new_timeo = nn->nfsd4_lease;
 
-	nfs4_lock_state();
-
 	dprintk("NFSD: laundromat service - starting\n");
 	nfsd4_end_grace(nn);
 	INIT_LIST_HEAD(&reaplist);
@@ -4179,7 +4177,6 @@ nfs4_laundromat(struct nfsd_net *nn)
 	spin_unlock(&nn->client_lock);
 
 	new_timeo = max_t(time_t, new_timeo, NFSD_LAUNDROMAT_MINTIMEOUT);
-	nfs4_unlock_state();
 	return new_timeo;
 }
 
-- 
1.9.3


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

* [PATCH v2 115/117] nfsd: remove nfs4_lock_state: nfs4_state_shutdown_net
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (113 preceding siblings ...)
  2014-06-26 19:21 ` [PATCH v2 114/117] nfsd: remove nfs4_lock_state: nfs4_laundromat Jeff Layton
@ 2014-06-26 19:21 ` Jeff Layton
  2014-06-26 19:21 ` [PATCH v2 116/117] nfsd: remove the client_mutex and the nfs4_lock/unlock_state wrappers Jeff Layton
                   ` (3 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:21 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

Signed-off-by: Jeff Layton <jlayton@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 b49c43c40832..55c3405d0327 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -6360,7 +6360,6 @@ nfs4_state_shutdown_net(struct net *net)
 	cancel_delayed_work_sync(&nn->laundromat_work);
 	locks_end_grace(&nn->nfsd4_manager);
 
-	nfs4_lock_state();
 	INIT_LIST_HEAD(&reaplist);
 	spin_lock(&state_lock);
 	list_for_each_safe(pos, next, &nn->del_recall_lru) {
@@ -6377,7 +6376,6 @@ nfs4_state_shutdown_net(struct net *net)
 
 	nfsd4_client_tracking_exit(net);
 	nfs4_state_destroy_net(net);
-	nfs4_unlock_state();
 }
 
 void
-- 
1.9.3


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

* [PATCH v2 116/117] nfsd: remove the client_mutex and the nfs4_lock/unlock_state wrappers
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (114 preceding siblings ...)
  2014-06-26 19:21 ` [PATCH v2 115/117] nfsd: remove nfs4_lock_state: nfs4_state_shutdown_net Jeff Layton
@ 2014-06-26 19:21 ` Jeff Layton
  2014-06-26 19:21 ` [PATCH v2 117/117] nfsd: add file documenting new state object model Jeff Layton
                   ` (2 subsequent siblings)
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:21 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

Signed-off-by: Jeff Layton <jlayton@primarydata.com>
---
 fs/nfsd/nfs4state.c | 15 ---------------
 1 file changed, 15 deletions(-)

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 55c3405d0327..d2103a67d6c6 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -83,9 +83,6 @@ static __be32 lookup_clientid(clientid_t *clid,
 
 /* Locking: */
 
-/* Currently used for almost all code touching nfsv4 state: */
-static DEFINE_MUTEX(client_mutex);
-
 /*
  * Currently used for the del_recall_lru and file hash table.  In an
  * effort to decrease the scope of the client_mutex, this spinlock may
@@ -105,12 +102,6 @@ static struct kmem_cache *file_slab;
 static struct kmem_cache *stateid_slab;
 static struct kmem_cache *deleg_slab;
 
-void
-nfs4_lock_state(void)
-{
-	mutex_lock(&client_mutex);
-}
-
 static void free_session(struct nfsd4_session *);
 
 static bool is_session_dead(struct nfsd4_session *ses)
@@ -126,12 +117,6 @@ static __be32 mark_session_dead_locked(struct nfsd4_session *ses, int ref_held_b
 	return nfs_ok;
 }
 
-void
-nfs4_unlock_state(void)
-{
-	mutex_unlock(&client_mutex);
-}
-
 static bool is_client_expired(struct nfs4_client *clp)
 {
 	return clp->cl_time == 0;
-- 
1.9.3


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

* [PATCH v2 117/117] nfsd: add file documenting new state object model
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (115 preceding siblings ...)
  2014-06-26 19:21 ` [PATCH v2 116/117] nfsd: remove the client_mutex and the nfs4_lock/unlock_state wrappers Jeff Layton
@ 2014-06-26 19:21 ` Jeff Layton
  2014-06-27 16:22 ` [PATCH v2 000/117] nfsd: eliminate the client_mutex J. Bruce Fields
  2014-06-30 12:51 ` Christoph Hellwig
  118 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:21 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

Signed-off-by: Jeff Layton <jlayton@primarydata.com>
---
 .../filesystems/nfs/nfsd4-state-objects.txt        | 105 +++++++++++++++++++++
 1 file changed, 105 insertions(+)
 create mode 100644 Documentation/filesystems/nfs/nfsd4-state-objects.txt

diff --git a/Documentation/filesystems/nfs/nfsd4-state-objects.txt b/Documentation/filesystems/nfs/nfsd4-state-objects.txt
new file mode 100644
index 000000000000..faad5a37fd9b
--- /dev/null
+++ b/Documentation/filesystems/nfs/nfsd4-state-objects.txt
@@ -0,0 +1,105 @@
+KNFSD4 State Object Model:
+==========================
+Written 2014 by Jeff Layton <jlayton@primarydata.com>
+
+Introduction:
+-------------
+The state model in NFSv4 is quite complex. Thus, the relationship between the
+objects to track this state in knfsd is also complex. This document attempts to
+lay out how all of the different objects relate to one another, and which ones
+hold references to others.
+
+In addition to the "persistent" references documented here, references to these
+objects can also be taken during the processing of compounds in order to ensure
+that the objects don't disappear suddenly.
+
+struct nfsd_net:
+----------------
+Represents a nfsd "container". With respect to nfsv4 state tracking, the fields
+of interest are the *_id_hashtbls and the *_name_tree. These track the
+nfs4_client objects by either short or long form clientid.
+
+Each nfsd_net runs a nfs4_laundromat workqueue job every lease period to clean
+up expired clients and delegations within the container.
+
+struct nfs4_file:
+-----------------
+These objects are global. nfsd only keeps one instance of a nfs4_file per inode
+(though it may keep multiple file descriptors open per inode). These are
+tracked in the file_hashtbl which is protected by the state_lock spinlock.
+
+struct nfs4_client:
+-------------------
+The initial object created by an NFS client using SETCLIENTID (for NFSv4.0) or
+EXCHANGE_ID (for NFSv4.1+). These objects are refcounted and timestamped. Each
+nfsd_net_ns object contains a set of these and they are tracked via short and
+long form clientid. They are hashed and searched for under the per-nfsd-net
+client_lock spinlock.
+
+References to it are only held during the processing of compounds, and in
+certain other operations. In their "resting state" they have a refcount of 0. If
+they are not renewed within a lease period, they become eligible for destruction
+by the laundromat.
+
+These objects can also be destroyed prematurely by the fault injection code,
+or if the client sends certain forms of SETCLIENTID or EXCHANGE_ID updates.
+Care is taken *not* to do this however when the objects have an elevated
+refcount.
+
+struct nfsd4_session:
+---------------------
+Represents a v4.1+ session. These are refcounted in a similar fashion to
+the nfs4_client. References are only taken when the server is actively working
+on the object (primarily during the processing of compounds).
+
+struct nfs4_stateowner:
+-----------------------
+A core object that represents either an open or lock owner. The object and lock
+owner objects have one of these embedded within them. Refcounts and other
+fields common to both owner types are contained within these structures.
+
+struct nfs4_openowner:
+----------------------
+When a file is opened, the client provides an open state owner opaque string
+that indicates the "owner" of that open. These objects are refcounted.
+References to it are held by each open state associated with it. This object is
+a superset of the nfs4_stateowner struct.
+
+struct nfs4_lockowner:
+----------------------
+Represents a generic "lockowner". Similar to an openowner. References to it are
+held by the lock stateids that are created on its behalf. This object is a
+superset of the nfs4_stateowner struct.
+
+strict nfs4_stid:
+-----------------
+A core object that represents a "common" stateid. These are generally embedded
+within the different (more specific) stateid objects and contain fields that
+are of general use to any stateid.
+
+struct nfs4_ol_stateid:
+-----------------------
+A generic struct representing either a open or lock stateid. The nfs4_client
+holds a reference to each of these objects, and they in turn hold a reference
+to their respective stateowners. The client's reference is released in response
+to a close or unlock (depending on whether it's an open or lock stateid) or
+when the client is being destroyed.
+
+In the case of v4.0, these objects are preserved for a little while after close
+in order to handle CLOSE replays. They are eventually reclaimed via a LRU
+scheme by the laundromat.
+
+This object is a superset of the nfs4_stid.
+
+struct nfs4_delegation:
+-----------------------
+Represents a delegation stateid. The nfs4_client holds references to these and
+they are put when it is being destroyed or when the delegation is returned by
+the client.
+
+If the server attempts to recall a delegation and the client doesn't do so
+before a timeout, the server may also revoke the delegation. In that case, the
+object will either be destroyed (v4.0) or moved to a per-client list of revoked
+delegations (v4.1+).
+
+This object is a superset of the nfs4_stid.
-- 
1.9.3


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

* Re: [PATCH v2 001/117] nfsd: fix file access refcount leak when nfsd4_truncate fails
  2014-06-26 19:11 ` [PATCH v2 001/117] nfsd: fix file access refcount leak when nfsd4_truncate fails Jeff Layton
@ 2014-06-26 19:24   ` Jeff Layton
  2014-06-28 11:00     ` Christoph Hellwig
  0 siblings, 1 reply; 162+ messages in thread
From: Jeff Layton @ 2014-06-26 19:24 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: bfields, linux-nfs

On Thu, 26 Jun 2014 15:11:41 -0400
Jeff Layton <jlayton@primarydata.com> wrote:

> From: Christoph Hellwig <hch@infradead.org>
> 
> nfsd4_process_open2 will currently will get access to the file, and then
> call nfsd4_truncate to (possibly) truncate it. If that operation fails
> though, then the access references will never be released as the
> nfs4_ol_stateid is never initialized.
> 
> Fix by moving the nfsd4_truncate call into nfs4_get_vfs_file, ensuring
> that the refcounts are properly put if the truncate fails.
> 
> Signed-off-by: Jeff Layton <jlayton@primarydata.com>
> Signed-off-by: Christoph Hellwig <hch@infradead.org>

Christoph, I took the liberty of composing a commit log and adding your
SOB line here. Let me know if you have any objections.

Thanks,
Jeff

> ---
>  fs/nfsd/nfs4state.c | 62
> ++++++++++++++++++++++++++--------------------------- 1 file changed,
> 30 insertions(+), 32 deletions(-)
> 
> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> index 2204e1fe5725..f9049516bfae 100644
> --- a/fs/nfsd/nfs4state.c
> +++ b/fs/nfsd/nfs4state.c
> @@ -3042,6 +3042,21 @@ static inline int nfs4_access_to_access(u32
> nfs4_access) return flags;
>  }
>  
> +static inline __be32
> +nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh,
> +		struct nfsd4_open *open)
> +{
> +	struct iattr iattr = {
> +		.ia_valid = ATTR_SIZE,
> +		.ia_size = 0,
> +	};
> +	if (!open->op_truncate)
> +		return 0;
> +	if (!(open->op_share_access & NFS4_SHARE_ACCESS_WRITE))
> +		return nfserr_inval;
> +	return nfsd_setattr(rqstp, fh, &iattr, 0, (time_t)0);
> +}
> +
>  static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct
> nfs4_file *fp, struct svc_fh *cur_fh, struct nfsd4_open *open)
>  {
> @@ -3053,53 +3068,39 @@ static __be32 nfs4_get_vfs_file(struct
> svc_rqst *rqstp, struct nfs4_file *fp, status = nfsd_open(rqstp,
> cur_fh, S_IFREG, access, &fp->fi_fds[oflag]);
>  		if (status)
> -			return status;
> +			goto out;
>  	}
>  	nfs4_file_get_access(fp, oflag);
>  
> +	status = nfsd4_truncate(rqstp, cur_fh, open);
> +	if (status)
> +		goto out_put_access;
> +
>  	return nfs_ok;
> -}
>  
> -static inline __be32
> -nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh,
> -		struct nfsd4_open *open)
> -{
> -	struct iattr iattr = {
> -		.ia_valid = ATTR_SIZE,
> -		.ia_size = 0,
> -	};
> -	if (!open->op_truncate)
> -		return 0;
> -	if (!(open->op_share_access & NFS4_SHARE_ACCESS_WRITE))
> -		return nfserr_inval;
> -	return nfsd_setattr(rqstp, fh, &iattr, 0, (time_t)0);
> +out_put_access:
> +	nfs4_file_put_access(fp, oflag);
> +out:
> +	return status;
>  }
>  
>  static __be32
>  nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp,
> struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp, struct nfsd4_open
> *open) { u32 op_share_access = open->op_share_access;
> -	bool new_access;
>  	__be32 status;
>  
> -	new_access = !test_access(op_share_access, stp);
> -	if (new_access) {
> +	if (!test_access(op_share_access, stp))
>  		status = nfs4_get_vfs_file(rqstp, fp, cur_fh, open);
> -		if (status)
> -			return status;
> -	}
> -	status = nfsd4_truncate(rqstp, cur_fh, open);
> -	if (status) {
> -		if (new_access) {
> -			int oflag =
> nfs4_access_to_omode(op_share_access);
> -			nfs4_file_put_access(fp, oflag);
> -		}
> +	else
> +		status = nfsd4_truncate(rqstp, cur_fh, open);
> +
> +	if (status)
>  		return status;
> -	}
> +
>  	/* remember the open */
>  	set_access(op_share_access, stp);
>  	set_deny(open->op_share_deny, stp);
> -
>  	return nfs_ok;
>  }
>  
> @@ -3350,9 +3351,6 @@ nfsd4_process_open2(struct svc_rqst *rqstp,
> struct svc_fh *current_fh, struct nf status =
> nfs4_get_vfs_file(rqstp, fp, current_fh, open); if (status)
>  			goto out;
> -		status = nfsd4_truncate(rqstp, current_fh, open);
> -		if (status)
> -			goto out;
>  		stp = open->op_stp;
>  		open->op_stp = NULL;
>  		init_open_stateid(stp, fp, open);


-- 
Jeff Layton <jlayton@poochiereds.net>

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

* Re: [PATCH v2 000/117] nfsd: eliminate the client_mutex
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (116 preceding siblings ...)
  2014-06-26 19:21 ` [PATCH v2 117/117] nfsd: add file documenting new state object model Jeff Layton
@ 2014-06-27 16:22 ` J. Bruce Fields
  2014-06-27 19:08   ` Jeff Layton
  2014-06-30 12:51 ` Christoph Hellwig
  118 siblings, 1 reply; 162+ messages in thread
From: J. Bruce Fields @ 2014-06-27 16:22 UTC (permalink / raw)
  To: Jeff Layton; +Cc: linux-nfs

On Thu, Jun 26, 2014 at 03:11:40PM -0400, Jeff Layton wrote:
> I'd still like to see this merged for v3.17, so it would be ideal to
> merge this into linux-next soon if possible. Bruce, please let me know
> what you think the prospects are.

I'm currently using the "for-3.17" branch at

	git://linux-nfs.org/~bfields/linux.git

to hold any changes that I think are well and truly committed (so that
should be rebased never or only very rarely) and "nfsd-next" for things
that have been posted but may still be waiting for review (including
these), and may still be revised or dropped.

I should probably come up with some more sensible scheme....

I already had the first six patches.  I assumed without checking really
carefully that you hadn't revised the versions you sent me, let me know
if otherwise.

--b.

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

* Re: [PATCH v2 000/117] nfsd: eliminate the client_mutex
  2014-06-27 16:22 ` [PATCH v2 000/117] nfsd: eliminate the client_mutex J. Bruce Fields
@ 2014-06-27 19:08   ` Jeff Layton
  0 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-27 19:08 UTC (permalink / raw)
  To: J. Bruce Fields; +Cc: linux-nfs

On Fri, 27 Jun 2014 12:22:34 -0400
"J. Bruce Fields" <bfields@fieldses.org> wrote:

> On Thu, Jun 26, 2014 at 03:11:40PM -0400, Jeff Layton wrote:
> > I'd still like to see this merged for v3.17, so it would be ideal to
> > merge this into linux-next soon if possible. Bruce, please let me know
> > what you think the prospects are.
> 
> I'm currently using the "for-3.17" branch at
> 
> 	git://linux-nfs.org/~bfields/linux.git
> 
> to hold any changes that I think are well and truly committed (so that
> should be rebased never or only very rarely) and "nfsd-next" for things
> that have been posted but may still be waiting for review (including
> these), and may still be revised or dropped.
> 
> I should probably come up with some more sensible scheme....
> 

Ahh ok, I had looked the other day and didn't see them merged so I
figured it wouldn't hurt to resend them. Thanks for putting the pile
into nfsd-next! Let's hope it shakes loose some more bugs ;)

> I already had the first six patches.  I assumed without checking really
> carefully that you hadn't revised the versions you sent me, let me know
> if otherwise.
> 

That's correct -- the first six patches are unchanged.

-- 
Jeff Layton <jlayton@primarydata.com>

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

* Re: [PATCH v2 033/117] nfsd: ensure that nfs4_file_get_access enforces deny modes
  2014-06-26 19:12 ` [PATCH v2 033/117] nfsd: ensure that nfs4_file_get_access enforces deny modes Jeff Layton
@ 2014-06-27 19:59   ` Jeff Layton
  0 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-27 19:59 UTC (permalink / raw)
  To: bfields; +Cc: linux-nfs

On Thu, 26 Jun 2014 15:12:13 -0400
Jeff Layton <jlayton@primarydata.com> wrote:

> The current enforcement of deny modes is both inefficient and scattered.
> The former is a problem now, and the latter problem will mean races once
> the client_mutex is removed.
> 
> First, we address the inefficiency. We (necessarily) track deny modes on
> a per-stateid basis, but when we go to enforce them we have to walk the
> entire list of stateids and check against each one. Instead of doing
> that, maintain a per-nfs4_file deny mode.
> 
> When a file is opened, we simply set any deny bits in that mode that
> were specified in the OPEN call. We can then use that unified deny mode
> to do a simple check to see whether there are any conflicts without
> needing to walk the entire stateid list.
> 
> The only time we'll need to walk the entire list of stateids is when
> a stateid that has a deny mode on it is being released, or one is having
> its deny mode downgraded. In that case, we must walk the entire list
> and recalculate the fi_share_deny field. Since deny modes are pretty
> rare today, this shouldn't happen much under normal workloads.
> 
> To address the potential for races once the client_mutex is removed, we
> first check for conflicting deny modes in nfs4_file_get_access prior to
> opening the file. If it turns out that we need to do a VFS layer open of
> the file, then do so and recheck for conflicting deny modes afterward.
> If there are any, then just put access to the file and return
> nfserr_share_denied.
> 
> Finally, deal with potential races in get_lock_access. Taking an
> fi_access reference must be done under the fi_lock, or that could race
> with a nfs4_file_put_access call. Since we will have just dropped the
> lock after finding a readable or writeable file, add some *_locked
> variants of find_readable_file and find_writeable_file that we can call
> while already holding the fi_lock.
> 
> Signed-off-by: Jeff Layton <jlayton@primarydata.com>
> ---
>  fs/nfsd/nfs4state.c | 229 +++++++++++++++++++++++++++++++++++++++-------------
>  fs/nfsd/state.h     |   1 +
>  2 files changed, 172 insertions(+), 58 deletions(-)
> 
> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> index 0b6cd933eac6..93d175661c8d 100644
> --- a/fs/nfsd/nfs4state.c
> +++ b/fs/nfsd/nfs4state.c
> @@ -276,27 +276,49 @@ static struct file *__nfs4_get_fd(struct nfs4_file *f, int oflag)
>  	return NULL;
>  }
>  
> -static struct file *find_writeable_file(struct nfs4_file *f)
> +static struct file *find_writeable_file_locked(struct nfs4_file *f)
>  {
>  	struct file *ret;
>  
> -	spin_lock(&f->fi_lock);
> +	lockdep_assert_held(&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)
> +static struct file *find_writeable_file(struct nfs4_file *f)
>  {
>  	struct file *ret;
>  
>  	spin_lock(&f->fi_lock);
> +	ret = find_writeable_file_locked(f);
> +	spin_unlock(&f->fi_lock);
> +
> +	return ret;
> +}
> +
> +static struct file *find_readable_file_locked(struct nfs4_file *f)
> +{
> +	struct file *ret;
> +
> +	lockdep_assert_held(&f->fi_lock);
> +
>  	ret = __nfs4_get_fd(f, O_RDONLY);
>  	if (!ret)
>  		ret = __nfs4_get_fd(f, O_RDWR);
> +	return ret;
> +}
> +
> +static struct file *find_readable_file(struct nfs4_file *f)
> +{
> +	struct file *ret;
> +
> +	spin_lock(&f->fi_lock);
> +	ret = find_readable_file_locked(f);
>  	spin_unlock(&f->fi_lock);
> +
>  	return ret;
>  }
>  
> @@ -362,26 +384,72 @@ static unsigned int file_hashval(struct inode *ino)
>  
>  static struct hlist_head file_hashtbl[FILE_HASH_SIZE];
>  
> -static void __nfs4_file_get_access(struct nfs4_file *fp, int oflag)
> +static void
> +__nfs4_file_get_access(struct nfs4_file *fp, u32 access)
>  {
> -	WARN_ON_ONCE(!(fp->fi_fds[oflag] || fp->fi_fds[O_RDWR]));
> -	atomic_inc(&fp->fi_access[oflag]);
> +	int oflag = nfs4_access_to_omode(access);
> +
> +	lockdep_assert_held(&fp->fi_lock);
> +
> +	if (oflag == O_RDWR) {
> +		atomic_inc(&fp->fi_access[O_RDONLY]);
> +		atomic_inc(&fp->fi_access[O_WRONLY]);
> +	} else
> +		atomic_inc(&fp->fi_access[oflag]);
>  }
>  
> -static void nfs4_file_get_access(struct nfs4_file *fp, u32 access)
> +static __be32
> +nfs4_file_get_access(struct nfs4_file *fp, u32 access)
>  {
> -	int oflag = nfs4_access_to_omode(access);
> -
>  	/* Note: relies on NFS4_SHARE_ACCESS_BOTH == READ|WRITE */
> -	access &= (NFS4_SHARE_ACCESS_READ|NFS4_SHARE_ACCESS_WRITE);
> +	access &= NFS4_SHARE_ACCESS_BOTH;
> +
> +	/* Does this access mask make sense? */
>  	if (access == 0)
> -		return;
> +		return nfserr_inval;
>  
> -	if (oflag == O_RDWR) {
> -		__nfs4_file_get_access(fp, O_RDONLY);
> -		__nfs4_file_get_access(fp, O_WRONLY);
> -	} else
> -		__nfs4_file_get_access(fp, oflag);
> +	/* Does it conflict with a deny mode already set? */
> +	if ((access & fp->fi_share_deny) != 0)
> +		return nfserr_share_denied;
> +
> +	__nfs4_file_get_access(fp, access);
> +	return nfs_ok;
> +}
> +
> +static __be32 nfs4_file_check_deny(struct nfs4_file *fp, u32 access, u32 deny)
> +{
> +	int rdcnt = 0;
> +	int wrcnt = 0;
> +
> +	lockdep_assert_held(&fp->fi_lock);
> +

We should optimize this function for the vastly common case where
"deny" is 0. Check for that and return nfs_ok immediately if it is.

> +	/*
> +	 * We must take into account any references that were already taken
> +	 * on behalf of this open attempt.
> +	 */
> +	switch (access) {
> +	case NFS4_SHARE_ACCESS_READ:
> +		++rdcnt;
> +		break;
> +	case NFS4_SHARE_ACCESS_WRITE:
> +		++wrcnt;
> +		break;
> +	case NFS4_SHARE_ACCESS_BOTH:
> +		++rdcnt;
> +		++wrcnt;
> +	}
> +
> +	/* Note: relies on NFS4_SHARE_DENY_BOTH == READ|WRITE */
> +	deny &= NFS4_SHARE_DENY_BOTH;
> +	if (deny) {
> +		if ((deny & NFS4_SHARE_DENY_READ) &&
> +		    (atomic_read(&fp->fi_access[O_RDONLY]) - rdcnt) > 0)
> +			return nfserr_share_denied;
> +		if ((deny & NFS4_SHARE_DENY_WRITE) &&
> +		    (atomic_read(&fp->fi_access[O_WRONLY]) - wrcnt) > 0)
> +			return nfserr_share_denied;
> +	}
> +	return nfs_ok;
>  }
>  
>  static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag)
> @@ -710,17 +778,6 @@ bmap_to_share_mode(unsigned long bmap) {
>  	return access;
>  }
>  
> -static bool
> -test_share(struct nfs4_ol_stateid *stp, struct nfsd4_open *open) {
> -	unsigned int access, deny;
> -
> -	access = bmap_to_share_mode(stp->st_access_bmap);
> -	deny = bmap_to_share_mode(stp->st_deny_bmap);
> -	if ((access & open->op_share_deny) || (deny & open->op_share_access))
> -		return false;
> -	return true;
> -}
> -
>  /* set share access for a given stateid */
>  static inline void
>  set_access(u32 access, struct nfs4_ol_stateid *stp)
> @@ -763,11 +820,31 @@ test_deny(u32 access, struct nfs4_ol_stateid *stp)
>  	return test_bit(access, &stp->st_deny_bmap);
>  }
>  
> +/*
> + * A stateid that had a deny mode associated with it is being released
> + * or downgraded. Recalculate the deny mode on the file.
> + */
> +static void
> +recalculate_deny_mode(struct nfs4_file *fp)
> +{
> +	struct nfs4_ol_stateid *stp;
> +
> +	spin_lock(&fp->fi_lock);
> +	fp->fi_share_deny = 0;
> +	list_for_each_entry(stp, &fp->fi_stateids, st_perfile)
> +		fp->fi_share_deny |= bmap_to_share_mode(stp->st_deny_bmap);
> +	spin_unlock(&fp->fi_lock);
> +}
> +
>  /* release all access and file references for a given stateid */
>  static void
>  release_all_access(struct nfs4_ol_stateid *stp)
>  {
>  	int i;
> +	struct nfs4_file *fp = stp->st_file;
> +
> +	if (fp && stp->st_deny_bmap != 0)
> +		recalculate_deny_mode(fp);
>  
>  	for (i = 1; i < 4; i++) {
>  		if (test_access(i, stp))
> @@ -2760,6 +2837,7 @@ static void nfsd4_init_file(struct nfs4_file *fp, struct inode *ino)
>  	fp->fi_inode = ino;
>  	fp->fi_had_conflict = false;
>  	fp->fi_lease = NULL;
> +	fp->fi_share_deny = 0;
>  	memset(fp->fi_fds, 0, sizeof(fp->fi_fds));
>  	memset(fp->fi_access, 0, sizeof(fp->fi_access));
>  	hlist_add_head(&fp->fi_hash, &file_hashtbl[hashval]);
> @@ -2988,22 +3066,15 @@ nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type)
>  {
>  	struct inode *ino = current_fh->fh_dentry->d_inode;
>  	struct nfs4_file *fp;
> -	struct nfs4_ol_stateid *stp;
> -	__be32 ret;
> +	__be32 ret = nfs_ok;
>  
>  	fp = find_file(ino);
>  	if (!fp)
> -		return nfs_ok;
> -	ret = nfserr_locked;
> -	/* Search for conflicting share reservations */
> +		return ret;
> +	/* Check 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))
> -			goto out;
> -	}
> -	ret = nfs_ok;
> -out:
> +	if (fp->fi_share_deny & deny_type)
> +		ret = nfserr_locked;
>  	spin_unlock(&fp->fi_lock);
>  	put_nfs4_file(fp);
>  	return ret;
> @@ -3204,21 +3275,18 @@ 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);
> +	lockdep_assert_held(&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)
>  			continue;
>  		/* remember if we have seen this open owner */
> -		if (local->st_stateowner == &oo->oo_owner)
> +		if (local->st_stateowner == &oo->oo_owner) {
>  			*stpp = local;
> -		/* check for conflicting share reservations */
> -		if (!test_share(local, open)) {
> -			spin_unlock(&fp->fi_lock);
> -			return nfserr_share_denied;
> +			break;
>  		}
>  	}
> -	spin_unlock(&fp->fi_lock);
>  	return nfs_ok;
>  }
>  
> @@ -3257,18 +3325,46 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
>  	int access = nfs4_access_to_access(open->op_share_access);
>  
>  	spin_lock(&fp->fi_lock);
> +	/* Are we trying to set a deny mode that would conflict? */
> +	status = nfs4_file_check_deny(fp, 0, open->op_share_deny);
> +	if (status != nfs_ok) {
> +		spin_unlock(&fp->fi_lock);
> +		goto out;
> +	}
> +
> +	/* Set access to the file */
> +	status = nfs4_file_get_access(fp, open->op_share_access);
> +	if (status != nfs_ok) {
> +		spin_unlock(&fp->fi_lock);
> +		goto out;
> +	}
> +
>  	if (!fp->fi_fds[oflag]) {
>  		spin_unlock(&fp->fi_lock);
>  		status = nfsd_open(rqstp, cur_fh, S_IFREG, access, &filp);
>  		if (status)
> -			goto out;
> +			goto out_put_access;
>  		spin_lock(&fp->fi_lock);
>  		if (!fp->fi_fds[oflag]) {
>  			fp->fi_fds[oflag] = filp;
>  			filp = NULL;
>  		}
> +
> +		/*
> +		 * Recheck: did someone race in and open the file in a way that
> +		 *	    would conflict with our deny bits?
> +		 */
> +		if (nfs4_file_check_deny(fp, open->op_share_access,
> +					 open->op_share_deny)) {
> +			spin_unlock(&fp->fi_lock);
> +			status = nfserr_share_denied;
> +			goto out_put_access;
> +		}
> +
> +		/* Set any new deny bits */
> +		fp->fi_share_deny |= (open->op_share_deny &
> +					NFS4_SHARE_DENY_BOTH);

Oof, I think we have a potential race here. It's possible that we'll
end up setting new bits in fi_share_deny, but then another task comes
along and does a recalculation of it just after the fi_lock is dropped
below. Since the stateid isn't hashed yet, it won't get factored into
the recalculated deny mode and we'll lose those bits.

I think the remedy is probably to go ahead and just hash the stateid
before calling nfs4_get_vfs_file. Then if it returns error, we'll just
have to unhash it and ensure that it's eventually destroyed.

So, this patch will probably need a respin to deal with that.

>  	}
> -	nfs4_file_get_access(fp, open->op_share_access);
>  	spin_unlock(&fp->fi_lock);
>  	if (filp)
>  		fput(filp);
> @@ -3276,13 +3372,11 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
>  	status = nfsd4_truncate(rqstp, cur_fh, open);
>  	if (status)
>  		goto out_put_access;
> -
> -	return nfs_ok;
> -
> -out_put_access:
> -	nfs4_file_put_access(fp, open->op_share_access);
>  out:
>  	return status;
> +out_put_access:
> +	nfs4_file_put_access(fp, open->op_share_access);
> +	goto out;
>  }
>  
>  static __be32
> @@ -3526,7 +3620,12 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
>  	 */
>  	fp = find_or_add_file(ino, open->op_file);
>  	if (fp != open->op_file) {
> -		if ((status = nfs4_check_open(fp, open, &stp)))
> +		spin_lock(&fp->fi_lock);
> +		status = nfs4_file_check_deny(fp, 0, open->op_share_deny);
> +		if (status == nfs_ok)
> +			status = nfs4_check_open(fp, open, &stp);
> +		spin_unlock(&fp->fi_lock);
> +		if (status)
>  			goto out;
>  		status = nfs4_check_deleg(cl, open, &dp);
>  		if (status)
> @@ -4241,10 +4340,16 @@ static void
>  reset_union_bmap_deny(unsigned long deny, struct nfs4_ol_stateid *stp)
>  {
>  	int i;
> +	u32 prev_deny = bmap_to_share_mode(stp->st_deny_bmap);
> +
>  	for (i = 0; i < 4; i++) {
>  		if ((i & deny) != i)
>  			clear_deny(i, stp);
>  	}
> +
> +	/* Downgrade per-file deny mode if this one changed */
> +	if (prev_deny != deny)
> +		recalculate_deny_mode(stp->st_file);
>  }
>  
>  __be32
> @@ -4541,9 +4646,11 @@ static void get_lock_access(struct nfs4_ol_stateid *lock_stp, u32 access)
>  {
>  	struct nfs4_file *fp = lock_stp->st_file;
>  
> +	lockdep_assert_held(&fp->fi_lock);
> +
>  	if (test_access(access, lock_stp))
>  		return;
> -	nfs4_file_get_access(fp, access);
> +	__nfs4_file_get_access(fp, access);
>  	set_access(access, lock_stp);
>  }
>  
> @@ -4595,6 +4702,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
>  	struct file *filp = NULL;
>  	struct file_lock *file_lock = NULL;
>  	struct file_lock *conflock = NULL;
> +	struct nfs4_file *fp;
>  	__be32 status = 0;
>  	bool new_state = false;
>  	int lkflg;
> @@ -4672,20 +4780,25 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
>  		goto out;
>  	}
>  
> +	fp = lock_stp->st_file;
>  	locks_init_lock(file_lock);
>  	switch (lock->lk_type) {
>  		case NFS4_READ_LT:
>  		case NFS4_READW_LT:
> -			filp = find_readable_file(lock_stp->st_file);
> +			spin_lock(&fp->fi_lock);
> +			filp = find_readable_file_locked(fp);
>  			if (filp)
>  				get_lock_access(lock_stp, NFS4_SHARE_ACCESS_READ);
> +			spin_unlock(&fp->fi_lock);
>  			file_lock->fl_type = F_RDLCK;
>  			break;
>  		case NFS4_WRITE_LT:
>  		case NFS4_WRITEW_LT:
> -			filp = find_writeable_file(lock_stp->st_file);
> +			spin_lock(&fp->fi_lock);
> +			filp = find_writeable_file_locked(fp);
>  			if (filp)
>  				get_lock_access(lock_stp, NFS4_SHARE_ACCESS_WRITE);
> +			spin_unlock(&fp->fi_lock);
>  			file_lock->fl_type = F_WRLCK;
>  			break;
>  		default:
> diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
> index dc56ec234df7..561b94181751 100644
> --- a/fs/nfsd/state.h
> +++ b/fs/nfsd/state.h
> @@ -392,6 +392,7 @@ struct nfs4_file {
>  	 *   + 1 to both of the above if NFS4_SHARE_ACCESS_BOTH is set.
>  	 */
>  	atomic_t		fi_access[2];
> +	u32			fi_share_deny;
>  	struct file		*fi_deleg_file;
>  	struct file_lock	*fi_lease;
>  	atomic_t		fi_delegees;


-- 
Jeff Layton <jlayton@primarydata.com>

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

* Re: [PATCH v2 001/117] nfsd: fix file access refcount leak when nfsd4_truncate fails
  2014-06-26 19:24   ` Jeff Layton
@ 2014-06-28 11:00     ` Christoph Hellwig
  0 siblings, 0 replies; 162+ messages in thread
From: Christoph Hellwig @ 2014-06-28 11:00 UTC (permalink / raw)
  To: Jeff Layton; +Cc: Christoph Hellwig, bfields, linux-nfs

On Thu, Jun 26, 2014 at 03:24:12PM -0400, Jeff Layton wrote:
> On Thu, 26 Jun 2014 15:11:41 -0400
> Jeff Layton <jlayton@primarydata.com> wrote:
> 
> > From: Christoph Hellwig <hch@infradead.org>
> > 
> > nfsd4_process_open2 will currently will get access to the file, and then
> > call nfsd4_truncate to (possibly) truncate it. If that operation fails
> > though, then the access references will never be released as the
> > nfs4_ol_stateid is never initialized.
> > 
> > Fix by moving the nfsd4_truncate call into nfs4_get_vfs_file, ensuring
> > that the refcounts are properly put if the truncate fails.
> > 
> > Signed-off-by: Jeff Layton <jlayton@primarydata.com>
> > Signed-off-by: Christoph Hellwig <hch@infradead.org>
> 
> Christoph, I took the liberty of composing a commit log and adding your
> SOB line here. Let me know if you have any objections.

Thanks, I should have done that myself earlier.


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

* Re: [PATCH v2 007/117] nfsd: properly handle embedded newlines in fault_injection input
  2014-06-26 19:11 ` [PATCH v2 007/117] nfsd: properly handle embedded newlines in fault_injection input Jeff Layton
@ 2014-06-28 11:01   ` Christoph Hellwig
  0 siblings, 0 replies; 162+ messages in thread
From: Christoph Hellwig @ 2014-06-28 11:01 UTC (permalink / raw)
  To: Jeff Layton; +Cc: bfields, linux-nfs

On Thu, Jun 26, 2014 at 03:11:47PM -0400, Jeff Layton wrote:
> Currently rpc_pton() fails to handle the case where you echo an address
> into the file, as it barfs on the newline. Ensure that we NULL out the
> first occurrence of any newline.
> 
> Signed-off-by: Jeff Layton <jlayton@primarydata.com>

Looks good,

Reviewed-by: Christoph Hellwig <hch@lst.de>

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

* Re: [PATCH v2 009/117] nfsd: wait to initialize work struct just prior to using it
  2014-06-26 19:11 ` [PATCH v2 009/117] nfsd: wait to initialize work struct just prior to using it Jeff Layton
@ 2014-06-28 11:02   ` Christoph Hellwig
  0 siblings, 0 replies; 162+ messages in thread
From: Christoph Hellwig @ 2014-06-28 11:02 UTC (permalink / raw)
  To: Jeff Layton; +Cc: bfields, linux-nfs

On Thu, Jun 26, 2014 at 03:11:49PM -0400, Jeff Layton wrote:
> There's a fair chance we won't ever need this work struct, so we might
> as well delay initializing it until just before we're going to use it.
> In a later patch, we'll need to intialize the work with a different
> function for delegation callbacks. By delaying this, we avoid having
> to do it twice.
> 
> Signed-off-by: Jeff Layton <jlayton@primarydata.com>

Looks good,

Reviewed-by: Christoph Hellwig <hch@lst.de>

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

* Re: [PATCH v2 010/117] nfsd: Avoid taking state_lock while holding inode lock in nfsd_break_one_deleg
  2014-06-26 19:11 ` [PATCH v2 010/117] nfsd: Avoid taking state_lock while holding inode lock in nfsd_break_one_deleg Jeff Layton
@ 2014-06-28 11:06   ` Christoph Hellwig
  2014-06-28 12:18     ` Jeff Layton
  0 siblings, 1 reply; 162+ messages in thread
From: Christoph Hellwig @ 2014-06-28 11:06 UTC (permalink / raw)
  To: Jeff Layton; +Cc: bfields, linux-nfs

> +static void nfsd4_do_callback_rpc(struct work_struct *w)

nfsd4_run_cb_null?

> +static void nfsd4_do_cb_recall(struct work_struct *w)

nfsd4_run_cb_recall?


Not entirely sure about the name, but I think they should be:

 a) consistent between the two
 b) have somewhat sensible name for the null/probe one

Otherwise looks good to me,

Reviewed-by: Christoph Hellwig <hch@lst.de>

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

* Re: [PATCH v2 015/117] nfsd: lock owners are not per open stateid
  2014-06-26 19:11 ` [PATCH v2 015/117] nfsd: lock owners are not per open stateid Jeff Layton
@ 2014-06-28 11:07   ` Christoph Hellwig
  0 siblings, 0 replies; 162+ messages in thread
From: Christoph Hellwig @ 2014-06-28 11:07 UTC (permalink / raw)
  To: Jeff Layton; +Cc: bfields, linux-nfs, Trond Myklebust

On Thu, Jun 26, 2014 at 03:11:55PM -0400, Jeff Layton wrote:
> From: Trond Myklebust <trond.myklebust@primarydata.com>
> 
> 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 stateids
> with a list of lock stateids.
> 
> Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>

Looks good,

Reviewed-by: Christoph Hellwig <hch@lst.de>

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

* Re: [PATCH v2 010/117] nfsd: Avoid taking state_lock while holding inode lock in nfsd_break_one_deleg
  2014-06-28 11:06   ` Christoph Hellwig
@ 2014-06-28 12:18     ` Jeff Layton
  0 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-28 12:18 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: bfields, linux-nfs

On Sat, 28 Jun 2014 04:06:42 -0700
Christoph Hellwig <hch@infradead.org> wrote:

> > +static void nfsd4_do_callback_rpc(struct work_struct *w)
> 
> nfsd4_run_cb_null?
> 
> > +static void nfsd4_do_cb_recall(struct work_struct *w)
> 
> nfsd4_run_cb_recall?
> 
> 
> Not entirely sure about the name, but I think they should be:
> 
>  a) consistent between the two
>  b) have somewhat sensible name for the null/probe one
> 
> Otherwise looks good to me,
> 
> Reviewed-by: Christoph Hellwig <hch@lst.de>

Those names sound fine to me. I'll change the patch to use them instead.

Thanks,
-- 
Jeff Layton <jlayton@primarydata.com>

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

* Re: [PATCH v2 018/117] nfsd: clean up nfs4_release_lockowner
  2014-06-26 19:11 ` [PATCH v2 018/117] nfsd: clean up nfs4_release_lockowner Jeff Layton
@ 2014-06-29  6:47   ` Christoph Hellwig
  2014-06-29 11:08     ` Jeff Layton
  0 siblings, 1 reply; 162+ messages in thread
From: Christoph Hellwig @ 2014-06-29  6:47 UTC (permalink / raw)
  To: Jeff Layton; +Cc: bfields, linux-nfs

On Thu, Jun 26, 2014 at 03:11:58PM -0400, Jeff Layton wrote:
> Now that we know that we won't have several lockowners with the same,
> owner->data, we can simplify nfs4_release_lockowner and get rid of
> the lo_list in the process.
> 
> Signed-off-by: Jeff Layton <jlayton@primarydata.com>
> ---
>  fs/nfsd/nfs4state.c | 44 ++++++++++++++++++++++----------------------
>  fs/nfsd/state.h     |  1 -
>  2 files changed, 22 insertions(+), 23 deletions(-)
> 
> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> index 00a1b2cda3ab..a5bb96b97f09 100644
> --- a/fs/nfsd/nfs4state.c
> +++ b/fs/nfsd/nfs4state.c
> @@ -4828,7 +4828,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
>  			struct nfsd4_release_lockowner *rlockowner)
>  {
>  	clientid_t *clid = &rlockowner->rl_clientid;
> -	struct nfs4_stateowner *sop;
> +	struct nfs4_stateowner *sop = NULL, *tmp;
>  	struct nfs4_lockowner *lo;
>  	struct nfs4_ol_stateid *stp;
>  	struct xdr_netobj *owner = &rlockowner->rl_owner;
> @@ -4849,31 +4849,31 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
>  	status = nfserr_locks_held;
>  	INIT_LIST_HEAD(&matches);

I think matches is unused now.

>  
> +	/* Find the matching lock stateowner */
> +	list_for_each_entry(tmp, &nn->ownerstr_hashtbl[hashval], so_strhash) {
> +		if (tmp->so_is_open_owner)
> +			continue;
> +		if (same_owner_str(tmp, owner, clid)) {
> +			sop = tmp;
> +			break;
>  		}
>  	}
> +
> +	/* No matching owner found, maybe a replay? Just declare victory... */
> +	if (!sop) {
> +		status = nfs_ok;
> +		goto out;
> +	}
> +
> +	lo = lockowner(sop);
> +	/* see if there are still any locks associated with it */
> +	list_for_each_entry(stp, &sop->so_stateids, st_perstateowner) {
> +		if (check_for_locks(stp->st_file, lo))
> +			goto out;
>  	}
> +
> +	status = nfs_ok;
> +	release_lockowner(lo);

I would seem simpler to do all the work in the loop, something like:

	list_for_each_entry(sop, &nn->ownerstr_hashtbl[hashval], so_strhash) {
		if (sop->so_is_open_owner)
			continue;
		if (!same_owner_str(sop, owner, clid))
			continue;

		list_for_each_entry(stp, &sop->so_stateids, st_perstateowner) {
			if (check_for_locks(stp->st_file, lockowner(sop))) {
				status = nfserr_locks_held;
				goto out;
			}
		}

		release_lockowner(lo);
		break;
	}


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

* Re: [PATCH v2 019/117] nfsd: declare v4.1+ openowners confirmed on creation
  2014-06-26 19:11 ` [PATCH v2 019/117] nfsd: declare v4.1+ openowners confirmed on creation Jeff Layton
@ 2014-06-29  6:48   ` Christoph Hellwig
  0 siblings, 0 replies; 162+ messages in thread
From: Christoph Hellwig @ 2014-06-29  6:48 UTC (permalink / raw)
  To: Jeff Layton; +Cc: bfields, linux-nfs

On Thu, Jun 26, 2014 at 03:11:59PM -0400, Jeff Layton wrote:
> There's no need to confirm an openowner in v4.1 and above, so we can
> go ahead and set NFS4_OO_CONFIRMED when we create openowners in
> those versions. This will also be necessary when we remove the
> client_mutex, as it'll be possible for two concurrent opens to race
> in versions >4.0.
> 
> Signed-off-by: Jeff Layton <jlayton@primarydata.com>

Looks good,

Reviewed-by: Christoph Hellwig <hch@lst.de>

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

* Re: [PATCH v2 020/117] nfsd: Cleanup - Let nfsd4_lookup_stateid() take a cstate argument
  2014-06-26 19:12 ` [PATCH v2 020/117] nfsd: Cleanup - Let nfsd4_lookup_stateid() take a cstate argument Jeff Layton
@ 2014-06-29  6:49   ` Christoph Hellwig
  0 siblings, 0 replies; 162+ messages in thread
From: Christoph Hellwig @ 2014-06-29  6:49 UTC (permalink / raw)
  To: Jeff Layton; +Cc: bfields, linux-nfs, Trond Myklebust

On Thu, Jun 26, 2014 at 03:12:00PM -0400, Jeff Layton wrote:
> From: Trond Myklebust <trond.myklebust@primarydata.com>
> 
> 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>

Looks good,

Reviewed-by: Christoph Hellwig <hch@lst.de>

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

* Re: [PATCH v2 018/117] nfsd: clean up nfs4_release_lockowner
  2014-06-29  6:47   ` Christoph Hellwig
@ 2014-06-29 11:08     ` Jeff Layton
  2014-06-30 11:02       ` Jeff Layton
  0 siblings, 1 reply; 162+ messages in thread
From: Jeff Layton @ 2014-06-29 11:08 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: bfields, linux-nfs

On Sat, 28 Jun 2014 23:47:38 -0700
Christoph Hellwig <hch@infradead.org> wrote:

> On Thu, Jun 26, 2014 at 03:11:58PM -0400, Jeff Layton wrote:
> > Now that we know that we won't have several lockowners with the same,
> > owner->data, we can simplify nfs4_release_lockowner and get rid of
> > the lo_list in the process.
> > 
> > Signed-off-by: Jeff Layton <jlayton@primarydata.com>
> > ---
> >  fs/nfsd/nfs4state.c | 44 ++++++++++++++++++++++----------------------
> >  fs/nfsd/state.h     |  1 -
> >  2 files changed, 22 insertions(+), 23 deletions(-)
> > 
> > diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> > index 00a1b2cda3ab..a5bb96b97f09 100644
> > --- a/fs/nfsd/nfs4state.c
> > +++ b/fs/nfsd/nfs4state.c
> > @@ -4828,7 +4828,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
> >  			struct nfsd4_release_lockowner *rlockowner)
> >  {
> >  	clientid_t *clid = &rlockowner->rl_clientid;
> > -	struct nfs4_stateowner *sop;
> > +	struct nfs4_stateowner *sop = NULL, *tmp;
> >  	struct nfs4_lockowner *lo;
> >  	struct nfs4_ol_stateid *stp;
> >  	struct xdr_netobj *owner = &rlockowner->rl_owner;
> > @@ -4849,31 +4849,31 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
> >  	status = nfserr_locks_held;
> >  	INIT_LIST_HEAD(&matches);
> 
> I think matches is unused now.
> 

Yep -- good catch.

> >  
> > +	/* Find the matching lock stateowner */
> > +	list_for_each_entry(tmp, &nn->ownerstr_hashtbl[hashval], so_strhash) {
> > +		if (tmp->so_is_open_owner)
> > +			continue;
> > +		if (same_owner_str(tmp, owner, clid)) {
> > +			sop = tmp;
> > +			break;
> >  		}
> >  	}
> > +
> > +	/* No matching owner found, maybe a replay? Just declare victory... */
> > +	if (!sop) {
> > +		status = nfs_ok;
> > +		goto out;
> > +	}
> > +
> > +	lo = lockowner(sop);
> > +	/* see if there are still any locks associated with it */
> > +	list_for_each_entry(stp, &sop->so_stateids, st_perstateowner) {
> > +		if (check_for_locks(stp->st_file, lo))
> > +			goto out;
> >  	}
> > +
> > +	status = nfs_ok;
> > +	release_lockowner(lo);
> 
> I would seem simpler to do all the work in the loop, something like:
> 
> 	list_for_each_entry(sop, &nn->ownerstr_hashtbl[hashval], so_strhash) {
> 		if (sop->so_is_open_owner)
> 			continue;
> 		if (!same_owner_str(sop, owner, clid))
> 			continue;
> 
> 		list_for_each_entry(stp, &sop->so_stateids, st_perstateowner) {
> 			if (check_for_locks(stp->st_file, lockowner(sop))) {
> 				status = nfserr_locks_held;
> 				goto out;
> 			}
> 		}
> 
> 		release_lockowner(lo);
> 		break;
> 	}
> 

Ok, sure...

-- 
Jeff Layton <jlayton@primarydata.com>

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

* Re: [PATCH v2 021/117] nfsd: clean up nfsd4_close_open_stateid
  2014-06-26 19:12 ` [PATCH v2 021/117] nfsd: clean up nfsd4_close_open_stateid Jeff Layton
@ 2014-06-29 12:00   ` Christoph Hellwig
  0 siblings, 0 replies; 162+ messages in thread
From: Christoph Hellwig @ 2014-06-29 12:00 UTC (permalink / raw)
  To: Jeff Layton; +Cc: bfields, linux-nfs, Trond Myklebust

On Thu, Jun 26, 2014 at 03:12:01PM -0400, Jeff Layton wrote:
> From: Trond Myklebust <trond.myklebust@primarydata.com>
> 
> Minor cleanup that should introduce no behavioral changes.
> 
> Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>

The actual change looks okay, the changelog is severly lacking,
as it nicer explains what changed nor why.


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

* Re: [PATCH v2 014/117] nfsd: Allow struct nfsd4_compound_state to cache the nfs4_client
  2014-06-26 19:11 ` [PATCH v2 014/117] nfsd: Allow struct nfsd4_compound_state to cache the nfs4_client Jeff Layton
@ 2014-06-29 12:05   ` Christoph Hellwig
  0 siblings, 0 replies; 162+ messages in thread
From: Christoph Hellwig @ 2014-06-29 12:05 UTC (permalink / raw)
  To: Jeff Layton; +Cc: bfields, linux-nfs, Trond Myklebust

On Thu, Jun 26, 2014 at 03:11:54PM -0400, Jeff Layton wrote:
> From: Trond Myklebust <trond.myklebust@primarydata.com>
> 
> This will be used later to accelerate lookups of the clientid.

While I've already given my reviewed by I need to get picky again here
after reviewing a later patch.  The description should clearly state
that we only cache it for 4.1+ here so far.

Unless something else speaks against that I'd also strongly recommend
we move the patch to also cache it for 4.0 right next after this patch.


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

* Re: [PATCH v2 022/117] nfsd: Cache the client that was looked up in lookup_clientid()
  2014-06-26 19:12 ` [PATCH v2 022/117] nfsd: Cache the client that was looked up in lookup_clientid() Jeff Layton
@ 2014-06-29 12:14   ` Christoph Hellwig
  2014-06-29 14:57     ` Jeff Layton
  0 siblings, 1 reply; 162+ messages in thread
From: Christoph Hellwig @ 2014-06-29 12:14 UTC (permalink / raw)
  To: Jeff Layton; +Cc: bfields, linux-nfs, Trond Myklebust

On Thu, Jun 26, 2014 at 03:12:02PM -0400, Jeff Layton wrote:
> From: Trond Myklebust <trond.myklebust@primarydata.com>
> 
> We want to use the nfsd4_compound_state to cache the nfs4_client
> in order to optimise away extra lookups of the clid.

Should mention that this is only for 4.0.  Actually, kooking at
"nfsd: Allow struct nfsd4_compound_state to cache the nfs4_client" that
patch seems to mostly be a few random code cleanups that should have
a different title so it might make more sense to move the caching
of the client for 4.1+ to this patch as well.

And please write proper, detailed changelogs :)

> +static __be32 lookup_clientid(clientid_t *clid,
> +		struct nfsd4_compound_state *cstate,
> +		struct nfsd_net *nn)

Now that we don't look up the client idea for the normal case but just
verify it we should probably rename this function to
nfsd4_verify_clientid or something similar.

While it doesn't belong into this patch:  why don't we cache the
nfsd_net in the nfsd4_compound_state

>  {
>  	struct nfs4_client *found;
>  
> +	if (cstate->clp != NULL) {
> +		found = cstate->clp;
> +		if (!same_clid(&found->cl_clientid, clid))
> +			return nfserr_stale_clientid;
> +	} else {
> +		if (STALE_CLIENTID(clid, nn))
> +			return nfserr_stale_clientid;
> +		/*
> +		 * Usually for v4.1+ we get the client in the SEQUENCE op, so

Usually implices there might be a case where we don't get it.  Which
case would that be?

> +		 * if we don't have one cached already then we know this is for
> +		 * is for v4.0 and "sessions" will be false.
> +		 */
> +		found = find_confirmed_client(clid, false, nn);
> +		/* Cache the nfs4_client in cstate! */
> +		if (found) {
> +			cstate->clp = found;
> +			atomic_inc(&found->cl_refcount);
> +		}
> +	}
>  	return found ? nfs_ok : nfserr_expired;

The whole thing could be simplified a little more:

	if (cstate->clp) {
		if (!same_clid(&cstate->clp->cl_clientid, clid))
			return nfserr_stale_clientid;
		retur nfs_ok;
	}

	if (STALE_CLIENTID(clid, nn))
		return nfserr_stale_clientid;

	found = find_confirmed_client(clid, false, nn);
	if (!found)
		return nfserr_expired;

	cstate->clp = found;
	atomic_inc(&found->cl_refcount);
	return nfs_ok;

> +	status = lookup_clientid(&stateid->si_opaque.so_clid, cstate, nn);
>  	if (status == nfserr_stale_clientid) {
> +		if (cstate->session)
>  			return nfserr_bad_stateid;
>  		return nfserr_stale_stateid;
>  	}

Why do we return a different error here for the 4.1+ case?  And why not
in other places using lookup_clientid?


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

* Re: [PATCH v2 023/117] nfsd: Convert nfsd4_process_open1() to work with lookup_clientid()
  2014-06-26 19:12 ` [PATCH v2 023/117] nfsd: Convert nfsd4_process_open1() to work with lookup_clientid() Jeff Layton
@ 2014-06-29 12:16   ` Christoph Hellwig
  2014-06-29 15:08     ` Jeff Layton
  0 siblings, 1 reply; 162+ messages in thread
From: Christoph Hellwig @ 2014-06-29 12:16 UTC (permalink / raw)
  To: Jeff Layton; +Cc: bfields, linux-nfs, Trond Myklebust

> +static __be32 lookup_clientid(clientid_t *clid,
> +		struct nfsd4_compound_state *cstate,
> +		struct nfsd_net *nn);

This hunk should have been in the previous patch.  Or given that
lookup_clientid was mostly rewritten it make sense to just move it to
avoid the forward declaration entirely.

Otherwise looks good to me,

Reviewed-by: Christoph Hellwig <hch@lst.de>

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

* Re: [PATCH v2 024/117] nfsd: Always use lookup_clientid() in nfsd4_process_open1
  2014-06-26 19:12 ` [PATCH v2 024/117] nfsd: Always use lookup_clientid() in nfsd4_process_open1 Jeff Layton
@ 2014-06-29 12:16   ` Christoph Hellwig
  0 siblings, 0 replies; 162+ messages in thread
From: Christoph Hellwig @ 2014-06-29 12:16 UTC (permalink / raw)
  To: Jeff Layton; +Cc: bfields, linux-nfs, Trond Myklebust

On Thu, Jun 26, 2014 at 03:12:04PM -0400, Jeff Layton wrote:
> From: Trond Myklebust <trond.myklebust@primarydata.com>
> 
> In later patches, we'll be moving the stateowner table into the
> nfs4_client, and by doing this we ensure that we have a cached
> nfs4_client pointer.
> 
> Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>

Looks good,

Reviewed-by: Christoph Hellwig <hch@lst.de>

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

* Re: [PATCH v2 025/117] nfsd: Convert nfs4_check_open_reclaim() to work with lookup_clientid()
  2014-06-26 19:12 ` [PATCH v2 025/117] nfsd: Convert nfs4_check_open_reclaim() to work with lookup_clientid() Jeff Layton
@ 2014-06-29 12:17   ` Christoph Hellwig
  0 siblings, 0 replies; 162+ messages in thread
From: Christoph Hellwig @ 2014-06-29 12:17 UTC (permalink / raw)
  To: Jeff Layton; +Cc: bfields, linux-nfs, Trond Myklebust

> -	return nfsd4_client_record_check(clp) ? nfserr_reclaim_bad : nfs_ok;
> +	return nfsd4_client_record_check(cstate->clp) ?
> +		nfserr_reclaim_bad : nfs_ok;

This would be more readanble with an good old if statement.

Otherwise looks good,

Reviewed-by: Christoph Hellwig <hch@lst.de>

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

* Re: [PATCH v2 022/117] nfsd: Cache the client that was looked up in lookup_clientid()
  2014-06-29 12:14   ` Christoph Hellwig
@ 2014-06-29 14:57     ` Jeff Layton
  2014-06-30 10:34       ` Christoph Hellwig
  0 siblings, 1 reply; 162+ messages in thread
From: Jeff Layton @ 2014-06-29 14:57 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: bfields, linux-nfs, Trond Myklebust

On Sun, 29 Jun 2014 05:14:19 -0700
Christoph Hellwig <hch@infradead.org> wrote:

> On Thu, Jun 26, 2014 at 03:12:02PM -0400, Jeff Layton wrote:
> > From: Trond Myklebust <trond.myklebust@primarydata.com>
> > 
> > We want to use the nfsd4_compound_state to cache the nfs4_client
> > in order to optimise away extra lookups of the clid.
> 
> Should mention that this is only for 4.0.  Actually, kooking at
> "nfsd: Allow struct nfsd4_compound_state to cache the nfs4_client" that
> patch seems to mostly be a few random code cleanups that should have
> a different title so it might make more sense to move the caching
> of the client for 4.1+ to this patch as well.
> 
> And please write proper, detailed changelogs :)
> 

Ok, I'll reshuffle those patches and squash them together, and flesh
out the changelog a bit more.

> > +static __be32 lookup_clientid(clientid_t *clid,
> > +		struct nfsd4_compound_state *cstate,
> > +		struct nfsd_net *nn)
> 
> Now that we don't look up the client idea for the normal case but just
> verify it we should probably rename this function to
> nfsd4_verify_clientid or something similar.
> 

Depends on what you mean by "normal case". For v4.0 we do look it up at
least once for each call into here. For v4.1 we get the pointer to the
client "for free" by virtue of looking up the session in the SEQUENCE
op. So, I think we are doing a bit more than just verifying the
clientid here. The name seems appropriate to me.

> While it doesn't belong into this patch:  why don't we cache the
> nfsd_net in the nfsd4_compound_state
> 

I'll go further and say that it doesn't really belong in this series.

If we have a pointer to the client, then we automatically have one to
the struct net. We certainly could cache the nfsd_net pointer and spare
some calls to net_generic, but I'd prefer that that be done as a
separate series on top of this one if it's worthwhile. I this series
brings us enough changes as it is. :)

> >  {
> >  	struct nfs4_client *found;
> >  
> > +	if (cstate->clp != NULL) {
> > +		found = cstate->clp;
> > +		if (!same_clid(&found->cl_clientid, clid))
> > +			return nfserr_stale_clientid;
> > +	} else {
> > +		if (STALE_CLIENTID(clid, nn))
> > +			return nfserr_stale_clientid;
> > +		/*
> > +		 * Usually for v4.1+ we get the client in the SEQUENCE op, so
> 
> Usually implices there might be a case where we don't get it.  Which
> case would that be?
> 

There are certain calls that don't require a SEQUENCE operation:

    BIND_CONN_TO_SESSION
    EXCHANGE_ID
    CREATE_SESSION
    DESTROY_SESSION

Granted, for those we don't use lookup_clientid but the "Usually" still
applies, in general. That said, if it bothers you I'll remove it.

> > +		 * if we don't have one cached already then we know this is for
> > +		 * is for v4.0 and "sessions" will be false.
> > +		 */
> > +		found = find_confirmed_client(clid, false, nn);
> > +		/* Cache the nfs4_client in cstate! */
> > +		if (found) {
> > +			cstate->clp = found;
> > +			atomic_inc(&found->cl_refcount);
> > +		}
> > +	}
> >  	return found ? nfs_ok : nfserr_expired;
> 
> The whole thing could be simplified a little more:
> 
> 	if (cstate->clp) {
> 		if (!same_clid(&cstate->clp->cl_clientid, clid))
> 			return nfserr_stale_clientid;
> 		retur nfs_ok;
> 	}
> 
> 	if (STALE_CLIENTID(clid, nn))
> 		return nfserr_stale_clientid;
> 
> 	found = find_confirmed_client(clid, false, nn);
> 	if (!found)
> 		return nfserr_expired;
> 
> 	cstate->clp = found;
> 	atomic_inc(&found->cl_refcount);
> 	return nfs_ok;
> 

Ok, I'll look into that.

> > +	status = lookup_clientid(&stateid->si_opaque.so_clid, cstate, nn);
> >  	if (status == nfserr_stale_clientid) {
> > +		if (cstate->session)
> >  			return nfserr_bad_stateid;
> >  		return nfserr_stale_stateid;
> >  	}
> 
> Why do we return a different error here for the 4.1+ case?  And why not
> in other places using lookup_clientid?
> 

That change predates this set, but see commit a8a7c6776f8d7478.

nfsd4_lookup_stateid is trying to look up a specific stateid -- the
other places that call lookup_clientid aren't necessarily doing so.
Returning that error may not be applicable there.

-- 
Jeff Layton <jlayton@primarydata.com>

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

* Re: [PATCH v2 023/117] nfsd: Convert nfsd4_process_open1() to work with lookup_clientid()
  2014-06-29 12:16   ` Christoph Hellwig
@ 2014-06-29 15:08     ` Jeff Layton
  2014-06-30 10:35       ` Christoph Hellwig
  0 siblings, 1 reply; 162+ messages in thread
From: Jeff Layton @ 2014-06-29 15:08 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: bfields, linux-nfs, Trond Myklebust

On Sun, 29 Jun 2014 05:16:00 -0700
Christoph Hellwig <hch@infradead.org> wrote:

> > +static __be32 lookup_clientid(clientid_t *clid,
> > +		struct nfsd4_compound_state *cstate,
> > +		struct nfsd_net *nn);
> 
> This hunk should have been in the previous patch.  Or given that
> lookup_clientid was mostly rewritten it make sense to just move it to
> avoid the forward declaration entirely.
> 

Does it? It's not until this patch that the forward declaration is
needed at all. That said, I have a general aversion to forward
declarations so moving it up sounds good to me.

> Otherwise looks good to me,
> 
> Reviewed-by: Christoph Hellwig <hch@lst.de>

Thanks!
-- 
Jeff Layton <jlayton@primarydata.com>

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

* Re: [PATCH v2 022/117] nfsd: Cache the client that was looked up in lookup_clientid()
  2014-06-29 14:57     ` Jeff Layton
@ 2014-06-30 10:34       ` Christoph Hellwig
  2014-06-30 10:59         ` Jeff Layton
  0 siblings, 1 reply; 162+ messages in thread
From: Christoph Hellwig @ 2014-06-30 10:34 UTC (permalink / raw)
  To: Jeff Layton; +Cc: bfields, linux-nfs, Trond Myklebust

On Sun, Jun 29, 2014 at 10:57:02AM -0400, Jeff Layton wrote:
> Depends on what you mean by "normal case". For v4.0 we do look it up at
> least once for each call into here. For v4.1 we get the pointer to the
> client "for free" by virtue of looking up the session in the SEQUENCE
> op. So, I think we are doing a bit more than just verifying the
> clientid here. The name seems appropriate to me.

So everything but the first call for 4.0 is just a small verification.
I'm not going to hold up the series for something as trivial, but the
name still smells a little..

> > While it doesn't belong into this patch:  why don't we cache the
> > nfsd_net in the nfsd4_compound_state
> > 
> 
> I'll go further and say that it doesn't really belong in this series.

Anything we can keep out of this series is good, agreed..

> There are certain calls that don't require a SEQUENCE operation:
> 
>     BIND_CONN_TO_SESSION
>     EXCHANGE_ID
>     CREATE_SESSION
>     DESTROY_SESSION
> 
> Granted, for those we don't use lookup_clientid but the "Usually" still
> applies, in general. That said, if it bothers you I'll remove it.

my major issue is the combination of the usually with this:

> > > +		 * if we don't have one cached already then we know this is for
> > > +		 * is for v4.0 and "sessions" will be false.

so we can have a case where we are 4.1 but don't have a cached session.
This is getting into deep nitpick land, but comments that aren't
entirely coherent always confuse me.


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

* Re: [PATCH v2 023/117] nfsd: Convert nfsd4_process_open1() to work with lookup_clientid()
  2014-06-29 15:08     ` Jeff Layton
@ 2014-06-30 10:35       ` Christoph Hellwig
  0 siblings, 0 replies; 162+ messages in thread
From: Christoph Hellwig @ 2014-06-30 10:35 UTC (permalink / raw)
  To: Jeff Layton; +Cc: Christoph Hellwig, bfields, linux-nfs, Trond Myklebust

On Sun, Jun 29, 2014 at 11:08:31AM -0400, Jeff Layton wrote:
> > This hunk should have been in the previous patch.  Or given that
> > lookup_clientid was mostly rewritten it make sense to just move it to
> > avoid the forward declaration entirely.
> > 
> 
> Does it? It's not until this patch that the forward declaration is
> needed at all.

You're right, sorry..


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

* Re: [PATCH v2 037/117] nfsd: clean up helper __release_lock_stateid
  2014-06-26 19:12 ` [PATCH v2 037/117] nfsd: clean up helper __release_lock_stateid Jeff Layton
@ 2014-06-30 10:40   ` Christoph Hellwig
  2014-06-30 10:53     ` Jeff Layton
  0 siblings, 1 reply; 162+ messages in thread
From: Christoph Hellwig @ 2014-06-30 10:40 UTC (permalink / raw)
  To: Jeff Layton; +Cc: bfields, linux-nfs, Trond Myklebust

On Thu, Jun 26, 2014 at 03:12:17PM -0400, Jeff Layton wrote:
> From: Trond Myklebust <trond.myklebust@primarydata.com>
> 
> Use filp_close instead of open coding. filp_close does a bit more than
> just release the locks and put the filp. It also calls ->flush and
> dnotify_flush, both of which should be done here anyway.

Looks good,

Reviewed-by: Christoph Hellwig <hch@lst.de>

and this can probably move before the locking changes..


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

* Re: [PATCH v2 037/117] nfsd: clean up helper __release_lock_stateid
  2014-06-30 10:40   ` Christoph Hellwig
@ 2014-06-30 10:53     ` Jeff Layton
  0 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-30 10:53 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: bfields, linux-nfs, Trond Myklebust

On Mon, 30 Jun 2014 03:40:14 -0700
Christoph Hellwig <hch@infradead.org> wrote:

> On Thu, Jun 26, 2014 at 03:12:17PM -0400, Jeff Layton wrote:
> > From: Trond Myklebust <trond.myklebust@primarydata.com>
> > 
> > Use filp_close instead of open coding. filp_close does a bit more than
> > just release the locks and put the filp. It also calls ->flush and
> > dnotify_flush, both of which should be done here anyway.
> 
> Looks good,
> 
> Reviewed-by: Christoph Hellwig <hch@lst.de>
> 
> and this can probably move before the locking changes..
> 

We can't, actually. filp_close also does an fput, and that doesn't get
added until this patch:

    nfsd: Add locking to the nfs4_file->fi_fds[] array

But I can (and will) move it just after that patch.

Thanks,
-- 
Jeff Layton <jlayton@primarydata.com>

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

* Re: [PATCH v2 022/117] nfsd: Cache the client that was looked up in lookup_clientid()
  2014-06-30 10:34       ` Christoph Hellwig
@ 2014-06-30 10:59         ` Jeff Layton
  2014-06-30 11:03           ` Christoph Hellwig
  0 siblings, 1 reply; 162+ messages in thread
From: Jeff Layton @ 2014-06-30 10:59 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: Jeff Layton, bfields, linux-nfs, Trond Myklebust

On Mon, 30 Jun 2014 03:34:53 -0700
Christoph Hellwig <hch@infradead.org> wrote:

> On Sun, Jun 29, 2014 at 10:57:02AM -0400, Jeff Layton wrote:
> > Depends on what you mean by "normal case". For v4.0 we do look it up at
> > least once for each call into here. For v4.1 we get the pointer to the
> > client "for free" by virtue of looking up the session in the SEQUENCE
> > op. So, I think we are doing a bit more than just verifying the
> > clientid here. The name seems appropriate to me.
> 
> So everything but the first call for 4.0 is just a small verification.
> I'm not going to hold up the series for something as trivial, but the
> name still smells a little..
> 

Fair enough. The "verify" name smells to me a little since we aren't
guaranteed to have one when the function is called. "lookup" seems
reasonable since we are looking it up, it's just that once this patch
goes in we'll usually have it cached in the cstate.

> > > While it doesn't belong into this patch:  why don't we cache the
> > > nfsd_net in the nfsd4_compound_state
> > > 
> > 
> > I'll go further and say that it doesn't really belong in this
> > series.
> 
> Anything we can keep out of this series is good, agreed..
> 
> > There are certain calls that don't require a SEQUENCE operation:
> > 
> >     BIND_CONN_TO_SESSION
> >     EXCHANGE_ID
> >     CREATE_SESSION
> >     DESTROY_SESSION
> > 
> > Granted, for those we don't use lookup_clientid but the "Usually"
> > still applies, in general. That said, if it bothers you I'll remove
> > it.
> 
> my major issue is the combination of the usually with this:
> 
> > > > +		 * if we don't have one cached already then we
> > > > know this is for
> > > > +		 * is for v4.0 and "sessions" will be false.
> 
> so we can have a case where we are 4.1 but don't have a cached
> session. This is getting into deep nitpick land, but comments that
> aren't entirely coherent always confuse me.
> 

Ok, that's understandable. How about this?

+       /*
+        * For v4.1+ we get the client in the SEQUENCE op. If we don't have one
+        * cached already then we know this is for is for v4.0 and "sessions"
+        * will be false.
+        */
+       found = find_confirmed_client(clid, false, nn);

FWIW, the main reason for the comment is to explain why we're
hardcoding the "session" arg to false here instead of using
cstate->session.

-- 
Jeff Layton <jlayton@primarydata.com>

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

* Re: [PATCH v2 018/117] nfsd: clean up nfs4_release_lockowner
  2014-06-29 11:08     ` Jeff Layton
@ 2014-06-30 11:02       ` Jeff Layton
  2014-06-30 11:04         ` Christoph Hellwig
  0 siblings, 1 reply; 162+ messages in thread
From: Jeff Layton @ 2014-06-30 11:02 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: bfields, linux-nfs

On Sun, 29 Jun 2014 07:08:12 -0400
Jeff Layton <jlayton@primarydata.com> wrote:

> On Sat, 28 Jun 2014 23:47:38 -0700
> Christoph Hellwig <hch@infradead.org> wrote:
> 
> > On Thu, Jun 26, 2014 at 03:11:58PM -0400, Jeff Layton wrote:
> > > Now that we know that we won't have several lockowners with the same,
> > > owner->data, we can simplify nfs4_release_lockowner and get rid of
> > > the lo_list in the process.
> > > 
> > > Signed-off-by: Jeff Layton <jlayton@primarydata.com>
> > > ---
> > >  fs/nfsd/nfs4state.c | 44 ++++++++++++++++++++++----------------------
> > >  fs/nfsd/state.h     |  1 -
> > >  2 files changed, 22 insertions(+), 23 deletions(-)
> > > 
> > > diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> > > index 00a1b2cda3ab..a5bb96b97f09 100644
> > > --- a/fs/nfsd/nfs4state.c
> > > +++ b/fs/nfsd/nfs4state.c
> > > @@ -4828,7 +4828,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
> > >  			struct nfsd4_release_lockowner *rlockowner)
> > >  {
> > >  	clientid_t *clid = &rlockowner->rl_clientid;
> > > -	struct nfs4_stateowner *sop;
> > > +	struct nfs4_stateowner *sop = NULL, *tmp;
> > >  	struct nfs4_lockowner *lo;
> > >  	struct nfs4_ol_stateid *stp;
> > >  	struct xdr_netobj *owner = &rlockowner->rl_owner;
> > > @@ -4849,31 +4849,31 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
> > >  	status = nfserr_locks_held;
> > >  	INIT_LIST_HEAD(&matches);
> > 
> > I think matches is unused now.
> > 
> 
> Yep -- good catch.
> 
> > >  
> > > +	/* Find the matching lock stateowner */
> > > +	list_for_each_entry(tmp, &nn->ownerstr_hashtbl[hashval], so_strhash) {
> > > +		if (tmp->so_is_open_owner)
> > > +			continue;
> > > +		if (same_owner_str(tmp, owner, clid)) {
> > > +			sop = tmp;
> > > +			break;
> > >  		}
> > >  	}
> > > +
> > > +	/* No matching owner found, maybe a replay? Just declare victory... */
> > > +	if (!sop) {
> > > +		status = nfs_ok;
> > > +		goto out;
> > > +	}
> > > +
> > > +	lo = lockowner(sop);
> > > +	/* see if there are still any locks associated with it */
> > > +	list_for_each_entry(stp, &sop->so_stateids, st_perstateowner) {
> > > +		if (check_for_locks(stp->st_file, lo))
> > > +			goto out;
> > >  	}
> > > +
> > > +	status = nfs_ok;
> > > +	release_lockowner(lo);
> > 
> > I would seem simpler to do all the work in the loop, something like:
> > 
> > 	list_for_each_entry(sop, &nn->ownerstr_hashtbl[hashval], so_strhash) {
> > 		if (sop->so_is_open_owner)
> > 			continue;
> > 		if (!same_owner_str(sop, owner, clid))
> > 			continue;
> > 
> > 		list_for_each_entry(stp, &sop->so_stateids, st_perstateowner) {
> > 			if (check_for_locks(stp->st_file, lockowner(sop))) {
> > 				status = nfserr_locks_held;
> > 				goto out;
> > 			}
> > 		}
> > 
> > 		release_lockowner(lo);
> > 		break;
> > 	}
> > 
> 
> Ok, sure...
> 

I started looking at reorganizing the function like you suggested, and
there's a bit of a problem. Once we start adding in locking this
becomes a bit of a mess, at least until the ownerstr_hashtbl gets moved
into the nfs4_client.

What I'd suggest is that we go ahead and take this patch as-is for now,
and I'll do the reorganization of the function along those lines in a
later patch once we only need to deal with the cl_lock there. Sound ok?

-- 
Jeff Layton <jlayton@primarydata.com>

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

* Re: [PATCH v2 022/117] nfsd: Cache the client that was looked up in lookup_clientid()
  2014-06-30 10:59         ` Jeff Layton
@ 2014-06-30 11:03           ` Christoph Hellwig
  2014-06-30 11:23             ` Jeff Layton
  0 siblings, 1 reply; 162+ messages in thread
From: Christoph Hellwig @ 2014-06-30 11:03 UTC (permalink / raw)
  To: Jeff Layton; +Cc: Christoph Hellwig, bfields, linux-nfs, Trond Myklebust

On Mon, Jun 30, 2014 at 06:59:13AM -0400, Jeff Layton wrote:
> +       /*
> +        * For v4.1+ we get the client in the SEQUENCE op. If we don't have one
> +        * cached already then we know this is for is for v4.0 and "sessions"
> +        * will be false.
> +        */
> +       found = find_confirmed_client(clid, false, nn);
> 
> FWIW, the main reason for the comment is to explain why we're
> hardcoding the "session" arg to false here instead of using
> cstate->session.

I'd either just use it to future proof it, or add an assert that it's
really not set..


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

* Re: [PATCH v2 018/117] nfsd: clean up nfs4_release_lockowner
  2014-06-30 11:02       ` Jeff Layton
@ 2014-06-30 11:04         ` Christoph Hellwig
  0 siblings, 0 replies; 162+ messages in thread
From: Christoph Hellwig @ 2014-06-30 11:04 UTC (permalink / raw)
  To: Jeff Layton; +Cc: Christoph Hellwig, bfields, linux-nfs

On Mon, Jun 30, 2014 at 07:02:08AM -0400, Jeff Layton wrote:
> I started looking at reorganizing the function like you suggested, and
> there's a bit of a problem. Once we start adding in locking this
> becomes a bit of a mess, at least until the ownerstr_hashtbl gets moved
> into the nfs4_client.
> 
> What I'd suggest is that we go ahead and take this patch as-is for now,
> and I'll do the reorganization of the function along those lines in a
> later patch once we only need to deal with the cl_lock there. Sound ok?

ok..


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

* Re: [PATCH v2 022/117] nfsd: Cache the client that was looked up in lookup_clientid()
  2014-06-30 11:03           ` Christoph Hellwig
@ 2014-06-30 11:23             ` Jeff Layton
  0 siblings, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-30 11:23 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: Jeff Layton, bfields, linux-nfs, Trond Myklebust

On Mon, 30 Jun 2014 04:03:22 -0700
Christoph Hellwig <hch@infradead.org> wrote:

> On Mon, Jun 30, 2014 at 06:59:13AM -0400, Jeff Layton wrote:
> > +       /*
> > +        * For v4.1+ we get the client in the SEQUENCE op. If we don't have one
> > +        * cached already then we know this is for is for v4.0 and "sessions"
> > +        * will be false.
> > +        */
> > +       found = find_confirmed_client(clid, false, nn);
> > 
> > FWIW, the main reason for the comment is to explain why we're
> > hardcoding the "session" arg to false here instead of using
> > cstate->session.
> 
> I'd either just use it to future proof it, or add an assert that it's
> really not set..
> 

An assertion sounds like a good idea. I'll add one in there...

-- 
Jeff Layton <jlayton@primarydata.com>

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

* Re: [PATCH v2 000/117] nfsd: eliminate the client_mutex
  2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
                   ` (117 preceding siblings ...)
  2014-06-27 16:22 ` [PATCH v2 000/117] nfsd: eliminate the client_mutex J. Bruce Fields
@ 2014-06-30 12:51 ` Christoph Hellwig
  2014-06-30 12:59   ` Jeff Layton
  118 siblings, 1 reply; 162+ messages in thread
From: Christoph Hellwig @ 2014-06-30 12:51 UTC (permalink / raw)
  To: Jeff Layton; +Cc: bfields, linux-nfs

I'm pretty happy with what's the first 25 patches in this version
with all the review comments addressed, so as far as I'm concerned
these are ready for for-next.  Does anyone else plan to do a review
as well?

I'll try to get to the locking changes as well soon, but I've got some
work keeping me fairly busy at the moment.  I guess it wasn't easily
feasible to move the various stateid refcounting to before the major
locking changes?

Btw, do you have any benchrmarks showing the improvements of the new
locking scheme?

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

* Re: [PATCH v2 000/117] nfsd: eliminate the client_mutex
  2014-06-30 12:51 ` Christoph Hellwig
@ 2014-06-30 12:59   ` Jeff Layton
  2014-06-30 19:32     ` J. Bruce Fields
  0 siblings, 1 reply; 162+ messages in thread
From: Jeff Layton @ 2014-06-30 12:59 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: bfields, linux-nfs

On Mon, 30 Jun 2014 05:51:42 -0700
Christoph Hellwig <hch@infradead.org> wrote:

> I'm pretty happy with what's the first 25 patches in this version
> with all the review comments addressed, so as far as I'm concerned
> these are ready for for-next.  Does anyone else plan to do a review
> as well?
> 

Thanks very much for the review so far.

> I'll try to get to the locking changes as well soon, but I've got some
> work keeping me fairly busy at the moment.  I guess it wasn't easily
> feasible to move the various stateid refcounting to before the major
> locking changes?
> 

Not really. If I had done the set from scratch I would have probably
done that instead, but Trond's original had those changes interleaved.
Separating them would be a lot of work that I'd prefer to avoid.

> Btw, do you have any benchrmarks showing the improvements of the new
> locking scheme?

No, I'm hoping to get those numbers soon from our QA folks. Most of the
testing I've done has been for correctness and stability. I'm pretty
happy with things at that end now, but I don't have any numbers that
show whether and how much this helps scalability.

-- 
Jeff Layton <jlayton@primarydata.com>

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

* Re: [PATCH v2 000/117] nfsd: eliminate the client_mutex
  2014-06-30 12:59   ` Jeff Layton
@ 2014-06-30 19:32     ` J. Bruce Fields
  2014-06-30 19:39       ` Jeff Layton
  2014-06-30 20:20       ` Jeff Layton
  0 siblings, 2 replies; 162+ messages in thread
From: J. Bruce Fields @ 2014-06-30 19:32 UTC (permalink / raw)
  To: Jeff Layton; +Cc: Christoph Hellwig, linux-nfs

On Mon, Jun 30, 2014 at 08:59:34AM -0400, Jeff Layton wrote:
> On Mon, 30 Jun 2014 05:51:42 -0700
> Christoph Hellwig <hch@infradead.org> wrote:
> 
> > I'm pretty happy with what's the first 25 patches in this version
> > with all the review comments addressed, so as far as I'm concerned
> > these are ready for for-next.  Does anyone else plan to do a review
> > as well?
> > 
> 
> Thanks very much for the review so far.
> 
> > I'll try to get to the locking changes as well soon, but I've got some
> > work keeping me fairly busy at the moment.  I guess it wasn't easily
> > feasible to move the various stateid refcounting to before the major
> > locking changes?
> > 
> 
> Not really. If I had done the set from scratch I would have probably
> done that instead, but Trond's original had those changes interleaved.
> Separating them would be a lot of work that I'd prefer to avoid.
> 
> > Btw, do you have any benchrmarks showing the improvements of the new
> > locking scheme?
> 
> No, I'm hoping to get those numbers soon from our QA folks. Most of the
> testing I've done has been for correctness and stability. I'm pretty
> happy with things at that end now, but I don't have any numbers that
> show whether and how much this helps scalability.

The open-create problem at least shouldn't be hard to confirm.

It's also the only problem I've actually seen a complaint about--I do
wish it were possible to do just the minimum required to fix that before
doing all the rest.

--b.

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

* Re: [PATCH v2 000/117] nfsd: eliminate the client_mutex
  2014-06-30 19:32     ` J. Bruce Fields
@ 2014-06-30 19:39       ` Jeff Layton
  2014-06-30 20:20       ` Jeff Layton
  1 sibling, 0 replies; 162+ messages in thread
From: Jeff Layton @ 2014-06-30 19:39 UTC (permalink / raw)
  To: J. Bruce Fields; +Cc: Jeff Layton, Christoph Hellwig, linux-nfs

On Mon, 30 Jun 2014 15:32:37 -0400
"J. Bruce Fields" <bfields@fieldses.org> wrote:

> On Mon, Jun 30, 2014 at 08:59:34AM -0400, Jeff Layton wrote:
> > On Mon, 30 Jun 2014 05:51:42 -0700
> > Christoph Hellwig <hch@infradead.org> wrote:
> > 
> > > I'm pretty happy with what's the first 25 patches in this version
> > > with all the review comments addressed, so as far as I'm concerned
> > > these are ready for for-next.  Does anyone else plan to do a review
> > > as well?
> > > 
> > 
> > Thanks very much for the review so far.
> > 
> > > I'll try to get to the locking changes as well soon, but I've got some
> > > work keeping me fairly busy at the moment.  I guess it wasn't easily
> > > feasible to move the various stateid refcounting to before the major
> > > locking changes?
> > > 
> > 
> > Not really. If I had done the set from scratch I would have probably
> > done that instead, but Trond's original had those changes interleaved.
> > Separating them would be a lot of work that I'd prefer to avoid.
> > 
> > > Btw, do you have any benchrmarks showing the improvements of the new
> > > locking scheme?
> > 
> > No, I'm hoping to get those numbers soon from our QA folks. Most of the
> > testing I've done has been for correctness and stability. I'm pretty
> > happy with things at that end now, but I don't have any numbers that
> > show whether and how much this helps scalability.
> 
> The open-create problem at least shouldn't be hard to confirm.
> 
> It's also the only problem I've actually seen a complaint about--I do
> wish it were possible to do just the minimum required to fix that before
> doing all the rest.
> 

Yeah, I started writing a testcase that just did a bunch of opens from
multiple tasks and timed it, but got sidetracked fixing other bugs in
this set. I'll see if I can polish that off and at least get some rough
numbers.

As far as speeding up opens/creates without touching other stuff...I
just don't see how it's possible. It's almost certain that the worst
serialization is coming from the client_mutex and I don't see how you'd
go about removing it from just that codepath.

-- 
Jeff Layton <jlayton@primarydata.com>

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

* Re: [PATCH v2 000/117] nfsd: eliminate the client_mutex
  2014-06-30 19:32     ` J. Bruce Fields
  2014-06-30 19:39       ` Jeff Layton
@ 2014-06-30 20:20       ` Jeff Layton
  2014-06-30 20:31         ` Trond Myklebust
  1 sibling, 1 reply; 162+ messages in thread
From: Jeff Layton @ 2014-06-30 20:20 UTC (permalink / raw)
  To: J. Bruce Fields; +Cc: Jeff Layton, Christoph Hellwig, linux-nfs

On Mon, 30 Jun 2014 15:32:37 -0400
"J. Bruce Fields" <bfields@fieldses.org> wrote:

> On Mon, Jun 30, 2014 at 08:59:34AM -0400, Jeff Layton wrote:
> > On Mon, 30 Jun 2014 05:51:42 -0700
> > Christoph Hellwig <hch@infradead.org> wrote:
> > 
> > > I'm pretty happy with what's the first 25 patches in this version
> > > with all the review comments addressed, so as far as I'm concerned
> > > these are ready for for-next.  Does anyone else plan to do a review
> > > as well?
> > > 
> > 
> > Thanks very much for the review so far.
> > 
> > > I'll try to get to the locking changes as well soon, but I've got some
> > > work keeping me fairly busy at the moment.  I guess it wasn't easily
> > > feasible to move the various stateid refcounting to before the major
> > > locking changes?
> > > 
> > 
> > Not really. If I had done the set from scratch I would have probably
> > done that instead, but Trond's original had those changes interleaved.
> > Separating them would be a lot of work that I'd prefer to avoid.
> > 
> > > Btw, do you have any benchrmarks showing the improvements of the new
> > > locking scheme?
> > 
> > No, I'm hoping to get those numbers soon from our QA folks. Most of the
> > testing I've done has been for correctness and stability. I'm pretty
> > happy with things at that end now, but I don't have any numbers that
> > show whether and how much this helps scalability.
> 
> The open-create problem at least shouldn't be hard to confirm.
> 
> It's also the only problem I've actually seen a complaint about--I do
> wish it were possible to do just the minimum required to fix that before
> doing all the rest.
> 
> --b.

So I wrote a small program to fork off children and have them create a
bunch of files. With 128 children creating 100 files each, and running
the program under "time". 

...with your for-3.17 branch:

[jlayton@tlielax lockperf]$ time ./opentest -n 128 -l 100 /mnt/rawhide/opentest

real	0m10.037s
user	0m0.065s
sys	0m0.340s
[jlayton@tlielax lockperf]$ time ./opentest -n 128 -l 100 /mnt/rawhide/opentest

real	0m10.378s
user	0m0.058s
sys	0m0.356s
[jlayton@tlielax lockperf]$ time ./opentest -n 128 -l 100 /mnt/rawhide/opentest

real	0m8.576s
user	0m0.063s
sys	0m0.352s

...with the entire pile of patches:

[jlayton@tlielax lockperf]$ time ./opentest -n 128 -l 100 /mnt/rawhide/opentest

real	0m7.150s
user	0m0.053s
sys	0m0.361s
[jlayton@tlielax lockperf]$ time ./opentest -n 128 -l 100 /mnt/rawhide/opentest

real	0m8.251s
user	0m0.053s
sys	0m0.369s
[jlayton@tlielax lockperf]$ time ./opentest -n 128 -l 100 /mnt/rawhide/opentest

real	0m8.661s
user	0m0.066s
sys	0m0.358s

...so it does seem to help, but there's a lot of variation in the
results. I'll see if I can come up with a better benchmark for this
and find a way to run this that doesn't involve virtualization.

Alternately, does anyone have a stock benchmark they can suggest that
might be better than my simple test program?

-- 
Jeff Layton <jlayton@primarydata.com>

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

* Re: [PATCH v2 000/117] nfsd: eliminate the client_mutex
  2014-06-30 20:20       ` Jeff Layton
@ 2014-06-30 20:31         ` Trond Myklebust
  2014-06-30 20:36           ` Jeff Layton
  0 siblings, 1 reply; 162+ messages in thread
From: Trond Myklebust @ 2014-06-30 20:31 UTC (permalink / raw)
  To: Jeff Layton; +Cc: J. Bruce Fields, Christoph Hellwig, Linux NFS Mailing List

On Mon, Jun 30, 2014 at 4:20 PM, Jeff Layton
<jeff.layton@primarydata.com> wrote:
> On Mon, 30 Jun 2014 15:32:37 -0400
> "J. Bruce Fields" <bfields@fieldses.org> wrote:
>
>> On Mon, Jun 30, 2014 at 08:59:34AM -0400, Jeff Layton wrote:
>> > On Mon, 30 Jun 2014 05:51:42 -0700
>> > Christoph Hellwig <hch@infradead.org> wrote:
>> >
>> > > I'm pretty happy with what's the first 25 patches in this version
>> > > with all the review comments addressed, so as far as I'm concerned
>> > > these are ready for for-next.  Does anyone else plan to do a review
>> > > as well?
>> > >
>> >
>> > Thanks very much for the review so far.
>> >
>> > > I'll try to get to the locking changes as well soon, but I've got some
>> > > work keeping me fairly busy at the moment.  I guess it wasn't easily
>> > > feasible to move the various stateid refcounting to before the major
>> > > locking changes?
>> > >
>> >
>> > Not really. If I had done the set from scratch I would have probably
>> > done that instead, but Trond's original had those changes interleaved.
>> > Separating them would be a lot of work that I'd prefer to avoid.
>> >
>> > > Btw, do you have any benchrmarks showing the improvements of the new
>> > > locking scheme?
>> >
>> > No, I'm hoping to get those numbers soon from our QA folks. Most of the
>> > testing I've done has been for correctness and stability. I'm pretty
>> > happy with things at that end now, but I don't have any numbers that
>> > show whether and how much this helps scalability.
>>
>> The open-create problem at least shouldn't be hard to confirm.
>>
>> It's also the only problem I've actually seen a complaint about--I do
>> wish it were possible to do just the minimum required to fix that before
>> doing all the rest.
>>
>> --b.
>
> So I wrote a small program to fork off children and have them create a
> bunch of files. With 128 children creating 100 files each, and running
> the program under "time".
>
> ...with your for-3.17 branch:
>
> [jlayton@tlielax lockperf]$ time ./opentest -n 128 -l 100 /mnt/rawhide/opentest
>
> real    0m10.037s
> user    0m0.065s
> sys     0m0.340s
> [jlayton@tlielax lockperf]$ time ./opentest -n 128 -l 100 /mnt/rawhide/opentest
>
> real    0m10.378s
> user    0m0.058s
> sys     0m0.356s
> [jlayton@tlielax lockperf]$ time ./opentest -n 128 -l 100 /mnt/rawhide/opentest
>
> real    0m8.576s
> user    0m0.063s
> sys     0m0.352s
>
> ...with the entire pile of patches:
>
> [jlayton@tlielax lockperf]$ time ./opentest -n 128 -l 100 /mnt/rawhide/opentest
>
> real    0m7.150s
> user    0m0.053s
> sys     0m0.361s
> [jlayton@tlielax lockperf]$ time ./opentest -n 128 -l 100 /mnt/rawhide/opentest
>
> real    0m8.251s
> user    0m0.053s
> sys     0m0.369s
> [jlayton@tlielax lockperf]$ time ./opentest -n 128 -l 100 /mnt/rawhide/opentest
>
> real    0m8.661s
> user    0m0.066s
> sys     0m0.358s
>
> ...so it does seem to help, but there's a lot of variation in the
> results. I'll see if I can come up with a better benchmark for this
> and find a way to run this that doesn't involve virtualization.
>
> Alternately, does anyone have a stock benchmark they can suggest that
> might be better than my simple test program?
>

Hi Jeff,

If the processes are all running under the same credential, then the
client will serialise them automatically due to them all sharing the
same open owner.

To really make this test fly, you probably want to do something like
allocating a bunch of gids, assign them as auxiliary groups to the
parent process, then do a 'setfsgid()' to a random member of that set
of gids after each fork.

That should give you a maze of twisty little open owners to play with...

-- 
Trond Myklebust

Linux NFS client maintainer, PrimaryData

trond.myklebust@primarydata.com

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

* Re: [PATCH v2 000/117] nfsd: eliminate the client_mutex
  2014-06-30 20:31         ` Trond Myklebust
@ 2014-06-30 20:36           ` Jeff Layton
  2014-07-01 14:10             ` Jeff Layton
  0 siblings, 1 reply; 162+ messages in thread
From: Jeff Layton @ 2014-06-30 20:36 UTC (permalink / raw)
  To: Trond Myklebust
  Cc: Jeff Layton, J. Bruce Fields, Christoph Hellwig, Linux NFS Mailing List

On Mon, 30 Jun 2014 16:31:24 -0400
Trond Myklebust <trond.myklebust@primarydata.com> wrote:

> On Mon, Jun 30, 2014 at 4:20 PM, Jeff Layton
> <jeff.layton@primarydata.com> wrote:
> > On Mon, 30 Jun 2014 15:32:37 -0400
> > "J. Bruce Fields" <bfields@fieldses.org> wrote:
> >
> >> On Mon, Jun 30, 2014 at 08:59:34AM -0400, Jeff Layton wrote:
> >> > On Mon, 30 Jun 2014 05:51:42 -0700
> >> > Christoph Hellwig <hch@infradead.org> wrote:
> >> >
> >> > > I'm pretty happy with what's the first 25 patches in this version
> >> > > with all the review comments addressed, so as far as I'm concerned
> >> > > these are ready for for-next.  Does anyone else plan to do a review
> >> > > as well?
> >> > >
> >> >
> >> > Thanks very much for the review so far.
> >> >
> >> > > I'll try to get to the locking changes as well soon, but I've got some
> >> > > work keeping me fairly busy at the moment.  I guess it wasn't easily
> >> > > feasible to move the various stateid refcounting to before the major
> >> > > locking changes?
> >> > >
> >> >
> >> > Not really. If I had done the set from scratch I would have probably
> >> > done that instead, but Trond's original had those changes interleaved.
> >> > Separating them would be a lot of work that I'd prefer to avoid.
> >> >
> >> > > Btw, do you have any benchrmarks showing the improvements of the new
> >> > > locking scheme?
> >> >
> >> > No, I'm hoping to get those numbers soon from our QA folks. Most of the
> >> > testing I've done has been for correctness and stability. I'm pretty
> >> > happy with things at that end now, but I don't have any numbers that
> >> > show whether and how much this helps scalability.
> >>
> >> The open-create problem at least shouldn't be hard to confirm.
> >>
> >> It's also the only problem I've actually seen a complaint about--I do
> >> wish it were possible to do just the minimum required to fix that before
> >> doing all the rest.
> >>
> >> --b.
> >
> > So I wrote a small program to fork off children and have them create a
> > bunch of files. With 128 children creating 100 files each, and running
> > the program under "time".
> >
> > ...with your for-3.17 branch:
> >
> > [jlayton@tlielax lockperf]$ time ./opentest -n 128 -l 100 /mnt/rawhide/opentest
> >
> > real    0m10.037s
> > user    0m0.065s
> > sys     0m0.340s
> > [jlayton@tlielax lockperf]$ time ./opentest -n 128 -l 100 /mnt/rawhide/opentest
> >
> > real    0m10.378s
> > user    0m0.058s
> > sys     0m0.356s
> > [jlayton@tlielax lockperf]$ time ./opentest -n 128 -l 100 /mnt/rawhide/opentest
> >
> > real    0m8.576s
> > user    0m0.063s
> > sys     0m0.352s
> >
> > ...with the entire pile of patches:
> >
> > [jlayton@tlielax lockperf]$ time ./opentest -n 128 -l 100 /mnt/rawhide/opentest
> >
> > real    0m7.150s
> > user    0m0.053s
> > sys     0m0.361s
> > [jlayton@tlielax lockperf]$ time ./opentest -n 128 -l 100 /mnt/rawhide/opentest
> >
> > real    0m8.251s
> > user    0m0.053s
> > sys     0m0.369s
> > [jlayton@tlielax lockperf]$ time ./opentest -n 128 -l 100 /mnt/rawhide/opentest
> >
> > real    0m8.661s
> > user    0m0.066s
> > sys     0m0.358s
> >
> > ...so it does seem to help, but there's a lot of variation in the
> > results. I'll see if I can come up with a better benchmark for this
> > and find a way to run this that doesn't involve virtualization.
> >
> > Alternately, does anyone have a stock benchmark they can suggest that
> > might be better than my simple test program?
> >
> 
> Hi Jeff,
> 
> If the processes are all running under the same credential, then the
> client will serialise them automatically due to them all sharing the
> same open owner.
> 
> To really make this test fly, you probably want to do something like
> allocating a bunch of gids, assign them as auxiliary groups to the
> parent process, then do a 'setfsgid()' to a random member of that set
> of gids after each fork.
> 
> That should give you a maze of twisty little open owners to play with...
> 

Ahh, good point. Yes, those were all done with the same creds. I'll see
if I can spin up such a test tomorrow, and I'll see if I can also build
a couple of bare-metal machines to test this with.

It's hard to trust KVM guests for performance testing...

-- 
Jeff Layton <jlayton@primarydata.com>

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

* Re: [PATCH v2 000/117] nfsd: eliminate the client_mutex
  2014-06-30 20:36           ` Jeff Layton
@ 2014-07-01 14:10             ` Jeff Layton
  2014-07-01 14:21               ` Trond Myklebust
  0 siblings, 1 reply; 162+ messages in thread
From: Jeff Layton @ 2014-07-01 14:10 UTC (permalink / raw)
  To: Trond Myklebust
  Cc: J. Bruce Fields, Christoph Hellwig, Linux NFS Mailing List

On Mon, 30 Jun 2014 16:36:47 -0400
Jeff Layton <jeff.layton@primarydata.com> wrote:

> On Mon, 30 Jun 2014 16:31:24 -0400
> Trond Myklebust <trond.myklebust@primarydata.com> wrote:
> 
> > On Mon, Jun 30, 2014 at 4:20 PM, Jeff Layton
> > <jeff.layton@primarydata.com> wrote:
> > > On Mon, 30 Jun 2014 15:32:37 -0400
> > > "J. Bruce Fields" <bfields@fieldses.org> wrote:
> > >
> > >> On Mon, Jun 30, 2014 at 08:59:34AM -0400, Jeff Layton wrote:
> > >> > On Mon, 30 Jun 2014 05:51:42 -0700
> > >> > Christoph Hellwig <hch@infradead.org> wrote:
> > >> >
> > >> > > I'm pretty happy with what's the first 25 patches in this version
> > >> > > with all the review comments addressed, so as far as I'm concerned
> > >> > > these are ready for for-next.  Does anyone else plan to do a review
> > >> > > as well?
> > >> > >
> > >> >
> > >> > Thanks very much for the review so far.
> > >> >
> > >> > > I'll try to get to the locking changes as well soon, but I've got some
> > >> > > work keeping me fairly busy at the moment.  I guess it wasn't easily
> > >> > > feasible to move the various stateid refcounting to before the major
> > >> > > locking changes?
> > >> > >
> > >> >
> > >> > Not really. If I had done the set from scratch I would have probably
> > >> > done that instead, but Trond's original had those changes interleaved.
> > >> > Separating them would be a lot of work that I'd prefer to avoid.
> > >> >
> > >> > > Btw, do you have any benchrmarks showing the improvements of the new
> > >> > > locking scheme?
> > >> >
> > >> > No, I'm hoping to get those numbers soon from our QA folks. Most of the
> > >> > testing I've done has been for correctness and stability. I'm pretty
> > >> > happy with things at that end now, but I don't have any numbers that
> > >> > show whether and how much this helps scalability.
> > >>
> > >> The open-create problem at least shouldn't be hard to confirm.
> > >>
> > >> It's also the only problem I've actually seen a complaint about--I do
> > >> wish it were possible to do just the minimum required to fix that before
> > >> doing all the rest.
> > >>
> > >> --b.
> > >
> > > So I wrote a small program to fork off children and have them create a
> > > bunch of files. With 128 children creating 100 files each, and running
> > > the program under "time".
> > >
> > > ...with your for-3.17 branch:
> > >
> > > [jlayton@tlielax lockperf]$ time ./opentest -n 128 -l 100 /mnt/rawhide/opentest
> > >
> > > real    0m10.037s
> > > user    0m0.065s
> > > sys     0m0.340s
> > > [jlayton@tlielax lockperf]$ time ./opentest -n 128 -l 100 /mnt/rawhide/opentest
> > >
> > > real    0m10.378s
> > > user    0m0.058s
> > > sys     0m0.356s
> > > [jlayton@tlielax lockperf]$ time ./opentest -n 128 -l 100 /mnt/rawhide/opentest
> > >
> > > real    0m8.576s
> > > user    0m0.063s
> > > sys     0m0.352s
> > >
> > > ...with the entire pile of patches:
> > >
> > > [jlayton@tlielax lockperf]$ time ./opentest -n 128 -l 100 /mnt/rawhide/opentest
> > >
> > > real    0m7.150s
> > > user    0m0.053s
> > > sys     0m0.361s
> > > [jlayton@tlielax lockperf]$ time ./opentest -n 128 -l 100 /mnt/rawhide/opentest
> > >
> > > real    0m8.251s
> > > user    0m0.053s
> > > sys     0m0.369s
> > > [jlayton@tlielax lockperf]$ time ./opentest -n 128 -l 100 /mnt/rawhide/opentest
> > >
> > > real    0m8.661s
> > > user    0m0.066s
> > > sys     0m0.358s
> > >
> > > ...so it does seem to help, but there's a lot of variation in the
> > > results. I'll see if I can come up with a better benchmark for this
> > > and find a way to run this that doesn't involve virtualization.
> > >
> > > Alternately, does anyone have a stock benchmark they can suggest that
> > > might be better than my simple test program?
> > >
> > 
> > Hi Jeff,
> > 
> > If the processes are all running under the same credential, then the
> > client will serialise them automatically due to them all sharing the
> > same open owner.
> > 
> > To really make this test fly, you probably want to do something like
> > allocating a bunch of gids, assign them as auxiliary groups to the
> > parent process, then do a 'setfsgid()' to a random member of that set
> > of gids after each fork.
> > 
> > That should give you a maze of twisty little open owners to play with...
> > 
> 
> Ahh, good point. Yes, those were all done with the same creds. I'll see
> if I can spin up such a test tomorrow, and I'll see if I can also build
> a couple of bare-metal machines to test this with.
> 
> It's hard to trust KVM guests for performance testing...
> 

Quite right. I changed the program to be run as root and had each child
process do an setfsuid/setfsgid to a different UID/GID combo:

[jlayton@tlielax lockperf]$ time sudo  ./opentest -n 128 -l 100 /mnt/rawhide/opentest

real	0m3.448s
user	0m0.078s
sys	0m0.377s
[jlayton@tlielax lockperf]$ time sudo  ./opentest -n 128 -l 100 /mnt/rawhide/opentest

real	0m3.344s
user	0m0.053s
sys	0m0.374s
[jlayton@tlielax lockperf]$ time sudo  ./opentest -n 128 -l 100 /mnt/rawhide/opentest

real	0m3.550s
user	0m0.049s
sys	0m0.394s


...so the speedup seems to be quite dramatic, actually -- 3x faster or
so with the patched kernel.

The underlying filesystem is ext4 here, and the config is a rawhide
debug kernel config. For my next trick, I'll build some non-debug
kernels and replicate the test with them. Stay tuned...

-- 
Jeff Layton <jlayton@poochiereds.net>

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

* Re: [PATCH v2 000/117] nfsd: eliminate the client_mutex
  2014-07-01 14:10             ` Jeff Layton
@ 2014-07-01 14:21               ` Trond Myklebust
  2014-07-01 18:46                 ` Jeff Layton
  0 siblings, 1 reply; 162+ messages in thread
From: Trond Myklebust @ 2014-07-01 14:21 UTC (permalink / raw)
  To: Jeff Layton; +Cc: J. Bruce Fields, Christoph Hellwig, Linux NFS Mailing List

On Tue, Jul 1, 2014 at 10:10 AM, Jeff Layton <jlayton@poochiereds.net> wrote:
>
> Quite right. I changed the program to be run as root and had each child
> process do an setfsuid/setfsgid to a different UID/GID combo:
>
> [jlayton@tlielax lockperf]$ time sudo  ./opentest -n 128 -l 100 /mnt/rawhide/opentest
>
> real    0m3.448s
> user    0m0.078s
> sys     0m0.377s
> [jlayton@tlielax lockperf]$ time sudo  ./opentest -n 128 -l 100 /mnt/rawhide/opentest
>
> real    0m3.344s
> user    0m0.053s
> sys     0m0.374s
> [jlayton@tlielax lockperf]$ time sudo  ./opentest -n 128 -l 100 /mnt/rawhide/opentest
>
> real    0m3.550s
> user    0m0.049s
> sys     0m0.394s
>
>
> ...so the speedup seems to be quite dramatic, actually -- 3x faster or
> so with the patched kernel.
>
> The underlying filesystem is ext4 here, and the config is a rawhide
> debug kernel config. For my next trick, I'll build some non-debug
> kernels and replicate the test with them. Stay tuned...

Just for grins, we should probably also try with the 3 client side
OPEN parallelisation patches in my 'devel' branch. I'd expect them to
give a slight performance improvement with your original test (i.e.
the one that doesn't play the UID/GID games)

Cheers
  Trond
-- 
Trond Myklebust

Linux NFS client maintainer, PrimaryData

trond.myklebust@primarydata.com

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

* Re: [PATCH v2 000/117] nfsd: eliminate the client_mutex
  2014-07-01 14:21               ` Trond Myklebust
@ 2014-07-01 18:46                 ` Jeff Layton
  2014-07-01 20:01                   ` J. Bruce Fields
  0 siblings, 1 reply; 162+ messages in thread
From: Jeff Layton @ 2014-07-01 18:46 UTC (permalink / raw)
  To: Trond Myklebust
  Cc: J. Bruce Fields, Christoph Hellwig, Linux NFS Mailing List

On Tue, 1 Jul 2014 10:21:40 -0400
Trond Myklebust <trond.myklebust@primarydata.com> wrote:

> On Tue, Jul 1, 2014 at 10:10 AM, Jeff Layton <jlayton@poochiereds.net> wrote:
> >
> > Quite right. I changed the program to be run as root and had each child
> > process do an setfsuid/setfsgid to a different UID/GID combo:
> >
> > [jlayton@tlielax lockperf]$ time sudo  ./opentest -n 128 -l 100 /mnt/rawhide/opentest
> >
> > real    0m3.448s
> > user    0m0.078s
> > sys     0m0.377s
> > [jlayton@tlielax lockperf]$ time sudo  ./opentest -n 128 -l 100 /mnt/rawhide/opentest
> >
> > real    0m3.344s
> > user    0m0.053s
> > sys     0m0.374s
> > [jlayton@tlielax lockperf]$ time sudo  ./opentest -n 128 -l 100 /mnt/rawhide/opentest
> >
> > real    0m3.550s
> > user    0m0.049s
> > sys     0m0.394s
> >
> >
> > ...so the speedup seems to be quite dramatic, actually -- 3x faster or
> > so with the patched kernel.
> >
> > The underlying filesystem is ext4 here, and the config is a rawhide
> > debug kernel config. For my next trick, I'll build some non-debug
> > kernels and replicate the test with them. Stay tuned...
> 
> Just for grins, we should probably also try with the 3 client side
> OPEN parallelisation patches in my 'devel' branch. I'd expect them to
> give a slight performance improvement with your original test (i.e.
> the one that doesn't play the UID/GID games)
> 


Ok, I haven't tested that yet, but I did put together a f20 machine on
bare metal to act as a server. Here are some results from a test that
forks 128 child processes and has each one create and close 1024 files.
Client is 3.14.8-200.fc20.x86_64 and using NFSv4.1:

With a stock Fedora kernel on the server running 3.14.8-200.fc20.x86_64:

$ time sudo ./opentest -n 128 -l 1024 /mnt/palma

real	59m5.022s
user	0m1.401s
sys	0m17.561s


...with the patched kernel 3.16.0-rc2.jlayton.1+ (basically Bruce's
for-3.17 branch with the rest of my patches piled on):

$ time sudo ./opentest -n 128 -l 1024 /mnt/palma

real	4m19.060s
user	0m1.259s
sys	0m13.059s

...so around a factor of 13x speedup on parallel creates. Again, this
is not a terribly scientific benchmark, but it does suggest that this
patchset helps immensely.

-- 
Jeff Layton <jlayton@primarydata.com>

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

* Re: [PATCH v2 000/117] nfsd: eliminate the client_mutex
  2014-07-01 18:46                 ` Jeff Layton
@ 2014-07-01 20:01                   ` J. Bruce Fields
  2014-07-01 20:13                     ` Jeff Layton
  0 siblings, 1 reply; 162+ messages in thread
From: J. Bruce Fields @ 2014-07-01 20:01 UTC (permalink / raw)
  To: Jeff Layton; +Cc: Trond Myklebust, Christoph Hellwig, Linux NFS Mailing List

On Tue, Jul 01, 2014 at 02:46:31PM -0400, Jeff Layton wrote:
> Ok, I haven't tested that yet, but I did put together a f20 machine on
> bare metal to act as a server. Here are some results from a test that
> forks 128 child processes and has each one create and close 1024 files.
> Client is 3.14.8-200.fc20.x86_64 and using NFSv4.1:
> 
> With a stock Fedora kernel on the server running 3.14.8-200.fc20.x86_64:
> 
> $ time sudo ./opentest -n 128 -l 1024 /mnt/palma
> 
> real	59m5.022s
> user	0m1.401s
> sys	0m17.561s
> 
> 
> ...with the patched kernel 3.16.0-rc2.jlayton.1+ (basically Bruce's
> for-3.17 branch with the rest of my patches piled on):
> 
> $ time sudo ./opentest -n 128 -l 1024 /mnt/palma
> 
> real	4m19.060s
> user	0m1.259s
> sys	0m13.059s
> 
> ...so around a factor of 13x speedup on parallel creates. Again, this
> is not a terribly scientific benchmark, but it does suggest that this
> patchset helps immensely.

Neat-o.

It might also be interesting to compare with NFSv3?

I wonder what a first good test of the smp scalability would be.

--b.

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

* Re: [PATCH v2 000/117] nfsd: eliminate the client_mutex
  2014-07-01 20:01                   ` J. Bruce Fields
@ 2014-07-01 20:13                     ` Jeff Layton
  2014-07-01 20:24                       ` J. Bruce Fields
  0 siblings, 1 reply; 162+ messages in thread
From: Jeff Layton @ 2014-07-01 20:13 UTC (permalink / raw)
  To: J. Bruce Fields
  Cc: Jeff Layton, Trond Myklebust, Christoph Hellwig, Linux NFS Mailing List

On Tue, 1 Jul 2014 16:01:35 -0400
"J. Bruce Fields" <bfields@fieldses.org> wrote:

> On Tue, Jul 01, 2014 at 02:46:31PM -0400, Jeff Layton wrote:
> > Ok, I haven't tested that yet, but I did put together a f20 machine on
> > bare metal to act as a server. Here are some results from a test that
> > forks 128 child processes and has each one create and close 1024 files.
> > Client is 3.14.8-200.fc20.x86_64 and using NFSv4.1:
> > 
> > With a stock Fedora kernel on the server running 3.14.8-200.fc20.x86_64:
> > 
> > $ time sudo ./opentest -n 128 -l 1024 /mnt/palma
> > 
> > real	59m5.022s
> > user	0m1.401s
> > sys	0m17.561s
> > 
> > 
> > ...with the patched kernel 3.16.0-rc2.jlayton.1+ (basically Bruce's
> > for-3.17 branch with the rest of my patches piled on):
> > 
> > $ time sudo ./opentest -n 128 -l 1024 /mnt/palma
> > 
> > real	4m19.060s
> > user	0m1.259s
> > sys	0m13.059s
> > 
> > ...so around a factor of 13x speedup on parallel creates. Again, this
> > is not a terribly scientific benchmark, but it does suggest that this
> > patchset helps immensely.
> 
> Neat-o.
> 
> It might also be interesting to compare with NFSv3?
> 
> I wonder what a first good test of the smp scalability would be.
> 
> --b.

Yeah, it is neato. And just to be sure that it wasn't some other random
change between 3.14 and 3.16, I popped off all of my patches, rebuilt
nfsd.ko and reran the test with everything else the same:

$ time sudo ./opentest -n 128 -l 1024 /mnt/palma

real	58m50.564s
user	0m1.513s
sys	0m18.963s

...so it really does appear that these changes make the difference.

-- 
Jeff Layton <jlayton@primarydata.com>

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

* Re: [PATCH v2 000/117] nfsd: eliminate the client_mutex
  2014-07-01 20:13                     ` Jeff Layton
@ 2014-07-01 20:24                       ` J. Bruce Fields
  0 siblings, 0 replies; 162+ messages in thread
From: J. Bruce Fields @ 2014-07-01 20:24 UTC (permalink / raw)
  To: Jeff Layton; +Cc: Trond Myklebust, Christoph Hellwig, Linux NFS Mailing List

On Tue, Jul 01, 2014 at 04:13:17PM -0400, Jeff Layton wrote:
> On Tue, 1 Jul 2014 16:01:35 -0400
> "J. Bruce Fields" <bfields@fieldses.org> wrote:
> 
> > On Tue, Jul 01, 2014 at 02:46:31PM -0400, Jeff Layton wrote:
> > > Ok, I haven't tested that yet, but I did put together a f20 machine on
> > > bare metal to act as a server. Here are some results from a test that
> > > forks 128 child processes and has each one create and close 1024 files.
> > > Client is 3.14.8-200.fc20.x86_64 and using NFSv4.1:
> > > 
> > > With a stock Fedora kernel on the server running 3.14.8-200.fc20.x86_64:
> > > 
> > > $ time sudo ./opentest -n 128 -l 1024 /mnt/palma
> > > 
> > > real	59m5.022s
> > > user	0m1.401s
> > > sys	0m17.561s
> > > 
> > > 
> > > ...with the patched kernel 3.16.0-rc2.jlayton.1+ (basically Bruce's
> > > for-3.17 branch with the rest of my patches piled on):
> > > 
> > > $ time sudo ./opentest -n 128 -l 1024 /mnt/palma
> > > 
> > > real	4m19.060s
> > > user	0m1.259s
> > > sys	0m13.059s
> > > 
> > > ...so around a factor of 13x speedup on parallel creates. Again, this
> > > is not a terribly scientific benchmark, but it does suggest that this
> > > patchset helps immensely.
> > 
> > Neat-o.
> > 
> > It might also be interesting to compare with NFSv3?
> > 
> > I wonder what a first good test of the smp scalability would be.
> > 
> > --b.
> 
> Yeah, it is neato. And just to be sure that it wasn't some other random
> change between 3.14 and 3.16, I popped off all of my patches, rebuilt
> nfsd.ko and reran the test with everything else the same:
> 
> $ time sudo ./opentest -n 128 -l 1024 /mnt/palma
> 
> real	58m50.564s
> user	0m1.513s
> sys	0m18.963s
> 
> ...so it really does appear that these changes make the difference.

Yes, and that number sounds about right: that's about 27ms per create,
which sounds like about the right number for latency of a create on a
normal hard drive?

(No idea how to think about the patched case.)

--b.

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

end of thread, other threads:[~2014-07-01 20:24 UTC | newest]

Thread overview: 162+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-06-26 19:11 [PATCH v2 000/117] nfsd: eliminate the client_mutex Jeff Layton
2014-06-26 19:11 ` [PATCH v2 001/117] nfsd: fix file access refcount leak when nfsd4_truncate fails Jeff Layton
2014-06-26 19:24   ` Jeff Layton
2014-06-28 11:00     ` Christoph Hellwig
2014-06-26 19:11 ` [PATCH v2 002/117] nfsd: fix return of nfs4_acl_write_who Jeff Layton
2014-06-26 19:11 ` [PATCH v2 003/117] nfsd: add __force to opaque verifier field casts Jeff Layton
2014-06-26 19:11 ` [PATCH v2 004/117] nfsd: clean up sparse endianness warnings in nfscache.c Jeff Layton
2014-06-26 19:11 ` [PATCH v2 005/117] nfsd: nfsd_splice_read and nfsd_readv should return __be32 Jeff Layton
2014-06-26 19:11 ` [PATCH v2 006/117] nfsd: add appropriate __force directives to filehandle generation code Jeff Layton
2014-06-26 19:11 ` [PATCH v2 007/117] nfsd: properly handle embedded newlines in fault_injection input Jeff Layton
2014-06-28 11:01   ` Christoph Hellwig
2014-06-26 19:11 ` [PATCH v2 008/117] nfsd: Protect addition to the file_hashtbl Jeff Layton
2014-06-26 19:11 ` [PATCH v2 009/117] nfsd: wait to initialize work struct just prior to using it Jeff Layton
2014-06-28 11:02   ` Christoph Hellwig
2014-06-26 19:11 ` [PATCH v2 010/117] nfsd: Avoid taking state_lock while holding inode lock in nfsd_break_one_deleg Jeff Layton
2014-06-28 11:06   ` Christoph Hellwig
2014-06-28 12:18     ` Jeff Layton
2014-06-26 19:11 ` [PATCH v2 011/117] nfsd: nfs4_preprocess_seqid_op should only set *stpp on success Jeff Layton
2014-06-26 19:11 ` [PATCH v2 012/117] nfsd: Cleanup nfs4svc_encode_compoundres Jeff Layton
2014-06-26 19:11 ` [PATCH v2 013/117] nfsd: Don't get a session reference without a client reference Jeff Layton
2014-06-26 19:11 ` [PATCH v2 014/117] nfsd: Allow struct nfsd4_compound_state to cache the nfs4_client Jeff Layton
2014-06-29 12:05   ` Christoph Hellwig
2014-06-26 19:11 ` [PATCH v2 015/117] nfsd: lock owners are not per open stateid Jeff Layton
2014-06-28 11:07   ` Christoph Hellwig
2014-06-26 19:11 ` [PATCH v2 016/117] nfsd: Allow lockowners to hold several stateids Jeff Layton
2014-06-26 19:11 ` [PATCH v2 017/117] nfsd: NFSv4 lock-owners are not associated to a specific file Jeff Layton
2014-06-26 19:11 ` [PATCH v2 018/117] nfsd: clean up nfs4_release_lockowner Jeff Layton
2014-06-29  6:47   ` Christoph Hellwig
2014-06-29 11:08     ` Jeff Layton
2014-06-30 11:02       ` Jeff Layton
2014-06-30 11:04         ` Christoph Hellwig
2014-06-26 19:11 ` [PATCH v2 019/117] nfsd: declare v4.1+ openowners confirmed on creation Jeff Layton
2014-06-29  6:48   ` Christoph Hellwig
2014-06-26 19:12 ` [PATCH v2 020/117] nfsd: Cleanup - Let nfsd4_lookup_stateid() take a cstate argument Jeff Layton
2014-06-29  6:49   ` Christoph Hellwig
2014-06-26 19:12 ` [PATCH v2 021/117] nfsd: clean up nfsd4_close_open_stateid Jeff Layton
2014-06-29 12:00   ` Christoph Hellwig
2014-06-26 19:12 ` [PATCH v2 022/117] nfsd: Cache the client that was looked up in lookup_clientid() Jeff Layton
2014-06-29 12:14   ` Christoph Hellwig
2014-06-29 14:57     ` Jeff Layton
2014-06-30 10:34       ` Christoph Hellwig
2014-06-30 10:59         ` Jeff Layton
2014-06-30 11:03           ` Christoph Hellwig
2014-06-30 11:23             ` Jeff Layton
2014-06-26 19:12 ` [PATCH v2 023/117] nfsd: Convert nfsd4_process_open1() to work with lookup_clientid() Jeff Layton
2014-06-29 12:16   ` Christoph Hellwig
2014-06-29 15:08     ` Jeff Layton
2014-06-30 10:35       ` Christoph Hellwig
2014-06-26 19:12 ` [PATCH v2 024/117] nfsd: Always use lookup_clientid() in nfsd4_process_open1 Jeff Layton
2014-06-29 12:16   ` Christoph Hellwig
2014-06-26 19:12 ` [PATCH v2 025/117] nfsd: Convert nfs4_check_open_reclaim() to work with lookup_clientid() Jeff Layton
2014-06-29 12:17   ` Christoph Hellwig
2014-06-26 19:12 ` [PATCH v2 026/117] nfsd: Move the delegation reference counter into the struct nfs4_stid Jeff Layton
2014-06-26 19:12 ` [PATCH v2 027/117] nfsd4: use cl_lock to synchronize all stateid idr calls Jeff Layton
2014-06-26 19:12 ` [PATCH v2 028/117] nfsd: Add fine grained protection for the nfs4_file->fi_stateids list Jeff Layton
2014-06-26 19:12 ` [PATCH v2 029/117] nfsd: Add a mutex to protect the NFSv4.0 open owner replay cache Jeff Layton
2014-06-26 19:12 ` [PATCH v2 030/117] nfsd: Add locking to the nfs4_file->fi_fds[] array Jeff Layton
2014-06-26 19:12 ` [PATCH v2 031/117] nfsd: refactor nfs4_file_get_access and nfs4_file_put_access Jeff Layton
2014-06-26 19:12 ` [PATCH v2 032/117] nfsd: remove nfs4_file_put_fd Jeff Layton
2014-06-26 19:12 ` [PATCH v2 033/117] nfsd: ensure that nfs4_file_get_access enforces deny modes Jeff Layton
2014-06-27 19:59   ` Jeff Layton
2014-06-26 19:12 ` [PATCH v2 034/117] nfsd: cleanup nfs4_check_open Jeff Layton
2014-06-26 19:12 ` [PATCH v2 035/117] locks: add file_has_lease to prevent delegation break races Jeff Layton
2014-06-26 19:12 ` [PATCH v2 036/117] nfsd: Protect the nfs4_file delegation fields using the fi_lock Jeff Layton
2014-06-26 19:12 ` [PATCH v2 037/117] nfsd: clean up helper __release_lock_stateid Jeff Layton
2014-06-30 10:40   ` Christoph Hellwig
2014-06-30 10:53     ` Jeff Layton
2014-06-26 19:12 ` [PATCH v2 038/117] nfsd: Simplify stateid management Jeff Layton
2014-06-26 19:12 ` [PATCH v2 039/117] nfsd: Fix delegation revocation Jeff Layton
2014-06-26 19:12 ` [PATCH v2 040/117] nfsd: Add reference counting to the lock and open stateids Jeff Layton
2014-06-26 19:12 ` [PATCH v2 041/117] nfsd: Add a struct nfs4_file field to struct nfs4_stid Jeff Layton
2014-06-26 19:12 ` [PATCH v2 042/117] nfsd: Replace nfs4_ol_stateid->st_file with the st_stid.sc_file Jeff Layton
2014-06-26 19:12 ` [PATCH v2 043/117] nfsd: Ensure stateids remain unique until they are freed Jeff Layton
2014-06-26 19:12 ` [PATCH v2 044/117] nfsd: Ensure atomicity of stateid destruction and idr tree removal Jeff Layton
2014-06-26 19:12 ` [PATCH v2 045/117] nfsd: Cleanup the freeing of stateids Jeff Layton
2014-06-26 19:12 ` [PATCH v2 046/117] nfsd: do filp_close in sc_free callback for lock stateids Jeff Layton
2014-06-26 19:12 ` [PATCH v2 047/117] nfsd: Add locking to protect the state owner lists Jeff Layton
2014-06-26 19:12 ` [PATCH v2 048/117] nfsd: clean up races in lock stateid searching and creation Jeff Layton
2014-06-26 19:12 ` [PATCH v2 049/117] nfsd: Convert delegation counter to an atomic_long_t type Jeff Layton
2014-06-26 19:12 ` [PATCH v2 050/117] nfsd: Slight cleanup of find_stateid() Jeff Layton
2014-06-26 19:12 ` [PATCH v2 051/117] nfsd: ensure atomicity in nfsd4_free_stateid and nfsd4_validate_stateid Jeff Layton
2014-06-26 19:12 ` [PATCH v2 052/117] nfsd: Add reference counting to lock stateids Jeff Layton
2014-06-26 19:12 ` [PATCH v2 053/117] nfsd: nfsd4_locku() must reference the lock stateid Jeff Layton
2014-06-26 19:12 ` [PATCH v2 054/117] nfsd: Ensure that nfs4_open_delegation() references the delegation stateid Jeff Layton
2014-06-26 19:12 ` [PATCH v2 055/117] nfsd: nfsd4_process_open2() must reference " Jeff Layton
2014-06-26 19:12 ` [PATCH v2 056/117] nfsd: nfsd4_process_open2() must reference the open stateid Jeff Layton
2014-06-26 19:12 ` [PATCH v2 057/117] nfsd: Prepare nfsd4_close() for open stateid referencing Jeff Layton
2014-06-26 19:12 ` [PATCH v2 058/117] nfsd: nfsd4_open_confirm() must reference the open stateid Jeff Layton
2014-06-26 19:12 ` [PATCH v2 059/117] nfsd: Add reference counting to nfs4_preprocess_confirmed_seqid_op Jeff Layton
2014-06-26 19:12 ` [PATCH v2 060/117] nfsd: Migrate the stateid reference into nfs4_preprocess_seqid_op Jeff Layton
2014-06-26 19:12 ` [PATCH v2 061/117] nfsd: Migrate the stateid reference into nfs4_lookup_stateid() Jeff Layton
2014-06-26 19:12 ` [PATCH v2 062/117] nfsd: Migrate the stateid reference into nfs4_find_stateid_by_type() Jeff Layton
2014-06-26 19:12 ` [PATCH v2 063/117] nfsd: Add reference counting to state owners Jeff Layton
2014-06-26 19:12 ` [PATCH v2 064/117] nfsd: Keep a reference to the open stateid for the NFSv4.0 replay cache Jeff Layton
2014-06-26 19:12 ` [PATCH v2 065/117] nfsd: clean up lockowner refcounting when finding them Jeff Layton
2014-06-26 19:12 ` [PATCH v2 066/117] nfsd: add an operation for unhashing a stateowner Jeff Layton
2014-06-26 19:12 ` [PATCH v2 067/117] nfsd: Make lock stateid take a reference to the lockowner Jeff Layton
2014-06-26 19:12 ` [PATCH v2 068/117] nfsd: clean up refcounting for lockowners Jeff Layton
2014-06-26 19:12 ` [PATCH v2 069/117] nfsd: make openstateids hold references to their openowners Jeff Layton
2014-06-26 19:12 ` [PATCH v2 070/117] nfsd: don't allow CLOSE to proceed until refcount on stateid drops Jeff Layton
2014-06-26 19:12 ` [PATCH v2 071/117] nfsd: Protect adding/removing open state owners using client_lock Jeff Layton
2014-06-26 19:12 ` [PATCH v2 072/117] nfsd: Protect adding/removing lock " Jeff Layton
2014-06-26 19:12 ` [PATCH v2 073/117] nfsd: Move the open owner hash table into struct nfs4_client Jeff Layton
2014-06-26 19:12 ` [PATCH v2 074/117] lockdep: add lockdep_assert_not_held Jeff Layton
2014-06-26 19:12 ` [PATCH v2 075/117] nfsd: add locking to stateowner release Jeff Layton
2014-06-26 19:12 ` [PATCH v2 076/117] nfsd: optimize destroy_lockowner cl_lock thrashing Jeff Layton
2014-06-26 19:12 ` [PATCH v2 077/117] nfsd: close potential race in nfsd4_free_stateid Jeff Layton
2014-06-26 19:12 ` [PATCH v2 078/117] nfsd: reduce cl_lock thrashing in release_openowner Jeff Layton
2014-06-26 19:12 ` [PATCH v2 079/117] nfsd: don't thrash the cl_lock while freeing an open stateid Jeff Layton
2014-06-26 19:13 ` [PATCH v2 080/117] nfsd: Ensure struct nfs4_client is unhashed before we try to destroy it Jeff Layton
2014-06-26 19:13 ` [PATCH v2 081/117] nfsd: Ensure that the laundromat unhashes the client before releasing locks Jeff Layton
2014-06-26 19:13 ` [PATCH v2 082/117] nfsd: Don't require client_lock in free_client Jeff Layton
2014-06-26 19:13 ` [PATCH v2 083/117] nfsd: Move create_client() call outside the lock Jeff Layton
2014-06-26 19:20 ` [PATCH v2 084/117] nfsd: Protect unconfirmed client creation using client_lock Jeff Layton
2014-06-26 19:20 ` [PATCH v2 085/117] nfsd: Protect session creation and client confirm " Jeff Layton
2014-06-26 19:20 ` [PATCH v2 086/117] nfsd: Protect nfsd4_destroy_clientid " Jeff Layton
2014-06-26 19:20 ` [PATCH v2 087/117] nfsd: Ensure lookup_clientid() takes client_lock Jeff Layton
2014-06-26 19:20 ` [PATCH v2 088/117] nfsd: Add lockdep assertions to document the nfs4_client/session locking Jeff Layton
2014-06-26 19:20 ` [PATCH v2 089/117] nfsd: protect the close_lru list and oo_last_closed_stid with client_lock Jeff Layton
2014-06-26 19:20 ` [PATCH v2 090/117] nfsd: ensure that clp->cl_revoked list is protected by clp->cl_lock Jeff Layton
2014-06-26 19:20 ` [PATCH v2 091/117] nfsd: move unhash_client_locked call into mark_client_expired_locked Jeff Layton
2014-06-26 19:21 ` [PATCH v2 092/117] nfsd: don't destroy client if mark_client_expired_locked fails Jeff Layton
2014-06-26 19:21 ` [PATCH v2 093/117] nfsd: don't destroy clients that are busy Jeff Layton
2014-06-26 19:21 ` [PATCH v2 094/117] nfsd: protect clid and verifier generation with client_lock Jeff Layton
2014-06-26 19:21 ` [PATCH v2 095/117] nfsd: abstract out the get and set routines into the fault injection ops Jeff Layton
2014-06-26 19:21 ` [PATCH v2 096/117] nfsd: add a forget_clients "get" routine with proper locking Jeff Layton
2014-06-26 19:21 ` [PATCH v2 097/117] nfsd: add a forget_client set_clnt routine Jeff Layton
2014-06-26 19:21 ` [PATCH v2 098/117] nfsd: add nfsd_inject_forget_clients Jeff Layton
2014-06-26 19:21 ` [PATCH v2 099/117] nfsd: add a list_head arg to nfsd_foreach_client_lock Jeff Layton
2014-06-26 19:21 ` [PATCH v2 100/117] nfsd: add more granular locking to forget_locks fault injector Jeff Layton
2014-06-26 19:21 ` [PATCH v2 101/117] nfsd: add more granular locking to forget_openowners " Jeff Layton
2014-06-26 19:21 ` [PATCH v2 102/117] nfsd: add more granular locking to *_delegations fault injectors Jeff Layton
2014-06-26 19:21 ` [PATCH v2 103/117] nfsd: remove old fault injection infrastructure Jeff Layton
2014-06-26 19:21 ` [PATCH v2 104/117] nfsd: Remove nfs4_lock_state(): nfs4_preprocess_stateid_op() Jeff Layton
2014-06-26 19:21 ` [PATCH v2 105/117] nfsd: Remove nfs4_lock_state(): nfsd4_test_stateid/nfsd4_free_stateid Jeff Layton
2014-06-26 19:21 ` [PATCH v2 106/117] nfsd: Remove nfs4_lock_state(): nfsd4_release_lockowner Jeff Layton
2014-06-26 19:21 ` [PATCH v2 107/117] nfsd: Remove nfs4_lock_state(): nfsd4_lock/locku/lockt() Jeff Layton
2014-06-26 19:21 ` [PATCH v2 108/117] nfsd: Remove nfs4_lock_state(): nfsd4_open_downgrade + nfsd4_close Jeff Layton
2014-06-26 19:21 ` [PATCH v2 109/117] nfsd: Remove nfs4_lock_state(): nfsd4_delegreturn() Jeff Layton
2014-06-26 19:21 ` [PATCH v2 110/117] nfsd: Remove nfs4_lock_state(): nfsd4_open and nfsd4_open_confirm Jeff Layton
2014-06-26 19:21 ` [PATCH v2 111/117] nfsd: Remove nfs4_lock_state(): exchange_id, create/destroy_session() Jeff Layton
2014-06-26 19:21 ` [PATCH v2 112/117] nfsd: Remove nfs4_lock_state(): setclientid, setclientid_confirm, renew Jeff Layton
2014-06-26 19:21 ` [PATCH v2 113/117] nfsd: Remove nfs4_lock_state(): reclaim_complete() Jeff Layton
2014-06-26 19:21 ` [PATCH v2 114/117] nfsd: remove nfs4_lock_state: nfs4_laundromat Jeff Layton
2014-06-26 19:21 ` [PATCH v2 115/117] nfsd: remove nfs4_lock_state: nfs4_state_shutdown_net Jeff Layton
2014-06-26 19:21 ` [PATCH v2 116/117] nfsd: remove the client_mutex and the nfs4_lock/unlock_state wrappers Jeff Layton
2014-06-26 19:21 ` [PATCH v2 117/117] nfsd: add file documenting new state object model Jeff Layton
2014-06-27 16:22 ` [PATCH v2 000/117] nfsd: eliminate the client_mutex J. Bruce Fields
2014-06-27 19:08   ` Jeff Layton
2014-06-30 12:51 ` Christoph Hellwig
2014-06-30 12:59   ` Jeff Layton
2014-06-30 19:32     ` J. Bruce Fields
2014-06-30 19:39       ` Jeff Layton
2014-06-30 20:20       ` Jeff Layton
2014-06-30 20:31         ` Trond Myklebust
2014-06-30 20:36           ` Jeff Layton
2014-07-01 14:10             ` Jeff Layton
2014-07-01 14:21               ` Trond Myklebust
2014-07-01 18:46                 ` Jeff Layton
2014-07-01 20:01                   ` J. Bruce Fields
2014-07-01 20:13                     ` Jeff Layton
2014-07-01 20:24                       ` J. Bruce Fields

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