aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKinglong Mee2017-01-18 05:04:42 -0600
committerSasha Levin2017-03-06 16:31:12 -0600
commit915a8d29e688bca2b8da9c283462cc30fc91c726 (patch)
tree38cee4a73ff9a2a17eb8717024cb526ac7f04f21
parentcb89bddc468b06e82ead6adbfe1e673b5a38f8a4 (diff)
downloadti-linux-kernel-915a8d29e688bca2b8da9c283462cc30fc91c726.tar.gz
ti-linux-kernel-915a8d29e688bca2b8da9c283462cc30fc91c726.tar.xz
ti-linux-kernel-915a8d29e688bca2b8da9c283462cc30fc91c726.zip
NFSD: Fix a null reference case in find_or_create_lock_stateid()
[ Upstream commit d19fb70dd68c4e960e2ac09b0b9c79dfdeefa726 ] nfsd assigns the nfs4_free_lock_stateid to .sc_free in init_lock_stateid(). If nfsd doesn't go through init_lock_stateid() and put stateid at end, there is a NULL reference to .sc_free when calling nfs4_put_stid(ns). This patch let the nfs4_stid.sc_free assignment to nfs4_alloc_stid(). Cc: stable@vger.kernel.org Fixes: 356a95ece7aa "nfsd: clean up races in lock stateid searching..." Signed-off-by: Kinglong Mee <kinglongmee@gmail.com> Reviewed-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: J. Bruce Fields <bfields@redhat.com> Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
-rw-r--r--fs/nfsd/nfs4layouts.c5
-rw-r--r--fs/nfsd/nfs4state.c19
-rw-r--r--fs/nfsd/state.h4
3 files changed, 13 insertions, 15 deletions
diff --git a/fs/nfsd/nfs4layouts.c b/fs/nfsd/nfs4layouts.c
index 6904213a4363..8b6ec3eab627 100644
--- a/fs/nfsd/nfs4layouts.c
+++ b/fs/nfsd/nfs4layouts.c
@@ -189,10 +189,11 @@ nfsd4_alloc_layout_stateid(struct nfsd4_compound_state *cstate,
189 struct nfs4_layout_stateid *ls; 189 struct nfs4_layout_stateid *ls;
190 struct nfs4_stid *stp; 190 struct nfs4_stid *stp;
191 191
192 stp = nfs4_alloc_stid(cstate->clp, nfs4_layout_stateid_cache); 192 stp = nfs4_alloc_stid(cstate->clp, nfs4_layout_stateid_cache,
193 nfsd4_free_layout_stateid);
193 if (!stp) 194 if (!stp)
194 return NULL; 195 return NULL;
195 stp->sc_free = nfsd4_free_layout_stateid; 196
196 get_nfs4_file(fp); 197 get_nfs4_file(fp);
197 stp->sc_file = fp; 198 stp->sc_file = fp;
198 199
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index bb6c324f1f3d..22e9799323ad 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -553,8 +553,8 @@ out:
553 return co; 553 return co;
554} 554}
555 555
556struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, 556struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *slab,
557 struct kmem_cache *slab) 557 void (*sc_free)(struct nfs4_stid *))
558{ 558{
559 struct nfs4_stid *stid; 559 struct nfs4_stid *stid;
560 int new_id; 560 int new_id;
@@ -570,6 +570,8 @@ struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl,
570 idr_preload_end(); 570 idr_preload_end();
571 if (new_id < 0) 571 if (new_id < 0)
572 goto out_free; 572 goto out_free;
573
574 stid->sc_free = sc_free;
573 stid->sc_client = cl; 575 stid->sc_client = cl;
574 stid->sc_stateid.si_opaque.so_id = new_id; 576 stid->sc_stateid.si_opaque.so_id = new_id;
575 stid->sc_stateid.si_opaque.so_clid = cl->cl_clientid; 577 stid->sc_stateid.si_opaque.so_clid = cl->cl_clientid;
@@ -594,15 +596,12 @@ out_free:
594static struct nfs4_ol_stateid * nfs4_alloc_open_stateid(struct nfs4_client *clp) 596static struct nfs4_ol_stateid * nfs4_alloc_open_stateid(struct nfs4_client *clp)
595{ 597{
596 struct nfs4_stid *stid; 598 struct nfs4_stid *stid;
597 struct nfs4_ol_stateid *stp;
598 599
599 stid = nfs4_alloc_stid(clp, stateid_slab); 600 stid = nfs4_alloc_stid(clp, stateid_slab, nfs4_free_ol_stateid);
600 if (!stid) 601 if (!stid)
601 return NULL; 602 return NULL;
602 603
603 stp = openlockstateid(stid); 604 return openlockstateid(stid);
604 stp->st_stid.sc_free = nfs4_free_ol_stateid;
605 return stp;
606} 605}
607 606
608static void nfs4_free_deleg(struct nfs4_stid *stid) 607static void nfs4_free_deleg(struct nfs4_stid *stid)
@@ -700,11 +699,10 @@ alloc_init_deleg(struct nfs4_client *clp, struct svc_fh *current_fh,
700 goto out_dec; 699 goto out_dec;
701 if (delegation_blocked(&current_fh->fh_handle)) 700 if (delegation_blocked(&current_fh->fh_handle))
702 goto out_dec; 701 goto out_dec;
703 dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab)); 702 dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab, nfs4_free_deleg));
704 if (dp == NULL) 703 if (dp == NULL)
705 goto out_dec; 704 goto out_dec;
706 705
707 dp->dl_stid.sc_free = nfs4_free_deleg;
708 /* 706 /*
709 * delegation seqid's are never incremented. The 4.1 special 707 * delegation seqid's are never incremented. The 4.1 special
710 * meaning of seqid 0 isn't meaningful, really, but let's avoid 708 * meaning of seqid 0 isn't meaningful, really, but let's avoid
@@ -5309,7 +5307,6 @@ init_lock_stateid(struct nfs4_ol_stateid *stp, struct nfs4_lockowner *lo,
5309 stp->st_stateowner = nfs4_get_stateowner(&lo->lo_owner); 5307 stp->st_stateowner = nfs4_get_stateowner(&lo->lo_owner);
5310 get_nfs4_file(fp); 5308 get_nfs4_file(fp);
5311 stp->st_stid.sc_file = fp; 5309 stp->st_stid.sc_file = fp;
5312 stp->st_stid.sc_free = nfs4_free_lock_stateid;
5313 stp->st_access_bmap = 0; 5310 stp->st_access_bmap = 0;
5314 stp->st_deny_bmap = open_stp->st_deny_bmap; 5311 stp->st_deny_bmap = open_stp->st_deny_bmap;
5315 stp->st_openstp = open_stp; 5312 stp->st_openstp = open_stp;
@@ -5352,7 +5349,7 @@ find_or_create_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fi,
5352 lst = find_lock_stateid(lo, fi); 5349 lst = find_lock_stateid(lo, fi);
5353 if (lst == NULL) { 5350 if (lst == NULL) {
5354 spin_unlock(&clp->cl_lock); 5351 spin_unlock(&clp->cl_lock);
5355 ns = nfs4_alloc_stid(clp, stateid_slab); 5352 ns = nfs4_alloc_stid(clp, stateid_slab, nfs4_free_lock_stateid);
5356 if (ns == NULL) 5353 if (ns == NULL)
5357 return NULL; 5354 return NULL;
5358 5355
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 67685b6cfef3..fa2430e3d6a8 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -589,8 +589,8 @@ extern __be32 nfs4_preprocess_stateid_op(struct net *net,
589__be32 nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate, 589__be32 nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate,
590 stateid_t *stateid, unsigned char typemask, 590 stateid_t *stateid, unsigned char typemask,
591 struct nfs4_stid **s, struct nfsd_net *nn); 591 struct nfs4_stid **s, struct nfsd_net *nn);
592struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, 592struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *slab,
593 struct kmem_cache *slab); 593 void (*sc_free)(struct nfs4_stid *));
594void nfs4_unhash_stid(struct nfs4_stid *s); 594void nfs4_unhash_stid(struct nfs4_stid *s);
595void nfs4_put_stid(struct nfs4_stid *s); 595void nfs4_put_stid(struct nfs4_stid *s);
596void nfs4_remove_reclaim_record(struct nfs4_client_reclaim *, struct nfsd_net *); 596void nfs4_remove_reclaim_record(struct nfs4_client_reclaim *, struct nfsd_net *);