aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTrond Myklebust <trond.myklebust@primarydata.com>2014-07-30 08:27:02 -0400
committerJ. Bruce Fields <bfields@redhat.com>2014-08-01 16:28:17 -0400
commit4beb345b37fc099e98f40d20c94da6c07654005c (patch)
tree23270d6f006b77bf09b95e662bd92c4cd112faa1
parent83e452fee81cf67a8e08fd843291a7cff62a3dc7 (diff)
nfsd: Ensure struct nfs4_client is unhashed before we try to destroy it
When we remove the client_mutex protection, we will need to ensure that it can't be found by other threads while we're destroying it. Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
-rw-r--r--fs/nfsd/nfs4state.c43
1 files changed, 33 insertions, 10 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 52ec47de1185..cb630db015b0 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1588,12 +1588,23 @@ free_client(struct nfs4_client *clp)
1588} 1588}
1589 1589
1590/* must be called under the client_lock */ 1590/* must be called under the client_lock */
1591static inline void 1591static void
1592unhash_client_locked(struct nfs4_client *clp) 1592unhash_client_locked(struct nfs4_client *clp)
1593{ 1593{
1594 struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
1594 struct nfsd4_session *ses; 1595 struct nfsd4_session *ses;
1595 1596
1596 list_del(&clp->cl_lru); 1597 /* Mark the client as expired! */
1598 clp->cl_time = 0;
1599 /* Make it invisible */
1600 if (!list_empty(&clp->cl_idhash)) {
1601 list_del_init(&clp->cl_idhash);
1602 if (test_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags))
1603 rb_erase(&clp->cl_namenode, &nn->conf_name_tree);
1604 else
1605 rb_erase(&clp->cl_namenode, &nn->unconf_name_tree);
1606 }
1607 list_del_init(&clp->cl_lru);
1597 spin_lock(&clp->cl_lock); 1608 spin_lock(&clp->cl_lock);
1598 list_for_each_entry(ses, &clp->cl_sessions, se_perclnt) 1609 list_for_each_entry(ses, &clp->cl_sessions, se_perclnt)
1599 list_del_init(&ses->se_hash); 1610 list_del_init(&ses->se_hash);
@@ -1601,7 +1612,17 @@ unhash_client_locked(struct nfs4_client *clp)
1601} 1612}
1602 1613
1603static void 1614static void
1604destroy_client(struct nfs4_client *clp) 1615unhash_client(struct nfs4_client *clp)
1616{
1617 struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
1618
1619 spin_lock(&nn->client_lock);
1620 unhash_client_locked(clp);
1621 spin_unlock(&nn->client_lock);
1622}
1623
1624static void
1625__destroy_client(struct nfs4_client *clp)
1605{ 1626{
1606 struct nfs4_openowner *oo; 1627 struct nfs4_openowner *oo;
1607 struct nfs4_delegation *dp; 1628 struct nfs4_delegation *dp;
@@ -1634,22 +1655,24 @@ destroy_client(struct nfs4_client *clp)
1634 nfsd4_shutdown_callback(clp); 1655 nfsd4_shutdown_callback(clp);
1635 if (clp->cl_cb_conn.cb_xprt) 1656 if (clp->cl_cb_conn.cb_xprt)
1636 svc_xprt_put(clp->cl_cb_conn.cb_xprt); 1657 svc_xprt_put(clp->cl_cb_conn.cb_xprt);
1637 list_del(&clp->cl_idhash);
1638 if (test_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags))
1639 rb_erase(&clp->cl_namenode, &nn->conf_name_tree);
1640 else
1641 rb_erase(&clp->cl_namenode, &nn->unconf_name_tree);
1642 spin_lock(&nn->client_lock); 1658 spin_lock(&nn->client_lock);
1643 unhash_client_locked(clp);
1644 WARN_ON_ONCE(atomic_read(&clp->cl_refcount)); 1659 WARN_ON_ONCE(atomic_read(&clp->cl_refcount));
1645 free_client(clp); 1660 free_client(clp);
1646 spin_unlock(&nn->client_lock); 1661 spin_unlock(&nn->client_lock);
1647} 1662}
1648 1663
1664static void
1665destroy_client(struct nfs4_client *clp)
1666{
1667 unhash_client(clp);
1668 __destroy_client(clp);
1669}
1670
1649static void expire_client(struct nfs4_client *clp) 1671static void expire_client(struct nfs4_client *clp)
1650{ 1672{
1673 unhash_client(clp);
1651 nfsd4_client_record_remove(clp); 1674 nfsd4_client_record_remove(clp);
1652 destroy_client(clp); 1675 __destroy_client(clp);
1653} 1676}
1654 1677
1655static void copy_verf(struct nfs4_client *target, nfs4_verifier *source) 1678static void copy_verf(struct nfs4_client *target, nfs4_verifier *source)