The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/lockd/host.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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/sched.h>
   13 #include <linux/slab.h>
   14 #include <linux/in.h>
   15 #include <linux/sunrpc/clnt.h>
   16 #include <linux/sunrpc/svc.h>
   17 #include <linux/lockd/lockd.h>
   18 #include <linux/lockd/sm_inter.h>
   19 
   20 
   21 #define NLMDBG_FACILITY         NLMDBG_HOSTCACHE
   22 #define NLM_HOST_MAX            64
   23 #define NLM_HOST_NRHASH         32
   24 #define NLM_ADDRHASH(addr)      (ntohl(addr) & (NLM_HOST_NRHASH-1))
   25 #define NLM_PTRHASH(ptr)        ((((u32)(unsigned long) ptr) / 32) & (NLM_HOST_NRHASH-1))
   26 #define NLM_HOST_REBIND         (60 * HZ)
   27 #define NLM_HOST_EXPIRE         ((nrhosts > NLM_HOST_MAX)? 300 * HZ : 120 * HZ)
   28 #define NLM_HOST_COLLECT        ((nrhosts > NLM_HOST_MAX)? 120 * HZ :  60 * HZ)
   29 #define NLM_HOST_ADDR(sv)       (&(sv)->s_nlmclnt->cl_xprt->addr)
   30 
   31 static struct nlm_host *        nlm_hosts[NLM_HOST_NRHASH];
   32 static unsigned long            next_gc;
   33 static int                      nrhosts;
   34 static DECLARE_MUTEX(nlm_host_sema);
   35 
   36 
   37 static void                     nlm_gc_hosts(void);
   38 
   39 /*
   40  * Find an NLM server handle in the cache. If there is none, create it.
   41  */
   42 struct nlm_host *
   43 nlmclnt_lookup_host(struct sockaddr_in *sin, int proto, int version)
   44 {
   45         return nlm_lookup_host(NULL, sin, proto, version);
   46 }
   47 
   48 /*
   49  * Find an NLM client handle in the cache. If there is none, create it.
   50  */
   51 struct nlm_host *
   52 nlmsvc_lookup_host(struct svc_rqst *rqstp)
   53 {
   54         return nlm_lookup_host(rqstp->rq_client, &rqstp->rq_addr,
   55                                rqstp->rq_prot, rqstp->rq_vers);
   56 }
   57 
   58 /*
   59  * Match the given host against client/address
   60  */
   61 static inline int
   62 nlm_match_host(struct nlm_host *host, struct svc_client *clnt,
   63                                         struct sockaddr_in *sin)
   64 {
   65         if (clnt)
   66                 return host->h_exportent == clnt;
   67         return nlm_cmp_addr(&host->h_addr, sin);
   68 }
   69 
   70 /*
   71  * Common host lookup routine for server & client
   72  */
   73 struct nlm_host *
   74 nlm_lookup_host(struct svc_client *clnt, struct sockaddr_in *sin,
   75                                         int proto, int version)
   76 {
   77         struct nlm_host *host, **hp;
   78         u32             addr;
   79         int             hash;
   80 
   81         if (!clnt && !sin) {
   82                 printk(KERN_NOTICE "lockd: no clnt or addr in lookup_host!\n");
   83                 return NULL;
   84         }
   85 
   86         dprintk("lockd: nlm_lookup_host(%08x, p=%d, v=%d)\n",
   87                         (unsigned)(sin? ntohl(sin->sin_addr.s_addr) : 0), proto, version);
   88 
   89         if (clnt)
   90                 hash = NLM_PTRHASH(clnt);
   91         else
   92                 hash = NLM_ADDRHASH(sin->sin_addr.s_addr);
   93 
   94         /* Lock hash table */
   95         down(&nlm_host_sema);
   96 
   97         if (time_after_eq(jiffies, next_gc))
   98                 nlm_gc_hosts();
   99 
  100         for (hp = &nlm_hosts[hash]; (host = *hp); hp = &host->h_next) {
  101                 if (proto && host->h_proto != proto)
  102                         continue;
  103                 if (version && host->h_version != version)
  104                         continue;
  105 
  106                 if (nlm_match_host(host, clnt, sin)) {
  107                         if (hp != nlm_hosts + hash) {
  108                                 *hp = host->h_next;
  109                                 host->h_next = nlm_hosts[hash];
  110                                 nlm_hosts[hash] = host;
  111                         }
  112                         nlm_get_host(host);
  113                         up(&nlm_host_sema);
  114                         return host;
  115                 }
  116         }
  117 
  118         /* special hack for nlmsvc_invalidate_client */
  119         if (sin == NULL)
  120                 goto nohost;
  121 
  122         /* Ooops, no host found, create it */
  123         dprintk("lockd: creating host entry\n");
  124 
  125         if (!(host = (struct nlm_host *) kmalloc(sizeof(*host), GFP_KERNEL)))
  126                 goto nohost;
  127         memset(host, 0, sizeof(*host));
  128 
  129         addr = sin->sin_addr.s_addr;
  130         sprintf(host->h_name, "%d.%d.%d.%d",
  131                         (unsigned char) (ntohl(addr) >> 24),
  132                         (unsigned char) (ntohl(addr) >> 16),
  133                         (unsigned char) (ntohl(addr) >>  8),
  134                         (unsigned char) (ntohl(addr) >>  0));
  135 
  136         host->h_addr       = *sin;
  137         host->h_addr.sin_port = 0;      /* ouch! */
  138         host->h_version    = version;
  139         host->h_proto      = proto;
  140         host->h_authflavor = RPC_AUTH_UNIX;
  141         host->h_rpcclnt    = NULL;
  142         init_MUTEX(&host->h_sema);
  143         host->h_nextrebind = jiffies + NLM_HOST_REBIND;
  144         host->h_expires    = jiffies + NLM_HOST_EXPIRE;
  145         host->h_count      = 1;
  146         init_waitqueue_head(&host->h_gracewait);
  147         host->h_state      = 0;                 /* pseudo NSM state */
  148         host->h_nsmstate   = 0;                 /* real NSM state */
  149         host->h_exportent  = clnt;
  150 
  151         host->h_next       = nlm_hosts[hash];
  152         nlm_hosts[hash]    = host;
  153 
  154         if (++nrhosts > NLM_HOST_MAX)
  155                 next_gc = 0;
  156 
  157 nohost:
  158         up(&nlm_host_sema);
  159         return host;
  160 }
  161 
  162 /*
  163  * Create the NLM RPC client for an NLM peer
  164  */
  165 struct rpc_clnt *
  166 nlm_bind_host(struct nlm_host *host)
  167 {
  168         struct rpc_clnt *clnt;
  169         struct rpc_xprt *xprt;
  170 
  171         dprintk("lockd: nlm_bind_host(%08x)\n",
  172                         (unsigned)ntohl(host->h_addr.sin_addr.s_addr));
  173 
  174         /* Lock host handle */
  175         down(&host->h_sema);
  176 
  177         /* If we've already created an RPC client, check whether
  178          * RPC rebind is required
  179          * Note: why keep rebinding if we're on a tcp connection?
  180          */
  181         if ((clnt = host->h_rpcclnt) != NULL) {
  182                 xprt = clnt->cl_xprt;
  183                 if (!xprt->stream && time_after_eq(jiffies, host->h_nextrebind)) {
  184                         clnt->cl_port = 0;
  185                         host->h_nextrebind = jiffies + NLM_HOST_REBIND;
  186                         dprintk("lockd: next rebind in %ld jiffies\n",
  187                                         host->h_nextrebind - jiffies);
  188                 }
  189         } else {
  190                 xprt = xprt_create_proto(host->h_proto, &host->h_addr, NULL);
  191                 if (xprt == NULL)
  192                         goto forgetit;
  193 
  194                 xprt_set_timeout(&xprt->timeout, 5, nlmsvc_timeout);
  195 
  196                 clnt = rpc_create_client(xprt, host->h_name, &nlm_program,
  197                                         host->h_version, host->h_authflavor);
  198                 if (clnt == NULL) {
  199                         xprt_destroy(xprt);
  200                         goto forgetit;
  201                 }
  202                 clnt->cl_autobind = 1;  /* turn on pmap queries */
  203                 xprt->nocong = 1;       /* No congestion control for NLM */
  204                 xprt->resvport = 1;     /* NLM requires a reserved port */
  205 
  206                 host->h_rpcclnt = clnt;
  207         }
  208 
  209         up(&host->h_sema);
  210         return clnt;
  211 
  212 forgetit:
  213         printk("lockd: couldn't create RPC handle for %s\n", host->h_name);
  214         up(&host->h_sema);
  215         return NULL;
  216 }
  217 
  218 /*
  219  * Force a portmap lookup of the remote lockd port
  220  */
  221 void
  222 nlm_rebind_host(struct nlm_host *host)
  223 {
  224         dprintk("lockd: rebind host %s\n", host->h_name);
  225         if (host->h_rpcclnt && time_after_eq(jiffies, host->h_nextrebind)) {
  226                 host->h_rpcclnt->cl_port = 0;
  227                 host->h_nextrebind = jiffies + NLM_HOST_REBIND;
  228         }
  229 }
  230 
  231 /*
  232  * Increment NLM host count
  233  */
  234 struct nlm_host * nlm_get_host(struct nlm_host *host)
  235 {
  236         if (host) {
  237                 dprintk("lockd: get host %s\n", host->h_name);
  238                 host->h_count ++;
  239                 host->h_expires = jiffies + NLM_HOST_EXPIRE;
  240         }
  241         return host;
  242 }
  243 
  244 /*
  245  * Release NLM host after use
  246  */
  247 void nlm_release_host(struct nlm_host *host)
  248 {
  249         if (host && host->h_count) {
  250                 dprintk("lockd: release host %s\n", host->h_name);
  251                 host->h_count --;
  252         }
  253 }
  254 
  255 /*
  256  * Shut down the hosts module.
  257  * Note that this routine is called only at server shutdown time.
  258  */
  259 void
  260 nlm_shutdown_hosts(void)
  261 {
  262         struct nlm_host *host;
  263         int             i;
  264 
  265         dprintk("lockd: shutting down host module\n");
  266         down(&nlm_host_sema);
  267 
  268         /* First, make all hosts eligible for gc */
  269         dprintk("lockd: nuking all hosts...\n");
  270         for (i = 0; i < NLM_HOST_NRHASH; i++) {
  271                 for (host = nlm_hosts[i]; host; host = host->h_next)
  272                         host->h_expires = 0;
  273         }
  274 
  275         /* Then, perform a garbage collection pass */
  276         nlm_gc_hosts();
  277         up(&nlm_host_sema);
  278 
  279         /* complain if any hosts are left */
  280         if (nrhosts) {
  281                 printk(KERN_WARNING "lockd: couldn't shutdown host module!\n");
  282                 dprintk("lockd: %d hosts left:\n", nrhosts);
  283                 for (i = 0; i < NLM_HOST_NRHASH; i++) {
  284                         for (host = nlm_hosts[i]; host; host = host->h_next) {
  285                                 dprintk("       %s (cnt %d use %d exp %ld)\n",
  286                                         host->h_name, host->h_count,
  287                                         host->h_inuse, host->h_expires);
  288                         }
  289                 }
  290         }
  291 }
  292 
  293 /*
  294  * Garbage collect any unused NLM hosts.
  295  * This GC combines reference counting for async operations with
  296  * mark & sweep for resources held by remote clients.
  297  */
  298 static void
  299 nlm_gc_hosts(void)
  300 {
  301         struct nlm_host **q, *host;
  302         struct rpc_clnt *clnt;
  303         int             i;
  304 
  305         dprintk("lockd: host garbage collection\n");
  306         for (i = 0; i < NLM_HOST_NRHASH; i++) {
  307                 for (host = nlm_hosts[i]; host; host = host->h_next)
  308                         host->h_inuse = 0;
  309         }
  310 
  311         /* Mark all hosts that hold locks, blocks or shares */
  312         nlmsvc_mark_resources();
  313 
  314         for (i = 0; i < NLM_HOST_NRHASH; i++) {
  315                 q = &nlm_hosts[i];
  316                 while ((host = *q) != NULL) {
  317                         if (host->h_count || host->h_inuse
  318                          || time_before(jiffies, host->h_expires)) {
  319                                 q = &host->h_next;
  320                                 continue;
  321                         }
  322                         dprintk("lockd: delete host %s\n", host->h_name);
  323                         *q = host->h_next;
  324                         /* Don't unmonitor hosts that have been invalidated */
  325                         if (host->h_monitored && !host->h_killed)
  326                                 nsm_unmonitor(host);
  327                         if ((clnt = host->h_rpcclnt) != NULL) {
  328                                 if (atomic_read(&clnt->cl_users)) {
  329                                         printk(KERN_WARNING
  330                                                 "lockd: active RPC handle\n");
  331                                         clnt->cl_dead = 1;
  332                                 } else {
  333                                         rpc_destroy_client(host->h_rpcclnt);
  334                                 }
  335                         }
  336                         kfree(host);
  337                         nrhosts--;
  338                 }
  339         }
  340 
  341         next_gc = jiffies + NLM_HOST_COLLECT;
  342 }
  343 

Cache object: 55315bce2d5afd2df3d965e0f0b2ab13


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.