aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTrond Myklebust <trond.myklebust@primarydata.com>2017-11-03 08:00:14 -0400
committerJ. Bruce Fields <bfields@redhat.com>2017-11-27 16:45:10 -0500
commitbeeca19cf1249a917ed737729dc92337c7633bea (patch)
treec118b4316b711a950f6792a8d4c2c47fea81886c
parentfd1fd685b30867122aafbe2998ce4065c8c87e8f (diff)
nfsd: Fix race in lock stateid creation
If we're looking up a new lock state, and the creation fails, then we want to unhash it, just like we do for OPEN. However in order to do so, we need to that no other LOCK requests can grab the mutex until we have unhashed it (and marked it as closed). Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
-rw-r--r--fs/nfsd/nfs4state.c70
1 files changed, 42 insertions, 28 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 49a9741fa132..6d5993caf9bc 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -5722,14 +5722,22 @@ find_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp)
5722 return NULL; 5722 return NULL;
5723} 5723}
5724 5724
5725static void 5725static struct nfs4_ol_stateid *
5726init_lock_stateid(struct nfs4_ol_stateid *stp, struct nfs4_lockowner *lo, 5726init_lock_stateid(struct nfs4_ol_stateid *stp, struct nfs4_lockowner *lo,
5727 struct nfs4_file *fp, struct inode *inode, 5727 struct nfs4_file *fp, struct inode *inode,
5728 struct nfs4_ol_stateid *open_stp) 5728 struct nfs4_ol_stateid *open_stp)
5729{ 5729{
5730 struct nfs4_client *clp = lo->lo_owner.so_client; 5730 struct nfs4_client *clp = lo->lo_owner.so_client;
5731 struct nfs4_ol_stateid *retstp;
5731 5732
5732 lockdep_assert_held(&clp->cl_lock); 5733 mutex_init(&stp->st_mutex);
5734 mutex_lock(&stp->st_mutex);
5735retry:
5736 spin_lock(&clp->cl_lock);
5737 spin_lock(&fp->fi_lock);
5738 retstp = find_lock_stateid(lo, fp);
5739 if (retstp)
5740 goto out_unlock;
5733 5741
5734 refcount_inc(&stp->st_stid.sc_count); 5742 refcount_inc(&stp->st_stid.sc_count);
5735 stp->st_stid.sc_type = NFS4_LOCK_STID; 5743 stp->st_stid.sc_type = NFS4_LOCK_STID;
@@ -5739,12 +5747,22 @@ init_lock_stateid(struct nfs4_ol_stateid *stp, struct nfs4_lockowner *lo,
5739 stp->st_access_bmap = 0; 5747 stp->st_access_bmap = 0;
5740 stp->st_deny_bmap = open_stp->st_deny_bmap; 5748 stp->st_deny_bmap = open_stp->st_deny_bmap;
5741 stp->st_openstp = open_stp; 5749 stp->st_openstp = open_stp;
5742 mutex_init(&stp->st_mutex);
5743 list_add(&stp->st_locks, &open_stp->st_locks); 5750 list_add(&stp->st_locks, &open_stp->st_locks);
5744 list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids); 5751 list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids);
5745 spin_lock(&fp->fi_lock);
5746 list_add(&stp->st_perfile, &fp->fi_stateids); 5752 list_add(&stp->st_perfile, &fp->fi_stateids);
5753out_unlock:
5747 spin_unlock(&fp->fi_lock); 5754 spin_unlock(&fp->fi_lock);
5755 spin_unlock(&clp->cl_lock);
5756 if (retstp) {
5757 if (nfsd4_lock_ol_stateid(retstp) != nfs_ok) {
5758 nfs4_put_stid(&retstp->st_stid);
5759 goto retry;
5760 }
5761 /* To keep mutex tracking happy */
5762 mutex_unlock(&stp->st_mutex);
5763 stp = retstp;
5764 }
5765 return stp;
5748} 5766}
5749 5767
5750static struct nfs4_ol_stateid * 5768static struct nfs4_ol_stateid *
@@ -5757,26 +5775,25 @@ find_or_create_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fi,
5757 struct nfs4_openowner *oo = openowner(ost->st_stateowner); 5775 struct nfs4_openowner *oo = openowner(ost->st_stateowner);
5758 struct nfs4_client *clp = oo->oo_owner.so_client; 5776 struct nfs4_client *clp = oo->oo_owner.so_client;
5759 5777
5778 *new = false;
5760 spin_lock(&clp->cl_lock); 5779 spin_lock(&clp->cl_lock);
5761 lst = find_lock_stateid(lo, fi); 5780 lst = find_lock_stateid(lo, fi);
5762 if (lst == NULL) {
5763 spin_unlock(&clp->cl_lock);
5764 ns = nfs4_alloc_stid(clp, stateid_slab, nfs4_free_lock_stateid);
5765 if (ns == NULL)
5766 return NULL;
5767
5768 spin_lock(&clp->cl_lock);
5769 lst = find_lock_stateid(lo, fi);
5770 if (likely(!lst)) {
5771 lst = openlockstateid(ns);
5772 init_lock_stateid(lst, lo, fi, inode, ost);
5773 ns = NULL;
5774 *new = true;
5775 }
5776 }
5777 spin_unlock(&clp->cl_lock); 5781 spin_unlock(&clp->cl_lock);
5778 if (ns) 5782 if (lst != NULL) {
5783 if (nfsd4_lock_ol_stateid(lst) == nfs_ok)
5784 goto out;
5785 nfs4_put_stid(&lst->st_stid);
5786 }
5787 ns = nfs4_alloc_stid(clp, stateid_slab, nfs4_free_lock_stateid);
5788 if (ns == NULL)
5789 return NULL;
5790
5791 lst = init_lock_stateid(openlockstateid(ns), lo, fi, inode, ost);
5792 if (lst == openlockstateid(ns))
5793 *new = true;
5794 else
5779 nfs4_put_stid(ns); 5795 nfs4_put_stid(ns);
5796out:
5780 return lst; 5797 return lst;
5781} 5798}
5782 5799
@@ -5828,17 +5845,12 @@ lookup_or_create_lock_state(struct nfsd4_compound_state *cstate,
5828 goto out; 5845 goto out;
5829 } 5846 }
5830 5847
5831retry:
5832 lst = find_or_create_lock_stateid(lo, fi, inode, ost, new); 5848 lst = find_or_create_lock_stateid(lo, fi, inode, ost, new);
5833 if (lst == NULL) { 5849 if (lst == NULL) {
5834 status = nfserr_jukebox; 5850 status = nfserr_jukebox;
5835 goto out; 5851 goto out;
5836 } 5852 }
5837 5853
5838 if (nfsd4_lock_ol_stateid(lst) != nfs_ok) {
5839 nfs4_put_stid(&lst->st_stid);
5840 goto retry;
5841 }
5842 status = nfs_ok; 5854 status = nfs_ok;
5843 *plst = lst; 5855 *plst = lst;
5844out: 5856out:
@@ -6044,14 +6056,16 @@ out:
6044 seqid_mutating_err(ntohl(status))) 6056 seqid_mutating_err(ntohl(status)))
6045 lock_sop->lo_owner.so_seqid++; 6057 lock_sop->lo_owner.so_seqid++;
6046 6058
6047 mutex_unlock(&lock_stp->st_mutex);
6048
6049 /* 6059 /*
6050 * If this is a new, never-before-used stateid, and we are 6060 * If this is a new, never-before-used stateid, and we are
6051 * returning an error, then just go ahead and release it. 6061 * returning an error, then just go ahead and release it.
6052 */ 6062 */
6053 if (status && new) 6063 if (status && new) {
6064 lock_stp->st_stid.sc_type = NFS4_CLOSED_STID;
6054 release_lock_stateid(lock_stp); 6065 release_lock_stateid(lock_stp);
6066 }
6067
6068 mutex_unlock(&lock_stp->st_mutex);
6055 6069
6056 nfs4_put_stid(&lock_stp->st_stid); 6070 nfs4_put_stid(&lock_stp->st_stid);
6057 } 6071 }