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
 165out:
 166        return host;
 167}
 168
 169/*
 170 * Destroy an nlm_host and free associated resources
 171 *
 172 * Caller must hold nlm_host_mutex.
 173 */
 174static void nlm_destroy_host_locked(struct nlm_host *host)
 175{
 176        struct rpc_clnt *clnt;
 177        struct lockd_net *ln = net_generic(host->net, lockd_net_id);
 178
 179        dprintk("lockd: destroy host %s\n", host->h_name);
 180
 181        hlist_del_init(&host->h_hash);
 182
 183        nsm_unmonitor(host);
 184        nsm_release(host->h_nsmhandle);
 185
 186        clnt = host->h_rpcclnt;
 187        if (clnt != NULL)
 188                rpc_shutdown_client(clnt);
 189        kfree(host);
 190
 191        ln->nrhosts--;
 192        nrhosts--;
 193}
 194
 195/**
 196 * nlmclnt_lookup_host - Find an NLM host handle matching a remote server
 197 * @sap: network address of server
 198 * @salen: length of server address
 199 * @protocol: transport protocol to use
 200 * @version: NLM protocol version
 201 * @hostname: '\0'-terminated hostname of server
 202 * @noresvport: 1 if non-privileged port should be used
 203 *
 204 * Returns an nlm_host structure that matches the passed-in
 205 * [server address, transport protocol, NLM version, server hostname].
 206 * If one doesn't already exist in the host cache, a new handle is
 207 * created and returned.
 208 */
 209struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap,
 210                                     const size_t salen,
 211                                     const unsigned short protocol,
 212                                     const u32 version,
 213                                     const char *hostname,
 214                                     int noresvport,
 215                                     struct net *net)
 216{
 217        struct nlm_lookup_host_info ni = {
 218                .server         = 0,
 219                .sap            = sap,
 220                .salen          = salen,
 221                .protocol       = protocol,
 222                .version        = version,
 223                .hostname       = hostname,
 224                .hostname_len   = strlen(hostname),
 225                .noresvport     = noresvport,
 226                .net            = net,
 227        };
 228        struct hlist_head *chain;
 229        struct nlm_host *host;
 230        struct nsm_handle *nsm = NULL;
 231        struct lockd_net *ln = net_generic(net, lockd_net_id);
 232
 233        dprintk("lockd: %s(host='%s', vers=%u, proto=%s)\n", __func__,
 234                        (hostname ? hostname : "<none>"), version,
 235                        (protocol == IPPROTO_UDP ? "udp" : "tcp"));
 236
 237        mutex_lock(&nlm_host_mutex);
 238
 239        chain = &nlm_client_hosts[nlm_hash_address(sap)];
 240        hlist_for_each_entry(host, chain, h_hash) {
 241                if (host->net != net)
 242                        continue;
 243                if (!rpc_cmp_addr(nlm_addr(host), sap))
 244                        continue;
 245
 246                /* Same address. Share an NSM handle if we already have one */
 247                if (nsm == NULL)
 248                        nsm = host->h_nsmhandle;
 249
 250                if (host->h_proto != protocol)
 251                        continue;
 252                if (host->h_version != version)
 253                        continue;
 254
 255                nlm_get_host(host);
 256                dprintk("lockd: %s found host %s (%s)\n", __func__,
 257                        host->h_name, host->h_addrbuf);
 258                goto out;
 259        }
 260
 261        host = nlm_alloc_host(&ni, nsm);
 262        if (unlikely(host == NULL))
 263                goto out;
 264
 265        hlist_add_head(&host->h_hash, chain);
 266        ln->nrhosts++;
 267        nrhosts++;
 268
 269        dprintk("lockd: %s created host %s (%s)\n", __func__,
 270                host->h_name, host->h_addrbuf);
 271
 272out:
 273        mutex_unlock(&nlm_host_mutex);
 274        return host;
 275}
 276
 277/**
 278 * nlmclnt_release_host - release client nlm_host
 279 * @host: nlm_host to release
 280 *
 281 */
 282void nlmclnt_release_host(struct nlm_host *host)
 283{
 284        if (host == NULL)
 285                return;
 286
 287        dprintk("lockd: release client host %s\n", host->h_name);
 288
 289        WARN_ON_ONCE(host->h_server);
 290
 291        if (atomic_dec_and_test(&host->h_count)) {
 292                WARN_ON_ONCE(!list_empty(&host->h_lockowners));
 293                WARN_ON_ONCE(!list_empty(&host->h_granted));
 294                WARN_ON_ONCE(!list_empty(&host->h_reclaim));
 295
 296                mutex_lock(&nlm_host_mutex);
 297                nlm_destroy_host_locked(host);
 298                mutex_unlock(&nlm_host_mutex);
 299        }
 300}
 301
 302/**
 303 * nlmsvc_lookup_host - Find an NLM host handle matching a remote client
 304 * @rqstp: incoming NLM request
 305 * @hostname: name of client host
 306 * @hostname_len: length of client hostname
 307 *
 308 * Returns an nlm_host structure that matches the [client address,
 309 * transport protocol, NLM version, client hostname] of the passed-in
 310 * NLM request.  If one doesn't already exist in the host cache, a
 311 * new handle is created and returned.
 312 *
 313 * Before possibly creating a new nlm_host, construct a sockaddr
 314 * for a specific source address in case the local system has
 315 * multiple network addresses.  The family of the address in
 316 * rq_daddr is guaranteed to be the same as the family of the
 317 * address in rq_addr, so it's safe to use the same family for
 318 * the source address.
 319 */
 320struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp,
 321                                    const char *hostname,
 322                                    const size_t hostname_len)
 323{
 324        struct hlist_head *chain;
 325        struct nlm_host *host = NULL;
 326        struct nsm_handle *nsm = NULL;
 327        struct sockaddr *src_sap = svc_daddr(rqstp);
 328        size_t src_len = rqstp->rq_daddrlen;
 329        struct net *net = SVC_NET(rqstp);
 330        struct nlm_lookup_host_info ni = {
 331                .server         = 1,
 332                .sap            = svc_addr(rqstp),
 333                .salen          = rqstp->rq_addrlen,
 334                .protocol       = rqstp->rq_prot,
 335                .version        = rqstp->rq_vers,
 336                .hostname       = hostname,
 337                .hostname_len   = hostname_len,
 338                .net            = net,
 339        };
 340        struct lockd_net *ln = net_generic(net, lockd_net_id);
 341
 342        dprintk("lockd: %s(host='%*s', vers=%u, proto=%s)\n", __func__,
 343                        (int)hostname_len, hostname, rqstp->rq_vers,
 344                        (rqstp->rq_prot == IPPROTO_UDP ? "udp" : "tcp"));
 345
 346        mutex_lock(&nlm_host_mutex);
 347
 348        if (time_after_eq(jiffies, ln->next_gc))
 349                nlm_gc_hosts(net);
 350
 351        chain = &nlm_server_hosts[nlm_hash_address(ni.sap)];
 352        hlist_for_each_entry(host, chain, h_hash) {
 353                if (host->net != net)
 354                        continue;
 355                if (!rpc_cmp_addr(nlm_addr(host), ni.sap))
 356                        continue;
 357
 358                /* Same address. Share an NSM handle if we already have one */
 359                if (nsm == NULL)
 360                        nsm = host->h_nsmhandle;
 361
 362                if (host->h_proto != ni.protocol)
 363                        continue;
 364                if (host->h_version != ni.version)
 365                        continue;
 366                if (!rpc_cmp_addr(nlm_srcaddr(host), src_sap))
 367                        continue;
 368
 369                /* Move to head of hash chain. */
 370                hlist_del(&host->h_hash);
 371                hlist_add_head(&host->h_hash, chain);
 372
 373                nlm_get_host(host);
 374                dprintk("lockd: %s found host %s (%s)\n",
 375                        __func__, host->h_name, host->h_addrbuf);
 376                goto out;
 377        }
 378
 379        host = nlm_alloc_host(&ni, nsm);
 380        if (unlikely(host == NULL))
 381                goto out;
 382
 383        memcpy(nlm_srcaddr(host), src_sap, src_len);
 384        host->h_srcaddrlen = src_len;
 385        hlist_add_head(&host->h_hash, chain);
 386        ln->nrhosts++;
 387        nrhosts++;
 388
 389        dprintk("lockd: %s created host %s (%s)\n",
 390                __func__, host->h_name, host->h_addrbuf);
 391
 392out:
 393        mutex_unlock(&nlm_host_mutex);
 394        return host;
 395}
 396
 397/**
 398 * nlmsvc_release_host - release server nlm_host
 399 * @host: nlm_host to release
 400 *
 401 * Host is destroyed later in nlm_gc_host().
 402 */
 403void nlmsvc_release_host(struct nlm_host *host)
 404{
 405        if (host == NULL)
 406                return;
 407
 408        dprintk("lockd: release server host %s\n", host->h_name);
 409
 410        WARN_ON_ONCE(!host->h_server);
 411        atomic_dec(&host->h_count);
 412}
 413
 414/*
 415 * Create the NLM RPC client for an NLM peer
 416 */
 417struct rpc_clnt *
 418nlm_bind_host(struct nlm_host *host)
 419{
 420        struct rpc_clnt *clnt;
 421
 422        dprintk("lockd: nlm_bind_host %s (%s)\n",
 423                        host->h_name, host->h_addrbuf);
 424
 425        /* Lock host handle */
 426        mutex_lock(&host->h_mutex);
 427
 428        /* If we've already created an RPC client, check whether
 429         * RPC rebind is required
 430         */
 431        if ((clnt = host->h_rpcclnt) != NULL) {
 432                if (time_after_eq(jiffies, host->h_nextrebind)) {
 433                        rpc_force_rebind(clnt);
 434                        host->h_nextrebind = jiffies + NLM_HOST_REBIND;
 435                        dprintk("lockd: next rebind in %lu jiffies\n",
 436                                        host->h_nextrebind - jiffies);
 437                }
 438        } else {
 439                unsigned long increment = nlmsvc_timeout;
 440                struct rpc_timeout timeparms = {
 441                        .to_initval     = increment,
 442                        .to_increment   = increment,
 443                        .to_maxval      = increment * 6UL,
 444                        .to_retries     = 5U,
 445                };
 446                struct rpc_create_args args = {
 447                        .net            = host->net,
 448                        .protocol       = host->h_proto,
 449                        .address        = nlm_addr(host),
 450                        .addrsize       = host->h_addrlen,
 451                        .timeout        = &timeparms,
 452                        .servername     = host->h_name,
 453                        .program        = &nlm_program,
 454                        .version        = host->h_version,
 455                        .authflavor     = RPC_AUTH_UNIX,
 456                        .flags          = (RPC_CLNT_CREATE_NOPING |
 457                                           RPC_CLNT_CREATE_AUTOBIND),
 458                };
 459
 460                /*
 461                 * lockd retries server side blocks automatically so we want
 462                 * those to be soft RPC calls. Client side calls need to be
 463                 * hard RPC tasks.
 464                 */
 465                if (!host->h_server)
 466                        args.flags |= RPC_CLNT_CREATE_HARDRTRY;
 467                if (host->h_noresvport)
 468                        args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
 469                if (host->h_srcaddrlen)
 470                        args.saddress = nlm_srcaddr(host);
 471
 472                clnt = rpc_create(&args);
 473                if (!IS_ERR(clnt))
 474                        host->h_rpcclnt = clnt;
 475                else {
 476                        printk("lockd: couldn't create RPC handle for %s\n", host->h_name);
 477                        clnt = NULL;
 478                }
 479        }
 480
 481        mutex_unlock(&host->h_mutex);
 482        return clnt;
 483}
 484
 485/*
 486 * Force a portmap lookup of the remote lockd port
 487 */
 488void
 489nlm_rebind_host(struct nlm_host *host)
 490{
 491        dprintk("lockd: rebind host %s\n", host->h_name);
 492        if (host->h_rpcclnt && time_after_eq(jiffies, host->h_nextrebind)) {
 493                rpc_force_rebind(host->h_rpcclnt);
 494                host->h_nextrebind = jiffies + NLM_HOST_REBIND;
 495        }
 496}
 497
 498/*
 499 * Increment NLM host count
 500 */
 501struct nlm_host * nlm_get_host(struct nlm_host *host)
 502{
 503        if (host) {
 504                dprintk("lockd: get host %s\n", host->h_name);
 505                atomic_inc(&host->h_count);
 506                host->h_expires = jiffies + NLM_HOST_EXPIRE;
 507        }
 508        return host;
 509}
 510
 511static struct nlm_host *next_host_state(struct hlist_head *cache,
 512                                        struct nsm_handle *nsm,
 513                                        const struct nlm_reboot *info)
 514{
 515        struct nlm_host *host;
 516        struct hlist_head *chain;
 517
 518        mutex_lock(&nlm_host_mutex);
 519        for_each_host(host, chain, cache) {
 520                if (host->h_nsmhandle == nsm
 521                    && host->h_nsmstate != info->state) {
 522                        host->h_nsmstate = info->state;
 523                        host->h_state++;
 524
 525                        nlm_get_host(host);
 526                        mutex_unlock(&nlm_host_mutex);
 527                        return host;
 528                }
 529        }
 530
 531        mutex_unlock(&nlm_host_mutex);
 532        return NULL;
 533}
 534
 535/**
 536 * nlm_host_rebooted - Release all resources held by rebooted host
 537 * @net:  network namespace
 538 * @info: pointer to decoded results of NLM_SM_NOTIFY call
 539 *
 540 * We were notified that the specified host has rebooted.  Release
 541 * all resources held by that peer.
 542 */
 543void nlm_host_rebooted(const struct net *net, const struct nlm_reboot *info)
 544{
 545        struct nsm_handle *nsm;
 546        struct nlm_host *host;
 547
 548        nsm = nsm_reboot_lookup(net, info);
 549        if (unlikely(nsm == NULL))
 550                return;
 551
 552        /* Mark all hosts tied to this NSM state as having rebooted.
 553         * We run the loop repeatedly, because we drop the host table
 554         * lock for this.
 555         * To avoid processing a host several times, we match the nsmstate.
 556         */
 557        while ((host = next_host_state(nlm_server_hosts, nsm, info)) != NULL) {
 558                nlmsvc_free_host_resources(host);
 559                nlmsvc_release_host(host);
 560        }
 561        while ((host = next_host_state(nlm_client_hosts, nsm, info)) != NULL) {
 562                nlmclnt_recovery(host);
 563                nlmclnt_release_host(host);
 564        }
 565
 566        nsm_release(nsm);
 567}
 568
 569static void nlm_complain_hosts(struct net *net)
 570{
 571        struct hlist_head *chain;
 572        struct nlm_host *host;
 573
 574        if (net) {
 575                struct lockd_net *ln = net_generic(net, lockd_net_id);
 576
 577                if (ln->nrhosts == 0)
 578                        return;
 579                printk(KERN_WARNING "lockd: couldn't shutdown host module for net %p!\n", net);
 580                dprintk("lockd: %lu hosts left in net %p:\n", ln->nrhosts, net);
 581        } else {
 582                if (nrhosts == 0)
 583                        return;
 584                printk(KERN_WARNING "lockd: couldn't shutdown host module!\n");
 585                dprintk("lockd: %lu hosts left:\n", nrhosts);
 586        }
 587
 588        for_each_host(host, chain, nlm_server_hosts) {
 589                if (net && host->net != net)
 590                        continue;
 591                dprintk("       %s (cnt %d use %d exp %ld net %p)\n",
 592                        host->h_name, atomic_read(&host->h_count),
 593                        host->h_inuse, host->h_expires, host->net);
 594        }
 595}
 596
 597void
 598nlm_shutdown_hosts_net(struct net *net)
 599{
 600        struct hlist_head *chain;
 601        struct nlm_host *host;
 602
 603        mutex_lock(&nlm_host_mutex);
 604
 605        /* First, make all hosts eligible for gc */
 606        dprintk("lockd: nuking all hosts in net %p...\n", net);
 607        for_each_host(host, chain, nlm_server_hosts) {
 608                if (net && host->net != net)
 609                        continue;
 610                host->h_expires = jiffies - 1;
 611                if (host->h_rpcclnt) {
 612                        rpc_shutdown_client(host->h_rpcclnt);
 613                        host->h_rpcclnt = NULL;
 614                }
 615        }
 616
 617        /* Then, perform a garbage collection pass */
 618        nlm_gc_hosts(net);
 619        mutex_unlock(&nlm_host_mutex);
 620
 621        nlm_complain_hosts(net);
 622}
 623
 624/*
 625 * Shut down the hosts module.
 626 * Note that this routine is called only at server shutdown time.
 627 */
 628void
 629nlm_shutdown_hosts(void)
 630{
 631        dprintk("lockd: shutting down host module\n");
 632        nlm_shutdown_hosts_net(NULL);
 633}
 634
 635/*
 636 * Garbage collect any unused NLM hosts.
 637 * This GC combines reference counting for async operations with
 638 * mark & sweep for resources held by remote clients.
 639 */
 640static void
 641nlm_gc_hosts(struct net *net)
 642{
 643        struct hlist_head *chain;
 644        struct hlist_node *next;
 645        struct nlm_host *host;
 646
 647        dprintk("lockd: host garbage collection for net %p\n", net);
 648        for_each_host(host, chain, nlm_server_hosts) {
 649                if (net && host->net != net)
 650                        continue;
 651                host->h_inuse = 0;
 652        }
 653
 654        /* Mark all hosts that hold locks, blocks or shares */
 655        nlmsvc_mark_resources(net);
 656
 657        for_each_host_safe(host, next, chain, nlm_server_hosts) {
 658                if (net && host->net != net)
 659                        continue;
 660                if (atomic_read(&host->h_count) || host->h_inuse
 661                 || time_before(jiffies, host->h_expires)) {
 662                        dprintk("nlm_gc_hosts skipping %s "
 663                                "(cnt %d use %d exp %ld net %p)\n",
 664                                host->h_name, atomic_read(&host->h_count),
 665                                host->h_inuse, host->h_expires, host->net);
 666                        continue;
 667                }
 668                nlm_destroy_host_locked(host);
 669        }
 670
 671        if (net) {
 672                struct lockd_net *ln = net_generic(net, lockd_net_id);
 673
 674                ln->next_gc = jiffies + NLM_HOST_COLLECT;
 675        }
 676}
 677