Patch "nfsd: don't return an unhashed lock stateid after taking mutex" has been added to the 4.7-stable tree
Subsystems (2)
This is a note to let you know that I've just added the patch titled
nfsd: don't return an unhashed lock stateid after taking mutex
to the 4.7-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
nfsd-don-t-return-an-unhashed-lock-stateid-after-taking-mutex.patch
and it can be found in the queue-4.7 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.
Quoted 1 line
From
dd257933fa4b9fea66a1195f8a15111029810abcMon Sep 17 00:00:00 2001
From: Jeff Layton <[email protected]>
Date: Thu, 11 Aug 2016 10:37:39 -0400
Subject: nfsd: don't return an unhashed lock stateid after taking mutex
From: Jeff Layton <[email protected]>
commit dd257933fa4b9fea66a1195f8a15111029810abc upstream.
nfsd4_lock will take the st_mutex before working with the stateid it gets, but between the time when we drop the cl_lock and take the mutex, the stateid could become unhashed (a'la FREE_STATEID). If that happens the lock stateid returned to the client will be forgotten.
Fix this by first moving the st_mutex acquisition into lookup_or_create_lock_state. Then, have it check to see if the lock stateid is still hashed after taking the mutex. If it's not, then put the stateid and try the find/create again.
--- fs/nfsd/nfs4state.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-)
fs/nfsd/nfs4state.c +20 -5
@@ -5526,7 +5526,7 @@ 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_ol_stateid **plst, bool *new) { __be32 status;struct nfs4_file *fi = ost->st_stid.sc_file;
@@ -5534,7 +5534,9 @@ lookup_or_create_lock_state(struct nfsd4struct nfs4_client *cl = oo->oo_owner.so_client;struct inode *inode =d_inode (cstate->current_fh.fh_dentry);struct nfs4_lockowner *lo; +struct nfs4_ol_stateid *lst;unsigned int strhashval; +bool hashed; lo =find_lockowner_str (cl, &lock->lk_new_owner);if (!lo) {
@@ -5550,12 +5552,27 @@ lookup_or_create_lock_state(struct nfsd4 goto out; } - *lst =find_or_create_lock_stateid (lo, fi, inode, ost, new); -if (*lst ==NULL ) { +retry: + lst =find_or_create_lock_stateid (lo, fi, inode, ost, new); +if (lst ==NULL ) { status = nfserr_jukebox; goto out; } + +mutex_lock (&lst->st_mutex); + +/* See if it's still hashed to avoid race with FREE_STATEID */ +spin_lock (&cl->cl_lock); + hashed = !list_empty (&lst->st_perfile); +spin_unlock (&cl->cl_lock); + +if (!hashed) { +mutex_unlock (&lst->st_mutex); +nfs4_put_stid (&lst->st_stid); + goto retry; + } status = nfs_ok; + *plst = lst; out:nfs4_put_stateowner (&lo->lo_owner);return status;
@@ -5622,8 +5639,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struc goto out; status =lookup_or_create_lock_state (cstate, open_stp, lock, &lock_stp, &new); -if (status == nfs_ok) -mutex_lock (&lock_stp->st_mutex); }else { status = nfs4_preprocess_seqid_op(cstate, lock->lk_old_lock_seqid,
Patches currently in stable-queue which might be from [email protected] are
queue-4.7/nfsd-fix-race-between-free_stateid-and-lock.patch queue-4.7/pnfs-separate-handling-of-nfs4err_layouttrylater-and-recallconflict.patch queue-4.7/cachefiles-fix-race-between-inactivating-and-culling-a-cache-object.patch queue-4.7/pnfs-handle-nfs4err_recallconflict-correctly-in-layoutget.patch queue-4.7/nfsd-don-t-return-an-unhashed-lock-stateid-after-taking-mutex.patch queue-4.7/pnfs-fix-layoutget-handling-of-nfs4err_bad_stateid-and-nfs4err_expired.patch queue-4.7/pnfs-fix-post-layoutget-error-handling-in-pnfs_update_layout.patch