nfsd: eliminate the client_mutex
Subsystems (6)
cover nfsd: eliminate the client_mutex
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.
I'd like to see this considered for v3.17. Obviously, getting it into linux-next ASAP would be a good thing once it passes review.
Some other highlights/notes:
- use of lockdep has been greatly increased. I found it was the only way to ensure that I didn't create lock inversion problems and such.
- clients are now only looked up once per compund and are cached in the cstate. This keeps us from having to keep searching for the same client for each compound op.
- openowners and lockowners are now handled more sanely. References to them are only held by the stateids that are associated with them, and they are destroyed when the last reference to them is put. Also, lockowners can now have more than one stateid (in accordance with the spec)
- the fault injection code has been overhauled. It should look the same to users, but it needed major work to deal with the new locking. It's probably possible to consolidate some of that code as well -- it more cut-and-pastey than I'd like.
- I've added a file to document how all of the moving parts fit together. It probably can use more fleshing out, but it's a start.
- the lease handling is now a bit more complex than I'd like. Lease removal in particular is currently called under a spinlock, which I think we'll need to eventually clean up. For now, this is ok since the first thing that vfs_setlease does is lock the i_lock, but I think we'll eventually need to do an i_lock pushdown in the lease handling code, and ensure that vfs_setlease isn't called under a spinlock.
As always, comments and review are welcome.
Benny Halevy (1):
nfsd4: use cl_lock to synchronize all stateid idr calls
Jeff Layton (40):
NFSd: Ensure that nfs4_file_get_access enforces share access modes
locks: add file_has_lease
NFSd: Protect the nfs4_file delegation fields using the fi_lock
NFSd: Allow lockowners to hold several stateids
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: clean up lockowner refcounting when finding them
nfsd: add an operation for unhashing a stateowner
nfsd: clean up nfs4_release_lockowner
nfsd: clean up refcounting for lockowners
nfsd: declare v4.1+ openowners confirmed on creation
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: reduce cl_lock trashing in release_openowner
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: fix misleading comment
nfsd: don't destroy client if mark_client_expired_locked fails
nfsd: don't destroy clients that are busy
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 (63):
nfsd: Protect addition to the file_hashtbl
NFSd: Avoid taking state_lock while holding inode lock in
nfsd_break_one_deleg
NFSd: nfs4_preprocess_seqid_op should only set *stpp on success
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: Lock owners are not per open stateid
NFSd: Clean up helper __release_lock_stateid
NFSd: NFSv4 lock-owners are not associated to a specific file
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: Move the delegation reference counter into the struct nfs4_stid
NFSd: Simplify stateid management
NFSd: Fix delegation revocation
NFSd: Add reference counting to the lock and open stateids
NFSd: clean up nfsd4_close_open_stateid
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 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: Cleanup - Let nfsd4_lookup_stateid() take a cstate argument
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: Move the open owner hash table into struct nfs4_client
NFSd: Convert nfs4_check_open_reclaim() to work with lookup_clientid()
NFSd: Ensure struct nfs4_client is unhashed before we try to destroy
it
NFSd: Ensure that the laundromat unhashes the client before releasing
locks
NFSd: Don't require client_lock in free_client
NFSd: Move create_client() call outside the lock
NFSd: Protect unconfirmed client creation using client_lock
NFSd: Protect nfsd4_destroy_clientid using client_lock
NFSd: Ensure lookup_clientid() takes client_lock
NFSd: Add 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 | 110 + fs/locks.c | 26 + fs/nfsd/fault_inject.c | 129 +- fs/nfsd/netns.h | 5 - fs/nfsd/nfs4callback.c | 18 +- fs/nfsd/nfs4proc.c | 16 +- fs/nfsd/nfs4state.c | 2569 ++++++++++++++------ fs/nfsd/nfs4xdr.c | 17 +- fs/nfsd/state.h | 86 +- fs/nfsd/xdr4.h | 8 +- include/linux/fs.h | 6 + include/linux/lockdep.h | 6 + 12 files changed, 2052 insertions(+), 944 deletions(-) create mode 100644 Documentation/filesystems/nfs/nfsd4-state-objects.txt
Signature · 1 line
1.9.3
PATCH 1/104 nfsd: Protect addition to the file_hashtbl
From: Trond Myklebust <[email protected]>
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.
--- fs/nfsd/nfs4state.c | 49 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 12 deletions(-)
fs/nfsd/nfs4state.c +37 -12
@@ -2535,17 +2535,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
@@ -2711,23 +2712,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
@@ -3246,21 +3273,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); }/*
Signature · 1 line
1.9.3
PATCH 2/104 NFSd: Avoid taking state_lock while holding inode lock in nfsd_break_one_deleg
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
state_lock is a heavily contended global lock. We don't want to grab that while simultaneously holding the inode->i_lock
Instead do the list manipulations from the work queue context prior to starting the rpc call.
--- fs/nfsd/nfs4callback.c | 18 ++++++++++++++++-- fs/nfsd/nfs4state.c | 42 ++++++++++++++++++++++++++++-------------- fs/nfsd/state.h | 2 ++ 3 files changed, 46 insertions(+), 16 deletions(-)
fs/nfsd/nfs4callback.c +16 -2
@@ -1011,9 +1011,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;
@@ -1031,11 +1030,25 @@ static void nfsd4_do_callback_rpc(struct work_struct *w) cb->cb_ops, cb); } +static void nfsd4_do_callback_rpc (struct work_struct *w) +{ + struct nfsd4_callback *cb = container_of(w, struct nfsd4_callback, cb_work); +nfsd4_run_callback_rpc (cb); +} +void nfsd4_init_callback (struct nfsd4_callback *cb) {INIT_WORK (&cb->cb_work, nfsd4_do_callback_rpc); } +static void nfsd4_do_cb_recall (struct work_struct *w) +{ + struct nfsd4_callback *cb = container_of(w, struct nfsd4_callback, cb_work); + +nfsd4_prepare_cb_recall (cb->cb_op); +nfsd4_run_callback_rpc (cb); +} +void nfsd4_cb_recall (struct nfs4_delegation *dp) {struct nfsd4_callback *cb = &dp->dl_recall;
@@ -1052,6 +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_cb_recall);run_nfsd4_cb (&dp->dl_recall); }
fs/nfsd/nfs4state.c +28 -14
90 lines not on this page · raw message
fs/nfsd/state.h +2 -0
@@ -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;
@@ -472,6 +473,7 @@ extern void nfsd4_cb_recall(struct nfs4_delegation *dp);extern int nfsd4_create_callback_queue (void );extern void nfsd4_destroy_callback_queue (void );extern void nfsd4_shutdown_callback (struct nfs4_client *); +extern void nfsd4_prepare_cb_recall (struct nfs4_delegation *dp);extern void nfs4_put_delegation (struct nfs4_delegation *dp);extern struct nfs4_client_reclaim *nfs4_client_to_reclaim (const char *name,struct nfsd_net *nn);
Signature · 1 line
1.9.3
Re: [PATCH v1 002/104] NFSd: Avoid taking state_lock while holding inode lock in nfsd_break_one_deleg
Quoted 6 lines · Jeff Layton
From: Trond Myklebust <[email protected]>
state_lockis a heavily contended global lock. We don't want to grab that while simultaneously holding theinode->i_lock
Instead do the list manipulations from the work queue context prior to starting the rpc call.
The description should mention that a new lock is added to facilitate this.
Quoted 4 lines
void
nfsd4_init_callback(struct nfsd4_callback *cb){
INIT_WORK(&cb->cb_work, nfsd4_do_callback_rpc);
}
We still call nfsd4_init_callback for delegations after this patch, and thus first initialize the work item to nfsd4_do_callback_rpc and later overide it. But I think initializing the work item before queueing up the callback is pretty silly anyway, so I'd suggest adding a patch before this one to just kill nfsd4_init_callback and initialize the item in do_probe_callback and nfsd4_cb_recall directly.
fs/nfsd/nfs4state.c out: · line 2801
Quoted 11 lines
fs/nfsd/nfs4state.c +5
-2-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 +*/
Can't is a little too strong given that it did indeed work before.
PATCH 3/104 NFSd: nfs4_preprocess_seqid_op should only set *stpp on success
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
--- fs/nfsd/nfs4state.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)
fs/nfsd/nfs4state.c +7 -3
@@ -3891,6 +3891,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));
@@ -3900,11 +3901,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,
Signature · 1 line
1.9.3
PATCH 4/104 nfsd4: use cl_lock to synchronize all stateid idr calls
In reply to Jeff LaytonFrom: Benny Halevy <[email protected]>
--- fs/nfsd/nfs4state.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-)
fs/nfsd/nfs4state.c +13 -4
@@ -326,7 +326,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;
@@ -334,7 +333,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;
@@ -396,9 +399,11 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct svstatic 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)
@@ -1141,7 +1146,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); }
@@ -1364,7 +1371,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;
Signature · 1 line
1.9.3
Re: [PATCH v1 004/104] nfsd4: use cl_lock to synchronize all stateid idr calls
This looks reasonable to me. Am I right to assume this is just a preparation for the state lock removal? As far as I can tell currently all calls are under nfs4_lock_state().
assuming it gets a proper patch description.
Re: [PATCH v1 004/104] nfsd4: use cl_lock to synchronize all stateid idr calls
Quoted 8 lines · On Mon, 23 Jun 2014 09:02:27 -0700 Christoph Hellwig <[email protected]> wrote:
This looks reasonable to me. Am I right to assume this is just a preparation for the state lock removal? As far as I can tell currently all calls are under
nfs4_lock_state().Reviewed-by Christoph Hellwig <[email protected]>assuming it gets a proper patch description.
Yes, that's correct, and that's the case with pretty much all of the patches that add locking here. I can explicitly spell that out in every patch description but that may get tedious over >100 patches.
Also, let's be careful about terminology here...
What we're removing is the client_mutex (which has unfortunately named wrappers around it called nfs4_lock_state and nfs4_unlock_state).
We have yet another spinlock called the "state_lock" which protects the nfs4_file hashes and such, as well as some of the delegation code.
Signature · 1 line
Jeff Layton <[email protected]>
PATCH 5/104 NFSd: Add fine grained protection for the nfs4_file->fi_stateids list
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
--- fs/nfsd/nfs4state.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-)
fs/nfsd/nfs4state.c +17 -3
@@ -625,7 +625,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); }
@@ -2672,7 +2676,6 @@ static void init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp, stp->st_stid.sc_type =NFS4_OPEN_STID ;INIT_LIST_HEAD (&stp->st_lockowners);list_add (&stp->st_perstateowner, &oo->oo_owner.so_stateids); -list_add (&stp->st_perfile, &fp->fi_stateids); stp->st_stateowner = &oo->oo_owner;get_nfs4_file (fp); stp->st_file = fp;
@@ -2681,6 +2684,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
@@ -2788,6 +2794,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))
@@ -2795,6 +2802,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; }
@@ -2993,6 +3001,7 @@ nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_ol_ststruct 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 )
@@ -3001,9 +3010,12 @@ nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_ol_stif (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; }
@@ -4308,7 +4320,6 @@ alloc_init_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp, structif (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);
@@ -4316,6 +4327,9 @@ alloc_init_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp, struct stp->st_access_bmap =0 ; stp->st_deny_bmap = open_stp->st_deny_bmap; stp->st_openstp = open_stp; +spin_lock (&fp->fi_lock); +list_add (&stp->st_perfile, &fp->fi_stateids); +spin_unlock (&fp->fi_lock);return stp; }
Signature · 1 line
1.9.3
Re: [PATCH v1 005/104] NFSd: Add fine grained protection for the nfs4_file->fi_stateids list
Quoted 3 lines · Jeff Layton
From: Trond Myklebust <[email protected]>
Signed-off-by Trond Myklebust <[email protected]>
Looks good, but should have a patch description that better tells why this is done (looks like preparing for nfs_lock_state() removal again, not fixing some existing race)
Re: [PATCH v1 005/104] NFSd: Add fine grained protection for the nfs4_file->fi_stateids list
Quoted 10 lines · On Mon, 23 Jun 2014 09:04:07 -0700 Christoph Hellwig <[email protected]> wrote:
Quoted 3 lines · Jeff Layton
From: Trond Myklebust <[email protected]>
Signed-off-by Trond Myklebust <[email protected]>Looks good, but should have a patch description that better tells why this is done (looks like preparing for
nfs_lock_state()removal again, not fixing some existing race)Reviewed-by Christoph Hellwig <[email protected]>
Correct. I'll add that into the desciption if you think it's warranted, but again that's the case with many of the patches in this series.
Signature · 1 line
Jeff Layton <[email protected]>
Re: [PATCH v1 005/104] NFSd: Add fine grained protection for the nfs4_file->fi_stateids list
Quoted 2 lines · Jeff Layton
Correct. I'll add that into the desciption if you think it's warranted, but again that's the case with many of the patches in this series.
It might be fairly obvious in the context of the series, it's not if someone goes back in history with a git-blame.
And it's not a 100% obvious with the series either, at least earlier versions also fixes pre-existing races, although all of that might be upstream now.
So as far as I am concerned a simple one-line blurb mentioning what the new locking is for would be useful to be added to all patches just changing the locking.
Re: [PATCH v1 005/104] NFSd: Add fine grained protection for the nfs4_file->fi_stateids list
Quoted 7 lines · On Mon, 23 Jun 2014 09:23:32 -0700 Christoph Hellwig <[email protected]> wrote:
Quoted 2 lines · Jeff Layton
Correct. I'll add that into the desciption if you think it's warranted, but again that's the case with many of the patches in this series.
It might be fairly obvious in the context of the series, it's not if someone goes back in history with a git-blame.
Quoted 7 lines
And it's not a 100% obvious with the series either, at least earlier versions also fixes pre-existing races, although all of that might be upstream now.
So as far as I am concerned a simple one-line blurb mentioning what the new locking is for would be useful to be added to all patches just changing the locking.
Fair enough. I'll do that.
Thanks,
Signature · 1 line
Jeff Layton <[email protected]>
Re: [PATCH v1 005/104] NFSd: Add fine grained protection for the nfs4_file->fi_stateids list
Quoted 14 lines · Jeff Layton
Quoted 11 lines · On Mon, 23 Jun 2014 09:23:32 -0700 Christoph Hellwig <[email protected]> wrote:
Quoted 2 lines · Jeff Layton
Correct. I'll add that into the desciption if you think it's warranted, but again that's the case with many of the patches in this series.
It might be fairly obvious in the context of the series, it's not if someone goes back in history with a git-blame.
And it's not a 100% obvious with the series either, at least earlier versions also fixes pre-existing races, although all of that might be upstream now.
Quoted 5 lines
Quoted 3 lines
So as far as I am concerned a simple one-line blurb mentioning what the new locking is for would be useful to be added to all patches just changing the locking.
Fair enough. I'll do that.
I appreciate that it's tedious but yes, thanks, that would be helpful.
--b.
PATCH 6/104 NFSd: Add a mutex to protect the NFSv4.0 open owner replay cache
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
We don't want to rely on the state_lock() for protection in the case of NFSv4 open owners. Instead, we add a mutex that will only be taken for NFSv4.0 state mutating operations, and that will be released once the entire compound is done.
--- fs/nfsd/nfs4proc.c | 13 +++++-------- fs/nfsd/nfs4state.c | 21 ++++++++------------- fs/nfsd/nfs4xdr.c | 2 -- fs/nfsd/state.h | 1 + fs/nfsd/xdr4.h | 19 +++++++++++++++++++ 5 files changed, 33 insertions(+), 23 deletions(-)
fs/nfsd/nfs4proc.c +5 -8
@@ -469,11 +469,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; }
@@ -1404,10 +1404,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);
fs/nfsd/nfs4state.c +8 -13
@@ -781,7 +781,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)
@@ -2622,6 +2622,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)
@@ -3923,8 +3924,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)
@@ -3985,8 +3985,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; }
@@ -4068,8 +4067,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; }
@@ -4126,8 +4124,7 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, } } out: -if (!cstate->replay_owner) -nfs4_unlock_state (); +nfs4_unlock_state ();return status; }
@@ -4539,8 +4536,7 @@ out:if (status && new_state)release_lockowner (lock_sop);nfsd4_bump_seqid (cstate, status); -if (!cstate->replay_owner) -nfs4_unlock_state (); +nfs4_unlock_state ();if (file_lock)locks_free_lock (file_lock);if (conflock)
@@ -4703,8 +4699,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;
fs/nfsd/nfs4xdr.c +0 -2
@@ -3923,8 +3923,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)
fs/nfsd/state.h +1 -0
@@ -329,6 +329,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 ]; };
fs/nfsd/xdr4.h +19 -0
@@ -73,6 +73,25 @@ static inline bool nfsd4_has_session(struct nfsd4_compound_state *cs)return cs->slot !=NULL ; } +static inline void nfsd4_cstate_assign_replay (struct nfsd4_compound_state *cstate, +struct nfs4_stateowner *so) +{ +if (!nfsd4_has_session (cstate)) { +mutex_lock (&so->so_replay.rp_mutex); + cstate->replay_owner = so; + } +} + +static inline void nfsd4_cstate_clear_replay (struct nfsd4_compound_state *cstate) +{ +struct nfs4_stateowner *so = cstate->replay_owner; + +if (so !=NULL ) { + cstate->replay_owner =NULL ; +mutex_unlock (&so->so_replay.rp_mutex); + } +} +struct nfsd4_change_info {u32 atomic;bool change_supported;
Signature · 1 line
1.9.3
Re: [PATCH v1 006/104] NFSd: Add a mutex to protect the NFSv4.0 open owner replay cache
Quoted 8 lines · Jeff Layton
From: Trond Myklebust <[email protected]>
We don't want to rely on the
state_lock()for protection in the case of NFSv4 open owners. Instead, we add a mutex that will only be taken for NFSv4.0 state mutating operations, and that will be released once the entire compound is done.Signed-off-by Trond Myklebust <[email protected]>
Looks reasonable to me, but doesn't this create a lock order reversal with the client_lock until it is removed?
Re: [PATCH v1 006/104] NFSd: Add a mutex to protect the NFSv4.0 open owner replay cache
Quoted 8 lines · On Mon, 23 Jun 2014 09:05:49 -0700 Christoph Hellwig <[email protected]> wrote:
Quoted 7 lines · Jeff Layton
From: Trond Myklebust <[email protected]>
We don't want to rely on the
state_lock()for protection in the case of NFSv4 open owners. Instead, we add a mutex that will only be taken for NFSv4.0 state mutating operations, and that will be released once the entire compound is done.
Quoted 5 lines
Quoted 1 line
Signed-off-by Trond Myklebust <[email protected]>Looks reasonable to me, but doesn't this create a lock order reversal with the
client_lockuntil it is removed?
No, I don't think so. AFAICT, the new mutex is always taken inside of the client_mutex until that point.
Signature · 1 line
Jeff Layton <[email protected]>
PATCH 7/104 NFSd: Add locking to the nfs4_file->fi_fds[] array
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
--- fs/nfsd/nfs4state.c | 105 ++++++++++++++++++++++++++++++++++++++++++++-------- fs/nfsd/state.h | 26 ------------- 2 files changed, 89 insertions(+), 42 deletions(-)
fs/nfsd/nfs4state.c +89 -16
@@ -249,6 +249,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;
@@ -297,20 +343,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); } }
@@ -653,8 +708,10 @@ static void release_lock_stateid(struct nfs4_ol_stateid *stp)unhash_generic_stateid (stp);unhash_stid (&stp->st_stid); file =find_any_file (stp->st_file); -if (file) +if (file) {locks_remove_posix (file, (fl_owner_t )lockowner (stp->st_stateowner)); +fput (file); + }close_generic_stateid (stp);free_generic_stateid (stp); }
@@ -3034,17 +3091,27 @@ static inline int nfs4_access_to_access(u32 nfs4_access)static __be32 nfs4_get_vfs_file (struct svc_rqst *rqstp,struct nfs4_file *fp,struct svc_fh *cur_fh,struct nfsd4_open *open) { +struct file *filp =NULL ;__be32 status;int oflag =nfs4_access_to_omode (open->op_share_access);int access =nfs4_access_to_access (open->op_share_access); +spin_lock (&fp->fi_lock);if (!fp->fi_fds[oflag]) { - status =nfsd_open (rqstp, cur_fh,S_IFREG , access, - &fp->fi_fds[oflag]); +spin_unlock (&fp->fi_lock); + status =nfsd_open (rqstp, cur_fh,S_IFREG , access, &filp);if (status)return status; +spin_lock (&fp->fi_lock); +if (!fp->fi_fds[oflag]) { + fp->fi_fds[oflag] = filp; + filp =NULL ; + } }nfs4_file_get_access (fp, oflag); +spin_unlock (&fp->fi_lock); +if (filp) +fput (filp);return nfs_ok; }
@@ -3143,13 +3210,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; }
@@ -3763,6 +3832,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 :
@@ -3790,7 +3860,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;
@@ -4533,6 +4603,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,break ; } out: +if (filp) +fput (filp);if (status && new_state)release_lockowner (lock_sop);nfsd4_bump_seqid (cstate, status);
@@ -4674,7 +4746,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 ;
@@ -4696,7 +4768,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 ();
@@ -4706,7 +4779,7 @@ out: out_nfserr: status =nfserrno (err); - goto out; + goto fput; }/*
fs/nfsd/state.h +0 -26
@@ -404,32 +404,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 */
Signature · 1 line
1.9.3
Re: [PATCH v1 007/104] NFSd: Add locking to the nfs4_file->fi_fds[] array
Missed the why the locking is added.
Also I pointed out a way to better factor this code in reply to one of Tronds previous postings of this one.
Re: [PATCH v1 007/104] NFSd: Add locking to the nfs4_file->fi_fds[] array
Quoted 5 lines · On Mon, 23 Jun 2014 09:06:36 -0700 Christoph Hellwig <[email protected]> wrote:
Missed the why the locking is added.
Also I pointed out a way to better factor this code in reply to one of Tronds previous postings of this one.
I saw your comments and even did some experimentation to that end. After playing around with some patches that tried to use FMODE flags instead, I tossed them out. It may have consolidated the code a bit, but the result was just too difficult to follow. I think it's better to go with clearer code here, even if it's a little more verbose.
Signature · 1 line
Jeff Layton <[email protected]>
Re: [PATCH v1 007/104] NFSd: Add locking to the nfs4_file->fi_fds[] array
Quoted 5 lines · Jeff Layton
I saw your comments and even did some experimentation to that end. After playing around with some patches that tried to use FMODE flags instead, I tossed them out. It may have consolidated the code a bit, but the result was just too difficult to follow. I think it's better to go with clearer code here, even if it's a little more verbose.
ok..
PATCH 8/104 NFSd: Ensure that nfs4_file_get_access enforces share access modes
In reply to Jeff LaytonLock atomicity requires us to check the share access mode when we actually open the file. Note that ideally this would also be atomic with file creation.
With the change to make nfs4_file_get_access enforce the share mode, we now have a bogus WARN_ON that can fire. It's now normal to call nfs4_file_get_access before populating the fi_fds field for the open flag, so we should no longer warn on that situation.
The other case is a WARN_ON that can occur if there's a O_RDWR open already present. I'm unclear on why we'd WARN_ON in that case. This patch removes it, but please do enlighten me if there's some reason we ought to keep it instead.
--- fs/nfsd/nfs4state.c | 163 +++++++++++++++++++++++++++++++++++++--------------- fs/nfsd/state.h | 1 + 2 files changed, 118 insertions(+), 46 deletions(-)
fs/nfsd/nfs4state.c +117 -46
@@ -320,6 +320,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? */
@@ -328,19 +342,33 @@ 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 __be32 nfs4_file_get_access (struct nfs4_file *fp,u32 access,u32 deny) { -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); -static void nfs4_file_get_access (struct nfs4_file *fp,int oflag) -{ +/* Note: relies on NFS4_SHARE_ACCESS_BOTH == READ|WRITE */ + access &= (NFS4_SHARE_ACCESS_READ |NFS4_SHARE_ACCESS_WRITE ); +if (access ==0 ) +return nfserr_inval; +if ((access & fp->fi_share_deny) !=0 ) +return nfserr_share_denied; +/* Note: relies on NFS4_SHARE_DENY_BOTH == READ|WRITE */ + deny &= (NFS4_SHARE_DENY_READ |NFS4_SHARE_DENY_WRITE ); +if (deny) { +if ((deny &NFS4_SHARE_DENY_READ ) && +atomic_read (&fp->fi_access[O_RDONLY ])) +return nfserr_share_denied; +if ((deny &NFS4_SHARE_DENY_WRITE ) && +atomic_read (&fp->fi_access[O_WRONLY ])) +return nfserr_share_denied; + fp->fi_share_deny |= deny; + }if (oflag ==O_RDWR ) { -__nfs4_file_get_access (fp,O_RDONLY ); -__nfs4_file_get_access (fp,O_WRONLY ); +atomic_inc (&fp->fi_access[O_RDONLY ]); +atomic_inc (&fp->fi_access[O_WRONLY ]); }else -__nfs4_file_get_access (fp, oflag); +atomic_inc (&fp->fi_access[oflag]); +return nfs_ok; }static struct file *nfs4_file_put_fd (struct nfs4_file *fp,int oflag)
@@ -352,6 +380,17 @@ static struct file *nfs4_file_put_fd(struct nfs4_file *fp, int oflag)return filp; } +static void __nfs4_file_put_deny (struct nfs4_file *fp,u32 deny) +{ +/* Note: relies on NFS4_SHARE_DENY_BOTH == READ|WRITE */ + deny &= (NFS4_SHARE_DENY_READ |NFS4_SHARE_DENY_WRITE ); +if (!deny) +return ; +spin_lock (&fp->fi_lock); + fp->fi_share_deny &= ~deny; +spin_unlock (&fp->fi_lock); +} +static void __nfs4_file_put_access (struct nfs4_file *fp,int oflag) {if (atomic_dec_and_lock (&fp->fi_access[oflag], &fp->fi_lock)) {
@@ -369,8 +408,16 @@ 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,u32 deny) { +int oflag; + +__nfs4_file_put_deny (fp, deny); +/* Note: relies on NFS4_SHARE_ACCESS_BOTH == READ|WRITE */ + 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 );
@@ -650,31 +697,21 @@ 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) { -int i; +u32 i;for (i =1 ; i <4 ; i++) { -if (test_access (i, stp)) -nfs4_file_put_access (stp->st_file, -nfs4_access_to_omode (i)); -clear_access (i, stp); +if (test_deny (i, stp)) { +nfs4_file_put_access (stp->st_file,0 , i); +clear_deny (i, stp); + } +if (test_access (i, stp)) { +nfs4_file_put_access (stp->st_file, i,0 ); +clear_access (i, stp); + } } }
@@ -2623,6 +2660,7 @@ static void nfsd4_init_file(struct nfs4_file *fp, struct inode *ino) fp->fi_lease =NULL ;memset (fp->fi_fds,0 ,sizeof (fp->fi_fds));memset (fp->fi_access,0 ,sizeof (fp->fi_access)); + fp->fi_share_deny =0 ;hlist_add_head (&fp->fi_hash, &file_hashtbl[hashval]); }
@@ -3097,23 +3135,31 @@ 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); + status =nfs4_file_get_access (fp, + open->op_share_access, + open->op_share_deny); +if (status) + goto out;if (!fp->fi_fds[oflag]) {spin_unlock (&fp->fi_lock); status =nfsd_open (rqstp, cur_fh,S_IFREG , access, &filp); -if (status) +if (status) { +nfs4_file_put_access (fp, open->op_share_access, + open->op_share_deny);return status; + }spin_lock (&fp->fi_lock);if (!fp->fi_fds[oflag]) { fp->fi_fds[oflag] = filp; filp =NULL ; } } -nfs4_file_get_access (fp, oflag); +out:spin_unlock (&fp->fi_lock);if (filp)fput (filp); -return nfs_ok; +return status; } static inline __be32
@@ -3146,10 +3192,9 @@ nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *c } 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); - } +if (new_access) +nfs4_file_put_access (fp, op_share_access, + open->op_share_deny);return status; }/* remember the open */
@@ -4059,17 +4104,25 @@ out:return status; } -static inline void nfs4_stateid_downgrade_bit (struct nfs4_ol_stateid *stp,u32 access) +static void nfs4_stateid_downgrade_bit (struct nfs4_ol_stateid *stp,u32 access) {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,0 );clear_access (access, stp); } -static inline void nfs4_stateid_downgrade (struct nfs4_ol_stateid *stp,u32 to_access) +static void nfs4_stateid_downgrade_deny_bit (struct nfs4_ol_stateid *stp,u32 deny) +{ +if (!test_deny (deny, stp)) +return ; +nfs4_file_put_access (stp->st_file,0 , deny); +clear_deny (deny, stp); +} + +static void nfs4_stateid_downgrade (struct nfs4_ol_stateid *stp,u32 to_access,u32 to_deny) { -switch (to_access) { +switch (to_access &NFS4_SHARE_ACCESS_BOTH ) {case NFS4_SHARE_ACCESS_READ :nfs4_stateid_downgrade_bit (stp,NFS4_SHARE_ACCESS_WRITE );nfs4_stateid_downgrade_bit (stp,NFS4_SHARE_ACCESS_BOTH );
@@ -4083,15 +4136,34 @@ static inline void nfs4_stateid_downgrade(struct nfs4_ol_stateid *stp, u32 to_acdefault :WARN_ON_ONCE (1 ); } + +switch (to_deny &NFS4_SHARE_DENY_BOTH ) { +case 0 : +nfs4_stateid_downgrade_deny_bit (stp,NFS4_SHARE_DENY_BOTH ); +nfs4_stateid_downgrade_deny_bit (stp,NFS4_SHARE_DENY_WRITE ); +nfs4_stateid_downgrade_deny_bit (stp,NFS4_SHARE_DENY_READ ); +break ; +case NFS4_SHARE_DENY_READ : +nfs4_stateid_downgrade_deny_bit (stp,NFS4_SHARE_DENY_BOTH ); +nfs4_stateid_downgrade_deny_bit (stp,NFS4_SHARE_DENY_WRITE ); +break ; +case NFS4_SHARE_DENY_WRITE : +nfs4_stateid_downgrade_deny_bit (stp,NFS4_SHARE_DENY_BOTH ); +nfs4_stateid_downgrade_deny_bit (stp,NFS4_SHARE_DENY_READ ); + } }static void reset_union_bmap_deny (unsigned long deny,struct nfs4_ol_stateid *stp) { -int i; -for (i =0 ; i <4 ; i++) { -if ((i & deny) != i) +u32 i; +for (i =3 ; i >0 ; i--) { +if (i == deny) +continue ; +if (test_deny (i, stp)) { +nfs4_file_put_access (stp->st_file,0 , i);clear_deny (i, stp); + } } }
@@ -4128,7 +4200,7 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp, stp->st_deny_bmap, od->od_share_deny); goto out; } -nfs4_stateid_downgrade (stp, od->od_share_access); +nfs4_stateid_downgrade (stp, od->od_share_access, od->od_share_deny);reset_union_bmap_deny (od->od_share_deny, stp);
@@ -4410,11 +4482,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,0 );set_access (access, lock_stp); }
fs/nfsd/state.h +1 -0
@@ -397,6 +397,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;
Signature · 1 line
1.9.3
Re: [PATCH v1 008/104] NFSd: Ensure that nfs4_file_get_access enforces share access modes
Quoted 8 lines · Jeff Layton
Lock atomicity requires us to check the share access mode when we actually open the file. Note that ideally this would also be atomic with file creation.
With the change to make
nfs4_file_get_accessenforce the share mode, we now have a bogusWARN_ONthat can fire. It's now normal to callnfs4_file_get_accessbefore populating thefi_fdsfield for the open flag, so we should no longer warn on that situation.
Which change is that? Seems like this is a previous commit, so it would be good to refer to it explicitly.
Quoted 4 lines
The other case is a
WARN_ONthat can occur if there's aO_RDWRopen already present. I'm unclear on why we'dWARN_ONin that case. This patch removes it, but please do enlighten me if there's some reason we ought to keep it instead.
I have a really hard time mapping from what's in this description to what happens in the patch.
Looking over the patch I can see that it:
adds a fi_share_deny field to struct nfs4_file, which gets set up in nfs4_file_get_access, and cleared from nfs4_file_put_access, as well as some general refactoring around nfs4_file_get_access. Can you split the refactor into a first patch that has a description what's going on, and keep the addition of the deny mask separate, again including a description of what it's trying to help with?
Re: [PATCH v1 008/104] NFSd: Ensure that nfs4_file_get_access enforces share access modes
Quoted 5 lines · On Mon, 23 Jun 2014 09:12:22 -0700 Christoph Hellwig <[email protected]> wrote:
Quoted 4 lines · Jeff Layton
Lock atomicity requires us to check the share access mode when we actually open the file. Note that ideally this would also be atomic with file creation.
Quoted 8 lines
Quoted 4 lines
With the change to make
nfs4_file_get_accessenforce the share mode, we now have a bogusWARN_ONthat can fire. It's now normal to callnfs4_file_get_accessbefore populating thefi_fdsfield for the open flag, so we should no longer warn on that situation.Which change is that? Seems like this is a previous commit, so it would be good to refer to it explicitly.
Sorry it wasn't clear. The change is in this patch. This is just an explanation of why the WARN_ON needed to be removed.
Quoted 8 lines
Quoted 4 lines
The other case is a
WARN_ONthat can occur if there's aO_RDWRopen already present. I'm unclear on why we'dWARN_ONin that case. This patch removes it, but please do enlighten me if there's some reason we ought to keep it instead.I have a really hard time mapping from what's in this description to what happens in the patch.
Quoted 8 lines
Looking over the patch I can see that it:
adds a
fi_share_denyfield to structnfs4_file, which gets set up innfs4_file_get_access, and cleared fromnfs4_file_put_access, as well as some general refactoring aroundnfs4_file_get_access. Can you split the refactor into a first patch that has a description what's going on, and keep the addition of the deny mask separate, again including a description of what it's trying to help with?
Ok, I'll see if I can break that up.
Signature · 1 line
Jeff Layton <[email protected]>
PATCH 9/104 locks: add file_has_lease
In reply to Jeff LaytonAdd a function that can tell us whether a file description has had a lease set on it.
--- fs/locks.c | 26 ++++++++++++++++++++++++++ include/linux/fs.h | 6 ++++++ 2 files changed, 32 insertions(+)
fs/locks.c +26 -0
@@ -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:
include/linux/fs.h +6 -0
@@ -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 ;
Signature · 1 line
1.9.3
Re: [PATCH v1 009/104] locks: add file_has_lease
Quoted 2 lines · Jeff Layton
Add a function that can tell us whether a file description has had a lease set on it.
The code looks good, but how is this information useful given that it will be stable as soon as i_lock is dropped?
Re: [PATCH v1 009/104] locks: add file_has_lease
Quoted 7 lines · On Mon, 23 Jun 2014 09:12:54 -0700 Christoph Hellwig <[email protected]> wrote:
Quoted 2 lines · Jeff Layton
Add a function that can tell us whether a file description has had a lease set on it.
The code looks good, but how is this information useful given that it will be stable as soon as
i_lockis dropped?
The next patch is what uses it. I can squash the two together, but I figured it was best to keep them separate since we're touching two different subsystems here.
The basic idea here is to avoid calling vfs_setlease under a spinlock. The next patch does that and then takes the spinlocks and hash the delegation once the lease is set.
Problem: what if the delegation got broken before we could hash it?
The workqueue job that's queued by break_deleg will take the state_lock spinlock before it can unhash the delegation. So, we take the state_lock and then call file_has_lease. If the lease is still present then we know that it hasn't been (and won't be) broken before we could hash it.
Signature · 1 line
Jeff Layton <[email protected]>
PATCH 10/104 NFSd: Protect the nfs4_file delegation fields using the fi_lock
In reply to Jeff LaytonThe 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 setting it up. 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.
--- fs/nfsd/nfs4state.c | 51 ++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 38 insertions(+), 13 deletions(-)
fs/nfsd/nfs4state.c +38 -13
@@ -524,6 +524,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)) {
@@ -543,11 +545,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); }
@@ -558,17 +559,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); }
@@ -3245,7 +3246,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)
@@ -3253,15 +3254,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);
@@ -3270,19 +3287,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 ; }
Signature · 1 line
1.9.3
PATCH 11/104 NFSd: Lock owners are not per open stateid
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
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.
--- fs/nfsd/nfs4state.c | 48 +++++++++++++++++++++++++++++++----------------- fs/nfsd/state.h | 3 +-- 2 files changed, 32 insertions(+), 19 deletions(-)
fs/nfsd/nfs4state.c +31 -17
@@ -739,10 +739,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);
@@ -759,12 +760,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); } }
@@ -780,22 +780,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); }
@@ -2771,7 +2785,7 @@ static void init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp,struct nfs4_openowner *oo = open->op_openowner; stp->st_stid.sc_type =NFS4_OPEN_STID ; -INIT_LIST_HEAD (&stp->st_lockowners); +INIT_LIST_HEAD (&stp->st_locks);list_add (&stp->st_perstateowner, &oo->oo_owner.so_stateids); stp->st_stateowner = &oo->oo_owner;get_nfs4_file (fp);
@@ -4447,7 +4461,6 @@ static void hash_lockowner(struct nfs4_lockowner *lo, unsigned int strhashval, slist_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); }/*
@@ -4491,6 +4504,7 @@ alloc_init_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp, struct stp->st_access_bmap =0 ; stp->st_deny_bmap = open_stp->st_deny_bmap; stp->st_openstp = open_stp; +list_add (&stp->st_locks, &open_stp->st_locks);spin_lock (&fp->fi_lock);list_add (&stp->st_perfile, &fp->fi_stateids);spin_unlock (&fp->fi_lock);
@@ -5081,18 +5095,18 @@ static void nfsd_print_count(struct nfs4_client *clp, unsigned int count,printk (KERN_INFO "NFS Client: %s has %u %s\n" , buf, count, type); } -static u64 nfsd_foreach_client_lock (struct nfs4_client *clp,u64 max,void (*func)(struct nfs4_lockowner *)) +static u64 nfsd_foreach_client_lock (struct nfs4_client *clp,u64 max,void (*func)(struct nfs4_ol_stateid *)) {struct nfs4_openowner *oop; -struct nfs4_lockowner *lop, *lo_next;struct nfs4_ol_stateid *stp, *st_next; +struct nfs4_ol_stateid *lst, *lst_next;u64 count =0 ;list_for_each_entry (oop, &clp->cl_openowners, oo_perclient) {list_for_each_entry_safe (stp, st_next, &oop->oo_owner.so_stateids, st_perstateowner) { -list_for_each_entry_safe (lop, lo_next, &stp->st_lockowners, lo_perstateid) { +list_for_each_entry_safe (lst, lst_next, &stp->st_locks, st_locks) {if (func) -func (lop); +func (lst);if (++count == max)return count; }
@@ -5104,7 +5118,7 @@ static u64 nfsd_foreach_client_lock(struct nfs4_client *clp, u64 max, void (*funu64 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)
fs/nfsd/state.h +1 -2
@@ -366,7 +366,6 @@ struct nfs4_openowner {struct nfs4_lockowner {struct nfs4_stateowner lo_owner;/* must be first element */ struct list_head lo_owner_ino_hash;/* hash by owner,file */ -struct list_head lo_perstateid;struct list_head lo_list;/* for temporary uses */ };
@@ -410,7 +409,7 @@ struct nfs4_ol_stateid {struct nfs4_stid st_stid;/* must be first field */ struct list_head st_perfile;struct list_head st_perstateowner; -struct list_head st_lockowners; +struct list_head st_locks;struct nfs4_stateowner * st_stateowner;struct nfs4_file * st_file;unsigned long st_access_bmap;
Signature · 1 line
1.9.3
Re: [PATCH v1 011/104] NFSd: Lock owners are not per open stateid
FYI, this is what I think should go into a separate inintial series.
Looks good,
Re: [PATCH v1 011/104] NFSd: Lock owners are not per open stateid
Quoted 5 lines · On Tue, 24 Jun 2014 04:50:58 -0700 Christoph Hellwig <[email protected]> wrote:
FYI, this is what I think should go into a separate inintial series.
Looks good,
Reviewed-by Christoph Hellwig <[email protected]>
Yeah, I was thinking about that last night. I think the parts that could be broken out are:
- the change to multiple stateids per lockowner
- moving some of the fields into nfs4_stid
- adding refcounting for stateids and stateowners and fixing the relationships between them
Unfortunately, that means a pretty significant respin of the set as a lot of the changes now are mashed in with those that add locking around those parts. I'll give it some more thought...
Signature · 1 line
Jeff Layton <[email protected]>
Re: [PATCH v1 011/104] NFSd: Lock owners are not per open stateid
Quoted 4 lines · Jeff Layton
Yeah, I was thinking about that last night. I think the parts that could be broken out are:
- the change to multiple stateids per lockowner
this one definitively should as it is a significant change in behavior.
The second batch that seems easily separatable is the improvements of the client lookup and caching, which includes a few patches.
Quoted 3 lines
- moving some of the fields into
nfs4_stid
- adding refcounting for stateids and stateowners and fixing the relationships between them
These are indeed deeply interwinded with the locking changes. I still think having them earlier would be useful, but if it's too much work we'll have to live with what we get.
PATCH 12/104 NFSd: Clean up helper __release_lock_stateid
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
Use filp_close() instead of open coding
--- fs/nfsd/nfs4state.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-)
fs/nfsd/nfs4state.c +6 -7
@@ -739,7 +739,8 @@ static void free_generic_stateid(struct nfs4_ol_stateid *stp)nfs4_free_stid (stateid_slab, &stp->st_stid); } -static void __release_lock_stateid (struct nfs4_ol_stateid *stp) +static void __release_lock_stateid (struct nfs4_lockowner *lo, +struct nfs4_ol_stateid *stp) {struct file *file;
@@ -747,10 +748,8 @@ static void __release_lock_stateid(struct nfs4_ol_stateid *stp)unhash_generic_stateid (stp);unhash_stid (&stp->st_stid); file =find_any_file (stp->st_file); -if (file) { -locks_remove_posix (file, (fl_owner_t )lockowner (stp->st_stateowner)); -fput (file); - } +if (file) +filp_close (file, (fl_owner_t )lo);close_generic_stateid (stp);free_generic_stateid (stp); }
@@ -764,7 +763,7 @@ static void unhash_lockowner(struct nfs4_lockowner *lo)while (!list_empty (&lo->lo_owner.so_stateids)) { stp =list_first_entry (&lo->lo_owner.so_stateids, struct nfs4_ol_stateid, st_perstateowner); -__release_lock_stateid (stp); +__release_lock_stateid (lo, stp); } }
@@ -791,7 +790,7 @@ static void release_lock_stateid(struct nfs4_ol_stateid *stp)struct nfs4_lockowner *lo; lo =lockowner (stp->st_stateowner); -__release_lock_stateid (stp); +__release_lock_stateid (lo, stp);release_lockowner_if_empty (lo); }
Signature · 1 line
1.9.3
Re: [PATCH v1 012/104] NFSd: Clean up helper __release_lock_stateid
Quoted 3 lines · Jeff Layton
From: Trond Myklebust <[email protected]>
Use
filp_close()instead of open coding
filp_close does more than what's currently opencoded here:
- file_count debug check which seems pointless but harmless
- calling ->flush. This doesn't do much on nfs exportable filesystem except for exofs, which does dumb shit in it that should be removed, but the maintainer refuse.
- call into dnotify, which we probably should be doing here.
fs/nfsd/nfs4state.c static void free_generic_stateid(struct nfs4_ol_stateid *stp) · line 743
Quoted 3 lines
fs/nfsd/nfs4state.c +2
-1-static void __release_lock_stateid (struct nfs4_ol_stateid *stp) +static void __release_lock_stateid (struct nfs4_lockowner *lo, +struct nfs4_ol_stateid *stp)
But what's the point of explicitly passing the lock owner instead of deriving it?
Re: [PATCH v1 012/104] NFSd: Clean up helper __release_lock_stateid
Quoted 5 lines · On Tue, 24 Jun 2014 04:53:36 -0700 Christoph Hellwig <[email protected]> wrote:
Quoted 3 lines · Jeff Layton
From: Trond Myklebust <[email protected]>
Use
filp_close()instead of open coding
Quoted 8 lines
filp_closedoes more than what's currently opencoded here:-
file_countdebug check which seems pointless but harmless
- calling ->flush. This doesn't do much on nfs exportable filesystem except for exofs, which does dumb shit in it that should be removed, but the maintainer refuse.
- call into dnotify, which we probably should be doing here.
Yeah. It is a small change in behavior but seems like the right thing to do. I'll flesh out the commit message to spell that out though.
Quoted 7 lines
fs/nfsd/nfs4state.c static void free_generic_stateid(struct nfs4_ol_stateid *stp) · line 743
Quoted 3 lines
fs/nfsd/nfs4state.c +2
-1-static void __release_lock_stateid (struct nfs4_ol_stateid *stp) +static void __release_lock_stateid (struct nfs4_lockowner *lo, +struct nfs4_ol_stateid *stp)But what's the point of explicitly passing the lock owner instead of deriving it?
I thought that was a little silly too, but didn't care enough to change it. I can only assume that Trond figured that the callers all needed to know what the lockowner was so you wouldn't need to do two lockowner() calls. Still, those are just container_of(), so I don't see the point in avoiding them either. I'll change it not to pass the owner.
Thanks,
Signature · 1 line
Jeff Layton <[email protected]>
PATCH 13/104 NFSd: Allow lockowners to hold several stateids
In reply to Jeff Layton--- fs/nfsd/nfs4state.c | 55 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 22 deletions(-)
fs/nfsd/nfs4state.c +33 -22
@@ -3956,12 +3956,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; }
@@ -4510,6 +4505,19 @@ alloc_init_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp, structreturn 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) {
@@ -4538,25 +4546,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; }
@@ -4715,7 +4726,7 @@ out:if (filp)fput (filp);if (status && new_state) -release_lockowner (lock_sop); +release_lockowner_if_empty (lock_sop);nfsd4_bump_seqid (cstate, status);nfs4_unlock_state ();if (file_lock)
Signature · 1 line
1.9.3
Re: [PATCH v1 013/104] NFSd: Allow lockowners to hold several stateids
Needs a good explanation on why we do this instead of having to rely on the context in the surrounding patches.
Otherwise looks good,
PATCH 14/104 NFSd: NFSv4 lock-owners are not associated to a specific file
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
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.
--- fs/nfsd/netns.h | 4 ---- fs/nfsd/nfs4state.c | 66 ++++++++++++----------------------------------------- fs/nfsd/state.h | 1 - 3 files changed, 14 insertions(+), 57 deletions(-)
fs/nfsd/netns.h +0 -4
@@ -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 512struct 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
fs/nfsd/nfs4state.c +14 -52
155 lines not on this page · raw message
fs/nfsd/state.h +0 -1
@@ -365,7 +365,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 */ };
Signature · 1 line
1.9.3
Re: [PATCH v1 014/104] NFSd: NFSv4 lock-owners are not associated to a specific file
fs/nfsd/nfs4state.c nevermind: · line 4432
Quoted 6 lines
fs/nfsd/nfs4state.c +1
-0+static void hash_lockowner (struct nfs4_lockowner *lo,unsigned int strhashval,struct nfs4_client *clp) {struct nfsd_net *nn =net_generic (clp->net, nfsd_net_id);list_add (&lo->lo_owner.so_strhash, &nn->ownerstr_hashtbl[strhashval]); }
I'd just merge this into the only caller.
Otherwise looks good,
PATCH 15/104 NFSd: Cleanup nfs4svc_encode_compoundres
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
Move the slot return, put session etc into a helper in fs/nfsd/nfs4state.c instead of open coding in nfs4svc_encode_compoundres.
--- 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(-)
fs/nfsd/nfs4state.c +22 -13
@@ -202,18 +202,6 @@ static void put_client_renew_locked(struct nfs4_client *clp)renew_client_locked (clp); } -void put_client_renew (struct nfs4_client *clp) -{ -struct nfsd_net *nn =net_generic (clp->net, nfsd_net_id); - -if (!atomic_dec_and_lock (&clp->cl_refcount, &nn->client_lock)) -return ; -if (!is_client_expired (clp)) -renew_client_locked (clp); -spin_unlock (&nn->client_lock); -} - -static inline u32 opaque_hashval (const void *ptr,int nbytes) {
@@ -1696,7 +1684,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;
@@ -2468,6 +2456,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) {
fs/nfsd/nfs4xdr.c +1 -14
@@ -3996,7 +3996,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 +
@@ -4010,19 +4009,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 ; }
fs/nfsd/state.h +0 -1
@@ -452,7 +452,6 @@ extern void nfs4_put_delegation(struct nfs4_delegation *dp);extern struct nfs4_client_reclaim *nfs4_client_to_reclaim (const char *name,struct nfsd_net *nn);extern bool nfs4_has_reclaimed_state (const char *name,struct nfsd_net *nn); -extern void put_client_renew (struct nfs4_client *clp);/* nfs4recover operations */ extern int nfsd4_client_tracking_init (struct net *net);
fs/nfsd/xdr4.h +1 -1
@@ -593,7 +593,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 *);
@@ -604,6 +603,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 *);
Signature · 1 line
1.9.3
Re: [PATCH v1 015/104] NFSd: Cleanup nfs4svc_encode_compoundres
This seems like another candidate for the prep series.
Looks good,
PATCH 16/104 NFSd: Don't get a session reference without a client reference
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
If the client were to disappear from underneath us while we're holding a session reference, things would be bad. This cleanup ensures that it cannot.
--- fs/nfsd/nfs4state.c | 112 +++++++++++++++++++++++++++++++--------------------- fs/nfsd/state.h | 2 - 2 files changed, 68 insertions(+), 46 deletions(-)
fs/nfsd/nfs4state.c +68 -44
@@ -102,12 +102,6 @@ static bool is_session_dead(struct nfsd4_session *ses)return ses->se_flags &NFS4_SESSION_DEAD ; } -void nfsd4_put_session (struct nfsd4_session *ses) -{ -if (atomic_dec_and_test (&ses->se_ref) &&is_session_dead (ses)) -free_session (ses); -} -static __be32 mark_session_dead_locked (struct nfsd4_session *ses,int ref_held_by_me) {if (atomic_read (&ses->se_ref) > ref_held_by_me)
@@ -116,14 +110,6 @@ static __be32 mark_session_dead_locked(struct nfsd4_session *ses, int ref_held_breturn nfs_ok; } -static __be32 nfsd4_get_session_locked (struct nfsd4_session *ses) -{ -if (is_session_dead (ses)) -return nfserr_badsession; -atomic_inc (&ses->se_ref); -return nfs_ok; -} -void nfs4_unlock_state (void ) {
@@ -202,6 +188,39 @@ static void put_client_renew_locked(struct nfs4_client *clp)renew_client_locked (clp); } +static __be32 nfsd4_get_session_locked (struct nfsd4_session *ses) +{ +__be32 status; + +if (is_session_dead (ses)) +return nfserr_badsession; + status =get_client_locked (ses->se_client); +if (status) +return status; +atomic_inc (&ses->se_ref); +return nfs_ok; +} + +static void nfsd4_put_session_locked (struct nfsd4_session *ses) +{ +struct nfs4_client *clp = ses->se_client; + +if (atomic_dec_and_test (&ses->se_ref) &&is_session_dead (ses)) +free_session (ses); +put_client_renew_locked (clp); +} + +static void nfsd4_put_session (struct nfsd4_session *ses) +{ +struct nfs4_client *clp = ses->se_client; +struct nfsd_net *nn =net_generic (clp->net, nfsd_net_id); + +spin_lock (&nn->client_lock); +nfsd4_put_session_locked (ses); +spin_unlock (&nn->client_lock); +} + +static inline u32 opaque_hashval (const void *ptr,int nbytes) {
@@ -1154,7 +1173,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;
@@ -1174,6 +1193,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)
@@ -2194,17 +2231,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;
@@ -2218,6 +2255,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; }
@@ -2237,7 +2276,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;
@@ -2248,14 +2288,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;
@@ -2267,7 +2305,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:
@@ -2342,7 +2380,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;
@@ -2356,17 +2395,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))
@@ -2450,9 +2482,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; }
@@ -2462,18 +2492,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); } }
fs/nfsd/state.h +0 -2
@@ -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;
Signature · 1 line
1.9.3
Re: [PATCH v1 016/104] NFSd: Don't get a session reference without a client reference
PATCH 17/104 NFSd: Allow struct nfsd4_compound_state to cache the nfs4_client
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
This will be used later to accelerate lookups of the clientid
--- fs/nfsd/nfs4state.c | 14 +++++++++++++- fs/nfsd/xdr4.h | 1 + 2 files changed, 14 insertions(+), 1 deletion(-)
fs/nfsd/nfs4state.c +13 -1
@@ -188,6 +188,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;
@@ -2428,6 +2437,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);
@@ -2462,6 +2472,7 @@ nfsd4_sequence(struct svc_rqst *rqstp, cstate->slot = slot; cstate->session = session; + cstate->clp = clp; out:switch (clp->cl_cb_state) {
@@ -2498,7 +2509,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
fs/nfsd/xdr4.h +1 -0
@@ -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;
Signature · 1 line
1.9.3
Re: [PATCH v1 017/104] NFSd: Allow struct nfsd4_compound_state to cache the nfs4_client
Another patch that doesn't seem to depend on the locking changes.
PATCH 18/104 NFSd: Move the delegation reference counter into the struct nfs4_stid
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
We will want to add reference counting to the lock stateid and open stateids too.
--- fs/nfsd/nfs4state.c | 13 +++++++------ fs/nfsd/state.h | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-)
fs/nfsd/nfs4state.c +7 -6
@@ -464,6 +464,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.
@@ -510,7 +511,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, ¤t_fh->fh_handle); dp->dl_time =0 ; -atomic_set (&dp->dl_count,1 );nfsd4_init_callback (&dp->dl_recall);return dp; }
@@ -532,7 +532,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--; }
@@ -2982,10 +2982,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);nfsd4_cb_recall (dp); }
fs/nfsd/state.h +1 -1
@@ -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;
Signature · 1 line
1.9.3
PATCH 19/104 NFSd: Simplify stateid management
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
Don't allow stateids to clear the open file pointer until they are being destroyed.
--- fs/nfsd/nfs4state.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-)
fs/nfsd/nfs4state.c +12 -12
@@ -447,7 +447,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 ;
@@ -459,11 +459,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 );/*
@@ -507,10 +505,8 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct svINIT_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, ¤t_fh->fh_handle); - dp->dl_time =0 ;nfsd4_init_callback (&dp->dl_recall);return dp; }
@@ -533,6 +529,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--; }
@@ -580,12 +578,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); }
@@ -745,13 +740,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); }
@@ -4329,8 +4324,13 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,if (cstate->minorversion)free_generic_stateid (stp); -else +else { +if (stp->st_file) { +put_nfs4_file (stp->st_file); + stp->st_file =NULL ; + } oo->oo_last_closed_stid = stp; + }if (list_empty (&oo->oo_owner.so_stateids)) {if (cstate->minorversion)
Signature · 1 line
1.9.3
PATCH 20/104 NFSd: Fix delegation revocation
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
Ensure that the delegations cannot be found by the laundromat etc once we add them to the various 'revoke' lists.
--- fs/nfsd/nfs4state.c | 56 +++++++++++++++++++++++++++++++++-------------------- 1 file changed, 35 insertions(+), 21 deletions(-)
fs/nfsd/nfs4state.c +35 -21
@@ -566,13 +566,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);
@@ -580,23 +580,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)
@@ -604,11 +613,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); } }
@@ -1317,12 +1325,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);
@@ -3449,7 +3458,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 &&
@@ -3703,7 +3712,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) {
@@ -4371,7 +4381,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 ();
@@ -5190,8 +5200,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 ; }
@@ -5440,11 +5452,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); }
Signature · 1 line
1.9.3
PATCH 21/104 NFSd: Add reference counting to the lock and open stateids
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
--- fs/nfsd/nfs4state.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-)
fs/nfsd/nfs4state.c +8 -6
@@ -750,8 +750,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);
@@ -770,7 +772,7 @@ static void __release_lock_stateid(struct nfs4_lockowner *lo,if (file)filp_close (file, (fl_owner_t )lo);close_generic_stateid (stp); -free_generic_stateid (stp); +put_generic_stateid (stp); }static void unhash_lockowner (struct nfs4_lockowner *lo)
@@ -833,7 +835,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)
@@ -854,7 +856,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 ; } }
@@ -3607,7 +3609,7 @@ void nfsd4_cleanup_open_state(struct nfsd4_open *open, __be32 status)if (open->op_file)nfsd4_free_file (open->op_file);if (open->op_stp) -free_generic_stateid (open->op_stp); +put_generic_stateid (open->op_stp); }static __be32 lookup_clientid (clientid_t *clid,bool session,struct nfsd_net *nn,struct nfs4_client **clp)
@@ -4333,7 +4335,7 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,nfsd4_close_open_stateid (stp);if (cstate->minorversion) -free_generic_stateid (stp); +put_generic_stateid (stp);else {if (stp->st_file) {put_nfs4_file (stp->st_file);
Signature · 1 line
1.9.3
PATCH 22/104 NFSd: clean up nfsd4_close_open_stateid
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
--- fs/nfsd/nfs4state.c | 47 ++++++++++++++++++++++------------------------- 1 file changed, 22 insertions(+), 25 deletions(-)
fs/nfsd/nfs4state.c +22 -25
@@ -4300,8 +4300,29 @@ 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) { +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); + s->st_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. +*/ +if (list_empty (&oo->oo_owner.so_stateids)) +move_to_close_lru (oo, clp->net); + } }/*
@@ -4312,7 +4333,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);
@@ -4328,33 +4348,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) -put_generic_stateid (stp); -else { -if (stp->st_file) { -put_nfs4_file (stp->st_file); - stp->st_file =NULL ; - } - 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:nfs4_unlock_state ();return status;
Signature · 1 line
1.9.3
PATCH 23/104 NFSd: Add a struct nfs4_file field to struct nfs4_stid
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
All stateids are associated with a nfs4_file. Let's consolidate... Start by Replacing delegation->dl_file with the dl_stid.sc_file
--- fs/nfsd/nfs4state.c | 18 +++++++++--------- fs/nfsd/state.h | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-)
fs/nfsd/nfs4state.c +9 -9
@@ -522,6 +522,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); }
@@ -529,8 +531,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--; }
@@ -569,7 +569,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);
@@ -2969,8 +2969,8 @@ out: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
@@ -3301,14 +3301,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 ;
@@ -3358,7 +3358,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);
@@ -3961,7 +3961,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;
fs/nfsd/state.h +1 -1
@@ -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: */
Signature · 1 line
1.9.3
PATCH 24/104 NFSd: Replace nfs4_ol_stateid->st_file with the st_stid.sc_file
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
--- fs/nfsd/nfs4state.c | 50 ++++++++++++++++++++++++-------------------------- fs/nfsd/state.h | 1 - 2 files changed, 24 insertions(+), 27 deletions(-)
fs/nfsd/nfs4state.c +24 -26
@@ -725,11 +725,11 @@ release_all_access(struct nfs4_ol_stateid *stp)for (i =1 ; i <4 ; i++) {if (test_deny (i, stp)) { -nfs4_file_put_access (stp->st_file,0 , i); +nfs4_file_put_access (stp->st_stid.sc_file,0 , i);clear_deny (i, stp); }if (test_access (i, stp)) { -nfs4_file_put_access (stp->st_file, i,0 ); +nfs4_file_put_access (stp->st_stid.sc_file, i,0 );clear_access (i, stp); } }
@@ -737,7 +737,7 @@ release_all_access(struct nfs4_ol_stateid *stp)static void unhash_generic_stateid (struct nfs4_ol_stateid *stp) { -struct nfs4_file *fp = stp->st_file; +struct nfs4_file *fp = stp->st_stid.sc_file;spin_lock (&fp->fi_lock);list_del (&stp->st_perfile);
@@ -755,8 +755,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); }
@@ -768,7 +766,7 @@ static void __release_lock_stateid(struct nfs4_lockowner *lo,list_del (&stp->st_locks);unhash_generic_stateid (stp);unhash_stid (&stp->st_stid); - file =find_any_file (stp->st_file); + file =find_any_file (stp->st_stid.sc_file);if (file)filp_close (file, (fl_owner_t )lo);close_generic_stateid (stp);
@@ -2838,7 +2836,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);
@@ -3449,7 +3447,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;
@@ -3755,7 +3753,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; }
@@ -3984,9 +3982,9 @@ nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate, goto out;if (filpp) {if (flags &RD_STATE ) - file =find_readable_file (stp->st_file); + file =find_readable_file (stp->st_stid.sc_file);else - file =find_writeable_file (stp->st_file); + file =find_writeable_file (stp->st_stid.sc_file); }break ;default :
@@ -4006,7 +4004,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;
@@ -4193,7 +4191,7 @@ static void nfs4_stateid_downgrade_bit(struct nfs4_ol_stateid *stp, u32 access) {if (!test_access (access, stp))return ; -nfs4_file_put_access (stp->st_file, access,0 ); +nfs4_file_put_access (stp->st_stid.sc_file, access,0 );clear_access (access, stp); }
@@ -4201,7 +4199,7 @@ static void nfs4_stateid_downgrade_deny_bit(struct nfs4_ol_stateid *stp, u32 den {if (!test_deny (deny, stp))return ; -nfs4_file_put_access (stp->st_file,0 , deny); +nfs4_file_put_access (stp->st_stid.sc_file,0 , deny);clear_deny (deny, stp); }
@@ -4246,7 +4244,7 @@ reset_union_bmap_deny(unsigned long deny, struct nfs4_ol_stateid *stp)if (i == deny)continue ;if (test_deny (i, stp)) { -nfs4_file_put_access (stp->st_file,0 , i); +nfs4_file_put_access (stp->st_stid.sc_file,0 , i);clear_deny (i, stp); } }
@@ -4311,9 +4309,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;/*
@@ -4523,7 +4521,7 @@ alloc_init_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp, structlist_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;
@@ -4540,7 +4538,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 ;
@@ -4556,7 +4554,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;if (test_access (access, lock_stp))return ;
@@ -4566,7 +4564,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;
@@ -4693,14 +4691,14 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,switch (lock->lk_type) {case NFS4_READ_LT :case NFS4_READW_LT : - filp =find_readable_file (lock_stp->st_file); + filp =find_readable_file (lock_stp->st_stid.sc_file);if (filp)get_lock_access (lock_stp,NFS4_SHARE_ACCESS_READ ); file_lock->fl_type =F_RDLCK ;break ;case NFS4_WRITE_LT :case NFS4_WRITEW_LT : - filp =find_writeable_file (lock_stp->st_file); + filp =find_writeable_file (lock_stp->st_stid.sc_file);if (filp)get_lock_access (lock_stp,NFS4_SHARE_ACCESS_WRITE ); file_lock->fl_type =F_WRLCK ;
@@ -4883,7 +4881,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;
@@ -4987,7 +4985,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,list_for_each_entry (stp, &sop->so_stateids, st_perstateowner) { lo =lockowner (sop); -if (check_for_locks (stp->st_file, lo)) +if (check_for_locks (stp->st_stid.sc_file, lo)) goto out;list_add (&lo->lo_list, &matches); }
fs/nfsd/state.h +0 -1
@@ -408,7 +408,6 @@ struct nfs4_ol_stateid {struct list_head st_perstateowner;struct list_head st_locks;struct nfs4_stateowner * st_stateowner; -struct nfs4_file * st_file;unsigned long st_access_bmap;unsigned long st_deny_bmap;struct nfs4_ol_stateid * st_openstp;
Signature · 1 line
1.9.3
PATCH 25/104 NFSd: Ensure stateids remain unique until they are freed
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
Add an extra delegation state to allow the stateid to remain in the idr tree until the last reference has been released.
--- fs/nfsd/nfs4state.c | 7 ++++--- fs/nfsd/state.h | 1 + 2 files changed, 5 insertions(+), 3 deletions(-)
fs/nfsd/nfs4state.c +4 -3
@@ -522,6 +522,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);
@@ -592,7 +593,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); }
@@ -605,7 +606,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)
@@ -754,7 +755,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); }
@@ -3890,6 +3890,7 @@ static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid)default :printk ("unknown stateid type %x\n" , s->sc_type);case NFS4_CLOSED_STID : +case NFS4_CLOSED_DELEG_STID :return nfserr_bad_stateid; } }
fs/nfsd/state.h +1 -0
@@ -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 32unsigned char sc_type;stateid_t sc_stateid;struct nfs4_client *sc_client;
Signature · 1 line
1.9.3
PATCH 26/104 NFSd: Ensure atomicity of stateid destruction and idr tree removal
In reply to Jeff Layton--- fs/nfsd/nfs4state.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-)
fs/nfsd/nfs4state.c +16 -11
@@ -511,30 +511,37 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct svreturn 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)
@@ -753,9 +760,7 @@ static void close_generic_stateid(struct nfs4_ol_stateid *stp)static void put_generic_stateid (struct nfs4_ol_stateid *stp) { -if (!atomic_dec_and_test (&stp->st_stid.sc_count)) -return ; -nfs4_free_stid (stateid_slab, &stp->st_stid); +nfs4_put_stid (stateid_slab, &stp->st_stid); } static void __release_lock_stateid(struct nfs4_lockowner *lo,
Signature · 1 line
1.9.3
PATCH 27/104 NFSd: Cleanup the freeing of stateids
In reply to Jeff LaytonAdd a ->free() callback to the struct nfs4_stid, so that we can release a reference to the stid without caring about the contents.
--- fs/nfsd/nfs4state.c | 62 +++++++++++++++++++++++++++++++++++------------------ fs/nfsd/state.h | 2 ++ 2 files changed, 43 insertions(+), 21 deletions(-)
fs/nfsd/nfs4state.c +41 -21
@@ -70,6 +70,7 @@ static u64 current_sessionid = 1;/* forward declarations */ static int check_for_locks (struct nfs4_file *filp,struct nfs4_lockowner *lowner); +static void nfs4_free_generic_stateid (struct nfs4_stid *stid);/* Locking: */
@@ -441,8 +442,15 @@ static void nfs4_file_put_access(struct nfs4_file *fp, u32 access, u32 deny)__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;
@@ -481,7 +489,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--; } static struct nfs4_delegation *
@@ -495,6 +518,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
@@ -518,30 +543,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)
@@ -753,14 +769,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_lockowner *lo,
@@ -774,7 +793,6 @@ static void __release_lock_stateid(struct nfs4_lockowner *lo, file =find_any_file (stp->st_stid.sc_file);if (file)filp_close (file, (fl_owner_t )lo); -close_generic_stateid (stp);put_generic_stateid (stp); }
@@ -832,7 +850,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)
@@ -4322,8 +4339,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); }
fs/nfsd/state.h +2 -0
@@ -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 {
Signature · 1 line
1.9.3
PATCH 28/104 nfsd: do filp_close in sc_free callback for lock stateids
In reply to Jeff LaytonIt seems wrong to release the locks on each put of the stateid, instead of doing so only when the stateid is actually released, and doing so complicates some later changes.
--- fs/nfsd/nfs4state.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-)
fs/nfsd/nfs4state.c +13 -5
@@ -777,6 +777,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);
@@ -785,14 +797,9 @@ static void put_generic_stateid(struct nfs4_ol_stateid *stp)static void __release_lock_stateid (struct nfs4_lockowner *lo,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 )lo);put_generic_stateid (stp); }
@@ -4548,6 +4555,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;
Signature · 1 line
1.9.3
PATCH 29/104 NFSd: Add locking to protect the state owner lists
In reply to Jeff LaytonWe use the clp->cl_lock for this. For now, there's a lot of cl_lock thrashing, but in a later patch we'll reduce that.
--- fs/nfsd/nfs4state.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-)
fs/nfsd/nfs4state.c +19 -2
@@ -763,6 +763,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);
@@ -797,9 +799,13 @@ static void put_generic_stateid(struct nfs4_ol_stateid *stp)static void __release_lock_stateid (struct nfs4_lockowner *lo,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); }
@@ -843,20 +849,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)
@@ -2862,7 +2874,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;
@@ -2871,9 +2882,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
@@ -4544,6 +4558,7 @@ alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, strstatic 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;
@@ -4551,7 +4566,6 @@ alloc_init_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp, structif (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;
@@ -4559,10 +4573,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; }
Signature · 1 line
1.9.3
PATCH 30/104 nfsd: clean up races in lock stateid searching and creation
In reply to Jeff LaytonCurrently, no lock is held when calling find_lock_state. Ensure that the cl_lock is held when calling that by adding a lockdep assertion.
Also, it's 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.
--- fs/nfsd/nfs4state.c | 58 +++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 17 deletions(-)
fs/nfsd/nfs4state.c +41 -17
@@ -4555,16 +4555,14 @@ alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, strreturn 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);
@@ -4573,20 +4571,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)
@@ -4595,6 +4593,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)
@@ -4636,14 +4664,10 @@ static __be32 lookup_or_create_lock_state(struct nfsd4_compound_state *cstate, sreturn 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; }
Signature · 1 line
1.9.3
PATCH 31/104 NFSd: Convert delegation counter to an atomic_long_t type
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
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'.
--- fs/nfsd/nfs4state.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-)
fs/nfsd/nfs4state.c +10 -6
@@ -312,7 +312,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;/*
@@ -504,20 +504,22 @@ 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); }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; dp =delegstateid (nfs4_alloc_stid (clp, deleg_slab));if (dp ==NULL ) -return dp; + goto out_dec; dp->dl_stid.sc_free = nfs4_free_deleg;/*
@@ -526,7 +528,6 @@ 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);
@@ -534,6 +535,9 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct svfh_copy_shallow (&dp->dl_fh, ¤t_fh->fh_handle);nfsd4_init_callback (&dp->dl_recall);return dp; +out_dec: +atomic_long_dec (&num_delegations); +return NULL ; }static void remove_stid_locked (struct nfs4_client *clp,struct nfs4_stid *s)
Signature · 1 line
1.9.3
PATCH 32/104 NFSd: Slight cleanup of find_stateid()
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
In preparation of reference counting...
--- fs/nfsd/nfs4state.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-)
fs/nfsd/nfs4state.c +17 -9
@@ -1561,28 +1561,36 @@ static void gen_confirm(struct nfs4_client *clp)memcpy (clp->cl_confirm.data, verf,sizeof (clp->cl_confirm.data)); } -static struct nfs4_stid *find_stateid (struct nfs4_client *cl,stateid_t *t) +static struct nfs4_stid *find_stateid_locked (struct nfs4_client *cl,stateid_t *t) {struct nfs4_stid *ret; -spin_lock (&cl->cl_lock); ret =idr_find (&cl->cl_stateids, t->si_opaque.so_id); -spin_unlock (&cl->cl_lock);if (!ret || !ret->sc_type)return NULL ;return ret; } +static struct nfs4_stid *find_stateid (struct nfs4_client *cl,stateid_t *t) +{ +struct nfs4_stid *ret; + +spin_lock (&cl->cl_lock); + ret =find_stateid_locked (cl, t); +spin_unlock (&cl->cl_lock); +return ret; +} +static struct nfs4_stid *find_stateid_by_type (struct nfs4_client *cl,stateid_t *t,char typemask) {struct nfs4_stid *s; - s =find_stateid (cl, t); -if (!s) -return NULL ; -if (typemask & s->sc_type) -return s; -return NULL ; +spin_lock (&cl->cl_lock); + s =find_stateid_locked (cl, t); +if (s !=NULL && !(typemask & s->sc_type)) + s =NULL ; +spin_unlock (&cl->cl_lock); +return s; } static struct nfs4_client *create_client(struct xdr_netobj name,
Signature · 1 line
1.9.3
PATCH 33/104 NFSd: Add reference counting to find_stateid
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
Ensure the stateids won't be freed while we're inspecting them.
--- fs/nfsd/nfs4state.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-)
fs/nfsd/nfs4state.c +18 -8
@@ -1577,6 +1577,8 @@ static struct nfs4_stid *find_stateid(struct nfs4_client *cl, stateid_t *t)spin_lock (&cl->cl_lock); ret =find_stateid_locked (cl, t); +if (ret !=NULL ) +atomic_inc (&ret->sc_count);spin_unlock (&cl->cl_lock);return ret; }
@@ -3928,26 +3930,33 @@ static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid)return nfserr_bad_stateid; status =check_stateid_generation (stateid, &s->sc_stateid,1 );if (status) -return status; + goto out_put_stid;switch (s->sc_type) {case NFS4_DELEG_STID : -return nfs_ok; + status = nfs_ok; +break ;case NFS4_REVOKED_DELEG_STID : -return nfserr_deleg_revoked; + status = nfserr_deleg_revoked; +break ;case NFS4_OPEN_STID :case NFS4_LOCK_STID : ols =openlockstateid (s);if (ols->st_stateowner->so_is_open_owner && !(openowner (ols->st_stateowner)->oo_flags &NFS4_OO_CONFIRMED )) -return nfserr_bad_stateid; -return nfs_ok; + status = nfserr_bad_stateid; +else + status = nfs_ok; +break ;default :printk ("unknown stateid type %x\n" , s->sc_type);case NFS4_CLOSED_STID :case NFS4_CLOSED_DELEG_STID : -return nfserr_bad_stateid; + status = nfserr_bad_stateid; } +out_put_stid: +nfs4_put_stid (s); +return status; } static __be32 nfsd4_lookup_stateid(stateid_t *stateid, unsigned char typemask,
@@ -4102,12 +4111,12 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,switch (s->sc_type) {case NFS4_DELEG_STID : ret = nfserr_locks_held; - goto out; +break ;case NFS4_OPEN_STID :case NFS4_LOCK_STID : ret =check_stateid_generation (stateid, &s->sc_stateid,1 );if (ret) - goto out; +break ;if (s->sc_type ==NFS4_LOCK_STID ) ret =nfsd4_free_lock_stateid (openlockstateid (s));else
@@ -4121,6 +4130,7 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,default : ret = nfserr_bad_stateid; } +nfs4_put_stid (s); out:nfs4_unlock_state ();return ret;
Signature · 1 line
1.9.3
PATCH 34/104 NFSd: Add reference counting to lock stateids
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
Ensure that nfsd4_lock() references the lock stateid while it is manipulating it.
--- fs/nfsd/nfs4state.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-)
fs/nfsd/nfs4state.c +12 -3
@@ -4585,6 +4585,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);
@@ -4609,8 +4610,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 ; }
@@ -4703,7 +4706,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 ;
@@ -4756,11 +4759,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);
@@ -4848,6 +4855,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);
Signature · 1 line
1.9.3
PATCH 35/104 NFSd: nfsd4_locku() must reference the lock stateid
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
Ensure that nfsd4_locku() keeps a reference to the lock stateid until it is done working with it.
--- fs/nfsd/nfs4state.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
fs/nfsd/nfs4state.c +5 -1
@@ -4987,10 +4987,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) {
@@ -5020,6 +5022,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 ();
Signature · 1 line
1.9.3
PATCH 36/104 NFSd: Ensure that nfs4_open_delegation() references the delegation stateid
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
Ensure that nfs4_open_delegation() keeps a reference to the delegation stateid until it is done working with it.
--- fs/nfsd/nfs4state.c | 2 ++ 1 file changed, 2 insertions(+)
fs/nfsd/nfs4state.c +2 -0
@@ -589,6 +589,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);
@@ -3513,6 +3514,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);
Signature · 1 line
1.9.3
PATCH 37/104 NFSd: nfsd4_process_open2() must reference the delegation stateid
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
Ensure that nfsd4_process_open2() keeps a reference to the delegation stateid until it is done working with it.
--- fs/nfsd/nfs4state.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-)
fs/nfsd/nfs4state.c +13 -5
@@ -3180,6 +3180,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); }
@@ -3195,14 +3197,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;
@@ -3644,6 +3650,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; }
Signature · 1 line
1.9.3
PATCH 38/104 NFSd: nfsd4_process_open2() must reference the open stateid
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
Ensure that nfsd4_process_open2() keeps a reference to the open stateid until it is done working with it.
--- fs/nfsd/nfs4state.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)
fs/nfsd/nfs4state.c +9 -1
@@ -2887,6 +2887,7 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, strstatic 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;
@@ -3223,6 +3224,7 @@ nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_ol_st {struct nfs4_ol_stateid *local;struct nfs4_openowner *oo = open->op_openowner; +struct nfs4_ol_stateid *ret =NULL ;spin_lock (&fp->fi_lock);list_for_each_entry (local, &fp->fi_stateids, st_perfile) {
@@ -3231,13 +3233,17 @@ nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_ol_stcontinue ;/* remember if we have seen this open owner */ if (local->st_stateowner == &oo->oo_owner) - *stpp = local; + ret = local;/* check for conflicting share reservations */ if (!test_share (local, open)) {spin_unlock (&fp->fi_lock);return nfserr_share_denied; } } +if (ret) { +atomic_inc (&ret->st_stid.sc_count); + *stpp = ret; + }spin_unlock (&fp->fi_lock);return nfs_ok; }
@@ -3652,6 +3658,8 @@ out: open->op_rflags |=NFS4_OPEN_RESULT_CONFIRM ;if (dp)nfs4_put_delegation (dp); +if (stp) +put_generic_stateid (stp);return status; }
Signature · 1 line
1.9.3
PATCH 39/104 NFSd: Prepare nfsd4_close() for open stateid referencing
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
Prepare nfsd4_close for a future where nfs4_preprocess_seqid_op() hands it a fully referenced open stateid.
--- fs/nfsd/nfs4state.c | 5 +++++ 1 file changed, 5 insertions(+)
fs/nfsd/nfs4state.c +5 -0
@@ -4433,10 +4433,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;
Signature · 1 line
1.9.3
PATCH 40/104 NFSd: nfsd4_open_confirm() must reference the open stateid
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
Ensure that nfsd4_open_confirm() keeps a reference to the open stateid until it is done working with it.
--- fs/nfsd/nfs4state.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
fs/nfsd/nfs4state.c +5 -1
@@ -4253,10 +4253,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));
@@ -4265,6 +4267,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 ();
Signature · 1 line
1.9.3
PATCH 41/104 NFSd: Add reference counting to nfs4_preprocess_confirmed_seqid_op
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
Ensure that all the callers put the open stateid after use.
--- fs/nfsd/nfs4state.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
fs/nfsd/nfs4state.c +9 -4
@@ -4224,6 +4224,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;
@@ -4364,12 +4366,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, od->od_share_deny);
@@ -4378,6 +4380,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 ();
@@ -4734,6 +4738,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 ;
@@ -4760,8 +4765,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,
@@ -4884,6 +4887,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);
Signature · 1 line
1.9.3
PATCH 42/104 NFSd: Migrate the stateid reference into nfs4_preprocess_seqid_op
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
Allow nfs4_preprocess_seqid_op to take the stateid reference, instead of having all the callers do so.
--- fs/nfsd/nfs4state.c | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-)
fs/nfsd/nfs4state.c +11 -15
@@ -4209,8 +4209,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; }
@@ -4219,16 +4222,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; }
@@ -4255,8 +4260,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 )
@@ -4441,8 +4444,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));
@@ -4794,9 +4795,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;
@@ -5019,8 +5017,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;
Signature · 1 line
1.9.3
PATCH 43/104 NFSd: Migrate the stateid reference into nfs4_lookup_stateid()
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
Allow nfs4_lookup_stateid to take the stateid reference, instead of having all the callers do so.
--- fs/nfsd/nfs4state.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-)
fs/nfsd/nfs4state.c +11 -6
@@ -3998,6 +3998,8 @@ static __be32 nfsd4_lookup_stateid(stateid_t *stateid, unsigned char typemask, *s =find_stateid_by_type (cl, stateid, typemask);if (!*s)return nfserr_bad_stateid; +/* FIXME: move into find_stateid_by_type */ +atomic_inc (&(*s)->sc_count);return nfs_ok; }
@@ -4031,7 +4033,7 @@ nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate, status =nfsd4_lookup_stateid (stateid,NFS4_DELEG_STID |NFS4_OPEN_STID |NFS4_LOCK_STID , &s, cstate->minorversion, nn);if (status) - goto out; + goto unlock_state; status =check_stateid_generation (stateid, &s->sc_stateid,nfsd4_has_session (cstate));if (status) goto out;
@@ -4078,6 +4080,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; }
@@ -4209,11 +4213,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; }
@@ -4477,9 +4480,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 ();
Signature · 1 line
1.9.3
PATCH 44/104 NFSd: Migrate the stateid reference into nfs4_find_stateid_by_type()
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
Allow nfs4_find_stateid_by_type to take the stateid reference, while still holding the &cl->cl_lock.
--- fs/nfsd/nfs4state.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
fs/nfsd/nfs4state.c +6 -6
@@ -1590,8 +1590,12 @@ static struct nfs4_stid *find_stateid_by_type(struct nfs4_client *cl, stateid_tspin_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; }
@@ -3181,8 +3185,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); }
@@ -3998,8 +4000,6 @@ static __be32 nfsd4_lookup_stateid(stateid_t *stateid, unsigned char typemask, *s =find_stateid_by_type (cl, stateid, typemask);if (!*s)return nfserr_bad_stateid; -/* FIXME: move into find_stateid_by_type */ -atomic_inc (&(*s)->sc_count);return nfs_ok; }
Signature · 1 line
1.9.3
PATCH 45/104 NFSd: Add reference counting to state owners
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
--- fs/nfsd/nfs4state.c | 42 ++++++++++++++++++++++++++++-------------- fs/nfsd/state.h | 3 +++ 2 files changed, 31 insertions(+), 14 deletions(-)
fs/nfsd/nfs4state.c +28 -14
@@ -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 void nfs4_put_stateowner (struct nfs4_stateowner *sop);/* Locking: */
@@ -826,16 +827,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)
@@ -905,18 +900,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
@@ -2860,9 +2849,17 @@ static inline void *alloc_stateowner(struct kmem_cache *slab, struct xdr_netobjINIT_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);
@@ -2871,6 +2868,14 @@ static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, ulist_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 nfs4_client *clp,struct nfsd4_open *open) {struct nfs4_openowner *oo;
@@ -2878,6 +2883,7 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, str 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 ;
@@ -4590,6 +4596,13 @@ static void hash_lockowner(struct nfs4_lockowner *lo, unsigned int strhashval, slist_add (&lo->lo_owner.so_strhash, &nn->ownerstr_hashtbl[strhashval]); } +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
@@ -4611,6 +4624,7 @@ alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, str* 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); + lo->lo_owner.so_free = nfs4_free_lockowner;return lo; }
fs/nfsd/state.h +3 -0
@@ -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 {
Signature · 1 line
1.9.3
PATCH 46/104 NFSd: Keep a reference to the open stateid for the NFSv4.0 replay cache
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
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.
--- fs/nfsd/nfs4proc.c | 5 +---- fs/nfsd/nfs4state.c | 26 +++++++++++++++++++++++++- fs/nfsd/xdr4.h | 24 ++++-------------------- 3 files changed, 30 insertions(+), 25 deletions(-)
fs/nfsd/nfs4proc.c +1 -4
@@ -468,10 +468,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;
fs/nfsd/nfs4state.c +25 -1
@@ -2831,6 +2831,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;
@@ -3672,7 +3693,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;
@@ -3686,6 +3708,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);
fs/nfsd/xdr4.h +4 -20
@@ -74,25 +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;
@@ -614,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,
@@ -645,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 /*
Signature · 1 line
1.9.3
PATCH 47/104 nfsd: clean up lockowner refcounting when finding them
In reply to Jeff LaytonEnsure 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.
--- fs/nfsd/nfs4state.c | 51 ++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 38 insertions(+), 13 deletions(-)
fs/nfsd/nfs4state.c +38 -13
@@ -4608,6 +4608,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 ;
@@ -4644,9 +4645,7 @@ alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, strreturn 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;hash_lockowner (lo, strhashval, clp); lo->lo_owner.so_free = nfs4_free_lockowner;return lo;
@@ -4741,8 +4740,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;
@@ -4757,19 +4761,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; }/*
@@ -4787,9 +4798,9 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,struct file_lock *file_lock =NULL ;struct file_lock *conflock =NULL ;__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);
@@ -4832,7 +4843,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,
@@ -4926,12 +4937,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)
@@ -4966,7 +4989,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);
@@ -5029,6 +5052,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);
Signature · 1 line
1.9.3
PATCH 48/104 nfsd: add an operation for unhashing a stateowner
In reply to Jeff LaytonAllow 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.
--- fs/nfsd/nfs4state.c | 45 +++++++++++++++++++++++++++++++++++---------- fs/nfsd/state.h | 1 + 2 files changed, 36 insertions(+), 10 deletions(-)
fs/nfsd/nfs4state.c +35 -10
@@ -817,9 +817,13 @@ static void __release_lock_stateid(struct nfs4_lockowner *lo,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);
@@ -830,6 +834,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); }
@@ -879,15 +884,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)
@@ -900,9 +898,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);
@@ -2878,6 +2888,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); }
@@ -2889,6 +2900,13 @@ static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, ulist_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);
@@ -2905,6 +2923,7 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, strif (!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 ;
@@ -4621,6 +4640,11 @@ static void hash_lockowner(struct nfs4_lockowner *lo, unsigned int strhashval, slist_add (&lo->lo_owner.so_strhash, &nn->ownerstr_hashtbl[strhashval]); } +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);
@@ -4648,6 +4672,7 @@ alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, str lo->lo_owner.so_seqid = lock->lk_new_lock_seqid;hash_lockowner (lo, strhashval, clp); lo->lo_owner.so_free = nfs4_free_lockowner; + lo->lo_owner.so_unhash = nfs4_unhash_lockowner;return lo; }
fs/nfsd/state.h +1 -0
@@ -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 {
Signature · 1 line
1.9.3
PATCH 49/104 NFSd: Make lock stateid take a reference to the lockowner
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
--- fs/nfsd/nfs4state.c | 3 +++ 1 file changed, 3 insertions(+)
fs/nfsd/nfs4state.c +3 -0
@@ -782,6 +782,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); }
@@ -4687,6 +4689,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;
Signature · 1 line
1.9.3
PATCH 50/104 nfsd: clean up nfs4_release_lockowner
In reply to Jeff LaytonNow 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.
--- fs/nfsd/nfs4state.c | 46 ++++++++++++++++++++++++---------------------- fs/nfsd/state.h | 1 - 2 files changed, 24 insertions(+), 23 deletions(-)
fs/nfsd/nfs4state.c +24 -22
@@ -5190,7 +5190,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;
@@ -5211,31 +5211,33 @@ 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_stid.sc_file, lo)) - goto out; -list_add (&lo->lo_list, &matches); +if (same_owner_str (tmp, owner, clid)) { + sop = tmp; +atomic_inc (&sop->so_count); +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_stid.sc_file, lo)) + goto out; + } + + status = nfs_ok; +release_lockowner (lo); +nfs4_put_stateowner (sop); out:nfs4_unlock_state ();return status;
fs/nfsd/state.h +0 -1
@@ -370,7 +370,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)
Signature · 1 line
1.9.3
PATCH 51/104 nfsd: clean up refcounting for lockowners
In reply to Jeff LaytonEnsure 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.
--- fs/nfsd/nfs4state.c | 34 ++++++++-------------------------- 1 file changed, 8 insertions(+), 26 deletions(-)
fs/nfsd/nfs4state.c +8 -26
@@ -804,8 +804,7 @@ static void put_generic_stateid(struct nfs4_ol_stateid *stp)nfs4_put_stid (&stp->st_stid); } -static void __release_lock_stateid (struct nfs4_lockowner *lo, -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);
@@ -829,32 +828,17 @@ 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 (lo, stp); +release_lock_stateid (stp); } } -static void release_lockowner (struct nfs4_lockowner *lo) +static void destroy_lockowner (struct nfs4_lockowner *lo) {unhash_lockowner (lo);release_lockowner_stateids (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 (lo, 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)
@@ -4144,7 +4128,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; }
@@ -4789,8 +4773,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;
@@ -4801,7 +4783,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; }
@@ -5231,13 +5212,14 @@ 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; -release_lockowner (lo); -nfs4_put_stateowner (sop); +destroy_lockowner (lo); out:nfs4_unlock_state ();return status;
Signature · 1 line
1.9.3
PATCH 52/104 nfsd: declare v4.1+ openowners confirmed on creation
In reply to Jeff Layton--- fs/nfsd/nfs4state.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)
fs/nfsd/nfs4state.c +7 -4
@@ -2902,7 +2902,10 @@ static void nfs4_free_openowner(struct nfs4_stateowner *so) }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);
@@ -2913,6 +2916,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);
@@ -3185,7 +3190,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;
@@ -3654,8 +3659,6 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfmemcpy (&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 ;
Signature · 1 line
1.9.3
PATCH 53/104 nfsd: make openstateids hold references to their openowners
In reply to Jeff LaytonChange 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.
--- fs/nfsd/nfs4state.c | 71 +++++++++++++++++++++++------------------------------ fs/nfsd/state.h | 1 - 2 files changed, 31 insertions(+), 41 deletions(-)
fs/nfsd/nfs4state.c +31 -40
@@ -782,7 +782,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); }
@@ -879,8 +879,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); } }
@@ -899,7 +900,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); }
@@ -1372,6 +1372,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);
@@ -2915,7 +2916,7 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, 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 ;
@@ -2932,6 +2933,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 ;
@@ -2947,13 +2949,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 (); }
@@ -2984,6 +3000,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; } }
@@ -3705,19 +3722,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);
@@ -3842,7 +3850,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 ();
@@ -4435,31 +4443,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); }/*
fs/nfsd/state.h +0 -1
@@ -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 4unsigned char oo_flags; };
Signature · 1 line
1.9.3
PATCH 54/104 nfsd: don't allow CLOSE to proceed until refcount on stateid drops
In reply to Jeff LaytonOnce 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.
--- fs/nfsd/nfs4state.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-)
fs/nfsd/nfs4state.c +27 -1
@@ -85,6 +85,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;
@@ -552,8 +558,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);
@@ -2963,11 +2971,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);
@@ -4447,6 +4467,12 @@ static void nfsd4_close_open_stateid(struct nfs4_ol_stateid *s) s->st_stid.sc_type =NFS4_CLOSED_STID ;unhash_open_stateid (s); +/* +* We can't safely clear the sc_file pointer while there are still +* other calls in flight that might be using it. At this point, the +* stateid is unhashed, so no new references for anything but another +* CLOSE can be acquired. Wait for the refcount to drop to '2' +*/ if (clp->cl_minorversion)put_generic_stateid (s);else
Signature · 1 line
1.9.3
PATCH 55/104 NFSd: Protect adding/removing open state owners using client_lock
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
* Ensure that alloc_init_open_stateowner() checks the hashtable under the lock before adding a new element.
--- fs/nfsd/nfs4state.c | 63 +++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 54 insertions(+), 9 deletions(-)
fs/nfsd/nfs4state.c +54 -9
@@ -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 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);/* Locking: */
@@ -876,8 +879,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); }
@@ -896,18 +904,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); }
@@ -2898,8 +2917,11 @@ static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, ustatic 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)
@@ -2915,7 +2937,8 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp,struct nfsd4_open *open, struct nfsd4_compound_state *cstate) { - 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)
@@ -2930,7 +2953,15 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, 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; }
@@ -3004,13 +3035,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 ;
@@ -3018,15 +3051,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)
Signature · 1 line
1.9.3
PATCH 56/104 NFSd: Protect adding/removing lock owners using client_lock
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
* Ensure that alloc_init_lock_stateowner() checks the hashtable under the lock before adding a new element.
--- fs/nfsd/nfs4state.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 59 insertions(+), 8 deletions(-)
fs/nfsd/nfs4state.c +59 -8
@@ -827,26 +827,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 destroy_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); }
@@ -4667,7 +4683,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);
@@ -4684,6 +4700,18 @@ 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 hash_lockowner (struct nfs4_lockowner *lo,unsigned int strhashval,struct nfs4_client *clp) {struct nfsd_net *nn =net_generic (clp->net, nfsd_net_id);
@@ -4693,7 +4721,11 @@ static void hash_lockowner(struct nfs4_lockowner *lo, unsigned int strhashval, sstatic 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)
@@ -4712,8 +4744,10 @@ static void nfs4_free_lockowner(struct nfs4_stateowner *sop)*/ 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)
@@ -4721,9 +4755,17 @@ alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, strINIT_LIST_HEAD (&lo->lo_owner.so_stateids); lo->lo_owner.so_is_open_owner =0 ; lo->lo_owner.so_seqid = lock->lk_new_lock_seqid; -hash_lockowner (lo, strhashval, clp); lo->lo_owner.so_free = nfs4_free_lockowner; lo->lo_owner.so_unhash = nfs4_unhash_lockowner; +spin_lock (&nn->client_lock); + ret =find_lockowner_str_locked (&clp->cl_clientid, + &lock->lk_new_owner, nn); +if (ret ==NULL ) { +hash_lockowner (lo, strhashval, clp); + ret = lo; + }else +nfs4_free_lockowner (&lo->lo_owner); +spin_unlock (&nn->client_lock);return lo; }
@@ -5244,6 +5286,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);
@@ -5258,6 +5301,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 ;
@@ -5267,6 +5311,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) {
@@ -5276,16 +5321,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 ;destroy_lockowner (lo); out: +if (sop) +nfs4_put_stateowner (sop);nfs4_unlock_state ();return status; }
Signature · 1 line
1.9.3
PATCH 57/104 NFSd: Cleanup - Let nfsd4_lookup_stateid() take a cstate argument
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
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.
--- fs/nfsd/nfs4state.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-)
fs/nfsd/nfs4state.c +10 -9
@@ -4106,12 +4106,14 @@ out_put_stid:return status; } -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;
@@ -4157,8 +4159,9 @@ nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate,nfs4_lock_state (); - status =nfsd4_lookup_stateid (stateid,NFS4_DELEG_STID |NFS4_OPEN_STID |NFS4_LOCK_STID , - &s, cstate->minorversion, nn); + status =nfsd4_lookup_stateid (cstate, stateid, +NFS4_DELEG_STID |NFS4_OPEN_STID |NFS4_LOCK_STID , + &s, nn);if (status) goto unlock_state; status =check_stateid_generation (stateid, &s->sc_stateid,nfsd4_has_session (cstate));
@@ -4332,8 +4335,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);
@@ -4589,8 +4591,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);
Signature · 1 line
1.9.3
PATCH 58/104 NFSd: Cache the client that was looked up in lookup_clientid()
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
We want to use the nfsd4_compound_state to cache the nfs4_client in order to optimise away extra lookups of the clid.
--- fs/nfsd/nfs4state.c | 44 +++++++++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 15 deletions(-)
fs/nfsd/nfs4state.c +29 -15
@@ -3814,15 +3814,31 @@ void nfsd4_cleanup_open_state(struct nfsd4_compound_state *cstate,put_generic_stateid (open->op_stp); } -static __be32 lookup_clientid (clientid_t *clid,bool session,struct nfsd_net *nn,struct nfs4_client **clp) +static __be32 lookup_clientid (clientid_t *clid, +struct nfsd4_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; }
@@ -3837,9 +3853,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 )
@@ -4111,22 +4128,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;
@@ -5119,7 +5133,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; }
@@ -5294,7 +5308,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;
Signature · 1 line
1.9.3
PATCH 59/104 NFSd: Convert nfsd4_process_open1() to work with lookup_clientid()
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
...and have alloc_init_open_stateowner just use the cstate->clp pointer instead of passing in a clp separately.
--- fs/nfsd/nfs4state.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-)
fs/nfsd/nfs4state.c +10 -7
@@ -75,6 +75,9 @@ 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, +struct nfsd_net *nn);/* Locking: */
@@ -2949,10 +2952,10 @@ static void nfs4_free_openowner(struct nfs4_stateowner *so) }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 nfsd_net *nn =net_generic (clp->net, nfsd_net_id);struct nfs4_openowner *oo, *ret;
@@ -3269,10 +3272,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 )) {
@@ -3288,7 +3291,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;
Signature · 1 line
1.9.3
PATCH 60/104 NFSd: Always use lookup_clientid() in nfsd4_process_open1
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
Preparation for moving the stateowner table into the nfs4_client
--- fs/nfsd/nfs4state.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-)
fs/nfsd/nfs4state.c +5 -6
@@ -3268,19 +3268,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;
@@ -3288,7 +3288,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);
Signature · 1 line
1.9.3
PATCH 61/104 NFSd: Move the open owner hash table into struct nfs4_client
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
* Convert the open owner hash table into a per-client table
* Protect it using the nfs4_client->cl_lock spin lock
--- fs/nfsd/netns.h | 1 - fs/nfsd/nfs4state.c | 185 +++++++++++++++++++++++----------------------------- fs/nfsd/state.h | 1 + 3 files changed, 83 insertions(+), 104 deletions(-)
fs/nfsd/netns.h +0 -1
@@ -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
fs/nfsd/nfs4state.c +82 -103
460 lines not on this page · raw message
fs/nfsd/state.h +1 -0
@@ -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;
Signature · 1 line
1.9.3
PATCH 62/104 lockdep: add lockdep_assert_not_held
In reply to Jeff LaytonWe 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).
--- include/linux/lockdep.h | 6 ++++++ 1 file changed, 6 insertions(+)
include/linux/lockdep.h +6 -0
@@ -362,6 +362,10 @@ extern void lockdep_trace_alloc(gfp_t mask);WARN_ON (debug_locks && !lockdep_is_held (l)); \ } while (0) +#define lockdep_assert_not_held (l) do { \ + WARN_ON(debug_locks && lockdep_is_held(l)); \ + } while (0) +#define lockdep_recursing (tsk) ((tsk)->lockdep_recursion)#else /* !CONFIG_LOCKDEP */
@@ -413,6 +417,8 @@ struct lock_class_key { };#define lockdep_assert_held (l) do { (void)(l); } while (0) +#define lockdep_assert_not_held (l) do { (void)(l); } while (0) +#define lockdep_recursing (tsk) (0)#endif /* !LOCKDEP */
Signature · 1 line
1.9.3
PATCH 63/104 nfsd: add locking to stateowner release
In reply to Jeff Layton--- fs/nfsd/nfs4state.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-)
fs/nfsd/nfs4state.c +8 -9
@@ -563,6 +563,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 ;
@@ -2923,9 +2925,14 @@ static inline void *alloc_stateowner(struct kmem_cache *slab, struct xdr_netobjstatic 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); }
@@ -2939,11 +2946,7 @@ static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, ustatic 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)
@@ -4730,11 +4733,7 @@ static void hash_lockowner(struct nfs4_lockowner *lo, unsigned int strhashval, sstatic 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)
Signature · 1 line
1.9.3
PATCH 64/104 nfsd: optimize destroy_lockowner cl_lock thrashing
In reply to Jeff LaytonReduce 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.
--- fs/nfsd/nfs4state.c | 49 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 17 deletions(-)
fs/nfsd/nfs4state.c +32 -17
@@ -819,14 +819,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); }
@@ -840,30 +849,36 @@ 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 destroy_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 destroy_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); }
Signature · 1 line
1.9.3
PATCH 65/104 nfsd: reduce cl_lock trashing in release_openowner
In reply to Jeff Layton--- fs/nfsd/nfs4state.c | 46 ++++++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 22 deletions(-)
fs/nfsd/nfs4state.c +24 -22
@@ -899,16 +899,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)
@@ -932,30 +926,36 @@ 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 the persistent reference to the stateid. If it's +* the last reference, then put it onto the reaplist +* for later destruction. +*/ +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_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); +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); + }release_last_closed_stateid (oo);nfs4_put_stateowner (&oo->oo_owner); }
@@ -4554,7 +4554,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);/* * We can't safely clear the sc_file pointer while there are still
Signature · 1 line
1.9.3
PATCH 66/104 NFSd: Convert nfs4_check_open_reclaim() to work with lookup_clientid()
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
--- fs/nfsd/nfs4proc.c | 3 +-- fs/nfsd/nfs4state.c | 13 ++++++++----- fs/nfsd/state.h | 3 ++- 3 files changed, 11 insertions(+), 8 deletions(-)
fs/nfsd/nfs4proc.c +1 -2
@@ -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 ;
fs/nfsd/nfs4state.c +8 -5
@@ -5446,16 +5446,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
fs/nfsd/state.h +2 -1
@@ -440,7 +440,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_init_callback (struct nfsd4_callback *);extern void nfsd4_probe_callback (struct nfs4_client *clp);
Signature · 1 line
1.9.3
PATCH 67/104 NFSd: Ensure struct nfs4_client is unhashed before we try to destroy it
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
When we remove the nfs4_lock_state() protection, we will need to ensure that it can't be found by other threads while we're destroying it.
--- fs/nfsd/nfs4state.c | 43 +++++++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 10 deletions(-)
fs/nfsd/nfs4state.c +33 -10
@@ -1399,12 +1399,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);
@@ -1412,7 +1423,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;
@@ -1445,22 +1466,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)
Signature · 1 line
1.9.3
PATCH 68/104 NFSd: Ensure that the laundromat unhashes the client before releasing locks
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
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.
--- fs/nfsd/nfs4state.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
fs/nfsd/nfs4state.c +3 -1
@@ -3949,13 +3949,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);
Signature · 1 line
1.9.3
PATCH 69/104 NFSd: Don't require client_lock in free_client
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
The struct nfs_client is supposed to be invisible and unreferenced before it gets here.
--- fs/nfsd/nfs4state.c | 13 ------------- 1 file changed, 13 deletions(-)
fs/nfsd/nfs4state.c +0 -13
@@ -1225,9 +1225,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);
@@ -1377,9 +1374,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,
@@ -1438,7 +1432,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);
@@ -1466,10 +1459,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
@@ -1683,7 +1673,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 )
@@ -1691,9 +1680,7 @@ static struct nfs4_client *create_client(struct xdr_netobj name, ret =copy_cred (&clp->cl_cred, &rqstp->rq_cred);if (ret) { -spin_lock (&nn->client_lock);free_client (clp); -spin_unlock (&nn->client_lock);return NULL ; }nfsd4_init_callback (&clp->cl_cb_null);
Signature · 1 line
1.9.3
PATCH 70/104 NFSd: Move create_client() call outside the lock
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
For efficiency reasons, and because we want to use spin locks.
--- fs/nfsd/nfs4state.c | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-)
fs/nfsd/nfs4state.c +19 -16
@@ -2002,6 +2002,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);
@@ -2028,7 +2032,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 */
@@ -2041,7 +2044,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 */
@@ -2059,29 +2061,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; }
@@ -2724,6 +2725,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);
@@ -2744,10 +2748,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);
@@ -2759,9 +2759,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; }
Signature · 1 line
1.9.3
PATCH 71/104 NFSd: Protect unconfirmed client creation using client_lock
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
--- fs/nfsd/nfs4state.c | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-)
fs/nfsd/nfs4state.c +22 -11
@@ -1744,7 +1744,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
@@ -1758,7 +1758,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 *
@@ -1771,7 +1771,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; } }
@@ -1973,7 +1973,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;
@@ -2008,6 +2009,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);
@@ -2039,7 +2041,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 */
@@ -2047,6 +2048,7 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, goto out_copy; }/* case 5, client reboot */ + conf =NULL ; goto out_new; }
@@ -2057,17 +2059,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;
@@ -2080,9 +2083,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; }
@@ -2721,7 +2727,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);
@@ -2730,6 +2737,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: */
@@ -2747,7 +2755,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);
@@ -2762,9 +2770,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; }
Signature · 1 line
1.9.3
PATCH 72/104 NFSd: Protect session creation and client confirm using client_lock
In reply to Jeff LaytonIn 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.
--- fs/nfsd/nfs4state.c | 63 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 38 insertions(+), 25 deletions(-)
fs/nfsd/nfs4state.c +38 -25
@@ -143,17 +143,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))
@@ -1246,12 +1235,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);
@@ -2232,6 +2219,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 ;
@@ -2258,6 +2246,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);
@@ -2276,7 +2265,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;
@@ -2294,10 +2282,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;
@@ -2313,7 +2301,7 @@ nfsd4_create_session(struct svc_rqst *rqstp, cr_ses->flags &= ~SESSION4_RDMA ;init_session (rqstp, new, conf, cr_ses); -nfsd4_init_conn (rqstp, conn, new); +nfsd4_get_session_locked (new);memcpy (cr_ses->sessionid.data, new->se_sessionid.data,NFS4_MAX_SESSIONID_LEN );
@@ -2322,11 +2310,20 @@ nfsd4_create_session(struct svc_rqst *rqstp,/* cache solo and embedded create sessions under the state lock */ nfsd4_cache_create_session (cr_ses, cs_slot, status); +spin_unlock (&nn->client_lock); +/* init connection and backchannel */ +nfsd4_init_conn (rqstp, conn, new); +nfsd4_put_session (new);nfs4_unlock_state (); +if (old) +expire_client (old);return status; out_free_conn: +spin_unlock (&nn->client_lock);nfs4_unlock_state ();free_conn (conn); +if (old) +expire_client (old); out_free_session:__free_session (new); out_release_drc_mem:
@@ -2786,6 +2783,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;
@@ -2795,6 +2793,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);/*
@@ -2818,21 +2817,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; }
@@ -5491,7 +5498,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 ;
Signature · 1 line
1.9.3
PATCH 73/104 NFSd: Protect nfsd4_destroy_clientid using client_lock
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
--- fs/nfsd/nfs4state.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
fs/nfsd/nfs4state.c +9 -4
@@ -2647,22 +2647,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 {
@@ -2670,12 +2671,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; }
Signature · 1 line
1.9.3
PATCH 74/104 NFSd: Ensure lookup_clientid() takes client_lock
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
Ensure that the client lookup is done safely under the client_lock.
--- fs/nfsd/nfs4state.c | 2 ++ 1 file changed, 2 insertions(+)
fs/nfsd/nfs4state.c +2 -0
@@ -3880,12 +3880,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; }
Signature · 1 line
1.9.3
PATCH 75/104 NFSd: Add assertions to document the nfs4_client/session locking
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
--- fs/nfsd/nfs4state.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+)
fs/nfsd/nfs4state.c +30 -0
@@ -145,6 +145,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);
@@ -185,6 +189,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))
@@ -216,6 +224,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);
@@ -1262,6 +1273,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 */
@@ -1298,6 +1311,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);
@@ -1386,6 +1404,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 */
@@ -1727,6 +1747,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);
@@ -1740,6 +1762,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);
@@ -1770,6 +1794,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); }
@@ -1778,6 +1803,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); }
@@ -1789,12 +1815,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); }
@@ -4758,6 +4786,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)continue ;
Signature · 1 line
1.9.3
PATCH 76/104 nfsd: protect the close_lru list and oo_last_closed_stid with client_lock
In reply to Jeff Layton--- fs/nfsd/nfs4state.c | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-)
fs/nfsd/nfs4state.c +27 -6
@@ -917,13 +917,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)
@@ -3098,6 +3104,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);
@@ -3121,10 +3128,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
@@ -3970,6 +3981,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;
@@ -4021,15 +4033,24 @@ 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); + +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;
Signature · 1 line
1.9.3
PATCH 77/104 nfsd: ensure that clp->cl_revoked list is protected by clp->cl_lock
In reply to Jeff LaytonCurrently, both destroy_revoked_delegation and revoke_delegation manipulate the cl_revoked list without any locking. 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, so we should be safe to walk the list without any locking, which 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.
--- fs/nfsd/nfs4state.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-)
fs/nfsd/nfs4state.c +13 -4
@@ -649,7 +649,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); }
@@ -657,11 +657,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); } }
@@ -1459,9 +1463,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)) {
@@ -4391,6 +4395,11 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,break ;case NFS4_REVOKED_DELEG_STID : dp =delegstateid (s); + +spin_lock (&cl->cl_lock); +list_del_init (&dp->dl_recall_lru); +spin_unlock (&cl->cl_lock); +destroy_revoked_delegation (dp); ret = nfs_ok;break ;
Signature · 1 line
1.9.3
PATCH 78/104 nfsd: move unhash_client_locked call into mark_client_expired_locked
In reply to Jeff LaytonAll 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.
--- fs/nfsd/nfs4state.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
fs/nfsd/nfs4state.c +2 -4
@@ -69,6 +69,7 @@ static u64 current_sessionid = 1;#define CURRENT_STATEID (stateid) (!memcmp((stateid), ¤tstateid, 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(
@@ -139,7 +140,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; }
@@ -2323,7 +2324,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;
@@ -2869,7 +2869,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;
@@ -4008,7 +4007,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);
Signature · 1 line
1.9.3
PATCH 79/104 nfsd: fix misleading comment
In reply to Jeff Layton...the client_lock now protects this.
--- fs/nfsd/nfs4state.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/nfsd/nfs4state.c +1 -1
@@ -2346,7 +2346,7 @@ nfsd4_create_session(struct svc_rqst *rqstp, 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 */
Signature · 1 line
1.9.3
PATCH 80/104 nfsd: don't destroy client if mark_client_expired_locked fails
In reply to Jeff Layton--- fs/nfsd/nfs4state.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
fs/nfsd/nfs4state.c +6 -2
@@ -2322,8 +2322,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;
@@ -2867,8 +2869,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;
Signature · 1 line
1.9.3
PATCH 81/104 nfsd: don't destroy clients that are busy
In reply to Jeff LaytonIt's possible that we'll have an in-progress call on some of the clients while we may be destroying the thing. Be sure to try and mark the client expired first, so that the refcount is respected.
--- fs/nfsd/nfs4state.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
fs/nfsd/nfs4state.c +8 -2
@@ -2089,8 +2089,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 );
@@ -2703,6 +2706,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;
Signature · 1 line
1.9.3
PATCH 82/104 nfsd: abstract out the get and set routines into the fault injection ops
In reply to Jeff LaytonFor now they all use the standard 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.
--- fs/nfsd/fault_inject.c | 128 +++++++++++++++++++++++++++++-------------------- 1 file changed, 77 insertions(+), 51 deletions(-)
fs/nfsd/fault_inject.c +77 -51
@@ -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,19 @@ 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) +printk (KERN_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 ) +printk (KERN_INFO "NFSD Fault Injection: %s (all)" , op->file); +else +printk (KERN_INFO "NFSD Fault Injection: %s (n = %llu)" , op->file, val); + val = op->set_val (op, val); +printk (KERN_INFO "NFSD: %s: found %llu" , op->file, val); }return len;/* on success, claim we got the whole input */ }
@@ -149,6 +130,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;
Signature · 1 line
1.9.3
PATCH 83/104 nfsd: add a forget_clients "get" routine with proper locking
In reply to Jeff Layton--- fs/nfsd/fault_inject.c | 3 +-- fs/nfsd/nfs4state.c | 29 +++++++++++++++++++++-------- fs/nfsd/state.h | 4 +++- 3 files changed, 25 insertions(+), 11 deletions(-)
fs/nfsd/fault_inject.c +1 -2
@@ -133,11 +133,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" ,
fs/nfsd/nfs4state.c +21 -8
@@ -5570,6 +5570,27 @@ 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)); +printk (KERN_INFO "NFS Client: %s\n" , buf); + ++count; + } +spin_unlock (&nn->client_lock); + +return count; +}u64 nfsd_forget_client (struct nfs4_client *clp,u64 max) {
@@ -5585,14 +5606,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) {
fs/nfsd/state.h +3 -1
@@ -467,18 +467,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 );
Signature · 1 line
1.9.3
PATCH 84/104 nfsd: add a forget_client set_clnt routine
In reply to Jeff Layton--- fs/nfsd/fault_inject.c | 2 +- fs/nfsd/nfs4state.c | 27 +++++++++++++++++++++++++++ fs/nfsd/state.h | 2 ++ 3 files changed, 30 insertions(+), 1 deletion(-)
fs/nfsd/fault_inject.c +1 -1
@@ -135,7 +135,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, }, {
fs/nfsd/nfs4state.c +27 -0
@@ -5606,6 +5606,33 @@ 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) {
fs/nfsd/state.h +2 -0
@@ -476,6 +476,8 @@ 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 );
Signature · 1 line
1.9.3
PATCH 85/104 nfsd: add nfsd_inject_forget_clients
In reply to Jeff Layton...and remove nfsd_forget_client.
--- fs/nfsd/fault_inject.c | 3 +-- fs/nfsd/nfs4state.c | 41 +++++++++++++++++++++++++++-------------- fs/nfsd/state.h | 2 +- 3 files changed, 29 insertions(+), 17 deletions(-)
fs/nfsd/fault_inject.c +1 -2
@@ -134,9 +134,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",
fs/nfsd/nfs4state.c +27 -14
53 lines not on this page · raw message
fs/nfsd/state.h +1 -1
@@ -475,8 +475,8 @@ 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 );
Signature · 1 line
1.9.3
PATCH 86/104 nfsd: add a list_head arg to nfsd_foreach_client_lock
In reply to Jeff LaytonIn a later patch, we'll want to collect the locks onto a list for later destruction.
--- fs/nfsd/nfs4state.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
fs/nfsd/nfs4state.c +9 -4
@@ -5654,7 +5654,9 @@ 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_ol_stateid *)) +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;struct nfs4_ol_stateid *stp, *st_next;
@@ -5664,8 +5666,11 @@ static u64 nfsd_foreach_client_lock(struct nfs4_client *clp, u64 max, void (*funlist_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 (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; }
@@ -5677,12 +5682,12 @@ static u64 nfsd_foreach_client_lock(struct nfs4_client *clp, u64 max, void (*funu64 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; }
Signature · 1 line
1.9.3
PATCH 87/104 nfsd: add more granular locking to forget_locks fault injector
In reply to Jeff Layton--- fs/nfsd/fault_inject.c | 8 ++-- fs/nfsd/nfs4state.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++--- fs/nfsd/state.h | 6 ++- 3 files changed, 117 insertions(+), 14 deletions(-)
fs/nfsd/fault_inject.c +3 -5
@@ -139,11 +139,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",
fs/nfsd/nfs4state.c +110 -7
153 lines not on this page · raw message
fs/nfsd/state.h +4 -2
@@ -478,12 +478,14 @@ 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_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 */
Signature · 1 line
1.9.3
PATCH 88/104 nfsd: add more granular locking to forget_openowners fault injector
In reply to Jeff LaytonAlso, 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.
--- fs/nfsd/fault_inject.c | 8 ++-- fs/nfsd/nfs4state.c | 113 +++++++++++++++++++++++++++++++++++++++++++++---- fs/nfsd/state.h | 6 ++- 3 files changed, 112 insertions(+), 15 deletions(-)
fs/nfsd/fault_inject.c +3 -5
@@ -145,11 +145,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",
fs/nfsd/nfs4state.c +105 -8
135 lines not on this page · raw message
fs/nfsd/state.h +4 -2
@@ -482,11 +482,13 @@ 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_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 ; }
Signature · 1 line
1.9.3
PATCH 89/104 nfsd: add more granular locking to *_delegations fault injectors
In reply to Jeff Layton--- fs/nfsd/fault_inject.c | 16 ++--- fs/nfsd/nfs4state.c | 156 ++++++++++++++++++++++++++++++++++++++++++------- fs/nfsd/state.h | 9 +-- 3 files changed, 145 insertions(+), 36 deletions(-)
fs/nfsd/fault_inject.c +6 -10
@@ -151,19 +151,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, }, };
fs/nfsd/nfs4state.c +134 -22
194 lines not on this page · raw message
fs/nfsd/state.h +5 -4
@@ -486,10 +486,11 @@ 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_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 ) {}
Signature · 1 line
1.9.3
PATCH 90/104 nfsd: remove old fault injection infrastructure
In reply to Jeff LaytonRemove 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.
--- fs/nfsd/fault_inject.c | 51 ++++--------------------------- fs/nfsd/nfs4state.c | 83 ++++++++++++++++++-------------------------------- fs/nfsd/state.h | 40 +++++++++++------------- 3 files changed, 54 insertions(+), 120 deletions(-)
fs/nfsd/fault_inject.c +6 -45
@@ -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)printk (KERN_INFO "NFSD [%s]: Client %s had %llu state object(s)\n" , op->file, write_buf, val);
@@ -113,7 +74,7 @@ static ssize_t fault_inject_write(struct file *file, const char __user *buf,printk (KERN_INFO "NFSD Fault Injection: %s (all)" , op->file); else printk(KERN_INFO "NFSD Fault Injection: %s (n = %llu)", op->file, val); - val = op->set_val (op, val); + val = op->set_val (val);printk (KERN_INFO "NFSD: %s: found %llu" , op->file, val); }return len;/* on success, claim we got the whole input */
fs/nfsd/nfs4state.c +30 -53
174 lines not on this page · raw message
fs/nfsd/state.h +18 -22
@@ -467,30 +467,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 ) {}
Signature · 1 line
1.9.3
PATCH 91/104 NFSd: Remove nfs4_lock_state(): nfs4_preprocess_stateid_op()
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
--- fs/nfsd/nfs4state.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-)
fs/nfsd/nfs4state.c +1 -5
@@ -4294,13 +4294,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;
@@ -4348,8 +4346,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; }
Signature · 1 line
1.9.3
PATCH 92/104 NFSd: Remove nfs4_lock_state(): nfsd4_test_stateid/nfsd4_free_stateid
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
--- fs/nfsd/nfs4state.c | 4 ---- 1 file changed, 4 deletions(-)
fs/nfsd/nfs4state.c +0 -4
@@ -4370,11 +4370,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; }
@@ -4389,7 +4387,6 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,struct nfs4_client *cl = cstate->session->se_client;__be32 ret = nfserr_bad_stateid; -nfs4_lock_state (); s =find_stateid (cl, stateid);if (!s) goto out;
@@ -4422,7 +4419,6 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, }nfs4_put_stid (s); out: -nfs4_unlock_state ();return ret; }
Signature · 1 line
1.9.3
PATCH 93/104 NFSd: Remove nfs4_lock_state(): nfsd4_release_lockowner
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
--- fs/nfsd/nfs4state.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-)
fs/nfsd/nfs4state.c +1 -4
@@ -5423,11 +5423,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);
@@ -5468,7 +5466,6 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, out:if (sop)nfs4_put_stateowner (sop); -nfs4_unlock_state ();return status; }
Signature · 1 line
1.9.3
PATCH 94/104 NFSd: Remove nfs4_lock_state(): nfsd4_lock/locku/lockt()
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
--- fs/nfsd/nfs4state.c | 9 --------- 1 file changed, 9 deletions(-)
fs/nfsd/nfs4state.c +0 -9
@@ -5065,8 +5065,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: */
@@ -5204,7 +5202,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)
@@ -5247,8 +5244,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)
@@ -5302,7 +5297,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;
@@ -5326,8 +5320,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);
@@ -5370,7 +5362,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;
Signature · 1 line
1.9.3
PATCH 95/104 NFSd: Remove nfs4_lock_state(): nfsd4_open_downgrade + nfsd4_close
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
--- fs/nfsd/nfs4state.c | 4 ---- 1 file changed, 4 deletions(-)
fs/nfsd/nfs4state.c +0 -4
@@ -4626,7 +4626,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)
@@ -4653,7 +4652,6 @@ put_stateid:put_generic_stateid (stp); out:nfsd4_bump_seqid (cstate, status); -nfs4_unlock_state ();return status; }
@@ -4693,7 +4691,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,
@@ -4709,7 +4706,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; }
Signature · 1 line
1.9.3
PATCH 96/104 NFSd: Remove nfs4_lock_state(): nfsd4_delegreturn()
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
--- fs/nfsd/nfs4state.c | 3 --- 1 file changed, 3 deletions(-)
fs/nfsd/nfs4state.c +0 -3
@@ -4722,7 +4722,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;
@@ -4735,8 +4734,6 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, put_stateid:nfs4_put_delegation (dp); out: -nfs4_unlock_state (); -return status; }
Signature · 1 line
1.9.3
PATCH 97/104 NFSd: Remove nfs4_lock_state(): nfsd4_open and nfsd4_open_confirm
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
--- fs/nfsd/nfs4proc.c | 3 --- fs/nfsd/nfs4state.c | 6 ------ 2 files changed, 9 deletions(-)
fs/nfsd/nfs4proc.c +0 -3
@@ -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; }
fs/nfsd/nfs4state.c +0 -6
@@ -3809,9 +3809,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) {
@@ -4519,8 +4516,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);
@@ -4542,7 +4537,6 @@ put_stateid:put_generic_stateid (stp); out:nfsd4_bump_seqid (cstate, status); -nfs4_unlock_state ();return status; }
Signature · 1 line
1.9.3
PATCH 98/104 NFSd: Remove nfs4_lock_state(): exchange_id, create/destroy_session()
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
Also destroy_clientid and bind_conn_to_session.
--- fs/nfsd/nfs4state.c | 11 ----------- 1 file changed, 11 deletions(-)
fs/nfsd/nfs4state.c +0 -11
@@ -2044,7 +2044,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) {
@@ -2123,7 +2122,6 @@ out_copy: out:spin_unlock (&nn->client_lock); -nfs4_unlock_state ();if (new)expire_client (new);if (unconf)
@@ -2297,7 +2295,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);
@@ -2367,13 +2364,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);
@@ -2429,7 +2424,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);
@@ -2450,7 +2444,6 @@ __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp, out:nfsd4_put_session (session); out_no_session: -nfs4_unlock_state ();return status; }
@@ -2472,7 +2465,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))
@@ -2502,7 +2494,6 @@ out_put_session: out_client_lock:spin_unlock (&nn->client_lock); out: -nfs4_unlock_state ();return status; }
@@ -2705,7 +2696,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);
@@ -2734,7 +2724,6 @@ nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstaunhash_client_locked (clp); out:spin_unlock (&nn->client_lock); -nfs4_unlock_state ();if (clp)expire_client (clp);return status;
Signature · 1 line
1.9.3
PATCH 99/104 NFSd: Remove nfs4_lock_state(): setclientid, setclientid_confirm, renew
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
--- fs/nfsd/nfs4state.c | 6 ------ 1 file changed, 6 deletions(-)
fs/nfsd/nfs4state.c +0 -6
@@ -2783,7 +2783,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) {
@@ -2818,7 +2817,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)
@@ -2841,7 +2839,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);
@@ -2891,7 +2888,6 @@ out:spin_unlock (&nn->client_lock);if (old)expire_client (old); -nfs4_unlock_state ();return status; }
@@ -3948,7 +3944,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);
@@ -3961,7 +3956,6 @@ nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, goto out; status = nfs_ok; out: -nfs4_unlock_state ();return status; }
Signature · 1 line
1.9.3
PATCH 100/104 NFSd: Remove nfs4_lock_state(): reclaim_complete()
In reply to Jeff LaytonFrom: Trond Myklebust <[email protected]>
--- fs/nfsd/nfs4state.c | 2 -- 1 file changed, 2 deletions(-)
fs/nfsd/nfs4state.c +0 -2
@@ -2744,7 +2744,6 @@ nfsd4_reclaim_complete(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstareturn nfs_ok; } -nfs4_lock_state (); status = nfserr_complete_already;if (test_and_set_bit (NFSD4_CLIENT_RECLAIM_COMPLETE , &cstate->session->se_client->cl_flags))
@@ -2764,7 +2763,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; }
Signature · 1 line
1.9.3
PATCH 101/104 nfsd: remove nfs4_lock_state: nfs4_laundromat
In reply to Jeff Layton--- fs/nfsd/nfs4state.c | 3 --- 1 file changed, 3 deletions(-)
fs/nfsd/nfs4state.c +0 -3
@@ -3987,8 +3987,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);
@@ -4052,7 +4050,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; }
Signature · 1 line
1.9.3
PATCH 102/104 nfsd: remove nfs4_lock_state: nfs4_state_shutdown_net
In reply to Jeff Layton--- fs/nfsd/nfs4state.c | 2 -- 1 file changed, 2 deletions(-)
fs/nfsd/nfs4state.c +0 -2
@@ -6199,7 +6199,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) {
@@ -6216,7 +6215,6 @@ nfs4_state_shutdown_net(struct net *net)nfsd4_client_tracking_exit (net);nfs4_state_destroy_net (net); -nfs4_unlock_state (); }void
Signature · 1 line
1.9.3
PATCH 103/104 nfsd: remove the client_mutex and the nfs4_lock/unlock_state wrappers
In reply to Jeff Layton--- fs/nfsd/nfs4state.c | 15 --------------- 1 file changed, 15 deletions(-)
fs/nfsd/nfs4state.c +0 -15
@@ -82,9 +82,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
@@ -104,12 +101,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)
@@ -125,12 +116,6 @@ static __be32 mark_session_dead_locked(struct nfsd4_session *ses, int ref_held_breturn 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 ;
Signature · 1 line
1.9.3
PATCH 104/104 nfsd: add file documenting new state object model
In reply to Jeff Layton--- .../filesystems/nfs/nfsd4-state-objects.txt | 110 +++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 Documentation/filesystems/nfs/nfsd4-state-objects.txt
Documentation/filesystems/nfs/nfsd4-state-objects.txt new file +110 -0
@@ -0,0 +1,110 @@ +KNFSD4 State Object Model: +========================== +Written 2014 by Jeff Layton <[email protected]> + +Introduction: +------------- +Until recently, knfsd relied heavily on a global mutex to ensure that objects +didn't disappear while they were being operated on. That has proven to be a +scalability bottleneck however, so the code has been overhauled to make heavy +use of reference counting and spinlocks for tracking the different objects. + +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. + +The lifecycle of these is a little strange. 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 "generic" 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.
Signature · 1 line
1.9.3
Re: [PATCH v1 104/104] nfsd: add file documenting new state object model
Documentation/filesystems/nfs/nfsd4-state-objects.txt line 10
Quoted 10 lines
Documentation/filesystems/nfs/nfsd4-state-objects.txt new file +10
-0+KNFSD4 State Object Model: +========================== +Written 2014 by Jeff Layton <[email protected]> + +Introduction: +------------- +Until recently, knfsd relied heavily on a global mutex to ensure that objects +didn't disappear while they were being operated on. That has proven to be a +scalability bottleneck however, so the code has been overhauled to make heavy +use of reference counting and spinlocks for tracking the different objects.
It's hard enough to keep documents uptodate with the current version of the code, so I don't think this historical blurb buys us anything.
Documentation/filesystems/nfs/nfsd4-state-objects.txt line 47
Quoted 12 lines
Documentation/filesystems/nfs/nfsd4-state-objects.txt new file +12
-0+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. + +The lifecycle of these is a little strange. 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.
That's the normal lifecycle of objects on a lru, so I'd strike the "strange" part.
Documentation/filesystems/nfs/nfsd4-state-objects.txt line 83
Quoted 5 lines
Documentation/filesystems/nfs/nfsd4-state-objects.txt new file +5
-0+strict nfs4_stid: +----------------- +A core object that represents a "generic" stateid. These are generally embedded +within the different (more specific) stateid objects and contain fields that +are of general use to any stateid.
Maybe replace "generic" stateid with common stateid or similar? The generic_stateid term is unfortunately is used in the code in a weird way for open/lock stateids. Or better yet fix up those names in the code..
Given how documentation outside the source code gets out of data easily maybe you should move these texts to comments above each of the structures?
Re: [PATCH v1 104/104] nfsd: add file documenting new state object model
Quoted 5 lines · On Tue, 24 Jun 2014 05:11:58 -0700 Christoph Hellwig <[email protected]> wrote:
Quoted 5 lines
Documentation/filesystems/nfs/nfsd4-state-objects.txt new file +5
-0+KNFSD4 State Object Model: +========================== +Written 2014 by Jeff Layton <[email protected]> + +Introduction:
Quoted 9 lines
Documentation/filesystems/nfs/nfsd4-state-objects.txt line 10
Quoted 5 lines
+-------------
Documentation/filesystems/nfs/nfsd4-state-objects.txt new file +4
-0+Until recently, knfsd relied heavily on a global mutex to ensure that objects +didn't disappear while they were being operated on. That has proven to be a +scalability bottleneck however, so the code has been overhauled to make heavy +use of reference counting and spinlocks for tracking the different objects.It's hard enough to keep documents uptodate with the current version of the code, so I don't think this historical blurb buys us anything.
OK
Quoted 7 lines
Quoted 7 lines
Documentation/filesystems/nfs/nfsd4-state-objects.txt new file +7
-0+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.
Quoted 9 lines
Documentation/filesystems/nfs/nfsd4-state-objects.txt line 47
Quoted 5 lines
Documentation/filesystems/nfs/nfsd4-state-objects.txt new file +5
-0+ +The lifecycle of these is a little strange. 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.That's the normal lifecycle of objects on a lru, so I'd strike the "strange" part.
Fair enough.
Quoted 10 lines
Documentation/filesystems/nfs/nfsd4-state-objects.txt line 83
Quoted 5 lines
Documentation/filesystems/nfs/nfsd4-state-objects.txt new file +5
-0+strict nfs4_stid: +----------------- +A core object that represents a "generic" stateid. These are generally embedded +within the different (more specific) stateid objects and contain fields that +are of general use to any stateid.Maybe replace "generic" stateid with common stateid or similar? The
generic_stateidterm is unfortunately is used in the code in a weird way for open/lock stateids. Or better yet fix up those names in the code..
Yeah, I didn't make that change here as we have enough "churn" going on, but maybe it's a good idea to just do it. "generic" really ought to refer to nfs4_stid, and we should rename the nfs4_ol_stateid to something besides "generic".
Quoted 4 lines
Given how documentation outside the source code gets out of data easily maybe you should move these texts to comments above each of the structures?
Yeah, probably so. This document started for my own benefit as I was going through the code and documenting things. We can drop it if it's not helpful but I figured I'd toss it on top of the pile in case it was.
Signature · 1 line
Jeff Layton <[email protected]>
Quoted 173 lines · On Thu, 19 Jun 2014 10:49:06 -0400 Jeff Layton <[email protected]> wrote:
Here it is. The long awaited removal of the
client_mutexfrom 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.
I'd like to see this considered for v3.17. Obviously, getting it into linux-next ASAP would be a good thing once it passes review.
Some other highlights/notes:
- use of lockdep has been greatly increased. I found it was the only way to ensure that I didn't create lock inversion problems and such.
- clients are now only looked up once per compund and are cached in the cstate. This keeps us from having to keep searching for the same client for each compound op.
- openowners and lockowners are now handled more sanely. References to them are only held by the stateids that are associated with them, and they are destroyed when the last reference to them is put. Also, lockowners can now have more than one stateid (in accordance with the spec)
- the fault injection code has been overhauled. It should look the same to users, but it needed major work to deal with the new locking. It's probably possible to consolidate some of that code as well -- it more cut-and-pastey than I'd like.
- I've added a file to document how all of the moving parts fit together. It probably can use more fleshing out, but it's a start.
- the lease handling is now a bit more complex than I'd like. Lease removal in particular is currently called under a spinlock, which I think we'll need to eventually clean up. For now, this is ok since the first thing that
vfs_setleasedoes is lock thei_lock, but I think we'll eventually need to do ani_lockpushdown in the lease handling code, and ensure thatvfs_setleaseisn't called under a spinlock.As always, comments and review are welcome.
Benny Halevy (1):
nfsd4: usecl_lockto synchronize all stateid idr callsJeff Layton (40):
NFSd: Ensure thatnfs4_file_get_accessenforces share access modes
locks: addfile_has_lease
NFSd: Protect thenfs4_filedelegation fields using thefi_lock
NFSd: Allow lockowners to hold several stateids
NFSd: Ensure atomicity of stateid destruction and idr tree removal
NFSd: Cleanup the freeing of stateids
nfsd: dofilp_closeinsc_freecallback for lock stateids
NFSd: Add locking to protect the state owner lists
nfsd: clean up races in lock stateid searching and creation
nfsd: clean up lockowner refcounting when finding them
nfsd: add an operation for unhashing a stateowner
nfsd: clean upnfs4_release_lockowner
nfsd: clean up refcounting for lockowners
nfsd: declare v4.1+ openowners confirmed on creation
nfsd: make openstateids hold references to their openowners
nfsd: don't allow CLOSE to proceed until refcount on stateid drops
lockdep: addlockdep_assert_not_held
nfsd: add locking to stateowner release
nfsd: optimizedestroy_lockownercl_lockthrashing
nfsd: reducecl_locktrashing inrelease_openowner
NFSd: Protect session creation and client confirm usingclient_lock
nfsd: protect theclose_lrulist andoo_last_closed_stidwith
client_lock
nfsd: ensure thatclp->cl_revokedlist is protected byclp->cl_lock
nfsd: moveunhash_client_lockedcall intomark_client_expired_locked
nfsd: fix misleading comment
nfsd: don't destroy client ifmark_client_expired_lockedfails
nfsd: don't destroy clients that are busy
nfsd: abstract out the get and set routines into the fault injection
ops
nfsd: add aforget_clients"get" routine with proper locking
nfsd: add aforget_clientset_clntroutine
nfsd: addnfsd_inject_forget_clients
nfsd: add alist_headarg tonfsd_foreach_client_lock
nfsd: add more granular locking toforget_locksfault injector
nfsd: add more granular locking toforget_openownersfault injector
nfsd: add more granular locking to*_delegationsfault injectors
nfsd: remove old fault injection infrastructure
nfsd: removenfs4_lock_state:nfs4_laundromat
nfsd: removenfs4_lock_state:nfs4_state_shutdown_net
nfsd: remove theclient_mutexand the nfs4_lock/unlock_state wrappers
nfsd: add file documenting new state object modelTrond Myklebust (63):
nfsd: Protect addition to thefile_hashtbl
NFSd: Avoid takingstate_lockwhile holding inode lock in
nfsd_break_one_deleg
NFSd:nfs4_preprocess_seqid_opshould only set *stpp on success
NFSd: Add fine grained protection for thenfs4_file->fi_stateidslist
NFSd: Add a mutex to protect the NFSv4.0 open owner replay cache
NFSd: Add locking to the nfs4_file->fi_fds[] array
NFSd: Lock owners are not per open stateid
NFSd: Clean up helper__release_lock_stateid
NFSd: NFSv4 lock-owners are not associated to a specific file
NFSd: Cleanupnfs4svc_encode_compoundres
NFSd: Don't get a session reference without a client reference
NFSd: Allow structnfsd4_compound_stateto cache thenfs4_client
NFSd: Move the delegation reference counter into the structnfs4_stid
NFSd: Simplify stateid management
NFSd: Fix delegation revocation
NFSd: Add reference counting to the lock and open stateids
NFSd: clean upnfsd4_close_open_stateid
NFSd: Add a structnfs4_filefield to structnfs4_stid
NFSd: Replacenfs4_ol_stateid->st_filewith the st_stid.sc_file
NFSd: Ensure stateids remain unique until they are freed
NFSd: Convert delegation counter to anatomic_long_ttype
NFSd: Slight cleanup offind_stateid()
NFSd: Add reference counting tofind_stateid
NFSd: Add reference counting to lock stateids
NFSd:nfsd4_locku()must reference the lock stateid
NFSd: Ensure thatnfs4_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: Preparenfsd4_close()for open stateid referencing
NFSd:nfsd4_open_confirm()must reference the open stateid
NFSd: Add reference counting tonfs4_preprocess_confirmed_seqid_op
NFSd: Migrate the stateid reference intonfs4_preprocess_seqid_op
NFSd: Migrate the stateid reference intonfs4_lookup_stateid()
NFSd: Migrate the stateid reference intonfs4_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 usingclient_lock
NFSd: Protect adding/removing lock owners usingclient_lock
NFSd: Cleanup - Letnfsd4_lookup_stateid()take a cstate argument
NFSd: Cache the client that was looked up inlookup_clientid()
NFSd: Convertnfsd4_process_open1()to work withlookup_clientid()
NFSd: Always uselookup_clientid()innfsd4_process_open1
NFSd: Move the open owner hash table into structnfs4_client
NFSd: Convertnfs4_check_open_reclaim()to work withlookup_clientid()
NFSd: Ensure structnfs4_clientis unhashed before we try to destroy
it
NFSd: Ensure that the laundromat unhashes the client before releasing
locks
NFSd: Don't requireclient_lockinfree_client
NFSd: Movecreate_client()call outside the lock
NFSd: Protect unconfirmed client creation usingclient_lock
NFSd: Protectnfsd4_destroy_clientidusingclient_lock
NFSd: Ensurelookup_clientid()takesclient_lock
NFSd: Add assertions to document the nfs4_client/session locking
NFSd: Removenfs4_lock_state():nfs4_preprocess_stateid_op()
NFSd: Removenfs4_lock_state(): nfsd4_test_stateid/nfsd4_free_stateid
NFSd: Removenfs4_lock_state():nfsd4_release_lockowner
NFSd: Removenfs4_lock_state(): nfsd4_lock/locku/lockt()
NFSd: Removenfs4_lock_state():nfsd4_open_downgrade+nfsd4_close
NFSd: Removenfs4_lock_state():nfsd4_delegreturn()
NFSd: Removenfs4_lock_state():nfsd4_openandnfsd4_open_confirm
NFSd: Removenfs4_lock_state():exchange_id, create/destroy_session()
NFSd: Removenfs4_lock_state(): setclientid,setclientid_confirm,
renew
NFSd: Removenfs4_lock_state():reclaim_complete()
Quoted 15 lines
.../filesystems/nfs/nfsd4-state-objects.txt | 110 + fs/locks.c | 26 + fs/nfsd/fault_inject.c | 129 +- fs/nfsd/netns.h | 5 - fs/nfsd/nfs4callback.c | 18 +- fs/nfsd/nfs4proc.c | 16 +- fs/nfsd/nfs4state.c | 2569 ++++++++++++++------ fs/nfsd/nfs4xdr.c | 17 +- fs/nfsd/state.h | 86 +- fs/nfsd/xdr4.h | 8 +- include/linux/fs.h | 6 + include/linux/lockdep.h | 6 + 12 files changed, 2052 insertions(+), 944 deletions(-) create mode 100644 Documentation/filesystems/nfs/nfsd4-state-objects.txt
Oh, I should also mention that this set is also available in my nfsd-devel branch at:
git://git.samba.org/jlayton/linux.git
I'll continue to push changes to the set to that branch as review comes in.
Thanks!
Signature · 1 line
Jeff Layton <[email protected]>
I'm seeing this, by the way.--b.
[ 512.960652] nfsd: non-standard errno: -7 [ 650.442646] ------------[ cut here ]------------ [ 650.442754] WARNING: CPU: 3 PID: 647 at fs/nfsd/nfs4state.c:761 revoke_delegation+0xa7/0xb0 [nfsd]() [ 650.442760] Modules linked in: rpcsec_gss_krb5 nfsd auth_rpcgss oid_registry nfs_acl lockd sunrpc [ 650.442792] CPU: 3 PID: 647 Comm: kworker/u8:2 Not tainted 3.16.0-rc2-00479-gb675b9c #2982 [ 650.442796] Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011 [ 650.442814] Workqueue: nfsd4 laundromat_main [nfsd] [ 650.442821] 0000000000000009 ffff880036287c48 ffffffff81a439d6 0000000000000001 [ 650.442836] 0000000000000000 ffff880036287c88 ffffffff8106d65c ffff880036287c68 [ 650.442851] ffff8800312aee60 ffff88001bcfe800 ffff8800312aeeb0 ffffffff822c7cc0 [ 650.442865] Call Trace: [ 650.442878] [<ffffffff81a439d6>] dump_stack+0x4f/0x7c [ 650.442889] [<ffffffff8106d65c>] warn_slowpath_common+0x8c/0xc0 [ 650.442897] [<ffffffff8106d6aa>] warn_slowpath_null+0x1a/0x20 [ 650.442917] [<ffffffffa011a607>] revoke_delegation+0xa7/0xb0 [nfsd] [ 650.442936] [<ffffffffa011aaec>] laundromat_main+0x2dc/0x480 [nfsd] [ 650.442956] [<ffffffffa011a9f4>] ? laundromat_main+0x1e4/0x480 [nfsd] [ 650.442967] [<ffffffff8108924e>] process_one_work+0x1ce/0x500 [ 650.442976] [<ffffffff810891db>] ? process_one_work+0x15b/0x500 [ 650.442985] [<ffffffff81089b9b>] worker_thread+0x11b/0x4f0 [ 650.442995] [<ffffffff810bba2d>] ? trace_hardirqs_on+0xd/0x10 [ 650.443004] [<ffffffff81a4c36b>] ? _raw_spin_unlock_irqrestore+0x4b/0x80 [ 650.443013] [<ffffffff81089a80>] ? init_pwq+0x190/0x190 [ 650.443022] [<ffffffff81090ac4>] kthread+0xe4/0x100 [ 650.443032] [<ffffffff810909e0>] ? __init_kthread_worker+0x70/0x70 [ 650.443041] [<ffffffff81a4caac>] ret_from_fork+0x7c/0xb0 [ 650.443050] [<ffffffff810909e0>] ? __init_kthread_worker+0x70/0x70 [ 650.443055] ---[ end trace e3faa7f0516143d3 ]---
Quoted 30 lines · On Wed, 25 Jun 2014 21:26:29 -0400 "J. Bruce Fields" <[email protected]>…
I'm seeing this, by the way.--b.
[ 512.960652] nfsd: non-standard errno: -7 [ 650.442646] ------------[ cut here ]------------ [ 650.442754] WARNING: CPU: 3 PID: 647 at fs/nfsd/nfs4state.c:761 revoke_delegation+0xa7/0xb0 [nfsd]() [ 650.442760] Modules linked in: rpcsec_gss_krb5 nfsd auth_rpcgss oid_registry nfs_acl lockd sunrpc [ 650.442792] CPU: 3 PID: 647 Comm: kworker/u8:2 Not tainted 3.16.0-rc2-00479-gb675b9c #2982 [ 650.442796] Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011 [ 650.442814] Workqueue: nfsd4 laundromat_main [nfsd] [ 650.442821] 0000000000000009 ffff880036287c48 ffffffff81a439d6 0000000000000001 [ 650.442836] 0000000000000000 ffff880036287c88 ffffffff8106d65c ffff880036287c68 [ 650.442851] ffff8800312aee60 ffff88001bcfe800 ffff8800312aeeb0 ffffffff822c7cc0 [ 650.442865] Call Trace: [ 650.442878] [<ffffffff81a439d6>] dump_stack+0x4f/0x7c [ 650.442889] [<ffffffff8106d65c>] warn_slowpath_common+0x8c/0xc0 [ 650.442897] [<ffffffff8106d6aa>] warn_slowpath_null+0x1a/0x20 [ 650.442917] [<ffffffffa011a607>] revoke_delegation+0xa7/0xb0 [nfsd] [ 650.442936] [<ffffffffa011aaec>] laundromat_main+0x2dc/0x480 [nfsd] [ 650.442956] [<ffffffffa011a9f4>] ? laundromat_main+0x1e4/0x480 [nfsd] [ 650.442967] [<ffffffff8108924e>] process_one_work+0x1ce/0x500 [ 650.442976] [<ffffffff810891db>] ? process_one_work+0x15b/0x500 [ 650.442985] [<ffffffff81089b9b>] worker_thread+0x11b/0x4f0 [ 650.442995] [<ffffffff810bba2d>] ? trace_hardirqs_on+0xd/0x10
Quoted 8 lines
[ 650.443004] [<ffffffff81a4c36b>] ? _raw_spin_unlock_irqrestore+0x4b/0x80 [ 650.443013] [<ffffffff81089a80>] ? init_pwq+0x190/0x190 [ 650.443022] [<ffffffff81090ac4>] kthread+0xe4/0x100 [ 650.443032] [<ffffffff810909e0>] ? __init_kthread_worker+0x70/0x70 [ 650.443041] [<ffffffff81a4caac>] ret_from_fork+0x7c/0xb0 [ 650.443050] [<ffffffff810909e0>] ? __init_kthread_worker+0x70/0x70 [ 650.443055] ---[ end trace e3faa7f0516143d3 ]---
Thanks, I think I just whacked that bug a little while ago:
http://git.samba.org/?p=jlayton/linux.git;a=commitdiff;h=81771b60b6fd17dae7975a2e3199fc37d181dacf
...I've squashed quite a few others in the last few days as well. I'm hoping to post an updated set in the next day or so.
Signature · 1 line
Jeff Layton <[email protected]>
Hi Jeff,
thanks for bringing this forward. I've started looking at the series, but I'm a little overwhelmed as it's growing bigger and bigger with each posting. That also makes me a little worried about putting all of it into 3.17. I know you've started separating a few bits out and some of those actually went into 3.16, but maybe we really should start to some easier to split piece in first and make sure they get into 3.17 and then see if we can get through the rest of it in time.
Besides the obvious fixes for bits that were racy before and don't just need better scalability one thing that strikes to mind are some of the higher level logic changes, like the changes fixes to various stateowner / stateid relations.
Besides that some higher level comments from glacing over the series:
- the patches that touch locks.c and the lockdep code should go first, and include the maintainer (at least for lockdep, locks.c is easy :)) and relevant mailing lists.
- lots of patches only have a subject line, but no explanation in the body at all. While this might be enough for trivial patches few of them are trivial enough that this would be enough.
- some patches have a signoff from Trond, but no From: line for him in the body. I suspect this just got lost somewhere.
- there is some confusion of NFSd vs nfsd in the subsystem prefixes. While it seems odd and against the usual naming NFSd seems to be the common one for nfs patches.
checkpatch.pl also has various valid complains (mostly about too long lines) and a few silly ones about printks, might be worth to address them.
Last but not least I get a new compiler warning with the whole series applied, as put_client is only used by the fault injection code, but still compiled when the config option for it is not set.
I hope I'll have some more useful detailed reviews soon.
Quoted 10 lines · On Mon, 23 Jun 2014 06:39:26 -0700 Christoph Hellwig <[email protected]> wrote:
Hi Jeff,
thanks for bringing this forward. I've started looking at the series, but I'm a little overwhelmed as it's growing bigger and bigger with each posting. That also makes me a little worried about putting all of it into 3.17. I know you've started separating a few bits out and some of those actually went into 3.16, but maybe we really should start to some easier to split piece in first and make sure they get into 3.17 and then see if we can get through the rest of it in time.
Thanks for taking a look. The big problem with breaking this set up is that it will likely result in at least some performance regression in the interim. We're adding more granular locking inside of the coarse-grained client_mutex, which is likely to mean at least some slowdown until the client_mutex is removed. Maybe that's worth it though.
Quoted 5 lines
Besides the obvious fixes for bits that were racy before and don't just need better scalability one thing that strikes to mind are some of the higher level logic changes, like the changes fixes to various stateowner / stateid relations.
I'll have to think about how to break those out. Unfortunately, there are strong dependencies between some of those changes, which makes it hard to do this in pieces.
Quoted 5 lines
Besides that some higher level comments from glacing over the series:
- the patches that touch
locks.cand the lockdep code should go first, and include the maintainer (at least for lockdep,locks.cis easy :)) and relevant mailing lists.
Fair enough. I meant to cc the lockdep folks on the lockdep_assert_not_held patch. I don't expect pushback from them, but you're correct that they should be Cc'ed.
Quoted 3 lines
- lots of patches only have a subject line, but no explanation in the body at all. While this might be enough for trivial patches few of them are trivial enough that this would be enough.
Ok. I'll try to flesh them out for the next posting.
Quoted 2 lines
- some patches have a signoff from Trond, but no From: line for him in the body. I suspect this just got lost somewhere.
Yeah. Some of them were originally written by Trond, but then I ended up having to do large scale rework of them. I prob should have just dropped his SOB lines from those. I'll go over those and do that or fix the From: lines.
Quoted 4 lines
- there is some confusion of NFSd vs nfsd in the subsystem prefixes. While it seems odd and against the usual naming NFSd seems to be the common one for nfs patches.
I tend to prefer "nfsd", but ok -- "NFSd" it is.
Quoted 4 lines
checkpatch.pl also has various valid complains (mostly about too long lines) and a few silly ones about printks, might be worth to address them.
Ahh right. I need to fix those -- Steve French reported a few of those too (and sent me patches privately).
Quoted 4 lines
Last but not least I get a new compiler warning with the whole series applied, as
put_clientis only used by the fault injection code, but still compiled when the config option for it is not set.
Good catch. I'll fix that.
Quoted 2 lines
I hope I'll have some more useful detailed reviews soon.
Thanks. I should also note that a couple of races were found in the nfs4_ol_stateid handling while testing this set, so I'll be respinning it to fix those up anyway.
Signature · 1 line
Jeff Layton <[email protected]>
Quoted 14 lines · Jeff Layton
Quoted 10 lines · On Mon, 23 Jun 2014 06:39:26 -0700 Christoph Hellwig <[email protected]> wrote:
Hi Jeff,
thanks for bringing this forward. I've started looking at the series, but I'm a little overwhelmed as it's growing bigger and bigger with each posting. That also makes me a little worried about putting all of it into 3.17. I know you've started separating a few bits out and some of those actually went into 3.16, but maybe we really should start to some easier to split piece in first and make sure they get into 3.17 and then see if we can get through the rest of it in time.
Quoted 6 lines
Thanks for taking a look. The big problem with breaking this set up is that it will likely result in at least some performance regression in the interim. We're adding more granular locking inside of the coarse-grained
client_mutex, which is likely to mean at least some slowdown until theclient_mutexis removed. Maybe that's worth it though.
I also don't know if the in-between state (when we have both new and old locking) is very interesting to test.
Quoted 10 lines
Quoted 6 lines
Besides the obvious fixes for bits that were racy before and don't just need better scalability one thing that strikes to mind are some of the higher level logic changes, like the changes fixes to various stateowner / stateid relations.
I'll have to think about how to break those out. Unfortunately, there are strong dependencies between some of those changes, which makes it hard to do this in pieces.
But, yes, if there's anything here it would be possible to take first that would help....
--b.
Quoted 6 lines · Jeff Layton
Thanks for taking a look. The big problem with breaking this set up is that it will likely result in at least some performance regression in the interim. We're adding more granular locking inside of the coarse-grained
client_mutex, which is likely to mean at least some slowdown until theclient_mutexis removed. Maybe that's worth it though.
That's why I didn't dare to ask for splitting the lock breakup, but rather the surrounding fixes and logic changes. But yes, if that's not doable either we'll have to bite the bullet.
Quoted 6 lines
Quoted 4 lines
- there is some confusion of NFSd vs nfsd in the subsystem prefixes. While it seems odd and against the usual naming NFSd seems to be the common one for nfs patches.
I tend to prefer "nfsd", but ok -- "NFSd" it is.
I'd prefer nfsd as well, but in Rome do as the Romans do, so..
Quoted 9 lines · Christoph Hellwig
Quoted 6 lines · Jeff Layton
Quoted 4 lines
- there is some confusion of NFSd vs nfsd in the subsystem prefixes. While it seems odd and against the usual naming NFSd seems to be the common one for nfs patches.
I tend to prefer "nfsd", but ok -- "NFSd" it is.
I'd prefer nfsd as well, but in Rome do as the Romans do, so..
These Romans?:
$ git log --pretty=format:"%s" fs/nfsd|cut -d: -f1|grep -v '^Merge'|sed 's/\[PATCH\] //'|sort|uniq -c|sort -n|tail
8 sunrpc
12 fs
13 locks
15 NFSd
30 SUNRPC
89 nfsd41
107 NFSD
228 knfsd
449 nfsd
594 nfsd4Anyway, I don't care.
--b.
Quoted 7 lines · J. Bruce Fields
Quoted 6 lines · Christoph Hellwig
Quoted 5 lines · Jeff Layton
Quoted 4 lines
- there is some confusion of NFSd vs nfsd in the subsystem prefixes. While it seems odd and against the usual naming NFSd seems to be the common one for nfs patches.
Quoted 5 lines
Quoted 3 lines
Quoted 1 line
I tend to prefer "nfsd", but ok -- "NFSd" it is.
I'd prefer nfsd as well, but in Rome do as the Romans do, so..
These Romans?:
Oops, sorry. It's mostly Trond for the client who is using the upper case NFS*.
Quoted 25 lines · On Mon, 23 Jun 2014 12:10:26 -0400 "J. Bruce Fields" <[email protected]>…
Quoted 9 lines · Christoph Hellwig
Quoted 6 lines · Jeff Layton
Quoted 4 lines
- there is some confusion of NFSd vs nfsd in the subsystem prefixes. While it seems odd and against the usual naming NFSd seems to be the common one for nfs patches.
I tend to prefer "nfsd", but ok -- "NFSd" it is.
I'd prefer nfsd as well, but in Rome do as the Romans do, so..
These Romans?:
$ git log --pretty=format:"%s" fs/nfsd|cut -d: -f1|grep -v '^Merge'|sed 's/\[PATCH\] //'|sort|uniq -c|sort -n|tail 8 sunrpc 12 fs 13 locks 15 NFSd 30 SUNRPC 89 nfsd41 107 NFSD 228 knfsd 449 nfsd 594 nfsd4
Quoted 3 lines
Anyway, I don't care.
--b.
In that case, I'll go with what I prefer -- "nfsd:". But I will at least go through and make them all consistent.
Thanks,
Signature · 1 line
Jeff Layton <[email protected]>