diff options
author | Kinglong Mee | 2017-01-18 05:04:42 -0600 |
---|---|---|
committer | Sasha Levin | 2017-03-06 16:31:12 -0600 |
commit | 915a8d29e688bca2b8da9c283462cc30fc91c726 (patch) | |
tree | 38cee4a73ff9a2a17eb8717024cb526ac7f04f21 | |
parent | cb89bddc468b06e82ead6adbfe1e673b5a38f8a4 (diff) | |
download | ti-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.c | 5 | ||||
-rw-r--r-- | fs/nfsd/nfs4state.c | 19 | ||||
-rw-r--r-- | fs/nfsd/state.h | 4 |
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 | ||
556 | struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, | 556 | struct 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: | |||
594 | static struct nfs4_ol_stateid * nfs4_alloc_open_stateid(struct nfs4_client *clp) | 596 | static 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 | ||
608 | static void nfs4_free_deleg(struct nfs4_stid *stid) | 607 | static 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(¤t_fh->fh_handle)) | 700 | if (delegation_blocked(¤t_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); |
592 | struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, | 592 | struct 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 *)); |
594 | void nfs4_unhash_stid(struct nfs4_stid *s); | 594 | void nfs4_unhash_stid(struct nfs4_stid *s); |
595 | void nfs4_put_stid(struct nfs4_stid *s); | 595 | void nfs4_put_stid(struct nfs4_stid *s); |
596 | void nfs4_remove_reclaim_record(struct nfs4_client_reclaim *, struct nfsd_net *); | 596 | void nfs4_remove_reclaim_record(struct nfs4_client_reclaim *, struct nfsd_net *); |