Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * linux/fs/lockd/host.c
0004  *
0005  * Management for NLM peer hosts. The nlm_host struct is shared
0006  * between client and server implementation. The only reason to
0007  * do so is to reduce code bloat.
0008  *
0009  * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
0010  */
0011 
0012 #include <linux/types.h>
0013 #include <linux/slab.h>
0014 #include <linux/in.h>
0015 #include <linux/in6.h>
0016 #include <linux/sunrpc/clnt.h>
0017 #include <linux/sunrpc/addr.h>
0018 #include <linux/sunrpc/svc.h>
0019 #include <linux/lockd/lockd.h>
0020 #include <linux/mutex.h>
0021 
0022 #include <linux/sunrpc/svc_xprt.h>
0023 
0024 #include <net/ipv6.h>
0025 
0026 #include "netns.h"
0027 
0028 #define NLMDBG_FACILITY     NLMDBG_HOSTCACHE
0029 #define NLM_HOST_NRHASH     32
0030 #define NLM_HOST_REBIND     (60 * HZ)
0031 #define NLM_HOST_EXPIRE     (300 * HZ)
0032 #define NLM_HOST_COLLECT    (120 * HZ)
0033 
0034 static struct hlist_head    nlm_server_hosts[NLM_HOST_NRHASH];
0035 static struct hlist_head    nlm_client_hosts[NLM_HOST_NRHASH];
0036 
0037 #define for_each_host(host, chain, table) \
0038     for ((chain) = (table); \
0039          (chain) < (table) + NLM_HOST_NRHASH; ++(chain)) \
0040         hlist_for_each_entry((host), (chain), h_hash)
0041 
0042 #define for_each_host_safe(host, next, chain, table) \
0043     for ((chain) = (table); \
0044          (chain) < (table) + NLM_HOST_NRHASH; ++(chain)) \
0045         hlist_for_each_entry_safe((host), (next), \
0046                         (chain), h_hash)
0047 
0048 static unsigned long        nrhosts;
0049 static DEFINE_MUTEX(nlm_host_mutex);
0050 
0051 static void         nlm_gc_hosts(struct net *net);
0052 
0053 struct nlm_lookup_host_info {
0054     const int       server;     /* search for server|client */
0055     const struct sockaddr   *sap;       /* address to search for */
0056     const size_t        salen;      /* it's length */
0057     const unsigned short    protocol;   /* transport to search for*/
0058     const u32       version;    /* NLM version to search for */
0059     const char      *hostname;  /* remote's hostname */
0060     const size_t        hostname_len;   /* it's length */
0061     const int       noresvport; /* use non-priv port */
0062     struct net      *net;       /* network namespace to bind */
0063     const struct cred   *cred;
0064 };
0065 
0066 /*
0067  * Hash function must work well on big- and little-endian platforms
0068  */
0069 static unsigned int __nlm_hash32(const __be32 n)
0070 {
0071     unsigned int hash = (__force u32)n ^ ((__force u32)n >> 16);
0072     return hash ^ (hash >> 8);
0073 }
0074 
0075 static unsigned int __nlm_hash_addr4(const struct sockaddr *sap)
0076 {
0077     const struct sockaddr_in *sin = (struct sockaddr_in *)sap;
0078     return __nlm_hash32(sin->sin_addr.s_addr);
0079 }
0080 
0081 static unsigned int __nlm_hash_addr6(const struct sockaddr *sap)
0082 {
0083     const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
0084     const struct in6_addr addr = sin6->sin6_addr;
0085     return __nlm_hash32(addr.s6_addr32[0]) ^
0086            __nlm_hash32(addr.s6_addr32[1]) ^
0087            __nlm_hash32(addr.s6_addr32[2]) ^
0088            __nlm_hash32(addr.s6_addr32[3]);
0089 }
0090 
0091 static unsigned int nlm_hash_address(const struct sockaddr *sap)
0092 {
0093     unsigned int hash;
0094 
0095     switch (sap->sa_family) {
0096     case AF_INET:
0097         hash = __nlm_hash_addr4(sap);
0098         break;
0099     case AF_INET6:
0100         hash = __nlm_hash_addr6(sap);
0101         break;
0102     default:
0103         hash = 0;
0104     }
0105     return hash & (NLM_HOST_NRHASH - 1);
0106 }
0107 
0108 /*
0109  * Allocate and initialize an nlm_host.  Common to both client and server.
0110  */
0111 static struct nlm_host *nlm_alloc_host(struct nlm_lookup_host_info *ni,
0112                        struct nsm_handle *nsm)
0113 {
0114     struct nlm_host *host = NULL;
0115     unsigned long now = jiffies;
0116 
0117     if (nsm != NULL)
0118         refcount_inc(&nsm->sm_count);
0119     else {
0120         host = NULL;
0121         nsm = nsm_get_handle(ni->net, ni->sap, ni->salen,
0122                     ni->hostname, ni->hostname_len);
0123         if (unlikely(nsm == NULL)) {
0124             dprintk("lockd: %s failed; no nsm handle\n",
0125                 __func__);
0126             goto out;
0127         }
0128     }
0129 
0130     host = kmalloc(sizeof(*host), GFP_KERNEL);
0131     if (unlikely(host == NULL)) {
0132         dprintk("lockd: %s failed; no memory\n", __func__);
0133         nsm_release(nsm);
0134         goto out;
0135     }
0136 
0137     memcpy(nlm_addr(host), ni->sap, ni->salen);
0138     host->h_addrlen    = ni->salen;
0139     rpc_set_port(nlm_addr(host), 0);
0140     host->h_srcaddrlen = 0;
0141 
0142     host->h_rpcclnt    = NULL;
0143     host->h_name       = nsm->sm_name;
0144     host->h_version    = ni->version;
0145     host->h_proto      = ni->protocol;
0146     host->h_reclaiming = 0;
0147     host->h_server     = ni->server;
0148     host->h_noresvport = ni->noresvport;
0149     host->h_inuse      = 0;
0150     init_waitqueue_head(&host->h_gracewait);
0151     init_rwsem(&host->h_rwsem);
0152     host->h_state      = 0;
0153     host->h_nsmstate   = 0;
0154     host->h_pidcount   = 0;
0155     refcount_set(&host->h_count, 1);
0156     mutex_init(&host->h_mutex);
0157     host->h_nextrebind = now + NLM_HOST_REBIND;
0158     host->h_expires    = now + NLM_HOST_EXPIRE;
0159     INIT_LIST_HEAD(&host->h_lockowners);
0160     spin_lock_init(&host->h_lock);
0161     INIT_LIST_HEAD(&host->h_granted);
0162     INIT_LIST_HEAD(&host->h_reclaim);
0163     host->h_nsmhandle  = nsm;
0164     host->h_addrbuf    = nsm->sm_addrbuf;
0165     host->net      = ni->net;
0166     host->h_cred       = get_cred(ni->cred);
0167     strlcpy(host->nodename, utsname()->nodename, sizeof(host->nodename));
0168 
0169 out:
0170     return host;
0171 }
0172 
0173 /*
0174  * Destroy an nlm_host and free associated resources
0175  *
0176  * Caller must hold nlm_host_mutex.
0177  */
0178 static void nlm_destroy_host_locked(struct nlm_host *host)
0179 {
0180     struct rpc_clnt *clnt;
0181     struct lockd_net *ln = net_generic(host->net, lockd_net_id);
0182 
0183     dprintk("lockd: destroy host %s\n", host->h_name);
0184 
0185     hlist_del_init(&host->h_hash);
0186 
0187     nsm_unmonitor(host);
0188     nsm_release(host->h_nsmhandle);
0189 
0190     clnt = host->h_rpcclnt;
0191     if (clnt != NULL)
0192         rpc_shutdown_client(clnt);
0193     put_cred(host->h_cred);
0194     kfree(host);
0195 
0196     ln->nrhosts--;
0197     nrhosts--;
0198 }
0199 
0200 /**
0201  * nlmclnt_lookup_host - Find an NLM host handle matching a remote server
0202  * @sap: network address of server
0203  * @salen: length of server address
0204  * @protocol: transport protocol to use
0205  * @version: NLM protocol version
0206  * @hostname: '\0'-terminated hostname of server
0207  * @noresvport: 1 if non-privileged port should be used
0208  * @net: pointer to net namespace
0209  * @cred: pointer to cred
0210  *
0211  * Returns an nlm_host structure that matches the passed-in
0212  * [server address, transport protocol, NLM version, server hostname].
0213  * If one doesn't already exist in the host cache, a new handle is
0214  * created and returned.
0215  */
0216 struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap,
0217                      const size_t salen,
0218                      const unsigned short protocol,
0219                      const u32 version,
0220                      const char *hostname,
0221                      int noresvport,
0222                      struct net *net,
0223                      const struct cred *cred)
0224 {
0225     struct nlm_lookup_host_info ni = {
0226         .server     = 0,
0227         .sap        = sap,
0228         .salen      = salen,
0229         .protocol   = protocol,
0230         .version    = version,
0231         .hostname   = hostname,
0232         .hostname_len   = strlen(hostname),
0233         .noresvport = noresvport,
0234         .net        = net,
0235         .cred       = cred,
0236     };
0237     struct hlist_head *chain;
0238     struct nlm_host *host;
0239     struct nsm_handle *nsm = NULL;
0240     struct lockd_net *ln = net_generic(net, lockd_net_id);
0241 
0242     dprintk("lockd: %s(host='%s', vers=%u, proto=%s)\n", __func__,
0243             (hostname ? hostname : "<none>"), version,
0244             (protocol == IPPROTO_UDP ? "udp" : "tcp"));
0245 
0246     mutex_lock(&nlm_host_mutex);
0247 
0248     chain = &nlm_client_hosts[nlm_hash_address(sap)];
0249     hlist_for_each_entry(host, chain, h_hash) {
0250         if (host->net != net)
0251             continue;
0252         if (!rpc_cmp_addr(nlm_addr(host), sap))
0253             continue;
0254 
0255         /* Same address. Share an NSM handle if we already have one */
0256         if (nsm == NULL)
0257             nsm = host->h_nsmhandle;
0258 
0259         if (host->h_proto != protocol)
0260             continue;
0261         if (host->h_version != version)
0262             continue;
0263 
0264         nlm_get_host(host);
0265         dprintk("lockd: %s found host %s (%s)\n", __func__,
0266             host->h_name, host->h_addrbuf);
0267         goto out;
0268     }
0269 
0270     host = nlm_alloc_host(&ni, nsm);
0271     if (unlikely(host == NULL))
0272         goto out;
0273 
0274     hlist_add_head(&host->h_hash, chain);
0275     ln->nrhosts++;
0276     nrhosts++;
0277 
0278     dprintk("lockd: %s created host %s (%s)\n", __func__,
0279         host->h_name, host->h_addrbuf);
0280 
0281 out:
0282     mutex_unlock(&nlm_host_mutex);
0283     return host;
0284 }
0285 
0286 /**
0287  * nlmclnt_release_host - release client nlm_host
0288  * @host: nlm_host to release
0289  *
0290  */
0291 void nlmclnt_release_host(struct nlm_host *host)
0292 {
0293     if (host == NULL)
0294         return;
0295 
0296     dprintk("lockd: release client host %s\n", host->h_name);
0297 
0298     WARN_ON_ONCE(host->h_server);
0299 
0300     if (refcount_dec_and_mutex_lock(&host->h_count, &nlm_host_mutex)) {
0301         WARN_ON_ONCE(!list_empty(&host->h_lockowners));
0302         WARN_ON_ONCE(!list_empty(&host->h_granted));
0303         WARN_ON_ONCE(!list_empty(&host->h_reclaim));
0304 
0305         nlm_destroy_host_locked(host);
0306         mutex_unlock(&nlm_host_mutex);
0307     }
0308 }
0309 
0310 /**
0311  * nlmsvc_lookup_host - Find an NLM host handle matching a remote client
0312  * @rqstp: incoming NLM request
0313  * @hostname: name of client host
0314  * @hostname_len: length of client hostname
0315  *
0316  * Returns an nlm_host structure that matches the [client address,
0317  * transport protocol, NLM version, client hostname] of the passed-in
0318  * NLM request.  If one doesn't already exist in the host cache, a
0319  * new handle is created and returned.
0320  *
0321  * Before possibly creating a new nlm_host, construct a sockaddr
0322  * for a specific source address in case the local system has
0323  * multiple network addresses.  The family of the address in
0324  * rq_daddr is guaranteed to be the same as the family of the
0325  * address in rq_addr, so it's safe to use the same family for
0326  * the source address.
0327  */
0328 struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp,
0329                     const char *hostname,
0330                     const size_t hostname_len)
0331 {
0332     struct hlist_head *chain;
0333     struct nlm_host *host = NULL;
0334     struct nsm_handle *nsm = NULL;
0335     struct sockaddr *src_sap = svc_daddr(rqstp);
0336     size_t src_len = rqstp->rq_daddrlen;
0337     struct net *net = SVC_NET(rqstp);
0338     struct nlm_lookup_host_info ni = {
0339         .server     = 1,
0340         .sap        = svc_addr(rqstp),
0341         .salen      = rqstp->rq_addrlen,
0342         .protocol   = rqstp->rq_prot,
0343         .version    = rqstp->rq_vers,
0344         .hostname   = hostname,
0345         .hostname_len   = hostname_len,
0346         .net        = net,
0347     };
0348     struct lockd_net *ln = net_generic(net, lockd_net_id);
0349 
0350     dprintk("lockd: %s(host='%.*s', vers=%u, proto=%s)\n", __func__,
0351             (int)hostname_len, hostname, rqstp->rq_vers,
0352             (rqstp->rq_prot == IPPROTO_UDP ? "udp" : "tcp"));
0353 
0354     mutex_lock(&nlm_host_mutex);
0355 
0356     if (time_after_eq(jiffies, ln->next_gc))
0357         nlm_gc_hosts(net);
0358 
0359     chain = &nlm_server_hosts[nlm_hash_address(ni.sap)];
0360     hlist_for_each_entry(host, chain, h_hash) {
0361         if (host->net != net)
0362             continue;
0363         if (!rpc_cmp_addr(nlm_addr(host), ni.sap))
0364             continue;
0365 
0366         /* Same address. Share an NSM handle if we already have one */
0367         if (nsm == NULL)
0368             nsm = host->h_nsmhandle;
0369 
0370         if (host->h_proto != ni.protocol)
0371             continue;
0372         if (host->h_version != ni.version)
0373             continue;
0374         if (!rpc_cmp_addr(nlm_srcaddr(host), src_sap))
0375             continue;
0376 
0377         /* Move to head of hash chain. */
0378         hlist_del(&host->h_hash);
0379         hlist_add_head(&host->h_hash, chain);
0380 
0381         nlm_get_host(host);
0382         dprintk("lockd: %s found host %s (%s)\n",
0383             __func__, host->h_name, host->h_addrbuf);
0384         goto out;
0385     }
0386 
0387     host = nlm_alloc_host(&ni, nsm);
0388     if (unlikely(host == NULL))
0389         goto out;
0390 
0391     memcpy(nlm_srcaddr(host), src_sap, src_len);
0392     host->h_srcaddrlen = src_len;
0393     hlist_add_head(&host->h_hash, chain);
0394     ln->nrhosts++;
0395     nrhosts++;
0396 
0397     refcount_inc(&host->h_count);
0398 
0399     dprintk("lockd: %s created host %s (%s)\n",
0400         __func__, host->h_name, host->h_addrbuf);
0401 
0402 out:
0403     mutex_unlock(&nlm_host_mutex);
0404     return host;
0405 }
0406 
0407 /**
0408  * nlmsvc_release_host - release server nlm_host
0409  * @host: nlm_host to release
0410  *
0411  * Host is destroyed later in nlm_gc_host().
0412  */
0413 void nlmsvc_release_host(struct nlm_host *host)
0414 {
0415     if (host == NULL)
0416         return;
0417 
0418     dprintk("lockd: release server host %s\n", host->h_name);
0419 
0420     WARN_ON_ONCE(!host->h_server);
0421     refcount_dec(&host->h_count);
0422 }
0423 
0424 /*
0425  * Create the NLM RPC client for an NLM peer
0426  */
0427 struct rpc_clnt *
0428 nlm_bind_host(struct nlm_host *host)
0429 {
0430     struct rpc_clnt *clnt;
0431 
0432     dprintk("lockd: nlm_bind_host %s (%s)\n",
0433             host->h_name, host->h_addrbuf);
0434 
0435     /* Lock host handle */
0436     mutex_lock(&host->h_mutex);
0437 
0438     /* If we've already created an RPC client, check whether
0439      * RPC rebind is required
0440      */
0441     if ((clnt = host->h_rpcclnt) != NULL) {
0442         nlm_rebind_host(host);
0443     } else {
0444         unsigned long increment = nlmsvc_timeout;
0445         struct rpc_timeout timeparms = {
0446             .to_initval = increment,
0447             .to_increment   = increment,
0448             .to_maxval  = increment * 6UL,
0449             .to_retries = 5U,
0450         };
0451         struct rpc_create_args args = {
0452             .net        = host->net,
0453             .protocol   = host->h_proto,
0454             .address    = nlm_addr(host),
0455             .addrsize   = host->h_addrlen,
0456             .timeout    = &timeparms,
0457             .servername = host->h_name,
0458             .program    = &nlm_program,
0459             .version    = host->h_version,
0460             .authflavor = RPC_AUTH_UNIX,
0461             .flags      = (RPC_CLNT_CREATE_NOPING |
0462                        RPC_CLNT_CREATE_AUTOBIND |
0463                        RPC_CLNT_CREATE_REUSEPORT),
0464             .cred       = host->h_cred,
0465         };
0466 
0467         /*
0468          * lockd retries server side blocks automatically so we want
0469          * those to be soft RPC calls. Client side calls need to be
0470          * hard RPC tasks.
0471          */
0472         if (!host->h_server)
0473             args.flags |= RPC_CLNT_CREATE_HARDRTRY;
0474         if (host->h_noresvport)
0475             args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
0476         if (host->h_srcaddrlen)
0477             args.saddress = nlm_srcaddr(host);
0478 
0479         clnt = rpc_create(&args);
0480         if (!IS_ERR(clnt))
0481             host->h_rpcclnt = clnt;
0482         else {
0483             printk("lockd: couldn't create RPC handle for %s\n", host->h_name);
0484             clnt = NULL;
0485         }
0486     }
0487 
0488     mutex_unlock(&host->h_mutex);
0489     return clnt;
0490 }
0491 
0492 /**
0493  * nlm_rebind_host - If needed, force a portmap lookup of the peer's lockd port
0494  * @host: NLM host handle for peer
0495  *
0496  * This is not needed when using a connection-oriented protocol, such as TCP.
0497  * The existing autobind mechanism is sufficient to force a rebind when
0498  * required, e.g. on connection state transitions.
0499  */
0500 void
0501 nlm_rebind_host(struct nlm_host *host)
0502 {
0503     if (host->h_proto != IPPROTO_UDP)
0504         return;
0505 
0506     if (host->h_rpcclnt && time_after_eq(jiffies, host->h_nextrebind)) {
0507         rpc_force_rebind(host->h_rpcclnt);
0508         host->h_nextrebind = jiffies + NLM_HOST_REBIND;
0509     }
0510 }
0511 
0512 /*
0513  * Increment NLM host count
0514  */
0515 struct nlm_host * nlm_get_host(struct nlm_host *host)
0516 {
0517     if (host) {
0518         dprintk("lockd: get host %s\n", host->h_name);
0519         refcount_inc(&host->h_count);
0520         host->h_expires = jiffies + NLM_HOST_EXPIRE;
0521     }
0522     return host;
0523 }
0524 
0525 static struct nlm_host *next_host_state(struct hlist_head *cache,
0526                     struct nsm_handle *nsm,
0527                     const struct nlm_reboot *info)
0528 {
0529     struct nlm_host *host;
0530     struct hlist_head *chain;
0531 
0532     mutex_lock(&nlm_host_mutex);
0533     for_each_host(host, chain, cache) {
0534         if (host->h_nsmhandle == nsm
0535             && host->h_nsmstate != info->state) {
0536             host->h_nsmstate = info->state;
0537             host->h_state++;
0538 
0539             nlm_get_host(host);
0540             mutex_unlock(&nlm_host_mutex);
0541             return host;
0542         }
0543     }
0544 
0545     mutex_unlock(&nlm_host_mutex);
0546     return NULL;
0547 }
0548 
0549 /**
0550  * nlm_host_rebooted - Release all resources held by rebooted host
0551  * @net:  network namespace
0552  * @info: pointer to decoded results of NLM_SM_NOTIFY call
0553  *
0554  * We were notified that the specified host has rebooted.  Release
0555  * all resources held by that peer.
0556  */
0557 void nlm_host_rebooted(const struct net *net, const struct nlm_reboot *info)
0558 {
0559     struct nsm_handle *nsm;
0560     struct nlm_host *host;
0561 
0562     nsm = nsm_reboot_lookup(net, info);
0563     if (unlikely(nsm == NULL))
0564         return;
0565 
0566     /* Mark all hosts tied to this NSM state as having rebooted.
0567      * We run the loop repeatedly, because we drop the host table
0568      * lock for this.
0569      * To avoid processing a host several times, we match the nsmstate.
0570      */
0571     while ((host = next_host_state(nlm_server_hosts, nsm, info)) != NULL) {
0572         nlmsvc_free_host_resources(host);
0573         nlmsvc_release_host(host);
0574     }
0575     while ((host = next_host_state(nlm_client_hosts, nsm, info)) != NULL) {
0576         nlmclnt_recovery(host);
0577         nlmclnt_release_host(host);
0578     }
0579 
0580     nsm_release(nsm);
0581 }
0582 
0583 static void nlm_complain_hosts(struct net *net)
0584 {
0585     struct hlist_head *chain;
0586     struct nlm_host *host;
0587 
0588     if (net) {
0589         struct lockd_net *ln = net_generic(net, lockd_net_id);
0590 
0591         if (ln->nrhosts == 0)
0592             return;
0593         pr_warn("lockd: couldn't shutdown host module for net %x!\n",
0594             net->ns.inum);
0595         dprintk("lockd: %lu hosts left in net %x:\n", ln->nrhosts,
0596             net->ns.inum);
0597     } else {
0598         if (nrhosts == 0)
0599             return;
0600         printk(KERN_WARNING "lockd: couldn't shutdown host module!\n");
0601         dprintk("lockd: %lu hosts left:\n", nrhosts);
0602     }
0603 
0604     for_each_host(host, chain, nlm_server_hosts) {
0605         if (net && host->net != net)
0606             continue;
0607         dprintk("       %s (cnt %d use %d exp %ld net %x)\n",
0608             host->h_name, refcount_read(&host->h_count),
0609             host->h_inuse, host->h_expires, host->net->ns.inum);
0610     }
0611 }
0612 
0613 void
0614 nlm_shutdown_hosts_net(struct net *net)
0615 {
0616     struct hlist_head *chain;
0617     struct nlm_host *host;
0618 
0619     mutex_lock(&nlm_host_mutex);
0620 
0621     /* First, make all hosts eligible for gc */
0622     dprintk("lockd: nuking all hosts in net %x...\n",
0623         net ? net->ns.inum : 0);
0624     for_each_host(host, chain, nlm_server_hosts) {
0625         if (net && host->net != net)
0626             continue;
0627         host->h_expires = jiffies - 1;
0628         if (host->h_rpcclnt) {
0629             rpc_shutdown_client(host->h_rpcclnt);
0630             host->h_rpcclnt = NULL;
0631         }
0632     }
0633 
0634     /* Then, perform a garbage collection pass */
0635     nlm_gc_hosts(net);
0636     nlm_complain_hosts(net);
0637     mutex_unlock(&nlm_host_mutex);
0638 }
0639 
0640 /*
0641  * Shut down the hosts module.
0642  * Note that this routine is called only at server shutdown time.
0643  */
0644 void
0645 nlm_shutdown_hosts(void)
0646 {
0647     dprintk("lockd: shutting down host module\n");
0648     nlm_shutdown_hosts_net(NULL);
0649 }
0650 
0651 /*
0652  * Garbage collect any unused NLM hosts.
0653  * This GC combines reference counting for async operations with
0654  * mark & sweep for resources held by remote clients.
0655  */
0656 static void
0657 nlm_gc_hosts(struct net *net)
0658 {
0659     struct hlist_head *chain;
0660     struct hlist_node *next;
0661     struct nlm_host *host;
0662 
0663     dprintk("lockd: host garbage collection for net %x\n",
0664         net ? net->ns.inum : 0);
0665     for_each_host(host, chain, nlm_server_hosts) {
0666         if (net && host->net != net)
0667             continue;
0668         host->h_inuse = 0;
0669     }
0670 
0671     /* Mark all hosts that hold locks, blocks or shares */
0672     nlmsvc_mark_resources(net);
0673 
0674     for_each_host_safe(host, next, chain, nlm_server_hosts) {
0675         if (net && host->net != net)
0676             continue;
0677         if (host->h_inuse || time_before(jiffies, host->h_expires)) {
0678             dprintk("nlm_gc_hosts skipping %s "
0679                 "(cnt %d use %d exp %ld net %x)\n",
0680                 host->h_name, refcount_read(&host->h_count),
0681                 host->h_inuse, host->h_expires,
0682                 host->net->ns.inum);
0683             continue;
0684         }
0685         if (refcount_dec_if_one(&host->h_count))
0686             nlm_destroy_host_locked(host);
0687     }
0688 
0689     if (net) {
0690         struct lockd_net *ln = net_generic(net, lockd_net_id);
0691 
0692         ln->next_gc = jiffies + NLM_HOST_COLLECT;
0693     }
0694 }