aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorKinglong Mee <kinglongmee@gmail.com>2017-01-18 06:04:42 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-02-09 02:08:27 -0500
commit743146d347f3141cd5a82f4c9aace1790a7537b9 (patch)
tree55290acb62309361a8f5eba79f90553321ac5a88 /fs
parent4c953848c95b74def08172b07c04a773071f69ee (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.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 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
636struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, 636struct 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:
675static struct nfs4_ol_stateid * nfs4_alloc_open_stateid(struct nfs4_client *clp) 677static 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
689static void nfs4_free_deleg(struct nfs4_stid *stid) 688static 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(&current_fh->fh_handle)) 781 if (delegation_blocked(&current_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);
606struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, 606struct 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 *));
608void nfs4_unhash_stid(struct nfs4_stid *s); 608void nfs4_unhash_stid(struct nfs4_stid *s);
609void nfs4_put_stid(struct nfs4_stid *s); 609void nfs4_put_stid(struct nfs4_stid *s);
610void nfs4_inc_and_copy_stateid(stateid_t *dst, struct nfs4_stid *stid); 610void nfs4_inc_and_copy_stateid(stateid_t *dst, struct nfs4_stid *stid);