diff options
author | Trond Myklebust <trond.myklebust@primarydata.com> | 2014-07-30 08:27:02 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2014-08-01 16:28:17 -0400 |
commit | 4beb345b37fc099e98f40d20c94da6c07654005c (patch) | |
tree | 23270d6f006b77bf09b95e662bd92c4cd112faa1 /fs/nfsd | |
parent | 83e452fee81cf67a8e08fd843291a7cff62a3dc7 (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>
Diffstat (limited to 'fs/nfsd')
-rw-r--r-- | fs/nfsd/nfs4state.c | 43 |
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 */ |
1591 | static inline void | 1591 | static void |
1592 | unhash_client_locked(struct nfs4_client *clp) | 1592 | unhash_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 | ||
1603 | static void | 1614 | static void |
1604 | destroy_client(struct nfs4_client *clp) | 1615 | unhash_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 | |||
1624 | static 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 | ||
1664 | static void | ||
1665 | destroy_client(struct nfs4_client *clp) | ||
1666 | { | ||
1667 | unhash_client(clp); | ||
1668 | __destroy_client(clp); | ||
1669 | } | ||
1670 | |||
1649 | static void expire_client(struct nfs4_client *clp) | 1671 | static 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 | ||
1655 | static void copy_verf(struct nfs4_client *target, nfs4_verifier *source) | 1678 | static void copy_verf(struct nfs4_client *target, nfs4_verifier *source) |