NFSD: Fix a null reference case in find_or_create_lock_stateid()
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: 356a95ece7
"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>
This commit is contained in:
parent
566cf877a1
commit
d19fb70dd6
|
@ -223,10 +223,11 @@ nfsd4_alloc_layout_stateid(struct nfsd4_compound_state *cstate,
|
|||
struct nfs4_layout_stateid *ls;
|
||||
struct nfs4_stid *stp;
|
||||
|
||||
stp = nfs4_alloc_stid(cstate->clp, nfs4_layout_stateid_cache);
|
||||
stp = nfs4_alloc_stid(cstate->clp, nfs4_layout_stateid_cache,
|
||||
nfsd4_free_layout_stateid);
|
||||
if (!stp)
|
||||
return NULL;
|
||||
stp->sc_free = nfsd4_free_layout_stateid;
|
||||
|
||||
get_nfs4_file(fp);
|
||||
stp->sc_file = fp;
|
||||
|
||||
|
|
|
@ -633,8 +633,8 @@ out:
|
|||
return co;
|
||||
}
|
||||
|
||||
struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl,
|
||||
struct kmem_cache *slab)
|
||||
struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *slab,
|
||||
void (*sc_free)(struct nfs4_stid *))
|
||||
{
|
||||
struct nfs4_stid *stid;
|
||||
int new_id;
|
||||
|
@ -650,6 +650,8 @@ struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl,
|
|||
idr_preload_end();
|
||||
if (new_id < 0)
|
||||
goto out_free;
|
||||
|
||||
stid->sc_free = sc_free;
|
||||
stid->sc_client = cl;
|
||||
stid->sc_stateid.si_opaque.so_id = new_id;
|
||||
stid->sc_stateid.si_opaque.so_clid = cl->cl_clientid;
|
||||
|
@ -675,15 +677,12 @@ out_free:
|
|||
static struct nfs4_ol_stateid * nfs4_alloc_open_stateid(struct nfs4_client *clp)
|
||||
{
|
||||
struct nfs4_stid *stid;
|
||||
struct nfs4_ol_stateid *stp;
|
||||
|
||||
stid = nfs4_alloc_stid(clp, stateid_slab);
|
||||
stid = nfs4_alloc_stid(clp, stateid_slab, nfs4_free_ol_stateid);
|
||||
if (!stid)
|
||||
return NULL;
|
||||
|
||||
stp = openlockstateid(stid);
|
||||
stp->st_stid.sc_free = nfs4_free_ol_stateid;
|
||||
return stp;
|
||||
return openlockstateid(stid);
|
||||
}
|
||||
|
||||
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,
|
|||
goto out_dec;
|
||||
if (delegation_blocked(¤t_fh->fh_handle))
|
||||
goto out_dec;
|
||||
dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab));
|
||||
dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab, nfs4_free_deleg));
|
||||
if (dp == NULL)
|
||||
goto out_dec;
|
||||
|
||||
dp->dl_stid.sc_free = nfs4_free_deleg;
|
||||
/*
|
||||
* delegation seqid's are never incremented. The 4.1 special
|
||||
* 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,
|
|||
stp->st_stateowner = nfs4_get_stateowner(&lo->lo_owner);
|
||||
get_nfs4_file(fp);
|
||||
stp->st_stid.sc_file = fp;
|
||||
stp->st_stid.sc_free = nfs4_free_lock_stateid;
|
||||
stp->st_access_bmap = 0;
|
||||
stp->st_deny_bmap = open_stp->st_deny_bmap;
|
||||
stp->st_openstp = open_stp;
|
||||
|
@ -5623,7 +5620,7 @@ find_or_create_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fi,
|
|||
lst = find_lock_stateid(lo, fi);
|
||||
if (lst == NULL) {
|
||||
spin_unlock(&clp->cl_lock);
|
||||
ns = nfs4_alloc_stid(clp, stateid_slab);
|
||||
ns = nfs4_alloc_stid(clp, stateid_slab, nfs4_free_lock_stateid);
|
||||
if (ns == NULL)
|
||||
return NULL;
|
||||
|
||||
|
|
|
@ -603,8 +603,8 @@ extern __be32 nfs4_preprocess_stateid_op(struct svc_rqst *rqstp,
|
|||
__be32 nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate,
|
||||
stateid_t *stateid, unsigned char typemask,
|
||||
struct nfs4_stid **s, struct nfsd_net *nn);
|
||||
struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl,
|
||||
struct kmem_cache *slab);
|
||||
struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *slab,
|
||||
void (*sc_free)(struct nfs4_stid *));
|
||||
void nfs4_unhash_stid(struct nfs4_stid *s);
|
||||
void nfs4_put_stid(struct nfs4_stid *s);
|
||||
void nfs4_inc_and_copy_stateid(stateid_t *dst, struct nfs4_stid *stid);
|
||||
|
|
Loading…
Reference in New Issue