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