Commit a663bdd8 authored by J. Bruce Fields's avatar J. Bruce Fields

nfsd4: fix connection allocation in sequence()

We're doing an allocation under a spinlock, and ignoring the
possibility of allocation failure.

A better fix wouldn't require an unnecessary allocation in the common
case, but we'll leave that for later.
Signed-off-by: default avatarJ. Bruce Fields <bfields@redhat.com>
parent 5d18c1c2
...@@ -1628,33 +1628,25 @@ nfsd4_destroy_session(struct svc_rqst *r, ...@@ -1628,33 +1628,25 @@ nfsd4_destroy_session(struct svc_rqst *r,
return status; return status;
} }
static struct nfsd4_conn *__nfsd4_find_conn(struct svc_rqst *r, struct nfsd4_session *s) static struct nfsd4_conn *__nfsd4_find_conn(struct svc_xprt *xpt, struct nfsd4_session *s)
{ {
struct nfsd4_conn *c; struct nfsd4_conn *c;
list_for_each_entry(c, &s->se_conns, cn_persession) { list_for_each_entry(c, &s->se_conns, cn_persession) {
if (c->cn_xprt == r->rq_xprt) { if (c->cn_xprt == xpt) {
return c; return c;
} }
} }
return NULL; return NULL;
} }
static void nfsd4_sequence_check_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses) static void nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_session *ses)
{ {
struct nfs4_client *clp = ses->se_client; struct nfs4_client *clp = ses->se_client;
struct nfsd4_conn *c, *new = NULL; struct nfsd4_conn *c;
spin_lock(&clp->cl_lock);
c = __nfsd4_find_conn(rqstp, ses);
spin_unlock(&clp->cl_lock);
if (c)
return;
new = alloc_conn(rqstp, NFS4_CDFC4_FORE);
spin_lock(&clp->cl_lock); spin_lock(&clp->cl_lock);
c = __nfsd4_find_conn(rqstp, ses); c = __nfsd4_find_conn(new->cn_xprt, ses);
if (c) { if (c) {
spin_unlock(&clp->cl_lock); spin_unlock(&clp->cl_lock);
free_conn(new); free_conn(new);
...@@ -1674,11 +1666,20 @@ nfsd4_sequence(struct svc_rqst *rqstp, ...@@ -1674,11 +1666,20 @@ nfsd4_sequence(struct svc_rqst *rqstp,
struct nfsd4_compoundres *resp = rqstp->rq_resp; struct nfsd4_compoundres *resp = rqstp->rq_resp;
struct nfsd4_session *session; struct nfsd4_session *session;
struct nfsd4_slot *slot; struct nfsd4_slot *slot;
struct nfsd4_conn *conn;
int status; int status;
if (resp->opcnt != 1) if (resp->opcnt != 1)
return nfserr_sequence_pos; return nfserr_sequence_pos;
/*
* Will be either used or freed by nfsd4_sequence_check_conn
* below.
*/
conn = alloc_conn(rqstp, NFS4_CDFC4_FORE);
if (!conn)
return nfserr_jukebox;
spin_lock(&client_lock); spin_lock(&client_lock);
status = nfserr_badsession; status = nfserr_badsession;
session = find_in_sessionid_hashtbl(&seq->sessionid); session = find_in_sessionid_hashtbl(&seq->sessionid);
...@@ -1710,7 +1711,8 @@ nfsd4_sequence(struct svc_rqst *rqstp, ...@@ -1710,7 +1711,8 @@ nfsd4_sequence(struct svc_rqst *rqstp,
if (status) if (status)
goto out; goto out;
nfsd4_sequence_check_conn(rqstp, session); nfsd4_sequence_check_conn(conn, session);
conn = NULL;
/* Success! bump slot seqid */ /* Success! bump slot seqid */
slot->sl_inuse = true; slot->sl_inuse = true;
...@@ -1726,6 +1728,7 @@ nfsd4_sequence(struct svc_rqst *rqstp, ...@@ -1726,6 +1728,7 @@ nfsd4_sequence(struct svc_rqst *rqstp,
nfsd4_get_session(cstate->session); nfsd4_get_session(cstate->session);
atomic_inc(&session->se_client->cl_refcount); atomic_inc(&session->se_client->cl_refcount);
} }
kfree(conn);
spin_unlock(&client_lock); spin_unlock(&client_lock);
dprintk("%s: return %d\n", __func__, ntohl(status)); dprintk("%s: return %d\n", __func__, ntohl(status));
return status; return status;
......
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