diff options
author | Kinglong Mee <kinglongmee@gmail.com> | 2017-01-18 06:04:42 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-02-09 02:08:27 -0500 |
commit | 743146d347f3141cd5a82f4c9aace1790a7537b9 (patch) | |
tree | 55290acb62309361a8f5eba79f90553321ac5a88 /fs | |
parent | 4c953848c95b74def08172b07c04a773071f69ee (diff) |
NFSD: Fix a null reference case in find_or_create_lock_stateid()
commit d19fb70dd68c4e960e2ac09b0b9c79dfdeefa726 upstream.
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().
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: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs')
-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 42aace4fc4c8..64813697f4c4 100644 --- a/fs/nfsd/nfs4layouts.c +++ b/fs/nfsd/nfs4layouts.c | |||
@@ -223,10 +223,11 @@ nfsd4_alloc_layout_stateid(struct nfsd4_compound_state *cstate, | |||
223 | struct nfs4_layout_stateid *ls; | 223 | struct nfs4_layout_stateid *ls; |
224 | struct nfs4_stid *stp; | 224 | struct nfs4_stid *stp; |
225 | 225 | ||
226 | stp = nfs4_alloc_stid(cstate->clp, nfs4_layout_stateid_cache); | 226 | stp = nfs4_alloc_stid(cstate->clp, nfs4_layout_stateid_cache, |
227 | nfsd4_free_layout_stateid); | ||
227 | if (!stp) | 228 | if (!stp) |
228 | return NULL; | 229 | return NULL; |
229 | stp->sc_free = nfsd4_free_layout_stateid; | 230 | |
230 | get_nfs4_file(fp); | 231 | get_nfs4_file(fp); |
231 | stp->sc_file = fp; | 232 | stp->sc_file = fp; |
232 | 233 | ||
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 4b4beaaa4eaa..a0dee8ae9f97 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -633,8 +633,8 @@ out: | |||
633 | return co; | 633 | return co; |
634 | } | 634 | } |
635 | 635 | ||
636 | struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, | 636 | struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *slab, |
637 | struct kmem_cache *slab) | 637 | void (*sc_free)(struct nfs4_stid *)) |
638 | { | 638 | { |
639 | struct nfs4_stid *stid; | 639 | struct nfs4_stid *stid; |
640 | int new_id; | 640 | int new_id; |
@@ -650,6 +650,8 @@ struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, | |||
650 | idr_preload_end(); | 650 | idr_preload_end(); |
651 | if (new_id < 0) | 651 | if (new_id < 0) |
652 | goto out_free; | 652 | goto out_free; |
653 | |||
654 | stid->sc_free = sc_free; | ||
653 | stid->sc_client = cl; | 655 | stid->sc_client = cl; |
654 | stid->sc_stateid.si_opaque.so_id = new_id; | 656 | stid->sc_stateid.si_opaque.so_id = new_id; |
655 | stid->sc_stateid.si_opaque.so_clid = cl->cl_clientid; | 657 | stid->sc_stateid.si_opaque.so_clid = cl->cl_clientid; |
@@ -675,15 +677,12 @@ out_free: | |||
675 | static struct nfs4_ol_stateid * nfs4_alloc_open_stateid(struct nfs4_client *clp) | 677 | static struct nfs4_ol_stateid * nfs4_alloc_open_stateid(struct nfs4_client *clp) |
676 | { | 678 | { |
677 | struct nfs4_stid *stid; | 679 | struct nfs4_stid *stid; |
678 | struct nfs4_ol_stateid *stp; | ||
679 | 680 | ||
680 | stid = nfs4_alloc_stid(clp, stateid_slab); | 681 | stid = nfs4_alloc_stid(clp, stateid_slab, nfs4_free_ol_stateid); |
681 | if (!stid) | 682 | if (!stid) |
682 | return NULL; | 683 | return NULL; |
683 | 684 | ||
684 | stp = openlockstateid(stid); | 685 | return openlockstateid(stid); |
685 | stp->st_stid.sc_free = nfs4_free_ol_stateid; | ||
686 | return stp; | ||
687 | } | 686 | } |
688 | 687 | ||
689 | static void nfs4_free_deleg(struct nfs4_stid *stid) | 688 | static void nfs4_free_deleg(struct nfs4_stid *stid) |
@@ -781,11 +780,10 @@ alloc_init_deleg(struct nfs4_client *clp, struct svc_fh *current_fh, | |||
781 | goto out_dec; | 780 | goto out_dec; |
782 | if (delegation_blocked(¤t_fh->fh_handle)) | 781 | if (delegation_blocked(¤t_fh->fh_handle)) |
783 | goto out_dec; | 782 | goto out_dec; |
784 | dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab)); | 783 | dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab, nfs4_free_deleg)); |
785 | if (dp == NULL) | 784 | if (dp == NULL) |
786 | goto out_dec; | 785 | goto out_dec; |
787 | 786 | ||
788 | dp->dl_stid.sc_free = nfs4_free_deleg; | ||
789 | /* | 787 | /* |
790 | * delegation seqid's are never incremented. The 4.1 special | 788 | * delegation seqid's are never incremented. The 4.1 special |
791 | * meaning of seqid 0 isn't meaningful, really, but let's avoid | 789 | * meaning of seqid 0 isn't meaningful, really, but let's avoid |
@@ -5580,7 +5578,6 @@ init_lock_stateid(struct nfs4_ol_stateid *stp, struct nfs4_lockowner *lo, | |||
5580 | stp->st_stateowner = nfs4_get_stateowner(&lo->lo_owner); | 5578 | stp->st_stateowner = nfs4_get_stateowner(&lo->lo_owner); |
5581 | get_nfs4_file(fp); | 5579 | get_nfs4_file(fp); |
5582 | stp->st_stid.sc_file = fp; | 5580 | stp->st_stid.sc_file = fp; |
5583 | stp->st_stid.sc_free = nfs4_free_lock_stateid; | ||
5584 | stp->st_access_bmap = 0; | 5581 | stp->st_access_bmap = 0; |
5585 | stp->st_deny_bmap = open_stp->st_deny_bmap; | 5582 | stp->st_deny_bmap = open_stp->st_deny_bmap; |
5586 | stp->st_openstp = open_stp; | 5583 | stp->st_openstp = open_stp; |
@@ -5623,7 +5620,7 @@ find_or_create_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fi, | |||
5623 | lst = find_lock_stateid(lo, fi); | 5620 | lst = find_lock_stateid(lo, fi); |
5624 | if (lst == NULL) { | 5621 | if (lst == NULL) { |
5625 | spin_unlock(&clp->cl_lock); | 5622 | spin_unlock(&clp->cl_lock); |
5626 | ns = nfs4_alloc_stid(clp, stateid_slab); | 5623 | ns = nfs4_alloc_stid(clp, stateid_slab, nfs4_free_lock_stateid); |
5627 | if (ns == NULL) | 5624 | if (ns == NULL) |
5628 | return NULL; | 5625 | return NULL; |
5629 | 5626 | ||
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index c9399366f9df..4516e8b7d776 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h | |||
@@ -603,8 +603,8 @@ extern __be32 nfs4_preprocess_stateid_op(struct svc_rqst *rqstp, | |||
603 | __be32 nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate, | 603 | __be32 nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate, |
604 | stateid_t *stateid, unsigned char typemask, | 604 | stateid_t *stateid, unsigned char typemask, |
605 | struct nfs4_stid **s, struct nfsd_net *nn); | 605 | struct nfs4_stid **s, struct nfsd_net *nn); |
606 | struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, | 606 | struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *slab, |
607 | struct kmem_cache *slab); | 607 | void (*sc_free)(struct nfs4_stid *)); |
608 | void nfs4_unhash_stid(struct nfs4_stid *s); | 608 | void nfs4_unhash_stid(struct nfs4_stid *s); |
609 | void nfs4_put_stid(struct nfs4_stid *s); | 609 | void nfs4_put_stid(struct nfs4_stid *s); |
610 | void nfs4_inc_and_copy_stateid(stateid_t *dst, struct nfs4_stid *stid); | 610 | void nfs4_inc_and_copy_stateid(stateid_t *dst, struct nfs4_stid *stid); |