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/nlm/nlm_prot_impl.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  * Copyright (c) 2008 Isilon Inc http://www.isilon.com/
    3  * Authors: Doug Rabson <dfr@rabson.org>
    4  * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org>
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  */
   27 
   28 #include "opt_inet6.h"
   29 
   30 #include <sys/cdefs.h>
   31 __FBSDID("$FreeBSD$");
   32 
   33 #include <sys/param.h>
   34 #include <sys/fcntl.h>
   35 #include <sys/kernel.h>
   36 #include <sys/kthread.h>
   37 #include <sys/lockf.h>
   38 #include <sys/malloc.h>
   39 #include <sys/mount.h>
   40 #if __FreeBSD_version >= 700000
   41 #include <sys/priv.h>
   42 #endif
   43 #include <sys/proc.h>
   44 #include <sys/socket.h>
   45 #include <sys/socketvar.h>
   46 #include <sys/syscall.h>
   47 #include <sys/sysctl.h>
   48 #include <sys/sysent.h>
   49 #include <sys/sysproto.h>
   50 #include <sys/systm.h>
   51 #include <sys/taskqueue.h>
   52 #include <sys/unistd.h>
   53 #include <sys/vnode.h>
   54 
   55 #include <nfs/nfsproto.h>
   56 #include <nfsclient/nfs.h>
   57 #include <nfsclient/nfsnode.h>
   58 
   59 #include <nlm/nlm_prot.h>
   60 #include <nlm/sm_inter.h>
   61 #include <nlm/nlm.h>
   62 #include <rpc/rpc_com.h>
   63 #include <rpc/rpcb_prot.h>
   64 
   65 MALLOC_DEFINE(M_NLM, "NLM", "Network Lock Manager");
   66 
   67 /*
   68  * If a host is inactive (and holds no locks) for this amount of
   69  * seconds, we consider it idle and stop tracking it.
   70  */
   71 #define NLM_IDLE_TIMEOUT        30
   72 
   73 /*
   74  * We check the host list for idle every few seconds.
   75  */
   76 #define NLM_IDLE_PERIOD         5
   77 
   78 /*
   79  * Support for sysctl vfs.nlm.sysid
   80  */
   81 SYSCTL_NODE(_vfs, OID_AUTO, nlm, CTLFLAG_RW, NULL, "Network Lock Manager");
   82 SYSCTL_NODE(_vfs_nlm, OID_AUTO, sysid, CTLFLAG_RW, NULL, "");
   83 
   84 /*
   85  * Syscall hooks
   86  */
   87 static int nlm_syscall_offset = SYS_nlm_syscall;
   88 static struct sysent nlm_syscall_prev_sysent;
   89 #if __FreeBSD_version < 700000
   90 static struct sysent nlm_syscall_sysent = {
   91         (sizeof(struct nlm_syscall_args) / sizeof(register_t)) | SYF_MPSAFE,
   92         (sy_call_t *) nlm_syscall
   93 };
   94 #else
   95 MAKE_SYSENT(nlm_syscall);
   96 #endif
   97 static bool_t nlm_syscall_registered = FALSE;
   98 
   99 /*
  100  * Debug level passed in from userland. We also support a sysctl hook
  101  * so that it can be changed on a live system.
  102  */
  103 static int nlm_debug_level;
  104 SYSCTL_INT(_debug, OID_AUTO, nlm_debug, CTLFLAG_RW, &nlm_debug_level, 0, "");
  105 
  106 /*
  107  * Grace period handling. The value of nlm_grace_threshold is the
  108  * value of time_uptime after which we are serving requests normally.
  109  */
  110 static time_t nlm_grace_threshold;
  111 
  112 /*
  113  * We check for idle hosts if time_uptime is greater than
  114  * nlm_next_idle_check,
  115  */
  116 static time_t nlm_next_idle_check;
  117 
  118 /*
  119  * A socket to use for RPC - shared by all IPv4 RPC clients.
  120  */
  121 static struct socket *nlm_socket;
  122 
  123 #ifdef INET6
  124 
  125 /*
  126  * A socket to use for RPC - shared by all IPv6 RPC clients.
  127  */
  128 static struct socket *nlm_socket6;
  129 
  130 #endif
  131 
  132 /*
  133  * An RPC client handle that can be used to communicate with the local
  134  * NSM.
  135  */
  136 static CLIENT *nlm_nsm;
  137 
  138 /*
  139  * An AUTH handle for the server's creds.
  140  */
  141 static AUTH *nlm_auth;
  142 
  143 /*
  144  * A zero timeval for sending async RPC messages.
  145  */
  146 struct timeval nlm_zero_tv = { 0, 0 };
  147 
  148 /*
  149  * The local NSM state number
  150  */
  151 int nlm_nsm_state;
  152 
  153 
  154 /*
  155  * A lock to protect the host list and waiting lock list.
  156  */
  157 static struct mtx nlm_global_lock;
  158 
  159 /*
  160  * Locks:
  161  * (l)          locked by nh_lock
  162  * (s)          only accessed via server RPC which is single threaded
  163  * (g)          locked by nlm_global_lock
  164  * (c)          const until freeing
  165  * (a)          modified using atomic ops
  166  */
  167 
  168 /*
  169  * A pending client-side lock request, stored on the nlm_waiting_locks
  170  * list.
  171  */
  172 struct nlm_waiting_lock {
  173         TAILQ_ENTRY(nlm_waiting_lock) nw_link; /* (g) */
  174         bool_t          nw_waiting;            /* (g) */
  175         nlm4_lock       nw_lock;               /* (c) */
  176         union nfsfh     nw_fh;                 /* (c) */
  177         struct vnode    *nw_vp;                /* (c) */
  178 };
  179 TAILQ_HEAD(nlm_waiting_lock_list, nlm_waiting_lock);
  180 
  181 struct nlm_waiting_lock_list nlm_waiting_locks; /* (g) */
  182 
  183 /*
  184  * A pending server-side asynchronous lock request, stored on the
  185  * nh_pending list of the NLM host.
  186  */
  187 struct nlm_async_lock {
  188         TAILQ_ENTRY(nlm_async_lock) af_link; /* (l) host's list of locks */
  189         struct task     af_task;        /* (c) async callback details */
  190         void            *af_cookie;     /* (l) lock manager cancel token */
  191         struct vnode    *af_vp;         /* (l) vnode to lock */
  192         struct flock    af_fl;          /* (c) lock details */
  193         struct nlm_host *af_host;       /* (c) host which is locking */
  194         CLIENT          *af_rpc;        /* (c) rpc client to send message */
  195         nlm4_testargs   af_granted;     /* (c) notification details */
  196 };
  197 TAILQ_HEAD(nlm_async_lock_list, nlm_async_lock);
  198 
  199 /*
  200  * NLM host.
  201  */
  202 enum nlm_host_state {
  203         NLM_UNMONITORED,
  204         NLM_MONITORED,
  205         NLM_MONITOR_FAILED,
  206         NLM_RECOVERING
  207 };
  208 struct nlm_host {
  209         struct mtx      nh_lock;
  210         volatile u_int  nh_refs;       /* (a) reference count */
  211         TAILQ_ENTRY(nlm_host) nh_link; /* (g) global list of hosts */
  212         char            nh_caller_name[MAXNAMELEN]; /* (c) printable name of host */
  213         uint32_t        nh_sysid;        /* (c) our allocaed system ID */
  214         char            nh_sysid_string[10]; /* (c) string rep. of sysid */
  215         struct sockaddr_storage nh_addr; /* (s) remote address of host */
  216         CLIENT          *nh_rpc;         /* (l) RPC handle to send to host */
  217         rpcvers_t       nh_vers;         /* (s) NLM version of host */
  218         int             nh_state;        /* (s) last seen NSM state of host */
  219         enum nlm_host_state nh_monstate; /* (l) local NSM monitoring state */
  220         time_t          nh_idle_timeout; /* (s) Time at which host is idle */
  221         time_t          nh_rpc_create_time; /* (s) Time we create RPC client */
  222         struct sysctl_ctx_list nh_sysctl; /* (c) vfs.nlm.sysid nodes */
  223         struct nlm_async_lock_list nh_pending; /* (l) pending async locks */
  224         struct nlm_async_lock_list nh_finished; /* (l) finished async locks */
  225 };
  226 TAILQ_HEAD(nlm_host_list, nlm_host);
  227 
  228 static struct nlm_host_list nlm_hosts; /* (g) */
  229 static uint32_t nlm_next_sysid = 1;    /* (g) */
  230 
  231 static void     nlm_host_unmonitor(struct nlm_host *);
  232 
  233 /**********************************************************************/
  234 
  235 /*
  236  * Initialise NLM globals.
  237  */
  238 static void
  239 nlm_init(void *dummy)
  240 {
  241         int error;
  242 
  243         mtx_init(&nlm_global_lock, "nlm_global_lock", NULL, MTX_DEF);
  244         TAILQ_INIT(&nlm_waiting_locks);
  245         TAILQ_INIT(&nlm_hosts);
  246 
  247         error = syscall_register(&nlm_syscall_offset, &nlm_syscall_sysent,
  248             &nlm_syscall_prev_sysent);
  249         if (error)
  250                 printf("Can't register NLM syscall\n");
  251         else
  252                 nlm_syscall_registered = TRUE;
  253 }
  254 SYSINIT(nlm_init, SI_SUB_LOCK, SI_ORDER_FIRST, nlm_init, NULL);
  255 
  256 static void
  257 nlm_uninit(void *dummy)
  258 {
  259 
  260         if (nlm_syscall_registered)
  261                 syscall_deregister(&nlm_syscall_offset,
  262                     &nlm_syscall_prev_sysent);
  263 }
  264 SYSUNINIT(nlm_uninit, SI_SUB_LOCK, SI_ORDER_FIRST, nlm_uninit, NULL);
  265 
  266 /*
  267  * Copy a struct netobj.
  268  */ 
  269 void
  270 nlm_copy_netobj(struct netobj *dst, struct netobj *src,
  271     struct malloc_type *type)
  272 {
  273 
  274         dst->n_len = src->n_len;
  275         dst->n_bytes = malloc(src->n_len, type, M_WAITOK);
  276         memcpy(dst->n_bytes, src->n_bytes, src->n_len);
  277 }
  278 
  279 /*
  280  * Create an RPC client handle for the given (address,prog,vers)
  281  * triple using UDP.
  282  */
  283 static CLIENT *
  284 nlm_get_rpc(struct sockaddr *sa, rpcprog_t prog, rpcvers_t vers)
  285 {
  286         const char *wchan = "nlmrcv";
  287         const char* protofmly;
  288         struct sockaddr_storage ss;
  289         struct socket *so;
  290         CLIENT *rpcb;
  291         struct timeval timo;
  292         RPCB parms;
  293         char *uaddr;
  294         enum clnt_stat stat = RPC_SUCCESS;
  295         int rpcvers = RPCBVERS4;
  296         bool_t do_tcp = FALSE;
  297         struct pmap mapping;
  298         u_short port = 0;
  299 
  300         /*
  301          * First we need to contact the remote RPCBIND service to find
  302          * the right port.
  303          */
  304         memcpy(&ss, sa, sa->sa_len);
  305         switch (ss.ss_family) {
  306         case AF_INET:
  307                 ((struct sockaddr_in *)&ss)->sin_port = htons(111);
  308                 protofmly = "inet";
  309                 so = nlm_socket;
  310                 break;
  311                 
  312 #ifdef INET6
  313         case AF_INET6:
  314                 ((struct sockaddr_in6 *)&ss)->sin6_port = htons(111);
  315                 protofmly = "inet6";
  316                 so = nlm_socket6;
  317                 break;
  318 #endif
  319 
  320         default:
  321                 /*
  322                  * Unsupported address family - fail.
  323                  */
  324                 return (NULL);
  325         }
  326 
  327         rpcb = clnt_dg_create(so, (struct sockaddr *)&ss,
  328             RPCBPROG, rpcvers, 0, 0);
  329         if (!rpcb)
  330                 return (NULL);
  331 
  332 try_tcp:
  333         parms.r_prog = prog;
  334         parms.r_vers = vers;
  335         if (do_tcp)
  336                 parms.r_netid = "tcp";
  337         else
  338                 parms.r_netid = "udp";
  339         parms.r_addr = "";
  340         parms.r_owner = "";
  341 
  342         /*
  343          * Use the default timeout.
  344          */
  345         timo.tv_sec = 25;
  346         timo.tv_usec = 0;
  347 again:
  348         switch (rpcvers) {
  349         case RPCBVERS4:
  350         case RPCBVERS:
  351                 /*
  352                  * Try RPCBIND 4 then 3.
  353                  */
  354                 uaddr = NULL;
  355                 stat = CLNT_CALL(rpcb, (rpcprog_t) RPCBPROC_GETADDR,
  356                     (xdrproc_t) xdr_rpcb, &parms,
  357                     (xdrproc_t) xdr_wrapstring, &uaddr, timo);
  358                 if (stat == RPC_PROGVERSMISMATCH) {
  359                         if (rpcvers == RPCBVERS4)
  360                                 rpcvers = RPCBVERS;
  361                         else if (rpcvers == RPCBVERS)
  362                                 rpcvers = PMAPVERS;
  363                         CLNT_CONTROL(rpcb, CLSET_VERS, &rpcvers);
  364                         goto again;
  365                 } else if (stat == RPC_SUCCESS) {
  366                         /*
  367                          * We have a reply from the remote RPCBIND - turn it
  368                          * into an appropriate address and make a new client
  369                          * that can talk to the remote NLM.
  370                          *
  371                          * XXX fixup IPv6 scope ID.
  372                          */
  373                         struct netbuf *a;
  374                         a = __rpc_uaddr2taddr_af(ss.ss_family, uaddr);
  375                         if (!a) {
  376                                 CLNT_DESTROY(rpcb);
  377                                 return (NULL);
  378                         }
  379                         memcpy(&ss, a->buf, a->len);
  380                         free(a->buf, M_RPC);
  381                         free(a, M_RPC);
  382                         xdr_free((xdrproc_t) xdr_wrapstring, &uaddr);
  383                 }
  384                 break;
  385         case PMAPVERS:
  386                 /*
  387                  * Try portmap.
  388                  */
  389                 mapping.pm_prog = parms.r_prog;
  390                 mapping.pm_vers = parms.r_vers;
  391                 mapping.pm_prot = do_tcp ? IPPROTO_TCP : IPPROTO_UDP;
  392                 mapping.pm_port = 0;
  393 
  394                 stat = CLNT_CALL(rpcb, (rpcprog_t) PMAPPROC_GETPORT,
  395                     (xdrproc_t) xdr_pmap, &mapping,
  396                     (xdrproc_t) xdr_u_short, &port, timo);
  397 
  398                 if (stat == RPC_SUCCESS) {
  399                         switch (ss.ss_family) {
  400                         case AF_INET:
  401                                 ((struct sockaddr_in *)&ss)->sin_port =
  402                                         htons(port);
  403                                 break;
  404                 
  405 #ifdef INET6
  406                         case AF_INET6:
  407                                 ((struct sockaddr_in6 *)&ss)->sin6_port =
  408                                         htons(port);
  409                                 break;
  410 #endif
  411                         }
  412                 }
  413                 break;
  414         default:
  415                 panic("invalid rpcvers %d", rpcvers);
  416         }
  417         /*
  418          * We may have a positive response from the portmapper, but the NLM
  419          * service was not found. Make sure we received a valid port.
  420          */
  421         switch (ss.ss_family) {
  422         case AF_INET:
  423                 port = ((struct sockaddr_in *)&ss)->sin_port;
  424                 break;
  425 #ifdef INET6
  426         case AF_INET6:
  427                 port = ((struct sockaddr_in6 *)&ss)->sin6_port;
  428                 break;
  429 #endif
  430         }
  431         if (stat != RPC_SUCCESS || !port) {
  432                 /*
  433                  * If we were able to talk to rpcbind or portmap, but the udp
  434                  * variant wasn't available, ask about tcp.
  435                  *
  436                  * XXX - We could also check for a TCP portmapper, but
  437                  * if the host is running a portmapper at all, we should be able
  438                  * to hail it over UDP.
  439                  */
  440                 if (stat == RPC_SUCCESS && !do_tcp) {
  441                         do_tcp = TRUE;
  442                         goto try_tcp;
  443                 }
  444 
  445                 /* Otherwise, bad news. */
  446                 printf("NLM: failed to contact remote rpcbind, "
  447                     "stat = %d, port = %d\n",
  448                     (int) stat, port);
  449                 CLNT_DESTROY(rpcb);
  450                 return (NULL);
  451         }
  452 
  453         if (do_tcp) {
  454                 /*
  455                  * Destroy the UDP client we used to speak to rpcbind and
  456                  * recreate as a TCP client.
  457                  */
  458                 struct netconfig *nconf = NULL;
  459 
  460                 CLNT_DESTROY(rpcb);
  461 
  462                 switch (ss.ss_family) {
  463                 case AF_INET:
  464                         nconf = getnetconfigent("tcp");
  465                         break;
  466 #ifdef INET6
  467                 case AF_INET6:
  468                         nconf = getnetconfigent("tcp6");
  469                         break;
  470 #endif
  471                 }
  472 
  473                 rpcb = clnt_reconnect_create(nconf, (struct sockaddr *)&ss,
  474                     prog, vers, 0, 0);
  475                 CLNT_CONTROL(rpcb, CLSET_WAITCHAN, &wchan);
  476                 rpcb->cl_auth = nlm_auth;
  477                 
  478         } else {
  479                 /*
  480                  * Re-use the client we used to speak to rpcbind.
  481                  */
  482                 CLNT_CONTROL(rpcb, CLSET_SVC_ADDR, &ss);
  483                 CLNT_CONTROL(rpcb, CLSET_PROG, &prog);
  484                 CLNT_CONTROL(rpcb, CLSET_VERS, &vers);
  485                 CLNT_CONTROL(rpcb, CLSET_WAITCHAN, &wchan);
  486                 rpcb->cl_auth = nlm_auth;
  487         }
  488 
  489         return (rpcb);
  490 }
  491 
  492 /*
  493  * This async callback after when an async lock request has been
  494  * granted. We notify the host which initiated the request.
  495  */
  496 static void
  497 nlm_lock_callback(void *arg, int pending)
  498 {
  499         struct nlm_async_lock *af = (struct nlm_async_lock *) arg;
  500         struct rpc_callextra ext;
  501 
  502         if (nlm_debug_level >= 2)
  503                 printf("NLM: async lock %p for %s (sysid %d) granted\n",
  504                     af, af->af_host->nh_caller_name,
  505                     af->af_host->nh_sysid);
  506 
  507         /*
  508          * Send the results back to the host.
  509          *
  510          * Note: there is a possible race here with nlm_host_notify
  511          * destroying the RPC client. To avoid problems, the first
  512          * thing nlm_host_notify does is to cancel pending async lock
  513          * requests.
  514          */
  515         memset(&ext, 0, sizeof(ext));
  516         ext.rc_auth = nlm_auth;
  517         if (af->af_host->nh_vers == NLM_VERS4) {
  518                 nlm4_granted_msg_4(&af->af_granted,
  519                     NULL, af->af_rpc, &ext, nlm_zero_tv);
  520         } else {
  521                 /*
  522                  * Back-convert to legacy protocol
  523                  */
  524                 nlm_testargs granted;
  525                 granted.cookie = af->af_granted.cookie;
  526                 granted.exclusive = af->af_granted.exclusive;
  527                 granted.alock.caller_name =
  528                         af->af_granted.alock.caller_name;
  529                 granted.alock.fh = af->af_granted.alock.fh;
  530                 granted.alock.oh = af->af_granted.alock.oh;
  531                 granted.alock.svid = af->af_granted.alock.svid;
  532                 granted.alock.l_offset =
  533                         af->af_granted.alock.l_offset;
  534                 granted.alock.l_len =
  535                         af->af_granted.alock.l_len;
  536 
  537                 nlm_granted_msg_1(&granted,
  538                     NULL, af->af_rpc, &ext, nlm_zero_tv);
  539         }
  540 
  541         /*
  542          * Move this entry to the nh_finished list. Someone else will
  543          * free it later - its too hard to do it here safely without
  544          * racing with cancel.
  545          *
  546          * XXX possibly we should have a third "granted sent but not
  547          * ack'ed" list so that we can re-send the granted message.
  548          */
  549         mtx_lock(&af->af_host->nh_lock);
  550         TAILQ_REMOVE(&af->af_host->nh_pending, af, af_link);
  551         TAILQ_INSERT_TAIL(&af->af_host->nh_finished, af, af_link);
  552         mtx_unlock(&af->af_host->nh_lock);
  553 }
  554 
  555 /*
  556  * Free an async lock request. The request must have been removed from
  557  * any list.
  558  */
  559 static void
  560 nlm_free_async_lock(struct nlm_async_lock *af)
  561 {
  562         /*
  563          * Free an async lock.
  564          */
  565         if (af->af_rpc)
  566                 CLNT_RELEASE(af->af_rpc);
  567         xdr_free((xdrproc_t) xdr_nlm4_testargs, &af->af_granted);
  568         if (af->af_vp)
  569                 vrele(af->af_vp);
  570         free(af, M_NLM);
  571 }
  572 
  573 /*
  574  * Cancel our async request - this must be called with
  575  * af->nh_host->nh_lock held. This is slightly complicated by a
  576  * potential race with our own callback. If we fail to cancel the
  577  * lock, it must already have been granted - we make sure our async
  578  * task has completed by calling taskqueue_drain in this case.
  579  */
  580 static int
  581 nlm_cancel_async_lock(struct nlm_async_lock *af)
  582 {
  583         struct nlm_host *host = af->af_host;
  584         int error;
  585 
  586         mtx_assert(&host->nh_lock, MA_OWNED);
  587 
  588         mtx_unlock(&host->nh_lock);
  589 
  590         error = VOP_ADVLOCKASYNC(af->af_vp, NULL, F_CANCEL, &af->af_fl,
  591             F_REMOTE, NULL, &af->af_cookie);
  592 
  593         if (error) {
  594                 /*
  595                  * We failed to cancel - make sure our callback has
  596                  * completed before we continue.
  597                  */
  598                 taskqueue_drain(taskqueue_thread, &af->af_task);
  599         }
  600 
  601         mtx_lock(&host->nh_lock);
  602         
  603         if (!error) {
  604                 if (nlm_debug_level >= 2)
  605                         printf("NLM: async lock %p for %s (sysid %d) "
  606                             "cancelled\n",
  607                             af, host->nh_caller_name, host->nh_sysid);
  608 
  609                 /*
  610                  * Remove from the nh_pending list and free now that
  611                  * we are safe from the callback.
  612                  */
  613                 TAILQ_REMOVE(&host->nh_pending, af, af_link);
  614                 mtx_unlock(&host->nh_lock);
  615                 nlm_free_async_lock(af);
  616                 mtx_lock(&host->nh_lock);
  617         }
  618 
  619         return (error);
  620 }
  621 
  622 static void
  623 nlm_free_finished_locks(struct nlm_host *host)
  624 {
  625         struct nlm_async_lock *af;
  626 
  627         mtx_lock(&host->nh_lock);
  628         while ((af = TAILQ_FIRST(&host->nh_finished)) != NULL) {
  629                 TAILQ_REMOVE(&host->nh_finished, af, af_link);
  630                 mtx_unlock(&host->nh_lock);
  631                 nlm_free_async_lock(af);
  632                 mtx_lock(&host->nh_lock);
  633         }
  634         mtx_unlock(&host->nh_lock);
  635 }
  636 
  637 /*
  638  * Free resources used by a host. This is called after the reference
  639  * count has reached zero so it doesn't need to worry about locks.
  640  */
  641 static void
  642 nlm_host_destroy(struct nlm_host *host)
  643 {
  644 
  645         mtx_lock(&nlm_global_lock);
  646         TAILQ_REMOVE(&nlm_hosts, host, nh_link);
  647         mtx_unlock(&nlm_global_lock);
  648 
  649         if (host->nh_rpc)
  650                 CLNT_RELEASE(host->nh_rpc);
  651         mtx_destroy(&host->nh_lock);
  652         sysctl_ctx_free(&host->nh_sysctl);
  653         free(host, M_NLM);
  654 }
  655 
  656 /*
  657  * Thread start callback for client lock recovery
  658  */
  659 static void
  660 nlm_client_recovery_start(void *arg)
  661 {
  662         struct nlm_host *host = (struct nlm_host *) arg;
  663 
  664         if (nlm_debug_level >= 1)
  665                 printf("NLM: client lock recovery for %s started\n",
  666                     host->nh_caller_name);
  667 
  668         nlm_client_recovery(host);
  669 
  670         if (nlm_debug_level >= 1)
  671                 printf("NLM: client lock recovery for %s completed\n",
  672                     host->nh_caller_name);
  673 
  674         host->nh_monstate = NLM_MONITORED;
  675         nlm_host_release(host);
  676 
  677         kthread_exit(0);
  678 }
  679 
  680 /*
  681  * This is called when we receive a host state change notification. We
  682  * unlock any active locks owned by the host. When rpc.lockd is
  683  * shutting down, this function is called with newstate set to zero
  684  * which allows us to cancel any pending async locks and clear the
  685  * locking state.
  686  */
  687 static void
  688 nlm_host_notify(struct nlm_host *host, int newstate)
  689 {
  690         struct nlm_async_lock *af;
  691 
  692         if (newstate) {
  693                 if (nlm_debug_level >= 1)
  694                         printf("NLM: host %s (sysid %d) rebooted, new "
  695                             "state is %d\n",
  696                             host->nh_caller_name, host->nh_sysid, newstate);
  697         }
  698 
  699         /*
  700          * Cancel any pending async locks for this host.
  701          */
  702         mtx_lock(&host->nh_lock);
  703         while ((af = TAILQ_FIRST(&host->nh_pending)) != NULL) {
  704                 /*
  705                  * nlm_cancel_async_lock will remove the entry from
  706                  * nh_pending and free it.
  707                  */
  708                 nlm_cancel_async_lock(af);
  709         }
  710         mtx_unlock(&host->nh_lock);
  711         nlm_free_finished_locks(host);
  712 
  713         /*
  714          * The host just rebooted - trash its locks.
  715          */
  716         lf_clearremotesys(host->nh_sysid);
  717         host->nh_state = newstate;
  718 
  719         /*
  720          * If we have any remote locks for this host (i.e. it
  721          * represents a remote NFS server that our local NFS client
  722          * has locks for), start a recovery thread.
  723          */
  724         if (newstate != 0
  725             && host->nh_monstate != NLM_RECOVERING
  726             && lf_countlocks(NLM_SYSID_CLIENT | host->nh_sysid) > 0) {
  727                 host->nh_monstate = NLM_RECOVERING;
  728                 refcount_acquire(&host->nh_refs);
  729                 kthread_create(nlm_client_recovery_start, host, NULL, 0, 0,
  730                     "NFS lock recovery for %s", host->nh_caller_name);
  731         }
  732 }
  733 
  734 /*
  735  * Sysctl handler to count the number of locks for a sysid.
  736  */
  737 static int
  738 nlm_host_lock_count_sysctl(SYSCTL_HANDLER_ARGS)
  739 {
  740         struct nlm_host *host;
  741         int count;
  742 
  743         host = oidp->oid_arg1;
  744         count = lf_countlocks(host->nh_sysid);
  745         return sysctl_handle_int(oidp, &count, 0, req);
  746 }
  747 
  748 /*
  749  * Sysctl handler to count the number of client locks for a sysid.
  750  */
  751 static int
  752 nlm_host_client_lock_count_sysctl(SYSCTL_HANDLER_ARGS)
  753 {
  754         struct nlm_host *host;
  755         int count;
  756 
  757         host = oidp->oid_arg1;
  758         count = lf_countlocks(NLM_SYSID_CLIENT | host->nh_sysid);
  759         return sysctl_handle_int(oidp, &count, 0, req);
  760 }
  761 
  762 /*
  763  * Create a new NLM host.
  764  */
  765 static struct nlm_host *
  766 nlm_create_host(const char* caller_name)
  767 {
  768         struct nlm_host *host;
  769         struct sysctl_oid *oid;
  770 
  771         mtx_assert(&nlm_global_lock, MA_OWNED);
  772 
  773         if (nlm_debug_level >= 1)
  774                 printf("NLM: new host %s (sysid %d)\n",
  775                     caller_name, nlm_next_sysid);
  776         host = malloc(sizeof(struct nlm_host), M_NLM, M_NOWAIT|M_ZERO);
  777         if (!host)
  778                 return (NULL);
  779         mtx_init(&host->nh_lock, "nh_lock", NULL, MTX_DEF);
  780         host->nh_refs = 1;
  781         strlcpy(host->nh_caller_name, caller_name, MAXNAMELEN);
  782         host->nh_sysid = nlm_next_sysid++;
  783         snprintf(host->nh_sysid_string, sizeof(host->nh_sysid_string),
  784                 "%d", host->nh_sysid);
  785         host->nh_rpc = NULL;
  786         host->nh_vers = 0;
  787         host->nh_state = 0;
  788         host->nh_monstate = NLM_UNMONITORED;
  789         TAILQ_INIT(&host->nh_pending);
  790         TAILQ_INIT(&host->nh_finished);
  791         TAILQ_INSERT_TAIL(&nlm_hosts, host, nh_link);
  792 
  793         mtx_unlock(&nlm_global_lock);
  794 
  795         sysctl_ctx_init(&host->nh_sysctl);
  796         oid = SYSCTL_ADD_NODE(&host->nh_sysctl,
  797             SYSCTL_STATIC_CHILDREN(_vfs_nlm_sysid),
  798             OID_AUTO, host->nh_sysid_string, CTLFLAG_RD, NULL, "");
  799         SYSCTL_ADD_STRING(&host->nh_sysctl, SYSCTL_CHILDREN(oid), OID_AUTO,
  800             "hostname", CTLFLAG_RD, host->nh_caller_name, 0, "");
  801         SYSCTL_ADD_INT(&host->nh_sysctl, SYSCTL_CHILDREN(oid), OID_AUTO,
  802             "version", CTLFLAG_RD, &host->nh_vers, 0, "");
  803         SYSCTL_ADD_INT(&host->nh_sysctl, SYSCTL_CHILDREN(oid), OID_AUTO,
  804             "monitored", CTLFLAG_RD, &host->nh_monstate, 0, "");
  805         SYSCTL_ADD_PROC(&host->nh_sysctl, SYSCTL_CHILDREN(oid), OID_AUTO,
  806             "lock_count", CTLTYPE_INT | CTLFLAG_RD, host, 0,
  807             nlm_host_lock_count_sysctl, "I", "");
  808         SYSCTL_ADD_PROC(&host->nh_sysctl, SYSCTL_CHILDREN(oid), OID_AUTO,
  809             "client_lock_count", CTLTYPE_INT | CTLFLAG_RD, host, 0,
  810             nlm_host_client_lock_count_sysctl, "I", "");
  811 
  812         mtx_lock(&nlm_global_lock);
  813 
  814         return (host);
  815 }
  816 
  817 /*
  818  * Return non-zero if the address parts of the two sockaddrs are the
  819  * same.
  820  */
  821 static int
  822 nlm_compare_addr(const struct sockaddr *a, const struct sockaddr *b)
  823 {
  824         const struct sockaddr_in *a4, *b4;
  825 #ifdef INET6
  826         const struct sockaddr_in6 *a6, *b6;
  827 #endif
  828 
  829         if (a->sa_family != b->sa_family)
  830                 return (FALSE);
  831 
  832         switch (a->sa_family) {
  833         case AF_INET:
  834                 a4 = (const struct sockaddr_in *) a;
  835                 b4 = (const struct sockaddr_in *) b;
  836                 return !memcmp(&a4->sin_addr, &b4->sin_addr,
  837                     sizeof(a4->sin_addr));
  838 #ifdef INET6
  839         case AF_INET6:
  840                 a6 = (const struct sockaddr_in6 *) a;
  841                 b6 = (const struct sockaddr_in6 *) b;
  842                 return !memcmp(&a6->sin6_addr, &b6->sin6_addr,
  843                     sizeof(a6->sin6_addr));
  844 #endif
  845         }
  846 
  847         return (0);
  848 }
  849 
  850 /*
  851  * Check for idle hosts and stop monitoring them. We could also free
  852  * the host structure here, possibly after a larger timeout but that
  853  * would require some care to avoid races with
  854  * e.g. nlm_host_lock_count_sysctl.
  855  */
  856 static void
  857 nlm_check_idle(void)
  858 {
  859         struct nlm_host *host;
  860 
  861         mtx_assert(&nlm_global_lock, MA_OWNED);
  862 
  863         if (time_uptime <= nlm_next_idle_check)
  864                 return;
  865 
  866         nlm_next_idle_check = time_uptime + NLM_IDLE_PERIOD;
  867 
  868         TAILQ_FOREACH(host, &nlm_hosts, nh_link) {
  869                 if (host->nh_monstate == NLM_MONITORED
  870                     && time_uptime > host->nh_idle_timeout) {
  871                         mtx_unlock(&nlm_global_lock);
  872                         if (lf_countlocks(host->nh_sysid) > 0
  873                             || lf_countlocks(NLM_SYSID_CLIENT
  874                                 + host->nh_sysid)) {
  875                                 host->nh_idle_timeout =
  876                                         time_uptime + NLM_IDLE_TIMEOUT;
  877                                 mtx_lock(&nlm_global_lock);
  878                                 continue;
  879                         }
  880                         nlm_host_unmonitor(host);
  881                         mtx_lock(&nlm_global_lock);
  882                 } 
  883         }
  884 }
  885 
  886 /*
  887  * Search for an existing NLM host that matches the given name
  888  * (typically the caller_name element of an nlm4_lock).  If none is
  889  * found, create a new host. If 'addr' is non-NULL, record the remote
  890  * address of the host so that we can call it back for async
  891  * responses. If 'vers' is greater than zero then record the NLM
  892  * program version to use to communicate with this client.
  893  */
  894 struct nlm_host *
  895 nlm_find_host_by_name(const char *name, const struct sockaddr *addr,
  896     rpcvers_t vers)
  897 {
  898         struct nlm_host *host;
  899 
  900         mtx_lock(&nlm_global_lock);
  901 
  902         /*
  903          * The remote host is determined by caller_name.
  904          */
  905         TAILQ_FOREACH(host, &nlm_hosts, nh_link) {
  906                 if (!strcmp(host->nh_caller_name, name))
  907                         break;
  908         }
  909 
  910         if (!host) {
  911                 host = nlm_create_host(name);
  912                 if (!host) {
  913                         mtx_unlock(&nlm_global_lock);
  914                         return (NULL);
  915                 }
  916         }
  917         refcount_acquire(&host->nh_refs);
  918 
  919         host->nh_idle_timeout = time_uptime + NLM_IDLE_TIMEOUT;
  920 
  921         /*
  922          * If we have an address for the host, record it so that we
  923          * can send async replies etc.
  924          */
  925         if (addr) {
  926                 
  927                 KASSERT(addr->sa_len < sizeof(struct sockaddr_storage),
  928                     ("Strange remote transport address length"));
  929 
  930                 /*
  931                  * If we have seen an address before and we currently
  932                  * have an RPC client handle, make sure the address is
  933                  * the same, otherwise discard the client handle.
  934                  */
  935                 if (host->nh_addr.ss_len && host->nh_rpc) {
  936                         if (!nlm_compare_addr(
  937                                     (struct sockaddr *) &host->nh_addr,
  938                                     addr)
  939                             || host->nh_vers != vers) {
  940                                 CLIENT *client;
  941                                 mtx_lock(&host->nh_lock);
  942                                 client = host->nh_rpc;
  943                                 host->nh_rpc = NULL;
  944                                 mtx_unlock(&host->nh_lock);
  945                                 if (client) {
  946                                         CLNT_RELEASE(client);
  947                                 }
  948                         }
  949                 }
  950                 memcpy(&host->nh_addr, addr, addr->sa_len);
  951                 host->nh_vers = vers;
  952         }
  953 
  954         nlm_check_idle();
  955 
  956         mtx_unlock(&nlm_global_lock);
  957 
  958         return (host);
  959 }
  960 
  961 /*
  962  * Search for an existing NLM host that matches the given remote
  963  * address. If none is found, create a new host with the requested
  964  * address and remember 'vers' as the NLM protocol version to use for
  965  * that host.
  966  */
  967 struct nlm_host *
  968 nlm_find_host_by_addr(const struct sockaddr *addr, int vers)
  969 {
  970         /*
  971          * Fake up a name using inet_ntop. This buffer is
  972          * large enough for an IPv6 address.
  973          */
  974         char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
  975         struct nlm_host *host;
  976 
  977         switch (addr->sa_family) {
  978         case AF_INET:
  979                 __rpc_inet_ntop(AF_INET,
  980                     &((const struct sockaddr_in *) addr)->sin_addr,
  981                     tmp, sizeof tmp);
  982                 break;
  983 #ifdef INET6
  984         case AF_INET6:
  985                 __rpc_inet_ntop(AF_INET6,
  986                     &((const struct sockaddr_in6 *) addr)->sin6_addr,
  987                     tmp, sizeof tmp);
  988                 break;
  989 #endif
  990         default:
  991                 strcmp(tmp, "<unknown>");
  992         }
  993 
  994 
  995         mtx_lock(&nlm_global_lock);
  996 
  997         /*
  998          * The remote host is determined by caller_name.
  999          */
 1000         TAILQ_FOREACH(host, &nlm_hosts, nh_link) {
 1001                 if (nlm_compare_addr(addr,
 1002                         (const struct sockaddr *) &host->nh_addr))
 1003                         break;
 1004         }
 1005 
 1006         if (!host) {
 1007                 host = nlm_create_host(tmp);
 1008                 if (!host) {
 1009                         mtx_unlock(&nlm_global_lock);
 1010                         return (NULL);
 1011                 }
 1012                 memcpy(&host->nh_addr, addr, addr->sa_len);
 1013                 host->nh_vers = vers;
 1014         }
 1015         refcount_acquire(&host->nh_refs);
 1016 
 1017         host->nh_idle_timeout = time_uptime + NLM_IDLE_TIMEOUT;
 1018 
 1019         nlm_check_idle();
 1020 
 1021         mtx_unlock(&nlm_global_lock);
 1022 
 1023         return (host);
 1024 }
 1025 
 1026 /*
 1027  * Find the NLM host that matches the value of 'sysid'. If none
 1028  * exists, return NULL.
 1029  */
 1030 static struct nlm_host *
 1031 nlm_find_host_by_sysid(int sysid)
 1032 {
 1033         struct nlm_host *host;
 1034 
 1035         TAILQ_FOREACH(host, &nlm_hosts, nh_link) {
 1036                 if (host->nh_sysid == sysid) {
 1037                         refcount_acquire(&host->nh_refs);
 1038                         return (host);
 1039                 }
 1040         }
 1041 
 1042         return (NULL);
 1043 }
 1044 
 1045 void nlm_host_release(struct nlm_host *host)
 1046 {
 1047         if (refcount_release(&host->nh_refs)) {
 1048                 /*
 1049                  * Free the host
 1050                  */
 1051                 nlm_host_destroy(host);
 1052         }
 1053 }
 1054 
 1055 /*
 1056  * Unregister this NLM host with the local NSM due to idleness.
 1057  */
 1058 static void
 1059 nlm_host_unmonitor(struct nlm_host *host)
 1060 {
 1061         mon_id smmonid;
 1062         sm_stat_res smstat;
 1063         struct timeval timo;
 1064         enum clnt_stat stat;
 1065 
 1066         if (nlm_debug_level >= 1)
 1067                 printf("NLM: unmonitoring %s (sysid %d)\n",
 1068                     host->nh_caller_name, host->nh_sysid);
 1069 
 1070         /*
 1071          * We put our assigned system ID value in the priv field to
 1072          * make it simpler to find the host if we are notified of a
 1073          * host restart.
 1074          */
 1075         smmonid.mon_name = host->nh_caller_name;
 1076         smmonid.my_id.my_name = "localhost";
 1077         smmonid.my_id.my_prog = NLM_PROG;
 1078         smmonid.my_id.my_vers = NLM_SM;
 1079         smmonid.my_id.my_proc = NLM_SM_NOTIFY;
 1080 
 1081         timo.tv_sec = 25;
 1082         timo.tv_usec = 0;
 1083         stat = CLNT_CALL(nlm_nsm, SM_UNMON,
 1084             (xdrproc_t) xdr_mon, &smmonid,
 1085             (xdrproc_t) xdr_sm_stat, &smstat, timo);
 1086 
 1087         if (stat != RPC_SUCCESS) {
 1088                 printf("Failed to contact local NSM - rpc error %d\n", stat);
 1089                 return;
 1090         }
 1091         if (smstat.res_stat == stat_fail) {
 1092                 printf("Local NSM refuses to unmonitor %s\n",
 1093                     host->nh_caller_name);
 1094                 return;
 1095         }
 1096 
 1097         host->nh_monstate = NLM_UNMONITORED;
 1098 }
 1099 
 1100 /*
 1101  * Register this NLM host with the local NSM so that we can be
 1102  * notified if it reboots.
 1103  */
 1104 void
 1105 nlm_host_monitor(struct nlm_host *host, int state)
 1106 {
 1107         mon smmon;
 1108         sm_stat_res smstat;
 1109         struct timeval timo;
 1110         enum clnt_stat stat;
 1111 
 1112         if (state && !host->nh_state) {
 1113                 /*
 1114                  * This is the first time we have seen an NSM state
 1115                  * value for this host. We record it here to help
 1116                  * detect host reboots.
 1117                  */
 1118                 host->nh_state = state;
 1119                 if (nlm_debug_level >= 1)
 1120                         printf("NLM: host %s (sysid %d) has NSM state %d\n",
 1121                             host->nh_caller_name, host->nh_sysid, state);
 1122         }
 1123 
 1124         mtx_lock(&host->nh_lock);
 1125         if (host->nh_monstate != NLM_UNMONITORED) {
 1126                 mtx_unlock(&host->nh_lock);
 1127                 return;
 1128         }
 1129         host->nh_monstate = NLM_MONITORED;
 1130         mtx_unlock(&host->nh_lock);
 1131 
 1132         if (nlm_debug_level >= 1)
 1133                 printf("NLM: monitoring %s (sysid %d)\n",
 1134                     host->nh_caller_name, host->nh_sysid);
 1135 
 1136         /*
 1137          * We put our assigned system ID value in the priv field to
 1138          * make it simpler to find the host if we are notified of a
 1139          * host restart.
 1140          */
 1141         smmon.mon_id.mon_name = host->nh_caller_name;
 1142         smmon.mon_id.my_id.my_name = "localhost";
 1143         smmon.mon_id.my_id.my_prog = NLM_PROG;
 1144         smmon.mon_id.my_id.my_vers = NLM_SM;
 1145         smmon.mon_id.my_id.my_proc = NLM_SM_NOTIFY;
 1146         memcpy(smmon.priv, &host->nh_sysid, sizeof(host->nh_sysid));
 1147 
 1148         timo.tv_sec = 25;
 1149         timo.tv_usec = 0;
 1150         stat = CLNT_CALL(nlm_nsm, SM_MON,
 1151             (xdrproc_t) xdr_mon, &smmon,
 1152             (xdrproc_t) xdr_sm_stat, &smstat, timo);
 1153 
 1154         if (stat != RPC_SUCCESS) {
 1155                 printf("Failed to contact local NSM - rpc error %d\n", stat);
 1156                 return;
 1157         }
 1158         if (smstat.res_stat == stat_fail) {
 1159                 printf("Local NSM refuses to monitor %s\n",
 1160                     host->nh_caller_name);
 1161                 mtx_lock(&host->nh_lock);
 1162                 host->nh_monstate = NLM_MONITOR_FAILED;
 1163                 mtx_unlock(&host->nh_lock);
 1164                 return;
 1165         }
 1166 
 1167         host->nh_monstate = NLM_MONITORED;
 1168 }
 1169 
 1170 /*
 1171  * Return an RPC client handle that can be used to talk to the NLM
 1172  * running on the given host.
 1173  */
 1174 CLIENT *
 1175 nlm_host_get_rpc(struct nlm_host *host)
 1176 {
 1177         CLIENT *client;
 1178 
 1179         mtx_lock(&host->nh_lock);
 1180 
 1181         /*
 1182          * We can't hold onto RPC handles for too long - the async
 1183          * call/reply protocol used by some NLM clients makes it hard
 1184          * to tell when they change port numbers (e.g. after a
 1185          * reboot). Note that if a client reboots while it isn't
 1186          * holding any locks, it won't bother to notify us. We
 1187          * expire the RPC handles after two minutes.
 1188          */
 1189         if (host->nh_rpc && time_uptime > host->nh_rpc_create_time + 2*60) {
 1190                 client = host->nh_rpc;
 1191                 host->nh_rpc = NULL;
 1192                 mtx_unlock(&host->nh_lock);
 1193                 CLNT_RELEASE(client);
 1194                 mtx_lock(&host->nh_lock);
 1195         }
 1196 
 1197         if (!host->nh_rpc) {
 1198                 mtx_unlock(&host->nh_lock);
 1199                 client = nlm_get_rpc((struct sockaddr *)&host->nh_addr,
 1200                     NLM_PROG, host->nh_vers);
 1201                 mtx_lock(&host->nh_lock);
 1202 
 1203                 if (client) {
 1204                         if (host->nh_rpc) {
 1205                                 mtx_unlock(&host->nh_lock);
 1206                                 CLNT_DESTROY(client);
 1207                                 mtx_lock(&host->nh_lock);
 1208                         } else {
 1209                                 host->nh_rpc = client;
 1210                                 host->nh_rpc_create_time = time_uptime;
 1211                         }
 1212                 }
 1213         }
 1214 
 1215         client = host->nh_rpc;
 1216         if (client)
 1217                 CLNT_ACQUIRE(client);
 1218         mtx_unlock(&host->nh_lock);
 1219 
 1220         return (client);
 1221 
 1222 }
 1223 
 1224 int nlm_host_get_sysid(struct nlm_host *host)
 1225 {
 1226 
 1227         return (host->nh_sysid);
 1228 }
 1229 
 1230 int
 1231 nlm_host_get_state(struct nlm_host *host)
 1232 {
 1233 
 1234         return (host->nh_state);
 1235 }
 1236 
 1237 void *
 1238 nlm_register_wait_lock(struct nlm4_lock *lock, struct vnode *vp)
 1239 {
 1240         struct nlm_waiting_lock *nw;
 1241 
 1242         nw = malloc(sizeof(struct nlm_waiting_lock), M_NLM, M_WAITOK);
 1243         nw->nw_lock = *lock;
 1244         memcpy(&nw->nw_fh.fh_bytes, nw->nw_lock.fh.n_bytes,
 1245             nw->nw_lock.fh.n_len);
 1246         nw->nw_lock.fh.n_bytes = nw->nw_fh.fh_bytes;
 1247         nw->nw_waiting = TRUE;
 1248         nw->nw_vp = vp;
 1249         mtx_lock(&nlm_global_lock);
 1250         TAILQ_INSERT_TAIL(&nlm_waiting_locks, nw, nw_link);
 1251         mtx_unlock(&nlm_global_lock);
 1252 
 1253         return nw;
 1254 }
 1255 
 1256 void
 1257 nlm_deregister_wait_lock(void *handle)
 1258 {
 1259         struct nlm_waiting_lock *nw = handle;
 1260 
 1261         mtx_lock(&nlm_global_lock);
 1262         TAILQ_REMOVE(&nlm_waiting_locks, nw, nw_link);
 1263         mtx_unlock(&nlm_global_lock);
 1264         
 1265         free(nw, M_NLM);
 1266 }
 1267 
 1268 int
 1269 nlm_wait_lock(void *handle, int timo)
 1270 {
 1271         struct nlm_waiting_lock *nw = handle;
 1272         int error;
 1273 
 1274         /*
 1275          * If the granted message arrived before we got here,
 1276          * nw->nw_waiting will be FALSE - in that case, don't sleep.
 1277          */
 1278         mtx_lock(&nlm_global_lock);
 1279         error = 0;
 1280         if (nw->nw_waiting)
 1281                 error = msleep(nw, &nlm_global_lock, PCATCH, "nlmlock", timo);
 1282         TAILQ_REMOVE(&nlm_waiting_locks, nw, nw_link);
 1283         if (error) {
 1284                 /*
 1285                  * The granted message may arrive after the
 1286                  * interrupt/timeout but before we manage to lock the
 1287                  * mutex. Detect this by examining nw_lock.
 1288                  */
 1289                 if (!nw->nw_waiting)
 1290                         error = 0;
 1291         } else {
 1292                 /*
 1293                  * If nlm_cancel_wait is called, then error will be
 1294                  * zero but nw_waiting will still be TRUE. We
 1295                  * translate this into EINTR.
 1296                  */
 1297                 if (nw->nw_waiting)
 1298                         error = EINTR;
 1299         }
 1300         mtx_unlock(&nlm_global_lock);
 1301 
 1302         free(nw, M_NLM);
 1303 
 1304         return (error);
 1305 }
 1306 
 1307 void
 1308 nlm_cancel_wait(struct vnode *vp)
 1309 {
 1310         struct nlm_waiting_lock *nw;
 1311 
 1312         mtx_lock(&nlm_global_lock);
 1313         TAILQ_FOREACH(nw, &nlm_waiting_locks, nw_link) {
 1314                 if (nw->nw_vp == vp) {
 1315                         wakeup(nw);
 1316                 }
 1317         }
 1318         mtx_unlock(&nlm_global_lock);
 1319 }
 1320 
 1321 
 1322 /**********************************************************************/
 1323 
 1324 /*
 1325  * Syscall interface with userland.
 1326  */
 1327 
 1328 extern void nlm_prog_0(struct svc_req *rqstp, SVCXPRT *transp);
 1329 extern void nlm_prog_1(struct svc_req *rqstp, SVCXPRT *transp);
 1330 extern void nlm_prog_3(struct svc_req *rqstp, SVCXPRT *transp);
 1331 extern void nlm_prog_4(struct svc_req *rqstp, SVCXPRT *transp);
 1332 
 1333 static int
 1334 nlm_register_services(SVCPOOL *pool, int addr_count, char **addrs)
 1335 {
 1336         static rpcvers_t versions[] = {
 1337                 NLM_SM, NLM_VERS, NLM_VERSX, NLM_VERS4
 1338         };
 1339         static void (*dispatchers[])(struct svc_req *, SVCXPRT *) = {
 1340                 nlm_prog_0, nlm_prog_1, nlm_prog_3, nlm_prog_4
 1341         };
 1342         static const int version_count = sizeof(versions) / sizeof(versions[0]);
 1343 
 1344         SVCXPRT **xprts;
 1345         char netid[16];
 1346         char uaddr[128];
 1347         struct netconfig *nconf;
 1348         int i, j, error;
 1349 
 1350         if (!addr_count) {
 1351                 printf("NLM: no service addresses given - can't start server");
 1352                 return (EINVAL);
 1353         }
 1354 
 1355         xprts = malloc(addr_count * sizeof(SVCXPRT *), M_NLM, M_WAITOK);
 1356         for (i = 0; i < version_count; i++) {
 1357                 for (j = 0; j < addr_count; j++) {
 1358                         /*
 1359                          * Create transports for the first version and
 1360                          * then just register everything else to the
 1361                          * same transports.
 1362                          */
 1363                         if (i == 0) {
 1364                                 char *up;
 1365 
 1366                                 error = copyin(&addrs[2*j], &up,
 1367                                     sizeof(char*));
 1368                                 if (error)
 1369                                         goto out;
 1370                                 error = copyinstr(up, netid, sizeof(netid),
 1371                                     NULL);
 1372                                 if (error)
 1373                                         goto out;
 1374                                 error = copyin(&addrs[2*j+1], &up,
 1375                                     sizeof(char*));
 1376                                 if (error)
 1377                                         goto out;
 1378                                 error = copyinstr(up, uaddr, sizeof(uaddr),
 1379                                     NULL);
 1380                                 if (error)
 1381                                         goto out;
 1382                                 nconf = getnetconfigent(netid);
 1383                                 if (!nconf) {
 1384                                         printf("Can't lookup netid %s\n",
 1385                                             netid);
 1386                                         error = EINVAL;
 1387                                         goto out;
 1388                                 }
 1389                                 xprts[j] = svc_tp_create(pool, dispatchers[i],
 1390                                     NLM_PROG, versions[i], uaddr, nconf);
 1391                                 if (!xprts[j]) {
 1392                                         printf("NLM: unable to create "
 1393                                             "(NLM_PROG, %d).\n", versions[i]);
 1394                                         error = EINVAL;
 1395                                         goto out;
 1396                                 }
 1397                                 freenetconfigent(nconf);
 1398                         } else {
 1399                                 nconf = getnetconfigent(xprts[j]->xp_netid);
 1400                                 rpcb_unset(NLM_PROG, versions[i], nconf);
 1401                                 if (!svc_reg(xprts[j], NLM_PROG, versions[i],
 1402                                         dispatchers[i], nconf)) {
 1403                                         printf("NLM: can't register "
 1404                                             "(NLM_PROG, %d)\n", versions[i]);
 1405                                         error = EINVAL;
 1406                                         goto out;
 1407                                 }
 1408                         }
 1409                 }
 1410         }
 1411         error = 0;
 1412 out:
 1413         free(xprts, M_NLM);
 1414         return (error);
 1415 }
 1416 
 1417 /*
 1418  * Main server entry point. Contacts the local NSM to get its current
 1419  * state and send SM_UNMON_ALL. Registers the NLM services and then
 1420  * services requests. Does not return until the server is interrupted
 1421  * by a signal.
 1422  */
 1423 static int
 1424 nlm_server_main(int addr_count, char **addrs)
 1425 {
 1426         struct thread *td = curthread;
 1427         int error;
 1428         SVCPOOL *pool = NULL;
 1429         struct sockopt opt;
 1430         int portlow;
 1431 #ifdef INET6
 1432         struct sockaddr_in6 sin6;
 1433 #endif
 1434         struct sockaddr_in sin;
 1435         my_id id;
 1436         sm_stat smstat;
 1437         struct timeval timo;
 1438         enum clnt_stat stat;
 1439         struct nlm_host *host, *nhost;
 1440         struct nlm_waiting_lock *nw;
 1441         vop_advlock_t *old_nfs_advlock;
 1442         vop_reclaim_t *old_nfs_reclaim;
 1443         int v4_used;
 1444 #ifdef INET6
 1445         int v6_used;
 1446 #endif
 1447 
 1448         if (nlm_socket) {
 1449                 printf("NLM: can't start server - it appears to be running already\n");
 1450                 return (EPERM);
 1451         }
 1452 
 1453         memset(&opt, 0, sizeof(opt));
 1454 
 1455         nlm_socket = NULL;
 1456         error = socreate(AF_INET, &nlm_socket, SOCK_DGRAM, 0,
 1457             td->td_ucred, td);
 1458         if (error) {
 1459                 printf("NLM: can't create IPv4 socket - error %d\n", error);
 1460                 return (error);
 1461         }
 1462         opt.sopt_dir = SOPT_SET;
 1463         opt.sopt_level = IPPROTO_IP;
 1464         opt.sopt_name = IP_PORTRANGE;
 1465         portlow = IP_PORTRANGE_LOW;
 1466         opt.sopt_val = &portlow;
 1467         opt.sopt_valsize = sizeof(portlow);
 1468         sosetopt(nlm_socket, &opt);
 1469 
 1470 #ifdef INET6
 1471         nlm_socket6 = NULL;
 1472         error = socreate(AF_INET6, &nlm_socket6, SOCK_DGRAM, 0,
 1473             td->td_ucred, td);
 1474         if (error) {
 1475                 printf("NLM: can't create IPv6 socket - error %d\n", error);
 1476                 goto out;
 1477                 return (error);
 1478         }
 1479         opt.sopt_dir = SOPT_SET;
 1480         opt.sopt_level = IPPROTO_IPV6;
 1481         opt.sopt_name = IPV6_PORTRANGE;
 1482         portlow = IPV6_PORTRANGE_LOW;
 1483         opt.sopt_val = &portlow;
 1484         opt.sopt_valsize = sizeof(portlow);
 1485         sosetopt(nlm_socket6, &opt);
 1486 #endif
 1487 
 1488         nlm_auth = authunix_create(curthread->td_ucred);
 1489 
 1490 #ifdef INET6
 1491         memset(&sin6, 0, sizeof(sin6));
 1492         sin6.sin6_len = sizeof(sin6);
 1493         sin6.sin6_family = AF_INET6;
 1494         sin6.sin6_addr = in6addr_loopback;
 1495         nlm_nsm = nlm_get_rpc((struct sockaddr *) &sin6, SM_PROG, SM_VERS);
 1496         if (!nlm_nsm) {
 1497 #endif
 1498                 memset(&sin, 0, sizeof(sin));
 1499                 sin.sin_len = sizeof(sin);
 1500                 sin.sin_family = AF_INET;
 1501                 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
 1502                 nlm_nsm = nlm_get_rpc((struct sockaddr *) &sin, SM_PROG,
 1503                     SM_VERS);
 1504 #ifdef INET6
 1505         }
 1506 #endif
 1507 
 1508         if (!nlm_nsm) {
 1509                 printf("Can't start NLM - unable to contact NSM\n");
 1510                 error = EINVAL;
 1511                 goto out;
 1512         }
 1513 
 1514         pool = svcpool_create();
 1515 
 1516         error = nlm_register_services(pool, addr_count, addrs);
 1517         if (error)
 1518                 goto out;
 1519 
 1520         memset(&id, 0, sizeof(id));
 1521         id.my_name = "NFS NLM";
 1522 
 1523         timo.tv_sec = 25;
 1524         timo.tv_usec = 0;
 1525         stat = CLNT_CALL(nlm_nsm, SM_UNMON_ALL,
 1526             (xdrproc_t) xdr_my_id, &id,
 1527             (xdrproc_t) xdr_sm_stat, &smstat, timo);
 1528 
 1529         if (stat != RPC_SUCCESS) {
 1530                 struct rpc_err err;
 1531 
 1532                 CLNT_GETERR(nlm_nsm, &err);
 1533                 printf("NLM: unexpected error contacting NSM, stat=%d, errno=%d\n",
 1534                     stat, err.re_errno);
 1535                 error = EINVAL;
 1536                 goto out;
 1537         }
 1538 
 1539         if (nlm_debug_level >= 1)
 1540                 printf("NLM: local NSM state is %d\n", smstat.state);
 1541         nlm_nsm_state = smstat.state;
 1542 
 1543         old_nfs_advlock = nfs_advlock_p;
 1544         nfs_advlock_p = nlm_advlock;
 1545         old_nfs_reclaim = nfs_reclaim_p;
 1546         nfs_reclaim_p = nlm_reclaim;
 1547 
 1548         svc_run(pool);
 1549         error = 0;
 1550 
 1551         nfs_advlock_p = old_nfs_advlock;
 1552         nfs_reclaim_p = old_nfs_reclaim;
 1553 
 1554 out:
 1555         if (pool)
 1556                 svcpool_destroy(pool);
 1557 
 1558         /*
 1559          * We are finished communicating with the NSM.
 1560          */
 1561         if (nlm_nsm) {
 1562                 CLNT_RELEASE(nlm_nsm);
 1563                 nlm_nsm = NULL;
 1564         }
 1565 
 1566         /*
 1567          * Trash all the existing state so that if the server
 1568          * restarts, it gets a clean slate. This is complicated by the
 1569          * possibility that there may be other threads trying to make
 1570          * client locking requests.
 1571          *
 1572          * First we fake a client reboot notification which will
 1573          * cancel any pending async locks and purge remote lock state
 1574          * from the local lock manager. We release the reference from
 1575          * nlm_hosts to the host (which may remove it from the list
 1576          * and free it). After this phase, the only entries in the
 1577          * nlm_host list should be from other threads performing
 1578          * client lock requests. We arrange to defer closing the
 1579          * sockets until the last RPC client handle is released.
 1580          */
 1581         v4_used = 0;
 1582 #ifdef INET6
 1583         v6_used = 0;
 1584 #endif
 1585         mtx_lock(&nlm_global_lock);
 1586         TAILQ_FOREACH(nw, &nlm_waiting_locks, nw_link) {
 1587                 wakeup(nw);
 1588         }
 1589         TAILQ_FOREACH_SAFE(host, &nlm_hosts, nh_link, nhost) {
 1590                 mtx_unlock(&nlm_global_lock);
 1591                 nlm_host_notify(host, 0);
 1592                 nlm_host_release(host);
 1593                 mtx_lock(&nlm_global_lock);
 1594         }
 1595         TAILQ_FOREACH_SAFE(host, &nlm_hosts, nh_link, nhost) {
 1596                 mtx_lock(&host->nh_lock);
 1597                 if (host->nh_rpc) {
 1598                         if (host->nh_addr.ss_family == AF_INET)
 1599                                 v4_used++;
 1600 #ifdef INET6
 1601                         if (host->nh_addr.ss_family == AF_INET6)
 1602                                 v6_used++;
 1603 #endif
 1604                         /*
 1605                          * Note that the rpc over udp code copes
 1606                          * correctly with the fact that a socket may
 1607                          * be used by many rpc handles.
 1608                          */
 1609                         CLNT_CONTROL(host->nh_rpc, CLSET_FD_CLOSE, 0);
 1610                 }
 1611                 mtx_unlock(&host->nh_lock);
 1612         }
 1613         mtx_unlock(&nlm_global_lock);
 1614 
 1615         AUTH_DESTROY(nlm_auth);
 1616 
 1617         if (!v4_used)
 1618                 soclose(nlm_socket);
 1619         nlm_socket = NULL;
 1620 #ifdef INET6
 1621         if (!v6_used)
 1622                 soclose(nlm_socket6);
 1623         nlm_socket6 = NULL;
 1624 #endif
 1625 
 1626         return (error);
 1627 }
 1628 
 1629 int
 1630 nlm_syscall(struct thread *td, struct nlm_syscall_args *uap)
 1631 {
 1632         int error;
 1633 
 1634 #if __FreeBSD_version >= 700000
 1635         error = priv_check(td, PRIV_NFS_LOCKD);
 1636 #else
 1637         error = suser(td);
 1638 #endif
 1639         if (error)
 1640                 return (error);
 1641 
 1642         nlm_debug_level = uap->debug_level;
 1643         nlm_grace_threshold = time_uptime + uap->grace_period;
 1644         nlm_next_idle_check = time_uptime + NLM_IDLE_PERIOD;
 1645 
 1646         return nlm_server_main(uap->addr_count, uap->addrs);
 1647 }
 1648 
 1649 /**********************************************************************/
 1650 
 1651 /*
 1652  * NLM implementation details, called from the RPC stubs.
 1653  */
 1654 
 1655 
 1656 void
 1657 nlm_sm_notify(struct nlm_sm_status *argp)
 1658 {
 1659         uint32_t sysid;
 1660         struct nlm_host *host;
 1661 
 1662         if (nlm_debug_level >= 3)
 1663                 printf("nlm_sm_notify(): mon_name = %s\n", argp->mon_name);
 1664         memcpy(&sysid, &argp->priv, sizeof(sysid));
 1665         host = nlm_find_host_by_sysid(sysid);
 1666         if (host) {
 1667                 nlm_host_notify(host, argp->state);
 1668                 nlm_host_release(host);
 1669         }
 1670 }
 1671 
 1672 static void
 1673 nlm_convert_to_fhandle_t(fhandle_t *fhp, struct netobj *p)
 1674 {
 1675         memcpy(fhp, p->n_bytes, sizeof(fhandle_t));
 1676 }
 1677 
 1678 struct vfs_state {
 1679         struct mount    *vs_mp;
 1680         struct vnode    *vs_vp;
 1681         int             vs_vfslocked;
 1682         int             vs_vnlocked;
 1683 };
 1684 
 1685 static int
 1686 nlm_get_vfs_state(struct nlm_host *host, struct svc_req *rqstp,
 1687     fhandle_t *fhp, struct vfs_state *vs)
 1688 {
 1689         int error, exflags, freecred;
 1690         struct ucred *cred = NULL, *credanon;
 1691         
 1692         memset(vs, 0, sizeof(*vs));
 1693         freecred = FALSE;
 1694 
 1695         vs->vs_mp = vfs_getvfs(&fhp->fh_fsid);
 1696         if (!vs->vs_mp) {
 1697                 return (ESTALE);
 1698         }
 1699         vs->vs_vfslocked = VFS_LOCK_GIANT(vs->vs_mp);
 1700 
 1701         error = VFS_CHECKEXP(vs->vs_mp, (struct sockaddr *)&host->nh_addr,
 1702             &exflags, &credanon);
 1703         if (error)
 1704                 goto out;
 1705 
 1706         if (exflags & MNT_EXRDONLY || (vs->vs_mp->mnt_flag & MNT_RDONLY)) {
 1707                 error = EROFS;
 1708                 goto out;
 1709         }
 1710 
 1711         error = VFS_FHTOVP(vs->vs_mp, &fhp->fh_fid, &vs->vs_vp);
 1712         if (error)
 1713                 goto out;
 1714         vs->vs_vnlocked = TRUE;
 1715 
 1716         cred = crget();
 1717         freecred = TRUE;
 1718         if (!svc_getcred(rqstp, cred, NULL)) {
 1719                 error = EINVAL;
 1720                 goto out;
 1721         }
 1722         if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
 1723                 crfree(cred);
 1724                 cred = credanon;
 1725                 freecred = FALSE;
 1726         }
 1727 
 1728         /*
 1729          * Check cred.
 1730          */
 1731         error = VOP_ACCESS(vs->vs_vp, VWRITE, cred, curthread);
 1732         if (error)
 1733                 goto out;
 1734 
 1735 #if __FreeBSD_version < 800011
 1736         VOP_UNLOCK(vs->vs_vp, 0, curthread);
 1737 #else
 1738         VOP_UNLOCK(vs->vs_vp, 0);
 1739 #endif
 1740         vs->vs_vnlocked = FALSE;
 1741 
 1742 out:
 1743         if (freecred)
 1744                 crfree(cred);
 1745 
 1746         return (error);
 1747 }
 1748 
 1749 static void
 1750 nlm_release_vfs_state(struct vfs_state *vs)
 1751 {
 1752 
 1753         if (vs->vs_vp) {
 1754                 if (vs->vs_vnlocked)
 1755                         vput(vs->vs_vp);
 1756                 else
 1757                         vrele(vs->vs_vp);
 1758         }
 1759         if (vs->vs_mp)
 1760                 vfs_rel(vs->vs_mp);
 1761         VFS_UNLOCK_GIANT(vs->vs_vfslocked);
 1762 }
 1763 
 1764 static nlm4_stats
 1765 nlm_convert_error(int error)
 1766 {
 1767 
 1768         if (error == ESTALE)
 1769                 return nlm4_stale_fh;
 1770         else if (error == EROFS)
 1771                 return nlm4_rofs;
 1772         else
 1773                 return nlm4_failed;
 1774 }
 1775 
 1776 int
 1777 nlm_do_test(nlm4_testargs *argp, nlm4_testres *result, struct svc_req *rqstp,
 1778         CLIENT **rpcp)
 1779 {
 1780         fhandle_t fh;
 1781         struct vfs_state vs;
 1782         struct nlm_host *host, *bhost;
 1783         int error, sysid;
 1784         struct flock fl;
 1785         
 1786         memset(result, 0, sizeof(*result));
 1787         memset(&vs, 0, sizeof(vs));
 1788 
 1789         host = nlm_find_host_by_name(argp->alock.caller_name,
 1790             (struct sockaddr *) rqstp->rq_xprt->xp_rtaddr.buf, rqstp->rq_vers);
 1791         if (!host) {
 1792                 result->stat.stat = nlm4_denied_nolocks;
 1793                 return (ENOMEM);
 1794         }
 1795 
 1796         if (nlm_debug_level >= 3)
 1797                 printf("nlm_do_test(): caller_name = %s (sysid = %d)\n",
 1798                     host->nh_caller_name, host->nh_sysid);
 1799 
 1800         nlm_free_finished_locks(host);
 1801         sysid = host->nh_sysid;
 1802 
 1803         nlm_convert_to_fhandle_t(&fh, &argp->alock.fh);
 1804         nlm_copy_netobj(&result->cookie, &argp->cookie, M_RPC);
 1805 
 1806         if (time_uptime < nlm_grace_threshold) {
 1807                 result->stat.stat = nlm4_denied_grace_period;
 1808                 goto out;
 1809         }
 1810 
 1811         error = nlm_get_vfs_state(host, rqstp, &fh, &vs);
 1812         if (error) {
 1813                 result->stat.stat = nlm_convert_error(error);
 1814                 goto out;
 1815         }
 1816 
 1817         fl.l_start = argp->alock.l_offset;
 1818         fl.l_len = argp->alock.l_len;
 1819         fl.l_pid = argp->alock.svid;
 1820         fl.l_sysid = sysid;
 1821         fl.l_whence = SEEK_SET;
 1822         if (argp->exclusive)
 1823                 fl.l_type = F_WRLCK;
 1824         else
 1825                 fl.l_type = F_RDLCK;
 1826         error = VOP_ADVLOCK(vs.vs_vp, NULL, F_GETLK, &fl, F_REMOTE);
 1827         if (error) {
 1828                 result->stat.stat = nlm4_failed;
 1829                 goto out;
 1830         }
 1831 
 1832         if (fl.l_type == F_UNLCK) {
 1833                 result->stat.stat = nlm4_granted;
 1834         } else {
 1835                 result->stat.stat = nlm4_denied;
 1836                 result->stat.nlm4_testrply_u.holder.exclusive =
 1837                         (fl.l_type == F_WRLCK);
 1838                 result->stat.nlm4_testrply_u.holder.svid = fl.l_pid;
 1839                 bhost = nlm_find_host_by_sysid(fl.l_sysid);
 1840                 if (bhost) {
 1841                         /*
 1842                          * We don't have any useful way of recording
 1843                          * the value of oh used in the original lock
 1844                          * request. Ideally, the test reply would have
 1845                          * a space for the owning host's name allowing
 1846                          * our caller's NLM to keep track.
 1847                          *
 1848                          * As far as I can see, Solaris uses an eight
 1849                          * byte structure for oh which contains a four
 1850                          * byte pid encoded in local byte order and
 1851                          * the first four bytes of the host
 1852                          * name. Linux uses a variable length string
 1853                          * 'pid@hostname' in ascii but doesn't even
 1854                          * return that in test replies.
 1855                          *
 1856                          * For the moment, return nothing in oh
 1857                          * (already zero'ed above).
 1858                          */
 1859                         nlm_host_release(bhost);
 1860                 }
 1861                 result->stat.nlm4_testrply_u.holder.l_offset = fl.l_start;
 1862                 result->stat.nlm4_testrply_u.holder.l_len = fl.l_len;
 1863         }
 1864 
 1865 out:
 1866         nlm_release_vfs_state(&vs);
 1867         if (rpcp)
 1868                 *rpcp = nlm_host_get_rpc(host);
 1869         nlm_host_release(host);
 1870         return (0);
 1871 }
 1872 
 1873 int
 1874 nlm_do_lock(nlm4_lockargs *argp, nlm4_res *result, struct svc_req *rqstp,
 1875     bool_t monitor, CLIENT **rpcp)
 1876 {
 1877         fhandle_t fh;
 1878         struct vfs_state vs;
 1879         struct nlm_host *host;
 1880         int error, sysid;
 1881         struct flock fl;
 1882         
 1883         memset(result, 0, sizeof(*result));
 1884         memset(&vs, 0, sizeof(vs));
 1885 
 1886         host = nlm_find_host_by_name(argp->alock.caller_name,
 1887             (struct sockaddr *) rqstp->rq_xprt->xp_rtaddr.buf, rqstp->rq_vers);
 1888         if (!host) {
 1889                 result->stat.stat = nlm4_denied_nolocks;
 1890                 return (ENOMEM);
 1891         }
 1892 
 1893         if (nlm_debug_level >= 3)
 1894                 printf("nlm_do_lock(): caller_name = %s (sysid = %d)\n",
 1895                     host->nh_caller_name, host->nh_sysid);
 1896 
 1897         if (monitor && host->nh_state && argp->state
 1898             && host->nh_state != argp->state) {
 1899                 /*
 1900                  * The host rebooted without telling us. Trash its
 1901                  * locks.
 1902                  */
 1903                 nlm_host_notify(host, argp->state);
 1904         }
 1905 
 1906         nlm_free_finished_locks(host);
 1907         sysid = host->nh_sysid;
 1908 
 1909         nlm_convert_to_fhandle_t(&fh, &argp->alock.fh);
 1910         nlm_copy_netobj(&result->cookie, &argp->cookie, M_RPC);
 1911 
 1912         if (time_uptime < nlm_grace_threshold && !argp->reclaim) {
 1913                 result->stat.stat = nlm4_denied_grace_period;
 1914                 goto out;
 1915         }
 1916 
 1917         error = nlm_get_vfs_state(host, rqstp, &fh, &vs);
 1918         if (error) {
 1919                 result->stat.stat = nlm_convert_error(error);
 1920                 goto out;
 1921         }
 1922 
 1923         fl.l_start = argp->alock.l_offset;
 1924         fl.l_len = argp->alock.l_len;
 1925         fl.l_pid = argp->alock.svid;
 1926         fl.l_sysid = sysid;
 1927         fl.l_whence = SEEK_SET;
 1928         if (argp->exclusive)
 1929                 fl.l_type = F_WRLCK;
 1930         else
 1931                 fl.l_type = F_RDLCK;
 1932         if (argp->block) {
 1933                 struct nlm_async_lock *af;
 1934                 CLIENT *client;
 1935 
 1936                 /*
 1937                  * First, make sure we can contact the host's NLM.
 1938                  */
 1939                 client = nlm_host_get_rpc(host);
 1940                 if (!client) {
 1941                         result->stat.stat = nlm4_failed;
 1942                         goto out;
 1943                 }
 1944 
 1945                 /*
 1946                  * First we need to check and see if there is an
 1947                  * existing blocked lock that matches. This could be a
 1948                  * badly behaved client or an RPC re-send. If we find
 1949                  * one, just return nlm4_blocked.
 1950                  */
 1951                 mtx_lock(&host->nh_lock);
 1952                 TAILQ_FOREACH(af, &host->nh_pending, af_link) {
 1953                         if (af->af_fl.l_start == fl.l_start
 1954                             && af->af_fl.l_len == fl.l_len
 1955                             && af->af_fl.l_pid == fl.l_pid
 1956                             && af->af_fl.l_type == fl.l_type) {
 1957                                 break;
 1958                         }
 1959                 }
 1960                 mtx_unlock(&host->nh_lock);
 1961                 if (af) {
 1962                         CLNT_RELEASE(client);
 1963                         result->stat.stat = nlm4_blocked;
 1964                         goto out;
 1965                 }
 1966 
 1967                 af = malloc(sizeof(struct nlm_async_lock), M_NLM,
 1968                     M_WAITOK|M_ZERO);
 1969                 TASK_INIT(&af->af_task, 0, nlm_lock_callback, af);
 1970                 af->af_vp = vs.vs_vp;
 1971                 af->af_fl = fl;
 1972                 af->af_host = host;
 1973                 af->af_rpc = client;
 1974                 /*
 1975                  * We use M_RPC here so that we can xdr_free the thing
 1976                  * later.
 1977                  */
 1978                 af->af_granted.exclusive = argp->exclusive;
 1979                 af->af_granted.alock.caller_name =
 1980                         strdup(argp->alock.caller_name, M_RPC);
 1981                 nlm_copy_netobj(&af->af_granted.alock.fh,
 1982                     &argp->alock.fh, M_RPC);
 1983                 nlm_copy_netobj(&af->af_granted.alock.oh,
 1984                     &argp->alock.oh, M_RPC);
 1985                 af->af_granted.alock.svid = argp->alock.svid;
 1986                 af->af_granted.alock.l_offset = argp->alock.l_offset;
 1987                 af->af_granted.alock.l_len = argp->alock.l_len;
 1988 
 1989                 /*
 1990                  * Put the entry on the pending list before calling
 1991                  * VOP_ADVLOCKASYNC. We do this in case the lock
 1992                  * request was blocked (returning EINPROGRESS) but
 1993                  * then granted before we manage to run again. The
 1994                  * client may receive the granted message before we
 1995                  * send our blocked reply but thats their problem.
 1996                  */
 1997                 mtx_lock(&host->nh_lock);
 1998                 TAILQ_INSERT_TAIL(&host->nh_pending, af, af_link);
 1999                 mtx_unlock(&host->nh_lock);
 2000 
 2001                 error = VOP_ADVLOCKASYNC(vs.vs_vp, NULL, F_SETLK, &fl, F_REMOTE,
 2002                     &af->af_task, &af->af_cookie);
 2003 
 2004                 /*
 2005                  * If the lock completed synchronously, just free the
 2006                  * tracking structure now.
 2007                  */
 2008                 if (error != EINPROGRESS) {
 2009                         CLNT_RELEASE(af->af_rpc);
 2010                         mtx_lock(&host->nh_lock);
 2011                         TAILQ_REMOVE(&host->nh_pending, af, af_link);
 2012                         mtx_unlock(&host->nh_lock);
 2013                         xdr_free((xdrproc_t) xdr_nlm4_testargs,
 2014                             &af->af_granted);
 2015                         free(af, M_NLM);
 2016                 } else {
 2017                         if (nlm_debug_level >= 2)
 2018                                 printf("NLM: pending async lock %p for %s "
 2019                                     "(sysid %d)\n",
 2020                                     af, host->nh_caller_name, sysid);
 2021                         /*
 2022                          * Don't vrele the vnode just yet - this must
 2023                          * wait until either the async callback
 2024                          * happens or the lock is cancelled.
 2025                          */
 2026                         vs.vs_vp = NULL;
 2027                 }
 2028         } else {
 2029                 error = VOP_ADVLOCK(vs.vs_vp, NULL, F_SETLK, &fl, F_REMOTE);
 2030         }
 2031 
 2032         if (error) {
 2033                 if (error == EINPROGRESS) {
 2034                         result->stat.stat = nlm4_blocked;
 2035                 } else if (error == EDEADLK) {
 2036                         result->stat.stat = nlm4_deadlck;
 2037                 } else if (error == EAGAIN) {
 2038                         result->stat.stat = nlm4_denied;
 2039                 } else {
 2040                         result->stat.stat = nlm4_failed;
 2041                 }
 2042         } else {
 2043                 if (monitor)
 2044                         nlm_host_monitor(host, argp->state);
 2045                 result->stat.stat = nlm4_granted;
 2046         }       
 2047 
 2048 out:
 2049         nlm_release_vfs_state(&vs);
 2050         if (rpcp)
 2051                 *rpcp = nlm_host_get_rpc(host);
 2052         nlm_host_release(host);
 2053         return (0);
 2054 }
 2055 
 2056 int
 2057 nlm_do_cancel(nlm4_cancargs *argp, nlm4_res *result, struct svc_req *rqstp,
 2058     CLIENT **rpcp)
 2059 {
 2060         fhandle_t fh;
 2061         struct vfs_state vs;
 2062         struct nlm_host *host;
 2063         int error, sysid;
 2064         struct flock fl;
 2065         struct nlm_async_lock *af;
 2066         
 2067         memset(result, 0, sizeof(*result));
 2068         memset(&vs, 0, sizeof(vs));
 2069 
 2070         host = nlm_find_host_by_name(argp->alock.caller_name,
 2071             (struct sockaddr *) rqstp->rq_xprt->xp_rtaddr.buf, rqstp->rq_vers);
 2072         if (!host) {
 2073                 result->stat.stat = nlm4_denied_nolocks;
 2074                 return (ENOMEM);
 2075         }
 2076 
 2077         if (nlm_debug_level >= 3)
 2078                 printf("nlm_do_cancel(): caller_name = %s (sysid = %d)\n",
 2079                     host->nh_caller_name, host->nh_sysid);
 2080 
 2081         nlm_free_finished_locks(host);
 2082         sysid = host->nh_sysid;
 2083 
 2084         nlm_convert_to_fhandle_t(&fh, &argp->alock.fh);
 2085         nlm_copy_netobj(&result->cookie, &argp->cookie, M_RPC);
 2086 
 2087         if (time_uptime < nlm_grace_threshold) {
 2088                 result->stat.stat = nlm4_denied_grace_period;
 2089                 goto out;
 2090         }
 2091 
 2092         error = nlm_get_vfs_state(host, rqstp, &fh, &vs);
 2093         if (error) {
 2094                 result->stat.stat = nlm_convert_error(error);
 2095                 goto out;
 2096         }
 2097 
 2098         fl.l_start = argp->alock.l_offset;
 2099         fl.l_len = argp->alock.l_len;
 2100         fl.l_pid = argp->alock.svid;
 2101         fl.l_sysid = sysid;
 2102         fl.l_whence = SEEK_SET;
 2103         if (argp->exclusive)
 2104                 fl.l_type = F_WRLCK;
 2105         else
 2106                 fl.l_type = F_RDLCK;
 2107 
 2108         /*
 2109          * First we need to try and find the async lock request - if
 2110          * there isn't one, we give up and return nlm4_denied.
 2111          */
 2112         mtx_lock(&host->nh_lock);
 2113 
 2114         TAILQ_FOREACH(af, &host->nh_pending, af_link) {
 2115                 if (af->af_fl.l_start == fl.l_start
 2116                     && af->af_fl.l_len == fl.l_len
 2117                     && af->af_fl.l_pid == fl.l_pid
 2118                     && af->af_fl.l_type == fl.l_type) {
 2119                         break;
 2120                 }
 2121         }
 2122 
 2123         if (!af) {
 2124                 mtx_unlock(&host->nh_lock);
 2125                 result->stat.stat = nlm4_denied;
 2126                 goto out;
 2127         }
 2128 
 2129         error = nlm_cancel_async_lock(af);
 2130 
 2131         if (error) {
 2132                 result->stat.stat = nlm4_denied;
 2133         } else {
 2134                 result->stat.stat = nlm4_granted;
 2135         }
 2136 
 2137         mtx_unlock(&host->nh_lock);
 2138 
 2139 out:
 2140         nlm_release_vfs_state(&vs);
 2141         if (rpcp)
 2142                 *rpcp = nlm_host_get_rpc(host);
 2143         nlm_host_release(host);
 2144         return (0);
 2145 }
 2146 
 2147 int
 2148 nlm_do_unlock(nlm4_unlockargs *argp, nlm4_res *result, struct svc_req *rqstp,
 2149     CLIENT **rpcp)
 2150 {
 2151         fhandle_t fh;
 2152         struct vfs_state vs;
 2153         struct nlm_host *host;
 2154         int error, sysid;
 2155         struct flock fl;
 2156         
 2157         memset(result, 0, sizeof(*result));
 2158         memset(&vs, 0, sizeof(vs));
 2159 
 2160         host = nlm_find_host_by_name(argp->alock.caller_name,
 2161             (struct sockaddr *) rqstp->rq_xprt->xp_rtaddr.buf, rqstp->rq_vers);
 2162         if (!host) {
 2163                 result->stat.stat = nlm4_denied_nolocks;
 2164                 return (ENOMEM);
 2165         }
 2166 
 2167         if (nlm_debug_level >= 3)
 2168                 printf("nlm_do_unlock(): caller_name = %s (sysid = %d)\n",
 2169                     host->nh_caller_name, host->nh_sysid);
 2170 
 2171         nlm_free_finished_locks(host);
 2172         sysid = host->nh_sysid;
 2173 
 2174         nlm_convert_to_fhandle_t(&fh, &argp->alock.fh);
 2175         nlm_copy_netobj(&result->cookie, &argp->cookie, M_RPC);
 2176 
 2177         if (time_uptime < nlm_grace_threshold) {
 2178                 result->stat.stat = nlm4_denied_grace_period;
 2179                 goto out;
 2180         }
 2181 
 2182         error = nlm_get_vfs_state(host, rqstp, &fh, &vs);
 2183         if (error) {
 2184                 result->stat.stat = nlm_convert_error(error);
 2185                 goto out;
 2186         }
 2187 
 2188         fl.l_start = argp->alock.l_offset;
 2189         fl.l_len = argp->alock.l_len;
 2190         fl.l_pid = argp->alock.svid;
 2191         fl.l_sysid = sysid;
 2192         fl.l_whence = SEEK_SET;
 2193         fl.l_type = F_UNLCK;
 2194         error = VOP_ADVLOCK(vs.vs_vp, NULL, F_UNLCK, &fl, F_REMOTE);
 2195 
 2196         /*
 2197          * Ignore the error - there is no result code for failure,
 2198          * only for grace period.
 2199          */
 2200         result->stat.stat = nlm4_granted;
 2201 
 2202 out:
 2203         nlm_release_vfs_state(&vs);
 2204         if (rpcp)
 2205                 *rpcp = nlm_host_get_rpc(host);
 2206         nlm_host_release(host);
 2207         return (0);
 2208 }
 2209 
 2210 int
 2211 nlm_do_granted(nlm4_testargs *argp, nlm4_res *result, struct svc_req *rqstp,
 2212 
 2213     CLIENT **rpcp)
 2214 {
 2215         struct nlm_host *host;
 2216         struct nlm_waiting_lock *nw;
 2217         
 2218         memset(result, 0, sizeof(*result));
 2219 
 2220         host = nlm_find_host_by_addr(
 2221                 (struct sockaddr *) rqstp->rq_xprt->xp_rtaddr.buf,
 2222                 rqstp->rq_vers);
 2223         if (!host) {
 2224                 result->stat.stat = nlm4_denied_nolocks;
 2225                 return (ENOMEM);
 2226         }
 2227 
 2228         nlm_copy_netobj(&result->cookie, &argp->cookie, M_RPC);
 2229         result->stat.stat = nlm4_denied;
 2230 
 2231         mtx_lock(&nlm_global_lock);
 2232         TAILQ_FOREACH(nw, &nlm_waiting_locks, nw_link) {
 2233                 if (!nw->nw_waiting)
 2234                         continue;
 2235                 if (argp->alock.svid == nw->nw_lock.svid
 2236                     && argp->alock.l_offset == nw->nw_lock.l_offset
 2237                     && argp->alock.l_len == nw->nw_lock.l_len
 2238                     && argp->alock.fh.n_len == nw->nw_lock.fh.n_len
 2239                     && !memcmp(argp->alock.fh.n_bytes, nw->nw_lock.fh.n_bytes,
 2240                         nw->nw_lock.fh.n_len)) {
 2241                         nw->nw_waiting = FALSE;
 2242                         wakeup(nw);
 2243                         result->stat.stat = nlm4_granted;
 2244                         break;
 2245                 }
 2246         }
 2247         mtx_unlock(&nlm_global_lock);
 2248         if (rpcp)
 2249                 *rpcp = nlm_host_get_rpc(host);
 2250         nlm_host_release(host);
 2251         return (0);
 2252 }
 2253 
 2254 void
 2255 nlm_do_free_all(nlm4_notify *argp)
 2256 {
 2257         struct nlm_host *host, *thost;
 2258 
 2259         TAILQ_FOREACH_SAFE(host, &nlm_hosts, nh_link, thost) {
 2260                 if (!strcmp(host->nh_caller_name, argp->name))
 2261                         nlm_host_notify(host, argp->state);
 2262         }
 2263 }
 2264 
 2265 /*
 2266  * Kernel module glue
 2267  */
 2268 static int
 2269 nfslockd_modevent(module_t mod, int type, void *data)
 2270 {
 2271 
 2272         return (0);
 2273 }
 2274 static moduledata_t nfslockd_mod = {
 2275         "nfslockd",
 2276         nfslockd_modevent,
 2277         NULL,
 2278 };
 2279 DECLARE_MODULE(nfslockd, nfslockd_mod, SI_SUB_VFS, SI_ORDER_ANY);
 2280 
 2281 /* So that loader and kldload(2) can find us, wherever we are.. */
 2282 MODULE_DEPEND(nfslockd, krpc, 1, 1, 1);
 2283 MODULE_DEPEND(nfslockd, nfs, 1, 1, 1);
 2284 MODULE_VERSION(nfslockd, 1);

Cache object: fbf139c7e78faa87d765a1d079114c1a


[ 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.