aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd/nfs4state.c
diff options
context:
space:
mode:
authorJ. Bruce Fields <bfields@redhat.com>2010-10-21 17:17:31 -0400
committerJ. Bruce Fields <bfields@redhat.com>2010-10-24 21:07:07 -0400
commita663bdd8c5d18d287f7468470816c9e0e66343c1 (patch)
tree9949b3b2b678c1da67e97ee2c312b1a17b98e4c8 /fs/nfsd/nfs4state.c
parent5d18c1c2a9a74e0f966c257520b8b7f5136c87b3 (diff)
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: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'fs/nfsd/nfs4state.c')
-rw-r--r--fs/nfsd/nfs4state.c31
1 files changed, 17 insertions, 14 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index ce0412fd23eb..d4aa1b59d84b 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1628,33 +1628,25 @@ out:
1628 return status; 1628 return status;
1629} 1629}
1630 1630
1631static struct nfsd4_conn *__nfsd4_find_conn(struct svc_rqst *r, struct nfsd4_session *s) 1631static struct nfsd4_conn *__nfsd4_find_conn(struct svc_xprt *xpt, struct nfsd4_session *s)
1632{ 1632{
1633 struct nfsd4_conn *c; 1633 struct nfsd4_conn *c;
1634 1634
1635 list_for_each_entry(c, &s->se_conns, cn_persession) { 1635 list_for_each_entry(c, &s->se_conns, cn_persession) {
1636 if (c->cn_xprt == r->rq_xprt) { 1636 if (c->cn_xprt == xpt) {
1637 return c; 1637 return c;
1638 } 1638 }
1639 } 1639 }
1640 return NULL; 1640 return NULL;
1641} 1641}
1642 1642
1643static void nfsd4_sequence_check_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses) 1643static void nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_session *ses)
1644{ 1644{
1645 struct nfs4_client *clp = ses->se_client; 1645 struct nfs4_client *clp = ses->se_client;
1646 struct nfsd4_conn *c, *new = NULL; 1646 struct nfsd4_conn *c;
1647
1648 spin_lock(&clp->cl_lock);
1649 c = __nfsd4_find_conn(rqstp, ses);
1650 spin_unlock(&clp->cl_lock);
1651 if (c)
1652 return;
1653
1654 new = alloc_conn(rqstp, NFS4_CDFC4_FORE);
1655 1647
1656 spin_lock(&clp->cl_lock); 1648 spin_lock(&clp->cl_lock);
1657 c = __nfsd4_find_conn(rqstp, ses); 1649 c = __nfsd4_find_conn(new->cn_xprt, ses);
1658 if (c) { 1650 if (c) {
1659 spin_unlock(&clp->cl_lock); 1651 spin_unlock(&clp->cl_lock);
1660 free_conn(new); 1652 free_conn(new);
@@ -1674,11 +1666,20 @@ nfsd4_sequence(struct svc_rqst *rqstp,
1674 struct nfsd4_compoundres *resp = rqstp->rq_resp; 1666 struct nfsd4_compoundres *resp = rqstp->rq_resp;
1675 struct nfsd4_session *session; 1667 struct nfsd4_session *session;
1676 struct nfsd4_slot *slot; 1668 struct nfsd4_slot *slot;
1669 struct nfsd4_conn *conn;
1677 int status; 1670 int status;
1678 1671
1679 if (resp->opcnt != 1) 1672 if (resp->opcnt != 1)
1680 return nfserr_sequence_pos; 1673 return nfserr_sequence_pos;
1681 1674
1675 /*
1676 * Will be either used or freed by nfsd4_sequence_check_conn
1677 * below.
1678 */
1679 conn = alloc_conn(rqstp, NFS4_CDFC4_FORE);
1680 if (!conn)
1681 return nfserr_jukebox;
1682
1682 spin_lock(&client_lock); 1683 spin_lock(&client_lock);
1683 status = nfserr_badsession; 1684 status = nfserr_badsession;
1684 session = find_in_sessionid_hashtbl(&seq->sessionid); 1685 session = find_in_sessionid_hashtbl(&seq->sessionid);
@@ -1710,7 +1711,8 @@ nfsd4_sequence(struct svc_rqst *rqstp,
1710 if (status) 1711 if (status)
1711 goto out; 1712 goto out;
1712 1713
1713 nfsd4_sequence_check_conn(rqstp, session); 1714 nfsd4_sequence_check_conn(conn, session);
1715 conn = NULL;
1714 1716
1715 /* Success! bump slot seqid */ 1717 /* Success! bump slot seqid */
1716 slot->sl_inuse = true; 1718 slot->sl_inuse = true;
@@ -1726,6 +1728,7 @@ out:
1726 nfsd4_get_session(cstate->session); 1728 nfsd4_get_session(cstate->session);
1727 atomic_inc(&session->se_client->cl_refcount); 1729 atomic_inc(&session->se_client->cl_refcount);
1728 } 1730 }
1731 kfree(conn);
1729 spin_unlock(&client_lock); 1732 spin_unlock(&client_lock);
1730 dprintk("%s: return %d\n", __func__, ntohl(status)); 1733 dprintk("%s: return %d\n", __func__, ntohl(status));
1731 return status; 1734 return status;