summaryrefslogtreecommitdiff
path: root/fs/lockd/host.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/lockd/host.c')
-rw-r--r--fs/lockd/host.c131
1 files changed, 77 insertions, 54 deletions
diff --git a/fs/lockd/host.c b/fs/lockd/host.c
index eb75ca7c2d6e..969d589c848d 100644
--- a/fs/lockd/host.c
+++ b/fs/lockd/host.c
@@ -13,6 +13,7 @@
#include <linux/in.h>
#include <linux/in6.h>
#include <linux/sunrpc/clnt.h>
+#include <linux/sunrpc/addr.h>
#include <linux/sunrpc/svc.h>
#include <linux/lockd/lockd.h>
#include <linux/mutex.h>
@@ -21,6 +22,8 @@
#include <net/ipv6.h>
+#include "netns.h"
+
#define NLMDBG_FACILITY NLMDBG_HOSTCACHE
#define NLM_HOST_NRHASH 32
#define NLM_HOST_REBIND (60 * HZ)
@@ -30,22 +33,21 @@
static struct hlist_head nlm_server_hosts[NLM_HOST_NRHASH];
static struct hlist_head nlm_client_hosts[NLM_HOST_NRHASH];
-#define for_each_host(host, pos, chain, table) \
+#define for_each_host(host, chain, table) \
for ((chain) = (table); \
(chain) < (table) + NLM_HOST_NRHASH; ++(chain)) \
- hlist_for_each_entry((host), (pos), (chain), h_hash)
+ hlist_for_each_entry((host), (chain), h_hash)
-#define for_each_host_safe(host, pos, next, chain, table) \
+#define for_each_host_safe(host, next, chain, table) \
for ((chain) = (table); \
(chain) < (table) + NLM_HOST_NRHASH; ++(chain)) \
- hlist_for_each_entry_safe((host), (pos), (next), \
+ hlist_for_each_entry_safe((host), (next), \
(chain), h_hash)
-static unsigned long next_gc;
static unsigned long nrhosts;
static DEFINE_MUTEX(nlm_host_mutex);
-static void nlm_gc_hosts(void);
+static void nlm_gc_hosts(struct net *net);
struct nlm_lookup_host_info {
const int server; /* search for server|client */
@@ -172,12 +174,10 @@ out:
static void nlm_destroy_host_locked(struct nlm_host *host)
{
struct rpc_clnt *clnt;
+ struct lockd_net *ln = net_generic(host->net, lockd_net_id);
dprintk("lockd: destroy host %s\n", host->h_name);
- BUG_ON(!list_empty(&host->h_lockowners));
- BUG_ON(atomic_read(&host->h_count));
-
hlist_del_init(&host->h_hash);
nsm_unmonitor(host);
@@ -188,6 +188,7 @@ static void nlm_destroy_host_locked(struct nlm_host *host)
rpc_shutdown_client(clnt);
kfree(host);
+ ln->nrhosts--;
nrhosts--;
}
@@ -225,9 +226,9 @@ struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap,
.net = net,
};
struct hlist_head *chain;
- struct hlist_node *pos;
struct nlm_host *host;
struct nsm_handle *nsm = NULL;
+ struct lockd_net *ln = net_generic(net, lockd_net_id);
dprintk("lockd: %s(host='%s', vers=%u, proto=%s)\n", __func__,
(hostname ? hostname : "<none>"), version,
@@ -236,7 +237,7 @@ struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap,
mutex_lock(&nlm_host_mutex);
chain = &nlm_client_hosts[nlm_hash_address(sap)];
- hlist_for_each_entry(host, pos, chain, h_hash) {
+ hlist_for_each_entry(host, chain, h_hash) {
if (host->net != net)
continue;
if (!rpc_cmp_addr(nlm_addr(host), sap))
@@ -262,6 +263,7 @@ struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap,
goto out;
hlist_add_head(&host->h_hash, chain);
+ ln->nrhosts++;
nrhosts++;
dprintk("lockd: %s created host %s (%s)\n", __func__,
@@ -284,13 +286,12 @@ void nlmclnt_release_host(struct nlm_host *host)
dprintk("lockd: release client host %s\n", host->h_name);
- BUG_ON(atomic_read(&host->h_count) < 0);
- BUG_ON(host->h_server);
+ WARN_ON_ONCE(host->h_server);
if (atomic_dec_and_test(&host->h_count)) {
- BUG_ON(!list_empty(&host->h_lockowners));
- BUG_ON(!list_empty(&host->h_granted));
- BUG_ON(!list_empty(&host->h_reclaim));
+ WARN_ON_ONCE(!list_empty(&host->h_lockowners));
+ WARN_ON_ONCE(!list_empty(&host->h_granted));
+ WARN_ON_ONCE(!list_empty(&host->h_reclaim));
mutex_lock(&nlm_host_mutex);
nlm_destroy_host_locked(host);
@@ -321,12 +322,11 @@ struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp,
const size_t hostname_len)
{
struct hlist_head *chain;
- struct hlist_node *pos;
struct nlm_host *host = NULL;
struct nsm_handle *nsm = NULL;
struct sockaddr *src_sap = svc_daddr(rqstp);
size_t src_len = rqstp->rq_daddrlen;
- struct net *net = rqstp->rq_xprt->xpt_net;
+ struct net *net = SVC_NET(rqstp);
struct nlm_lookup_host_info ni = {
.server = 1,
.sap = svc_addr(rqstp),
@@ -337,6 +337,7 @@ struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp,
.hostname_len = hostname_len,
.net = net,
};
+ struct lockd_net *ln = net_generic(net, lockd_net_id);
dprintk("lockd: %s(host='%*s', vers=%u, proto=%s)\n", __func__,
(int)hostname_len, hostname, rqstp->rq_vers,
@@ -344,11 +345,11 @@ struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp,
mutex_lock(&nlm_host_mutex);
- if (time_after_eq(jiffies, next_gc))
- nlm_gc_hosts();
+ if (time_after_eq(jiffies, ln->next_gc))
+ nlm_gc_hosts(net);
chain = &nlm_server_hosts[nlm_hash_address(ni.sap)];
- hlist_for_each_entry(host, pos, chain, h_hash) {
+ hlist_for_each_entry(host, chain, h_hash) {
if (host->net != net)
continue;
if (!rpc_cmp_addr(nlm_addr(host), ni.sap))
@@ -382,6 +383,7 @@ struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp,
memcpy(nlm_srcaddr(host), src_sap, src_len);
host->h_srcaddrlen = src_len;
hlist_add_head(&host->h_hash, chain);
+ ln->nrhosts++;
nrhosts++;
dprintk("lockd: %s created host %s (%s)\n",
@@ -405,8 +407,7 @@ void nlmsvc_release_host(struct nlm_host *host)
dprintk("lockd: release server host %s\n", host->h_name);
- BUG_ON(atomic_read(&host->h_count) < 0);
- BUG_ON(!host->h_server);
+ WARN_ON_ONCE(!host->h_server);
atomic_dec(&host->h_count);
}
@@ -513,10 +514,9 @@ static struct nlm_host *next_host_state(struct hlist_head *cache,
{
struct nlm_host *host;
struct hlist_head *chain;
- struct hlist_node *pos;
mutex_lock(&nlm_host_mutex);
- for_each_host(host, pos, chain, cache) {
+ for_each_host(host, chain, cache) {
if (host->h_nsmhandle == nsm
&& host->h_nsmstate != info->state) {
host->h_nsmstate = info->state;
@@ -565,19 +565,45 @@ void nlm_host_rebooted(const struct nlm_reboot *info)
nsm_release(nsm);
}
+static void nlm_complain_hosts(struct net *net)
+{
+ struct hlist_head *chain;
+ struct nlm_host *host;
+
+ if (net) {
+ struct lockd_net *ln = net_generic(net, lockd_net_id);
+
+ if (ln->nrhosts == 0)
+ return;
+ printk(KERN_WARNING "lockd: couldn't shutdown host module for net %p!\n", net);
+ dprintk("lockd: %lu hosts left in net %p:\n", ln->nrhosts, net);
+ } else {
+ if (nrhosts == 0)
+ return;
+ printk(KERN_WARNING "lockd: couldn't shutdown host module!\n");
+ dprintk("lockd: %lu hosts left:\n", nrhosts);
+ }
+
+ for_each_host(host, chain, nlm_server_hosts) {
+ if (net && host->net != net)
+ continue;
+ dprintk(" %s (cnt %d use %d exp %ld net %p)\n",
+ host->h_name, atomic_read(&host->h_count),
+ host->h_inuse, host->h_expires, host->net);
+ }
+}
+
void
nlm_shutdown_hosts_net(struct net *net)
{
struct hlist_head *chain;
- struct hlist_node *pos;
struct nlm_host *host;
- dprintk("lockd: shutting down host module\n");
mutex_lock(&nlm_host_mutex);
/* First, make all hosts eligible for gc */
- dprintk("lockd: nuking all hosts...\n");
- for_each_host(host, pos, chain, nlm_server_hosts) {
+ dprintk("lockd: nuking all hosts in net %p...\n", net);
+ for_each_host(host, chain, nlm_server_hosts) {
if (net && host->net != net)
continue;
host->h_expires = jiffies - 1;
@@ -588,8 +614,10 @@ nlm_shutdown_hosts_net(struct net *net)
}
/* Then, perform a garbage collection pass */
- nlm_gc_hosts();
+ nlm_gc_hosts(net);
mutex_unlock(&nlm_host_mutex);
+
+ nlm_complain_hosts(net);
}
/*
@@ -599,22 +627,8 @@ nlm_shutdown_hosts_net(struct net *net)
void
nlm_shutdown_hosts(void)
{
- struct hlist_head *chain;
- struct hlist_node *pos;
- struct nlm_host *host;
-
+ dprintk("lockd: shutting down host module\n");
nlm_shutdown_hosts_net(NULL);
-
- /* complain if any hosts are left */
- if (nrhosts != 0) {
- printk(KERN_WARNING "lockd: couldn't shutdown host module!\n");
- dprintk("lockd: %lu hosts left:\n", nrhosts);
- for_each_host(host, pos, chain, nlm_server_hosts) {
- dprintk(" %s (cnt %d use %d exp %ld net %p)\n",
- host->h_name, atomic_read(&host->h_count),
- host->h_inuse, host->h_expires, host->net);
- }
- }
}
/*
@@ -623,30 +637,39 @@ nlm_shutdown_hosts(void)
* mark & sweep for resources held by remote clients.
*/
static void
-nlm_gc_hosts(void)
+nlm_gc_hosts(struct net *net)
{
struct hlist_head *chain;
- struct hlist_node *pos, *next;
+ struct hlist_node *next;
struct nlm_host *host;
- dprintk("lockd: host garbage collection\n");
- for_each_host(host, pos, chain, nlm_server_hosts)
+ dprintk("lockd: host garbage collection for net %p\n", net);
+ for_each_host(host, chain, nlm_server_hosts) {
+ if (net && host->net != net)
+ continue;
host->h_inuse = 0;
+ }
/* Mark all hosts that hold locks, blocks or shares */
- nlmsvc_mark_resources();
+ nlmsvc_mark_resources(net);
- for_each_host_safe(host, pos, next, chain, nlm_server_hosts) {
+ for_each_host_safe(host, next, chain, nlm_server_hosts) {
+ if (net && host->net != net)
+ continue;
if (atomic_read(&host->h_count) || host->h_inuse
|| time_before(jiffies, host->h_expires)) {
dprintk("nlm_gc_hosts skipping %s "
- "(cnt %d use %d exp %ld)\n",
+ "(cnt %d use %d exp %ld net %p)\n",
host->h_name, atomic_read(&host->h_count),
- host->h_inuse, host->h_expires);
+ host->h_inuse, host->h_expires, host->net);
continue;
}
nlm_destroy_host_locked(host);
}
- next_gc = jiffies + NLM_HOST_COLLECT;
+ if (net) {
+ struct lockd_net *ln = net_generic(net, lockd_net_id);
+
+ ln->next_gc = jiffies + NLM_HOST_COLLECT;
+ }
}