linux/fs/lockd/host.c
<<
>>
Prefs
   1/*
   2 * linux/fs/lockd/host.c
   3 *
   4 * Management for NLM peer hosts. The nlm_host struct is shared
   5 * between client and server implementation. The only reason to
   6 * do so is to reduce code bloat.
   7 *
   8 * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
   9 */
  10
  11#include <linux/types.h>
  12#include <linux/slab.h>
  13#include <linux/in.h>
  14#include <linux/in6.h>
  15#include <linux/sunrpc/clnt.h>
  16#include <linux/sunrpc/addr.h>
  17#include <linux/sunrpc/svc.h>
  18#include <linux/lockd/lockd.h>
  19#include <linux/mutex.h>
  20
  21#include <linux/sunrpc/svc_xprt.h>
  22
  23#include <net/ipv6.h>
  24
  25#include "netns.h"
  26
  27#define NLMDBG_FACILITY         NLMDBG_HOSTCACHE
  28#define NLM_HOST_NRHASH         32
  29#define NLM_HOST_REBIND         (60 * HZ)
  30#define NLM_HOST_EXPIRE         (300 * HZ)
  31#define NLM_HOST_COLLECT        (120 * HZ)
  32
  33static struct hlist_head        nlm_server_hosts[NLM_HOST_NRHASH];
  34static struct hlist_head        nlm_client_hosts[NLM_HOST_NRHASH];
  35
  36#define for_each_host(host, chain, table) \
  37        for ((chain) = (table); \
  38             (chain) < (table) + NLM_HOST_NRHASH; ++(chain)) \
  39                hlist_for_each_entry((host), (chain), h_hash)
  40
  41#define for_each_host_safe(host, next, chain, table) \
  42        for ((chain) = (table); \
  43             (chain) < (table) + NLM_HOST_NRHASH; ++(chain)) \
  44                hlist_for_each_entry_safe((host), (next), \
  45                                                (chain), h_hash)
  46
  47static unsigned long            nrhosts;
  48static DEFINE_MUTEX(nlm_host_mutex);
  49
  50static void                     nlm_gc_hosts(struct net *net);
  51
  52struct nlm_lookup_host_info {
  53        const int               server;         /* search for server|client */
  54        const struct sockaddr   *sap;           /* address to search for */
  55        const size_t            salen;          /* it's length */
  56        const unsigned short    protocol;       /* transport to search for*/
  57        const u32               version;        /* NLM version to search for */
  58        const char              *hostname;      /* remote's hostname */
  59        const size_t            hostname_len;   /* it's length */
  60        const int               noresvport;     /* use non-priv port */
  61        struct net              *net;           /* network namespace to bind */
  62};
  63
  64/*
  65 * Hash function must work well on big- and little-endian platforms
  66 */
  67static unsigned int __nlm_hash32(const __be32 n)
  68{
  69        unsigned int hash = (__force u32)n ^ ((__force u32)n >> 16);
  70        return hash ^ (hash >> 8);
  71}
  72
  73static unsigned int __nlm_hash_addr4(const struct sockaddr *sap)
  74{
  75        const struct sockaddr_in *sin = (struct sockaddr_in *)sap;
  76        return __nlm_hash32(sin->sin_addr.s_addr);
  77}
  78
  79static unsigned int __nlm_hash_addr6(const struct sockaddr *sap)
  80{
  81        const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
  82        const struct in6_addr addr = sin6->sin6_addr;
  83        return __nlm_hash32(addr.s6_addr32[0]) ^
  84               __nlm_hash32(addr.s6_addr32[1]) ^
  85               __nlm_hash32(addr.s6_addr32[2]) ^
  86               __nlm_hash32(addr.s6_addr32[3]);
  87}
  88
  89static unsigned int nlm_hash_address(const struct sockaddr *sap)
  90{
  91        unsigned int hash;
  92
  93        switch (sap->sa_family) {
  94        case AF_INET:
  95                hash = __nlm_hash_addr4(sap);
  96                break;
  97        case AF_INET6:
  98                hash = __nlm_hash_addr6(sap);
  99                break;
 100        default:
 101                hash = 0;
 102        }
 103        return hash & (NLM_HOST_NRHASH - 1);
 104}
 105
 106/*
 107 * Allocate and initialize an nlm_host.  Common to both client and server.
 108 */
 109static struct nlm_host *nlm_alloc_host(struct nlm_lookup_host_info *ni,
 110                                       struct nsm_handle *nsm)
 111{
 112        struct nlm_host *host = NULL;
 113        unsigned long now = jiffies;
 114
 115        if (nsm != NULL)
 116                atomic_inc(&nsm->sm_count);
 117        else {
 118                host = NULL;
 119                nsm = nsm_get_handle(ni->net, ni->sap, ni->salen,
 120                                        ni->hostname, ni->hostname_len);
 121                if (unlikely(nsm == NULL)) {
 122                        dprintk("lockd: %s failed; no nsm handle\n",
 123                                __func__);
 124                        goto out;
 125                }
 126        }
 127
 128        host = kmalloc(sizeof(*host), GFP_KERNEL);
 129        if (unlikely(host == NULL)) {
 130                dprintk("lockd: %s failed; no memory\n", __func__);
 131                nsm_release(nsm);
 132                goto out;
 133        }
 134
 135        memcpy(nlm_addr(host), ni->sap, ni->salen);
 136        host->h_addrlen    = ni->salen;
 137        rpc_set_port(nlm_addr(host), 0);
 138        host->h_srcaddrlen = 0;
 139
 140        host->h_rpcclnt    = NULL;
 141        host->h_name       = nsm->sm_name;
 142        host->h_version    = ni->version;
 143        host->h_proto      = ni->protocol;
 144        host->h_reclaiming = 0;
 145        host->h_server     = ni->server;
 146        host->h_noresvport = ni->noresvport;
 147        host->h_inuse      = 0;
 148        init_waitqueue_head(&host->h_gracewait);
 149        init_rwsem(&host->h_rwsem);
 150        host->h_state      = 0;
 151        host->h_nsmstate   = 0;
 152        host->h_pidcount   = 0;
 153        atomic_set(&host->h_count, 1);
 154        mutex_init(&host->h_mutex);
 155        host->h_nextrebind = now + NLM_HOST_REBIND;
 156        host->h_expires    = now + NLM_HOST_EXPIRE;
 157        INIT_LIST_HEAD(&host->h_lockowners);
 158        spin_lock_init(&host->h_lock);
 159        INIT_LIST_HEAD(&host->h_granted);
 160        INIT_LIST_HEAD(&host->h_reclaim);
 161        host->h_nsmhandle  = nsm;
 162        host->h_addrbuf    = nsm->sm_addrbuf;
 163        host->net          = ni->net;
 164        strlcpy(host->nodename, utsname()->nodename, sizeof(host->nodename));
 165
 166out:
 167        return host;
 168}
 169
 170/*
 171 * Destroy an nlm_host and free associated resources
 172 *
 173 * Caller must hold nlm_host_mutex.
 174 */
 175static void nlm_destroy_host_locked(struct nlm_host *host)
 176{
 177        struct rpc_clnt *clnt;
 178        struct lockd_net *ln = net_generic(host->net, lockd_net_id);
 179
 180        dprintk("lockd: destroy host %s\n", host->h_name);
 181
 182        hlist_del_init(&host->h_hash);
 183
 184        nsm_unmonitor(host);
 185        nsm_release(host->h_nsmhandle);
 186
 187        clnt = host->h_rpcclnt;
 188        if (clnt != NULL)
 189                rpc_shutdown_client(clnt);
 190        kfree(host);
 191
 192        ln->nrhosts--;
 193        nrhosts--;
 194}
 195
 196/**
 197 * nlmclnt_lookup_host - Find an NLM host handle matching a remote server
 198 * @sap: network address of server
 199 * @salen: length of server address
 200 * @protocol: transport protocol to use
 201 * @version: NLM protocol version
 202 * @hostname: '\0'-terminated hostname of server
 203 * @noresvport: 1 if non-privileged port should be used
 204 *
 205 * Returns an nlm_host structure that matches the passed-in
 206 * [server address, transport protocol, NLM version, server hostname].
 207 * If one doesn't already exist in the host cache, a new handle is
 208 * created and returned.
 209 */
 210struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap,
 211                                     const size_t salen,
 212                                     const unsigned short protocol,
 213                                     const u32 version,
 214                                     const char *hostname,
 215                                     int noresvport,
 216                                     struct net *net)
 217{
 218        struct nlm_lookup_host_info ni = {
 219                .server         = 0,
 220                .sap            = sap,
 221                .salen          = salen,
 222                .protocol       = protocol,
 223                .version        = version,
 224                .hostname       = hostname,
 225                .hostname_len   = strlen(hostname),
 226                .noresvport     = noresvport,
 227                .net            = net,
 228        };
 229        struct hlist_head *chain;
 230        struct nlm_host *host;
 231        struct nsm_handle *nsm = NULL;
 232        struct lockd_net *ln = net_generic(net, lockd_net_id);
 233
 234        dprintk("lockd: %s(host='%s', vers=%u, proto=%s)\n", __func__,
 235                        (hostname ? hostname : "<none>"), version,
 236                        (protocol == IPPROTO_UDP ? "udp" : "tcp"));
 237
 238        mutex_lock(&nlm_host_mutex);
 239
 240        chain = &nlm_client_hosts[nlm_hash_address(sap)];
 241        hlist_for_each_entry(host, chain, h_hash) {
 242                if (host->net != net)
 243                        continue;
 244                if (!rpc_cmp_addr(nlm_addr(host), sap))
 245                        continue;
 246
 247                /* Same address. Share an NSM handle if we already have one */
 248                if (nsm == NULL)
 249                        nsm = host->h_nsmhandle;
 250
 251                if (host->h_proto != protocol)
 252                        continue;
 253                if (host->h_version != version)
 254                        continue;
 255
 256                nlm_get_host(host);
 257                dprintk("lockd: %s found host %s (%s)\n", __func__,
 258                        host->h_name, host->h_addrbuf);
 259                goto out;
 260        }
 261
 262        host = nlm_alloc_host(&ni, nsm);
 263        if (unlikely(host == NULL))
 264                goto out;
 265
 266        hlist_add_head(&host->h_hash, chain);
 267        ln->nrhosts++;
 268        nrhosts++;
 269
 270        dprintk("lockd: %s created host %s (%s)\n", __func__,
 271                host->h_name, host->h_addrbuf);
 272
 273out:
 274        mutex_unlock(&nlm_host_mutex);
 275        return host;
 276}
 277
 278/**
 279 * nlmclnt_release_host - release client nlm_host
 280 * @host: nlm_host to release
 281 *
 282 */
 283void nlmclnt_release_host(struct nlm_host *host)
 284{
 285        if (host == NULL)
 286                return;
 287
 288        dprintk("lockd: release client host %s\n", host->h_name);
 289
 290        WARN_ON_ONCE(host->h_server);
 291
 292        if (atomic_dec_and_test(&host->h_count)) {
 293                WARN_ON_ONCE(!list_empty(&host->h_lockowners));
 294                WARN_ON_ONCE(!list_empty(&host->h_granted));
 295                WARN_ON_ONCE(!list_empty(&host->h_reclaim));
 296
 297                mutex_lock(&nlm_host_mutex);
 298                nlm_destroy_host_locked(host);
 299                mutex_unlock(&nlm_host_mutex);
 300        }
 301}
 302
 303/**
 304 * nlmsvc_lookup_host - Find an NLM host handle matching a remote client
 305 * @rqstp: incoming NLM request
 306 * @hostname: name of client host
 307 * @hostname_len: length of client hostname
 308 *
 309 * Returns an nlm_host structure that matches the [client address,
 310 * transport protocol, NLM version, client hostname] of the passed-in
 311 * NLM request.  If one doesn't already exist in the host cache, a
 312 * new handle is created and returned.
 313 *
 314 * Before possibly creating a new nlm_host, construct a sockaddr
 315 * for a specific source address in case the local system has
 316 * multiple network addresses.  The family of the address in
 317 * rq_daddr is guaranteed to be the same as the family of the
 318 * address in rq_addr, so it's safe to use the same family for
 319 * the source address.
 320 */
 321struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp,
 322                                    const char *hostname,
 323                                    const size_t hostname_len)
 324{
 325        struct hlist_head *chain;
 326        struct nlm_host *host = NULL;
 327        struct nsm_handle *nsm = NULL;
 328        struct sockaddr *src_sap = svc_daddr(rqstp);
 329        size_t src_len = rqstp->rq_daddrlen;
 330        struct net *net = SVC_NET(rqstp);
 331        struct nlm_lookup_host_info ni = {
 332                .server         = 1,
 333                .sap            = svc_addr(rqstp),
 334                .salen          = rqstp->rq_addrlen,
 335                .protocol       = rqstp->rq_prot,
 336                .version        = rqstp->rq_vers,
 337                .hostname       = hostname,
 338                .hostname_len   = hostname_len,
 339                .net            = net,
 340        };
 341        struct lockd_net *ln = net_generic(net, lockd_net_id);
 342
 343        dprintk("lockd: %s(host='%*s', vers=%u, proto=%s)\n", __func__,
 344                        (int)hostname_len, hostname, rqstp->rq_vers,
 345                        (rqstp->rq_prot == IPPROTO_UDP ? "udp" : "tcp"));
 346
 347        mutex_lock(&nlm_host_mutex);
 348
 349        if (time_after_eq(jiffies, ln->next_gc))
 350                nlm_gc_hosts(net);
 351
 352        chain = &nlm_server_hosts[nlm_hash_address(ni.sap)];
 353        hlist_for_each_entry(host, chain, h_hash) {
 354                if (host->net != net)
 355                        continue;
 356                if (!rpc_cmp_addr(nlm_addr(host), ni.sap))
 357                        continue;
 358
 359                /* Same address. Share an NSM handle if we already have one */
 360                if (nsm == NULL)
 361                        nsm = host->h_nsmhandle;
 362
 363                if (host->h_proto != ni.protocol)
 364                        continue;
 365                if (host->h_version != ni.version)
 366                        continue;
 367                if (!rpc_cmp_addr(nlm_srcaddr(host), src_sap))
 368                        continue;
 369
 370                /* Move to head of hash chain. */
 371                hlist_del(&host->h_hash);
 372                hlist_add_head(&host->h_hash, chain);
 373
 374                nlm_get_host(host);
 375                dprintk("lockd: %s found host %s (%s)\n",
 376                        __func__, host->h_name, host->h_addrbuf);
 377                goto out;
 378        }
 379
 380        host = nlm_alloc_host(&ni, nsm);
 381        if (unlikely(host == NULL))
 382                goto out;
 383
 384        memcpy(nlm_srcaddr(host), src_sap, src_len);
 385        host->h_srcaddrlen = src_len;
 386        hlist_add_head(&host->h_hash, chain);
 387        ln->nrhosts++;
 388        nrhosts++;
 389
 390        dprintk("lockd: %s created host %s (%s)\n",
 391                __func__, host->h_name, host->h_addrbuf);
 392
 393out:
 394        mutex_unlock(&nlm_host_mutex);
 395        return host;
 396}
 397
 398/**
 399 * nlmsvc_release_host - release server nlm_host
 400 * @host: nlm_host to release
 401 *
 402 * Host is destroyed later in nlm_gc_host().
 403 */
 404void nlmsvc_release_host(struct nlm_host *host)
 405{
 406        if (host == NULL)
 407                return;
 408
 409        dprintk("lockd: release server host %s\n", host->h_name);
 410
 411        WARN_ON_ONCE(!host->h_server);
 412        atomic_dec(&host->h_count);
 413}
 414
 415/*
 416 * Create the NLM RPC client for an NLM peer
 417 */
 418struct rpc_clnt *
 419nlm_bind_host(struct nlm_host *host)
 420{
 421        struct rpc_clnt *clnt;
 422
 423        dprintk("lockd: nlm_bind_host %s (%s)\n",
 424                        host->h_name, host->h_addrbuf);
 425
 426        /* Lock host handle */
 427        mutex_lock(&host->h_mutex);
 428
 429        /* If we've already created an RPC client, check whether
 430         * RPC rebind is required
 431         */
 432        if ((clnt = host->h_rpcclnt) != NULL) {
 433                if (time_after_eq(jiffies, host->h_nextrebind)) {
 434                        rpc_force_rebind(clnt);
 435                        host->h_nextrebind = jiffies + NLM_HOST_REBIND;
 436                        dprintk("lockd: next rebind in %lu jiffies\n",
 437                                        host->h_nextrebind - jiffies);
 438                }
 439        } else {
 440                unsigned long increment = nlmsvc_timeout;
 441                struct rpc_timeout timeparms = {
 442                        .to_initval     = increment,
 443                        .to_increment   = increment,
 444                        .to_maxval      = increment * 6UL,
 445                        .to_retries     = 5U,
 446                };
 447                struct rpc_create_args args = {
 448                        .net            = host->net,
 449                        .protocol       = host->h_proto,
 450                        .address        = nlm_addr(host),
 451                        .addrsize       = host->h_addrlen,
 452                        .timeout        = &timeparms,
 453                        .servername     = host->h_name,
 454                        .program        = &nlm_program,
 455                        .version        = host->h_version,
 456                        .authflavor     = RPC_AUTH_UNIX,
 457                        .flags          = (RPC_CLNT_CREATE_NOPING |
 458                                           RPC_CLNT_CREATE_AUTOBIND),
 459                };
 460
 461                /*
 462                 * lockd retries server side blocks automatically so we want
 463                 * those to be soft RPC calls. Client side calls need to be
 464                 * hard RPC tasks.
 465                 */
 466                if (!host->h_server)
 467                        args.flags |= RPC_CLNT_CREATE_HARDRTRY;
 468                if (host->h_noresvport)
 469                        args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
 470                if (host->h_srcaddrlen)
 471                        args.saddress = nlm_srcaddr(host);
 472
 473                clnt = rpc_create(&args);
 474                if (!IS_ERR(clnt))
 475                        host->h_rpcclnt = clnt;
 476                else {
 477                        printk("lockd: couldn't create RPC handle for %s\n", host->h_name);
 478                        clnt = NULL;
 479                }
 480        }
 481
 482        mutex_unlock(&host->h_mutex);
 483        return clnt;
 484}
 485
 486/*
 487 * Force a portmap lookup of the remote lockd port
 488 */
 489void
 490nlm_rebind_host(struct nlm_host *host)
 491{
 492        dprintk("lockd: rebind host %s\n", host->h_name);
 493        if (host->h_rpcclnt && time_after_eq(jiffies, host->h_nextrebind)) {
 494                rpc_force_rebind(host->h_rpcclnt);
 495                host->h_nextrebind = jiffies + NLM_HOST_REBIND;
 496        }
 497}
 498
 499/*
 500 * Increment NLM host count
 501 */
 502struct nlm_host * nlm_get_host(struct nlm_host *host)
 503{
 504        if (host) {
 505                dprintk("lockd: get host %s\n", host->h_name);
 506                atomic_inc(&host->h_count);
 507                host->h_expires = jiffies + NLM_HOST_EXPIRE;
 508        }
 509        return host;
 510}
 511
 512static struct nlm_host *next_host_state(struct hlist_head *cache,
 513                                        struct nsm_handle *nsm,
 514                                        const struct nlm_reboot *info)
 515{
 516        struct nlm_host *host;
 517        struct hlist_head *chain;
 518
 519        mutex_lock(&nlm_host_mutex);
 520        for_each_host(host, chain, cache) {
 521                if (host->h_nsmhandle == nsm
 522                    && host->h_nsmstate != info->state) {
 523                        host->h_nsmstate = info->state;
 524                        host->h_state++;
 525
 526                        nlm_get_host(host);
 527                        mutex_unlock(&nlm_host_mutex);
 528                        return host;
 529                }
 530        }
 531
 532        mutex_unlock(&nlm_host_mutex);
 533        return NULL;
 534}
 535
 536/**
 537 * nlm_host_rebooted - Release all resources held by rebooted host
 538 * @net:  network namespace
 539 * @info: pointer to decoded results of NLM_SM_NOTIFY call
 540 *
 541 * We were notified that the specified host has rebooted.  Release
 542 * all resources held by that peer.
 543 */
 544void nlm_host_rebooted(const struct net *net, const struct nlm_reboot *info)
 545{
 546        struct nsm_handle *nsm;
 547        struct nlm_host *host;
 548
 549        nsm = nsm_reboot_lookup(net, info);
 550        if (unlikely(nsm == NULL))
 551                return;
 552
 553        /* Mark all hosts tied to this NSM state as having rebooted.
 554         * We run the loop repeatedly, because we drop the host table
 555         * lock for this.
 556         * To avoid processing a host several times, we match the nsmstate.
 557         */
 558        while ((host = next_host_state(nlm_server_hosts, nsm, info)) != NULL) {
 559                nlmsvc_free_host_resources(host);
 560                nlmsvc_release_host(host);
 561        }
 562        while ((host = next_host_state(nlm_client_hosts, nsm, info)) != NULL) {
 563                nlmclnt_recovery(host);
 564                nlmclnt_release_host(host);
 565        }
 566
 567        nsm_release(nsm);
 568}
 569
 570static void nlm_complain_hosts(struct net *net)
 571{
 572        struct hlist_head *chain;
 573        struct nlm_host *host;
 574
 575        if (net) {
 576                struct lockd_net *ln = net_generic(net, lockd_net_id);
 577
 578                if (ln->nrhosts == 0)
 579                        return;
 580                printk(KERN_WARNING "lockd: couldn't shutdown host module for net %p!\n", net);
 581                dprintk("lockd: %lu hosts left in net %p:\n", ln->nrhosts, net);
 582        } else {
 583                if (nrhosts == 0)
 584                        return;
 585                printk(KERN_WARNING "lockd: couldn't shutdown host module!\n");
 586                dprintk("lockd: %lu hosts left:\n", nrhosts);
 587        }
 588
 589        for_each_host(host, chain, nlm_server_hosts) {
 590                if (net && host->net != net)
 591                        continue;
 592                dprintk("       %s (cnt %d use %d exp %ld net %p)\n",
 593                        host->h_name, atomic_read(&host->h_count),
 594                        host->h_inuse, host->h_expires, host->net);
 595        }
 596}
 597
 598void
 599nlm_shutdown_hosts_net(struct net *net)
 600{
 601        struct hlist_head *chain;
 602        struct nlm_host *host;
 603
 604        mutex_lock(&nlm_host_mutex);
 605
 606        /* First, make all hosts eligible for gc */
 607        dprintk("lockd: nuking all hosts in net %p...\n", net);
 608        for_each_host(host, chain, nlm_server_hosts) {
 609                if (net && host->net != net)
 610                        continue;
 611                host->h_expires = jiffies - 1;
 612                if (host->h_rpcclnt) {
 613                        rpc_shutdown_client(host->h_rpcclnt);
 614                        host->h_rpcclnt = NULL;
 615                }
 616        }
 617
 618        /* Then, perform a garbage collection pass */
 619        nlm_gc_hosts(net);
 620        mutex_unlock(&nlm_host_mutex);
 621
 622        nlm_complain_hosts(net);
 623}
 624
 625/*
 626 * Shut down the hosts module.
 627 * Note that this routine is called only at server shutdown time.
 628 */
 629void
 630nlm_shutdown_hosts(void)
 631{
 632        dprintk("lockd: shutting down host module\n");
 633        nlm_shutdown_hosts_net(NULL);
 634}
 635
 636/*
 637 * Garbage collect any unused NLM hosts.
 638 * This GC combines reference counting for async operations with
 639 * mark & sweep for resources held by remote clients.
 640 */
 641static void
 642nlm_gc_hosts(struct net *net)
 643{
 644        struct hlist_head *chain;
 645        struct hlist_node *next;
 646        struct nlm_host *host;
 647
 648        dprintk("lockd: host garbage collection for net %p\n", net);
 649        for_each_host(host, chain, nlm_server_hosts) {
 650                if (net && host->net != net)
 651                        continue;
 652                host->h_inuse = 0;
 653        }
 654
 655        /* Mark all hosts that hold locks, blocks or shares */
 656        nlmsvc_mark_resources(net);
 657
 658        for_each_host_safe(host, next, chain, nlm_server_hosts) {
 659                if (net && host->net != net)
 660                        continue;
 661                if (atomic_read(&host->h_count) || host->h_inuse
 662                 || time_before(jiffies, host->h_expires)) {
 663                        dprintk("nlm_gc_hosts skipping %s "
 664                                "(cnt %d use %d exp %ld net %p)\n",
 665                                host->h_name, atomic_read(&host->h_count),
 666                                host->h_inuse, host->h_expires, host->net);
 667                        continue;
 668                }
 669                nlm_destroy_host_locked(host);
 670        }
 671
 672        if (net) {
 673                struct lockd_net *ln = net_generic(net, lockd_net_id);
 674
 675                ln->next_gc = jiffies + NLM_HOST_COLLECT;
 676        }
 677}
 678