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