Commit 915a8d29 authored by Kinglong Mee's avatar Kinglong Mee Committed by Sasha Levin

NFSD: Fix a null reference case in find_or_create_lock_stateid()

[ Upstream commit d19fb70d ]

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: 356a95ec "nfsd: clean up races in lock stateid searching..."
Signed-off-by: default avatarKinglong Mee <kinglongmee@gmail.com>
Reviewed-by: default avatarJeff Layton <jlayton@redhat.com>
Signed-off-by: default avatarJ. Bruce Fields <bfields@redhat.com>
Signed-off-by: default avatarSasha Levin <alexander.levin@verizon.com>
parent cb89bddc
...@@ -189,10 +189,11 @@ nfsd4_alloc_layout_stateid(struct nfsd4_compound_state *cstate, ...@@ -189,10 +189,11 @@ nfsd4_alloc_layout_stateid(struct nfsd4_compound_state *cstate,
struct nfs4_layout_stateid *ls; struct nfs4_layout_stateid *ls;
struct nfs4_stid *stp; 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) if (!stp)
return NULL; return NULL;
stp->sc_free = nfsd4_free_layout_stateid;
get_nfs4_file(fp); get_nfs4_file(fp);
stp->sc_file = fp; stp->sc_file = fp;
......
...@@ -553,8 +553,8 @@ find_or_hash_clnt_odstate(struct nfs4_file *fp, struct nfs4_clnt_odstate *new) ...@@ -553,8 +553,8 @@ find_or_hash_clnt_odstate(struct nfs4_file *fp, struct nfs4_clnt_odstate *new)
return co; return co;
} }
struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *slab,
struct kmem_cache *slab) void (*sc_free)(struct nfs4_stid *))
{ {
struct nfs4_stid *stid; struct nfs4_stid *stid;
int new_id; int new_id;
...@@ -570,6 +570,8 @@ struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, ...@@ -570,6 +570,8 @@ struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl,
idr_preload_end(); idr_preload_end();
if (new_id < 0) if (new_id < 0)
goto out_free; goto out_free;
stid->sc_free = sc_free;
stid->sc_client = cl; stid->sc_client = cl;
stid->sc_stateid.si_opaque.so_id = new_id; stid->sc_stateid.si_opaque.so_id = new_id;
stid->sc_stateid.si_opaque.so_clid = cl->cl_clientid; stid->sc_stateid.si_opaque.so_clid = cl->cl_clientid;
...@@ -594,15 +596,12 @@ struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, ...@@ -594,15 +596,12 @@ struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl,
static struct nfs4_ol_stateid * nfs4_alloc_open_stateid(struct nfs4_client *clp) static struct nfs4_ol_stateid * nfs4_alloc_open_stateid(struct nfs4_client *clp)
{ {
struct nfs4_stid *stid; 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) if (!stid)
return NULL; return NULL;
stp = openlockstateid(stid); return openlockstateid(stid);
stp->st_stid.sc_free = nfs4_free_ol_stateid;
return stp;
} }
static void nfs4_free_deleg(struct nfs4_stid *stid) 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,11 +699,10 @@ alloc_init_deleg(struct nfs4_client *clp, struct svc_fh *current_fh,
goto out_dec; goto out_dec;
if (delegation_blocked(&current_fh->fh_handle)) if (delegation_blocked(&current_fh->fh_handle))
goto out_dec; 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) if (dp == NULL)
goto out_dec; goto out_dec;
dp->dl_stid.sc_free = nfs4_free_deleg;
/* /*
* delegation seqid's are never incremented. The 4.1 special * delegation seqid's are never incremented. The 4.1 special
* meaning of seqid 0 isn't meaningful, really, but let's avoid * 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,7 +5307,6 @@ init_lock_stateid(struct nfs4_ol_stateid *stp, struct nfs4_lockowner *lo,
stp->st_stateowner = nfs4_get_stateowner(&lo->lo_owner); stp->st_stateowner = nfs4_get_stateowner(&lo->lo_owner);
get_nfs4_file(fp); get_nfs4_file(fp);
stp->st_stid.sc_file = fp; stp->st_stid.sc_file = fp;
stp->st_stid.sc_free = nfs4_free_lock_stateid;
stp->st_access_bmap = 0; stp->st_access_bmap = 0;
stp->st_deny_bmap = open_stp->st_deny_bmap; stp->st_deny_bmap = open_stp->st_deny_bmap;
stp->st_openstp = open_stp; stp->st_openstp = open_stp;
...@@ -5352,7 +5349,7 @@ find_or_create_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fi, ...@@ -5352,7 +5349,7 @@ find_or_create_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fi,
lst = find_lock_stateid(lo, fi); lst = find_lock_stateid(lo, fi);
if (lst == NULL) { if (lst == NULL) {
spin_unlock(&clp->cl_lock); 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) if (ns == NULL)
return NULL; return NULL;
......
...@@ -589,8 +589,8 @@ extern __be32 nfs4_preprocess_stateid_op(struct net *net, ...@@ -589,8 +589,8 @@ extern __be32 nfs4_preprocess_stateid_op(struct net *net,
__be32 nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate, __be32 nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate,
stateid_t *stateid, unsigned char typemask, stateid_t *stateid, unsigned char typemask,
struct nfs4_stid **s, struct nfsd_net *nn); struct nfs4_stid **s, struct nfsd_net *nn);
struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *slab,
struct kmem_cache *slab); void (*sc_free)(struct nfs4_stid *));
void nfs4_unhash_stid(struct nfs4_stid *s); void nfs4_unhash_stid(struct nfs4_stid *s);
void nfs4_put_stid(struct nfs4_stid *s); void nfs4_put_stid(struct nfs4_stid *s);
void nfs4_remove_reclaim_record(struct nfs4_client_reclaim *, struct nfsd_net *); void nfs4_remove_reclaim_record(struct nfs4_client_reclaim *, struct nfsd_net *);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment