1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2016 Nexenta Systems, Inc. All rights reserved. 24 * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved. 25 * Copyright (c) 2015 by Delphix. All rights reserved. 26 * Copyright (c) 2015 Joyent, Inc. All rights reserved. 27 */ 28 29 #include <sys/param.h> 30 #include <sys/errno.h> 31 #include <sys/vfs.h> 32 #include <sys/vnode.h> 33 #include <sys/cred.h> 34 #include <sys/cmn_err.h> 35 #include <sys/systm.h> 36 #include <sys/kmem.h> 37 #include <sys/pathname.h> 38 #include <sys/utsname.h> 39 #include <sys/debug.h> 40 #include <sys/door.h> 41 #include <sys/sdt.h> 42 #include <sys/thread.h> 43 #include <sys/avl.h> 44 45 #include <rpc/types.h> 46 #include <rpc/auth.h> 47 #include <rpc/clnt.h> 48 49 #include <nfs/nfs.h> 50 #include <nfs/export.h> 51 #include <nfs/nfs_clnt.h> 52 #include <nfs/auth.h> 53 54 static struct kmem_cache *exi_cache_handle; 55 static void exi_cache_reclaim(void *); 56 static void exi_cache_trim(struct exportinfo *exi); 57 58 extern pri_t minclsyspri; 59 60 volatile uint_t nfsauth_cache_hit; 61 volatile uint_t nfsauth_cache_miss; 62 volatile uint_t nfsauth_cache_refresh; 63 volatile uint_t nfsauth_cache_reclaim; 64 volatile uint_t exi_cache_auth_reclaim_failed; 65 volatile uint_t exi_cache_clnt_reclaim_failed; 66 67 /* 68 * The lifetime of an auth cache entry: 69 * ------------------------------------ 70 * 71 * An auth cache entry is created with both the auth_time 72 * and auth_freshness times set to the current time. 73 * 74 * Upon every client access which results in a hit, the 75 * auth_time will be updated. 76 * 77 * If a client access determines that the auth_freshness 78 * indicates that the entry is STALE, then it will be 79 * refreshed. Note that this will explicitly reset 80 * auth_time. 81 * 82 * When the REFRESH successfully occurs, then the 83 * auth_freshness is updated. 84 * 85 * There are two ways for an entry to leave the cache: 86 * 87 * 1) Purged by an action on the export (remove or changed) 88 * 2) Memory backpressure from the kernel (check against NFSAUTH_CACHE_TRIM) 89 * 90 * For 2) we check the timeout value against auth_time. 91 */ 92 93 /* 94 * Number of seconds until we mark for refresh an auth cache entry. 95 */ 96 #define NFSAUTH_CACHE_REFRESH 600 97 98 /* 99 * Number of idle seconds until we yield to backpressure 100 * to trim a cache entry. 101 */ 102 #define NFSAUTH_CACHE_TRIM 3600 103 104 /* 105 * While we could encapuslate the exi_list inside the 106 * exi structure, we can't do that for the auth_list. 107 * So, to keep things looking clean, we keep them both 108 * in these external lists. 109 */ 110 typedef struct refreshq_exi_node { 111 struct exportinfo *ren_exi; 112 list_t ren_authlist; 113 list_node_t ren_node; 114 } refreshq_exi_node_t; 115 116 typedef struct refreshq_auth_node { 117 struct auth_cache *ran_auth; 118 char *ran_netid; 119 list_node_t ran_node; 120 } refreshq_auth_node_t; 121 122 /* 123 * Used to manipulate things on the refreshq_queue. 124 * Note that the refresh thread will effectively 125 * pop a node off of the queue, at which point it 126 * will no longer need to hold the mutex. 127 */ 128 static kmutex_t refreshq_lock; 129 static list_t refreshq_queue; 130 static kcondvar_t refreshq_cv; 131 132 /* 133 * If there is ever a problem with loading the 134 * module, then nfsauth_fini() needs to be called 135 * to remove state. In that event, since the 136 * refreshq thread has been started, they need to 137 * work together to get rid of state. 138 */ 139 typedef enum nfsauth_refreshq_thread_state { 140 REFRESHQ_THREAD_RUNNING, 141 REFRESHQ_THREAD_FINI_REQ, 142 REFRESHQ_THREAD_HALTED 143 } nfsauth_refreshq_thread_state_t; 144 145 nfsauth_refreshq_thread_state_t 146 refreshq_thread_state = REFRESHQ_THREAD_HALTED; 147 148 static void nfsauth_free_node(struct auth_cache *); 149 static void nfsauth_refresh_thread(void); 150 151 static int nfsauth_cache_compar(const void *, const void *); 152 153 /* 154 * mountd is a server-side only daemon. This will need to be 155 * revisited if the NFS server is ever made zones-aware. 156 */ 157 kmutex_t mountd_lock; 158 door_handle_t mountd_dh; 159 160 void 161 mountd_args(uint_t did) 162 { 163 mutex_enter(&mountd_lock); 164 if (mountd_dh != NULL) 165 door_ki_rele(mountd_dh); 166 mountd_dh = door_ki_lookup(did); 167 mutex_exit(&mountd_lock); 168 } 169 170 void 171 nfsauth_init(void) 172 { 173 /* 174 * mountd can be restarted by smf(5). We need to make sure 175 * the updated door handle will safely make it to mountd_dh 176 */ 177 mutex_init(&mountd_lock, NULL, MUTEX_DEFAULT, NULL); 178 179 mutex_init(&refreshq_lock, NULL, MUTEX_DEFAULT, NULL); 180 list_create(&refreshq_queue, sizeof (refreshq_exi_node_t), 181 offsetof(refreshq_exi_node_t, ren_node)); 182 183 cv_init(&refreshq_cv, NULL, CV_DEFAULT, NULL); 184 185 /* 186 * Allocate nfsauth cache handle 187 */ 188 exi_cache_handle = kmem_cache_create("exi_cache_handle", 189 sizeof (struct auth_cache), 0, NULL, NULL, 190 exi_cache_reclaim, NULL, NULL, 0); 191 192 refreshq_thread_state = REFRESHQ_THREAD_RUNNING; 193 (void) zthread_create(NULL, 0, nfsauth_refresh_thread, 194 NULL, 0, minclsyspri); 195 } 196 197 /* 198 * Finalization routine for nfsauth. It is important to call this routine 199 * before destroying the exported_lock. 200 */ 201 void 202 nfsauth_fini(void) 203 { 204 refreshq_exi_node_t *ren; 205 206 /* 207 * Prevent the nfsauth_refresh_thread from getting new 208 * work. 209 */ 210 mutex_enter(&refreshq_lock); 211 if (refreshq_thread_state != REFRESHQ_THREAD_HALTED) { 212 refreshq_thread_state = REFRESHQ_THREAD_FINI_REQ; 213 cv_broadcast(&refreshq_cv); 214 215 /* 216 * Also, wait for nfsauth_refresh_thread() to exit. 217 */ 218 while (refreshq_thread_state != REFRESHQ_THREAD_HALTED) { 219 cv_wait(&refreshq_cv, &refreshq_lock); 220 } 221 } 222 mutex_exit(&refreshq_lock); 223 224 /* 225 * Walk the exi_list and in turn, walk the auth_lists and free all 226 * lists. In addition, free INVALID auth_cache entries. 227 */ 228 while ((ren = list_remove_head(&refreshq_queue))) { 229 refreshq_auth_node_t *ran; 230 231 while ((ran = list_remove_head(&ren->ren_authlist)) != NULL) { 232 struct auth_cache *p = ran->ran_auth; 233 if (p->auth_state == NFS_AUTH_INVALID) 234 nfsauth_free_node(p); 235 strfree(ran->ran_netid); 236 kmem_free(ran, sizeof (refreshq_auth_node_t)); 237 } 238 239 list_destroy(&ren->ren_authlist); 240 exi_rele(ren->ren_exi); 241 kmem_free(ren, sizeof (refreshq_exi_node_t)); 242 } 243 list_destroy(&refreshq_queue); 244 245 cv_destroy(&refreshq_cv); 246 mutex_destroy(&refreshq_lock); 247 248 mutex_destroy(&mountd_lock); 249 250 /* 251 * Deallocate nfsauth cache handle 252 */ 253 kmem_cache_destroy(exi_cache_handle); 254 } 255 256 /* 257 * Convert the address in a netbuf to 258 * a hash index for the auth_cache table. 259 */ 260 static int 261 hash(struct netbuf *a) 262 { 263 int i, h = 0; 264 265 for (i = 0; i < a->len; i++) 266 h ^= a->buf[i]; 267 268 return (h & (AUTH_TABLESIZE - 1)); 269 } 270 271 /* 272 * Mask out the components of an 273 * address that do not identify 274 * a host. For socket addresses the 275 * masking gets rid of the port number. 276 */ 277 static void 278 addrmask(struct netbuf *addr, struct netbuf *mask) 279 { 280 int i; 281 282 for (i = 0; i < addr->len; i++) 283 addr->buf[i] &= mask->buf[i]; 284 } 285 286 /* 287 * nfsauth4_access is used for NFS V4 auth checking. Besides doing 288 * the common nfsauth_access(), it will check if the client can 289 * have a limited access to this vnode even if the security flavor 290 * used does not meet the policy. 291 */ 292 int 293 nfsauth4_access(struct exportinfo *exi, vnode_t *vp, struct svc_req *req, 294 cred_t *cr, uid_t *uid, gid_t *gid, uint_t *ngids, gid_t **gids) 295 { 296 int access; 297 298 access = nfsauth_access(exi, req, cr, uid, gid, ngids, gids); 299 300 /* 301 * There are cases that the server needs to allow the client 302 * to have a limited view. 303 * 304 * e.g. 305 * /export is shared as "sec=sys,rw=dfs-test-4,sec=krb5,rw" 306 * /export/home is shared as "sec=sys,rw" 307 * 308 * When the client mounts /export with sec=sys, the client 309 * would get a limited view with RO access on /export to see 310 * "home" only because the client is allowed to access 311 * /export/home with auth_sys. 312 */ 313 if (access & NFSAUTH_DENIED || access & NFSAUTH_WRONGSEC) { 314 /* 315 * Allow ro permission with LIMITED view if there is a 316 * sub-dir exported under vp. 317 */ 318 if (has_visible(exi, vp)) 319 return (NFSAUTH_LIMITED); 320 } 321 322 return (access); 323 } 324 325 static void 326 sys_log(const char *msg) 327 { 328 static time_t tstamp = 0; 329 time_t now; 330 331 /* 332 * msg is shown (at most) once per minute 333 */ 334 now = gethrestime_sec(); 335 if ((tstamp + 60) < now) { 336 tstamp = now; 337 cmn_err(CE_WARN, msg); 338 } 339 } 340 341 /* 342 * Callup to the mountd to get access information in the kernel. 343 */ 344 static bool_t 345 nfsauth_retrieve(struct exportinfo *exi, char *req_netid, int flavor, 346 struct netbuf *addr, int *access, cred_t *clnt_cred, uid_t *srv_uid, 347 gid_t *srv_gid, uint_t *srv_gids_cnt, gid_t **srv_gids) 348 { 349 varg_t varg = {0}; 350 nfsauth_res_t res = {0}; 351 XDR xdrs; 352 size_t absz; 353 caddr_t abuf; 354 int last = 0; 355 door_arg_t da; 356 door_info_t di; 357 door_handle_t dh; 358 uint_t ntries = 0; 359 360 /* 361 * No entry in the cache for this client/flavor 362 * so we need to call the nfsauth service in the 363 * mount daemon. 364 */ 365 366 varg.vers = V_PROTO; 367 varg.arg_u.arg.cmd = NFSAUTH_ACCESS; 368 varg.arg_u.arg.areq.req_client.n_len = addr->len; 369 varg.arg_u.arg.areq.req_client.n_bytes = addr->buf; 370 varg.arg_u.arg.areq.req_netid = req_netid; 371 varg.arg_u.arg.areq.req_path = exi->exi_export.ex_path; 372 varg.arg_u.arg.areq.req_flavor = flavor; 373 varg.arg_u.arg.areq.req_clnt_uid = crgetuid(clnt_cred); 374 varg.arg_u.arg.areq.req_clnt_gid = crgetgid(clnt_cred); 375 varg.arg_u.arg.areq.req_clnt_gids.len = crgetngroups(clnt_cred); 376 varg.arg_u.arg.areq.req_clnt_gids.val = (gid_t *)crgetgroups(clnt_cred); 377 378 DTRACE_PROBE1(nfsserv__func__nfsauth__varg, varg_t *, &varg); 379 380 /* 381 * Setup the XDR stream for encoding the arguments. Notice that 382 * in addition to the args having variable fields (req_netid and 383 * req_path), the argument data structure is itself versioned, 384 * so we need to make sure we can size the arguments buffer 385 * appropriately to encode all the args. If we can't get sizing 386 * info _or_ properly encode the arguments, there's really no 387 * point in continuting, so we fail the request. 388 */ 389 if ((absz = xdr_sizeof(xdr_varg, &varg)) == 0) { 390 *access = NFSAUTH_DENIED; 391 return (FALSE); 392 } 393 394 abuf = (caddr_t)kmem_alloc(absz, KM_SLEEP); 395 xdrmem_create(&xdrs, abuf, absz, XDR_ENCODE); 396 if (!xdr_varg(&xdrs, &varg)) { 397 XDR_DESTROY(&xdrs); 398 goto fail; 399 } 400 XDR_DESTROY(&xdrs); 401 402 /* 403 * Prepare the door arguments 404 * 405 * We don't know the size of the message the daemon 406 * will pass back to us. By setting rbuf to NULL, 407 * we force the door code to allocate a buf of the 408 * appropriate size. We must set rsize > 0, however, 409 * else the door code acts as if no response was 410 * expected and doesn't pass the data to us. 411 */ 412 da.data_ptr = (char *)abuf; 413 da.data_size = absz; 414 da.desc_ptr = NULL; 415 da.desc_num = 0; 416 da.rbuf = NULL; 417 da.rsize = 1; 418 419 retry: 420 mutex_enter(&mountd_lock); 421 dh = mountd_dh; 422 if (dh != NULL) 423 door_ki_hold(dh); 424 mutex_exit(&mountd_lock); 425 426 if (dh == NULL) { 427 /* 428 * The rendezvous point has not been established yet! 429 * This could mean that either mountd(1m) has not yet 430 * been started or that _this_ routine nuked the door 431 * handle after receiving an EINTR for a REVOKED door. 432 * 433 * Returning NFSAUTH_DROP will cause the NFS client 434 * to retransmit the request, so let's try to be more 435 * rescillient and attempt for ntries before we bail. 436 */ 437 if (++ntries % NFSAUTH_DR_TRYCNT) { 438 delay(hz); 439 goto retry; 440 } 441 442 kmem_free(abuf, absz); 443 444 sys_log("nfsauth: mountd has not established door"); 445 *access = NFSAUTH_DROP; 446 return (FALSE); 447 } 448 449 ntries = 0; 450 451 /* 452 * Now that we've got what we need, place the call. 453 */ 454 switch (door_ki_upcall_limited(dh, &da, NULL, SIZE_MAX, 0)) { 455 case 0: /* Success */ 456 door_ki_rele(dh); 457 458 if (da.data_ptr == NULL && da.data_size == 0) { 459 /* 460 * The door_return that contained the data 461 * failed! We're here because of the 2nd 462 * door_return (w/o data) such that we can 463 * get control of the thread (and exit 464 * gracefully). 465 */ 466 DTRACE_PROBE1(nfsserv__func__nfsauth__door__nil, 467 door_arg_t *, &da); 468 goto fail; 469 } 470 471 break; 472 473 case EAGAIN: 474 /* 475 * Server out of resources; back off for a bit 476 */ 477 door_ki_rele(dh); 478 delay(hz); 479 goto retry; 480 /* NOTREACHED */ 481 482 case EINTR: 483 if (!door_ki_info(dh, &di)) { 484 door_ki_rele(dh); 485 486 if (di.di_attributes & DOOR_REVOKED) { 487 /* 488 * The server barfed and revoked 489 * the (existing) door on us; we 490 * want to wait to give smf(5) a 491 * chance to restart mountd(1m) 492 * and establish a new door handle. 493 */ 494 mutex_enter(&mountd_lock); 495 if (dh == mountd_dh) { 496 door_ki_rele(mountd_dh); 497 mountd_dh = NULL; 498 } 499 mutex_exit(&mountd_lock); 500 delay(hz); 501 goto retry; 502 } 503 /* 504 * If the door was _not_ revoked on us, 505 * then more than likely we took an INTR, 506 * so we need to fail the operation. 507 */ 508 goto fail; 509 } 510 /* 511 * The only failure that can occur from getting 512 * the door info is EINVAL, so we let the code 513 * below handle it. 514 */ 515 /* FALLTHROUGH */ 516 517 case EBADF: 518 case EINVAL: 519 default: 520 /* 521 * If we have a stale door handle, give smf a last 522 * chance to start it by sleeping for a little bit. 523 * If we're still hosed, we'll fail the call. 524 * 525 * Since we're going to reacquire the door handle 526 * upon the retry, we opt to sleep for a bit and 527 * _not_ to clear mountd_dh. If mountd restarted 528 * and was able to set mountd_dh, we should see 529 * the new instance; if not, we won't get caught 530 * up in the retry/DELAY loop. 531 */ 532 door_ki_rele(dh); 533 if (!last) { 534 delay(hz); 535 last++; 536 goto retry; 537 } 538 sys_log("nfsauth: stale mountd door handle"); 539 goto fail; 540 } 541 542 ASSERT(da.rbuf != NULL); 543 544 /* 545 * No door errors encountered; setup the XDR stream for decoding 546 * the results. If we fail to decode the results, we've got no 547 * other recourse than to fail the request. 548 */ 549 xdrmem_create(&xdrs, da.rbuf, da.rsize, XDR_DECODE); 550 if (!xdr_nfsauth_res(&xdrs, &res)) { 551 xdr_free(xdr_nfsauth_res, (char *)&res); 552 XDR_DESTROY(&xdrs); 553 kmem_free(da.rbuf, da.rsize); 554 goto fail; 555 } 556 XDR_DESTROY(&xdrs); 557 kmem_free(da.rbuf, da.rsize); 558 559 DTRACE_PROBE1(nfsserv__func__nfsauth__results, nfsauth_res_t *, &res); 560 switch (res.stat) { 561 case NFSAUTH_DR_OKAY: 562 *access = res.ares.auth_perm; 563 *srv_uid = res.ares.auth_srv_uid; 564 *srv_gid = res.ares.auth_srv_gid; 565 566 if ((*srv_gids_cnt = res.ares.auth_srv_gids.len) != 0) { 567 *srv_gids = kmem_alloc(*srv_gids_cnt * 568 sizeof (gid_t), KM_SLEEP); 569 bcopy(res.ares.auth_srv_gids.val, *srv_gids, 570 *srv_gids_cnt * sizeof (gid_t)); 571 } else { 572 *srv_gids = NULL; 573 } 574 575 break; 576 577 case NFSAUTH_DR_EFAIL: 578 case NFSAUTH_DR_DECERR: 579 case NFSAUTH_DR_BADCMD: 580 default: 581 xdr_free(xdr_nfsauth_res, (char *)&res); 582 fail: 583 *access = NFSAUTH_DENIED; 584 kmem_free(abuf, absz); 585 return (FALSE); 586 /* NOTREACHED */ 587 } 588 589 xdr_free(xdr_nfsauth_res, (char *)&res); 590 kmem_free(abuf, absz); 591 592 return (TRUE); 593 } 594 595 static void 596 nfsauth_refresh_thread(void) 597 { 598 refreshq_exi_node_t *ren; 599 refreshq_auth_node_t *ran; 600 601 struct exportinfo *exi; 602 603 int access; 604 bool_t retrieval; 605 606 callb_cpr_t cprinfo; 607 608 CALLB_CPR_INIT(&cprinfo, &refreshq_lock, callb_generic_cpr, 609 "nfsauth_refresh"); 610 611 for (;;) { 612 mutex_enter(&refreshq_lock); 613 if (refreshq_thread_state != REFRESHQ_THREAD_RUNNING) { 614 /* Keep the hold on the lock! */ 615 break; 616 } 617 618 ren = list_remove_head(&refreshq_queue); 619 if (ren == NULL) { 620 CALLB_CPR_SAFE_BEGIN(&cprinfo); 621 cv_wait(&refreshq_cv, &refreshq_lock); 622 CALLB_CPR_SAFE_END(&cprinfo, &refreshq_lock); 623 mutex_exit(&refreshq_lock); 624 continue; 625 } 626 mutex_exit(&refreshq_lock); 627 628 exi = ren->ren_exi; 629 ASSERT(exi != NULL); 630 631 /* 632 * Since the ren was removed from the refreshq_queue above, 633 * this is the only thread aware about the ren existence, so we 634 * have the exclusive ownership of it and we do not need to 635 * protect it by any lock. 636 */ 637 while ((ran = list_remove_head(&ren->ren_authlist))) { 638 uid_t uid; 639 gid_t gid; 640 uint_t ngids; 641 gid_t *gids; 642 struct auth_cache *p = ran->ran_auth; 643 char *netid = ran->ran_netid; 644 645 ASSERT(p != NULL); 646 ASSERT(netid != NULL); 647 648 kmem_free(ran, sizeof (refreshq_auth_node_t)); 649 650 mutex_enter(&p->auth_lock); 651 652 /* 653 * Once the entry goes INVALID, it can not change 654 * state. 655 * 656 * No need to refresh entries also in a case we are 657 * just shutting down. 658 * 659 * In general, there is no need to hold the 660 * refreshq_lock to test the refreshq_thread_state. We 661 * do hold it at other places because there is some 662 * related thread synchronization (or some other tasks) 663 * close to the refreshq_thread_state check. 664 * 665 * The check for the refreshq_thread_state value here 666 * is purely advisory to allow the faster 667 * nfsauth_refresh_thread() shutdown. In a case we 668 * will miss such advisory, nothing catastrophic 669 * happens: we will just spin longer here before the 670 * shutdown. 671 */ 672 if (p->auth_state == NFS_AUTH_INVALID || 673 refreshq_thread_state != REFRESHQ_THREAD_RUNNING) { 674 mutex_exit(&p->auth_lock); 675 676 if (p->auth_state == NFS_AUTH_INVALID) 677 nfsauth_free_node(p); 678 679 strfree(netid); 680 681 continue; 682 } 683 684 /* 685 * Make sure the state is valid. Note that once we 686 * change the state to NFS_AUTH_REFRESHING, no other 687 * thread will be able to work on this entry. 688 */ 689 ASSERT(p->auth_state == NFS_AUTH_STALE); 690 691 p->auth_state = NFS_AUTH_REFRESHING; 692 mutex_exit(&p->auth_lock); 693 694 DTRACE_PROBE2(nfsauth__debug__cache__refresh, 695 struct exportinfo *, exi, 696 struct auth_cache *, p); 697 698 /* 699 * The first caching of the access rights 700 * is done with the netid pulled out of the 701 * request from the client. All subsequent 702 * users of the cache may or may not have 703 * the same netid. It doesn't matter. So 704 * when we refresh, we simply use the netid 705 * of the request which triggered the 706 * refresh attempt. 707 */ 708 retrieval = nfsauth_retrieve(exi, netid, 709 p->auth_flavor, &p->auth_clnt->authc_addr, &access, 710 p->auth_clnt_cred, &uid, &gid, &ngids, &gids); 711 712 /* 713 * This can only be set in one other place 714 * and the state has to be NFS_AUTH_FRESH. 715 */ 716 strfree(netid); 717 718 mutex_enter(&p->auth_lock); 719 if (p->auth_state == NFS_AUTH_INVALID) { 720 mutex_exit(&p->auth_lock); 721 nfsauth_free_node(p); 722 if (retrieval == TRUE) 723 kmem_free(gids, ngids * sizeof (gid_t)); 724 } else { 725 /* 726 * If we got an error, do not reset the 727 * time. This will cause the next access 728 * check for the client to reschedule this 729 * node. 730 */ 731 if (retrieval == TRUE) { 732 p->auth_access = access; 733 734 p->auth_srv_uid = uid; 735 p->auth_srv_gid = gid; 736 kmem_free(p->auth_srv_gids, 737 p->auth_srv_ngids * sizeof (gid_t)); 738 p->auth_srv_ngids = ngids; 739 p->auth_srv_gids = gids; 740 741 p->auth_freshness = gethrestime_sec(); 742 } 743 p->auth_state = NFS_AUTH_FRESH; 744 745 cv_broadcast(&p->auth_cv); 746 mutex_exit(&p->auth_lock); 747 } 748 } 749 750 list_destroy(&ren->ren_authlist); 751 exi_rele(ren->ren_exi); 752 kmem_free(ren, sizeof (refreshq_exi_node_t)); 753 } 754 755 refreshq_thread_state = REFRESHQ_THREAD_HALTED; 756 cv_broadcast(&refreshq_cv); 757 CALLB_CPR_EXIT(&cprinfo); 758 zthread_exit(); 759 } 760 761 int 762 nfsauth_cache_clnt_compar(const void *v1, const void *v2) 763 { 764 int c; 765 766 const struct auth_cache_clnt *a1 = (const struct auth_cache_clnt *)v1; 767 const struct auth_cache_clnt *a2 = (const struct auth_cache_clnt *)v2; 768 769 if (a1->authc_addr.len < a2->authc_addr.len) 770 return (-1); 771 if (a1->authc_addr.len > a2->authc_addr.len) 772 return (1); 773 774 c = memcmp(a1->authc_addr.buf, a2->authc_addr.buf, a1->authc_addr.len); 775 if (c < 0) 776 return (-1); 777 if (c > 0) 778 return (1); 779 780 return (0); 781 } 782 783 static int 784 nfsauth_cache_compar(const void *v1, const void *v2) 785 { 786 int c; 787 788 const struct auth_cache *a1 = (const struct auth_cache *)v1; 789 const struct auth_cache *a2 = (const struct auth_cache *)v2; 790 791 if (a1->auth_flavor < a2->auth_flavor) 792 return (-1); 793 if (a1->auth_flavor > a2->auth_flavor) 794 return (1); 795 796 if (crgetuid(a1->auth_clnt_cred) < crgetuid(a2->auth_clnt_cred)) 797 return (-1); 798 if (crgetuid(a1->auth_clnt_cred) > crgetuid(a2->auth_clnt_cred)) 799 return (1); 800 801 if (crgetgid(a1->auth_clnt_cred) < crgetgid(a2->auth_clnt_cred)) 802 return (-1); 803 if (crgetgid(a1->auth_clnt_cred) > crgetgid(a2->auth_clnt_cred)) 804 return (1); 805 806 if (crgetngroups(a1->auth_clnt_cred) < crgetngroups(a2->auth_clnt_cred)) 807 return (-1); 808 if (crgetngroups(a1->auth_clnt_cred) > crgetngroups(a2->auth_clnt_cred)) 809 return (1); 810 811 c = memcmp(crgetgroups(a1->auth_clnt_cred), 812 crgetgroups(a2->auth_clnt_cred), crgetngroups(a1->auth_clnt_cred)); 813 if (c < 0) 814 return (-1); 815 if (c > 0) 816 return (1); 817 818 return (0); 819 } 820 821 /* 822 * Get the access information from the cache or callup to the mountd 823 * to get and cache the access information in the kernel. 824 */ 825 static int 826 nfsauth_cache_get(struct exportinfo *exi, struct svc_req *req, int flavor, 827 cred_t *cr, uid_t *uid, gid_t *gid, uint_t *ngids, gid_t **gids) 828 { 829 struct netbuf *taddrmask; 830 struct netbuf addr; /* temporary copy of client's address */ 831 const struct netbuf *claddr; 832 avl_tree_t *tree; 833 struct auth_cache ac; /* used as a template for avl_find() */ 834 struct auth_cache_clnt *c; 835 struct auth_cache_clnt acc; /* used as a template for avl_find() */ 836 struct auth_cache *p = NULL; 837 int access; 838 839 uid_t tmpuid; 840 gid_t tmpgid; 841 uint_t tmpngids; 842 gid_t *tmpgids; 843 844 avl_index_t where; /* used for avl_find()/avl_insert() */ 845 846 ASSERT(cr != NULL); 847 848 /* 849 * Now check whether this client already 850 * has an entry for this flavor in the cache 851 * for this export. 852 * Get the caller's address, mask off the 853 * parts of the address that do not identify 854 * the host (port number, etc), and then hash 855 * it to find the chain of cache entries. 856 */ 857 858 claddr = svc_getrpccaller(req->rq_xprt); 859 addr = *claddr; 860 addr.buf = kmem_alloc(addr.maxlen, KM_SLEEP); 861 bcopy(claddr->buf, addr.buf, claddr->len); 862 863 SVC_GETADDRMASK(req->rq_xprt, SVC_TATTR_ADDRMASK, (void **)&taddrmask); 864 ASSERT(taddrmask != NULL); 865 addrmask(&addr, taddrmask); 866 867 ac.auth_flavor = flavor; 868 ac.auth_clnt_cred = crdup(cr); 869 870 acc.authc_addr = addr; 871 872 tree = exi->exi_cache[hash(&addr)]; 873 874 rw_enter(&exi->exi_cache_lock, RW_READER); 875 c = (struct auth_cache_clnt *)avl_find(tree, &acc, NULL); 876 877 if (c == NULL) { 878 struct auth_cache_clnt *nc; 879 880 rw_exit(&exi->exi_cache_lock); 881 882 nc = kmem_alloc(sizeof (*nc), KM_NOSLEEP | KM_NORMALPRI); 883 if (nc == NULL) 884 goto retrieve; 885 886 /* 887 * Initialize the new auth_cache_clnt 888 */ 889 nc->authc_addr = addr; 890 nc->authc_addr.buf = kmem_alloc(addr.maxlen, 891 KM_NOSLEEP | KM_NORMALPRI); 892 if (addr.maxlen != 0 && nc->authc_addr.buf == NULL) { 893 kmem_free(nc, sizeof (*nc)); 894 goto retrieve; 895 } 896 bcopy(addr.buf, nc->authc_addr.buf, addr.len); 897 rw_init(&nc->authc_lock, NULL, RW_DEFAULT, NULL); 898 avl_create(&nc->authc_tree, nfsauth_cache_compar, 899 sizeof (struct auth_cache), 900 offsetof(struct auth_cache, auth_link)); 901 902 rw_enter(&exi->exi_cache_lock, RW_WRITER); 903 c = (struct auth_cache_clnt *)avl_find(tree, &acc, &where); 904 if (c == NULL) { 905 avl_insert(tree, nc, where); 906 rw_downgrade(&exi->exi_cache_lock); 907 c = nc; 908 } else { 909 rw_downgrade(&exi->exi_cache_lock); 910 911 avl_destroy(&nc->authc_tree); 912 rw_destroy(&nc->authc_lock); 913 kmem_free(nc->authc_addr.buf, nc->authc_addr.maxlen); 914 kmem_free(nc, sizeof (*nc)); 915 } 916 } 917 918 ASSERT(c != NULL); 919 920 rw_enter(&c->authc_lock, RW_READER); 921 p = (struct auth_cache *)avl_find(&c->authc_tree, &ac, NULL); 922 923 if (p == NULL) { 924 struct auth_cache *np; 925 926 rw_exit(&c->authc_lock); 927 928 np = kmem_cache_alloc(exi_cache_handle, 929 KM_NOSLEEP | KM_NORMALPRI); 930 if (np == NULL) { 931 rw_exit(&exi->exi_cache_lock); 932 goto retrieve; 933 } 934 935 /* 936 * Initialize the new auth_cache 937 */ 938 np->auth_clnt = c; 939 np->auth_flavor = flavor; 940 np->auth_clnt_cred = ac.auth_clnt_cred; 941 np->auth_srv_ngids = 0; 942 np->auth_srv_gids = NULL; 943 np->auth_time = np->auth_freshness = gethrestime_sec(); 944 np->auth_state = NFS_AUTH_NEW; 945 mutex_init(&np->auth_lock, NULL, MUTEX_DEFAULT, NULL); 946 cv_init(&np->auth_cv, NULL, CV_DEFAULT, NULL); 947 948 rw_enter(&c->authc_lock, RW_WRITER); 949 rw_exit(&exi->exi_cache_lock); 950 951 p = (struct auth_cache *)avl_find(&c->authc_tree, &ac, &where); 952 if (p == NULL) { 953 avl_insert(&c->authc_tree, np, where); 954 rw_downgrade(&c->authc_lock); 955 p = np; 956 } else { 957 rw_downgrade(&c->authc_lock); 958 959 cv_destroy(&np->auth_cv); 960 mutex_destroy(&np->auth_lock); 961 crfree(ac.auth_clnt_cred); 962 kmem_cache_free(exi_cache_handle, np); 963 } 964 } else { 965 rw_exit(&exi->exi_cache_lock); 966 crfree(ac.auth_clnt_cred); 967 } 968 969 mutex_enter(&p->auth_lock); 970 rw_exit(&c->authc_lock); 971 972 /* 973 * If the entry is in the WAITING state then some other thread is just 974 * retrieving the required info. The entry was either NEW, or the list 975 * of client's supplemental groups is going to be changed (either by 976 * this thread, or by some other thread). We need to wait until the 977 * nfsauth_retrieve() is done. 978 */ 979 while (p->auth_state == NFS_AUTH_WAITING) 980 cv_wait(&p->auth_cv, &p->auth_lock); 981 982 /* 983 * Here the entry cannot be in WAITING or INVALID state. 984 */ 985 ASSERT(p->auth_state != NFS_AUTH_WAITING); 986 ASSERT(p->auth_state != NFS_AUTH_INVALID); 987 988 /* 989 * If the cache entry is not valid yet, we need to retrieve the 990 * info ourselves. 991 */ 992 if (p->auth_state == NFS_AUTH_NEW) { 993 bool_t res; 994 /* 995 * NFS_AUTH_NEW is the default output auth_state value in a 996 * case we failed somewhere below. 997 */ 998 auth_state_t state = NFS_AUTH_NEW; 999 1000 p->auth_state = NFS_AUTH_WAITING; 1001 mutex_exit(&p->auth_lock); 1002 kmem_free(addr.buf, addr.maxlen); 1003 addr = p->auth_clnt->authc_addr; 1004 1005 atomic_inc_uint(&nfsauth_cache_miss); 1006 1007 res = nfsauth_retrieve(exi, svc_getnetid(req->rq_xprt), flavor, 1008 &addr, &access, cr, &tmpuid, &tmpgid, &tmpngids, &tmpgids); 1009 1010 p->auth_access = access; 1011 p->auth_time = p->auth_freshness = gethrestime_sec(); 1012 1013 if (res == TRUE) { 1014 if (uid != NULL) 1015 *uid = tmpuid; 1016 if (gid != NULL) 1017 *gid = tmpgid; 1018 if (ngids != NULL && gids != NULL) { 1019 *ngids = tmpngids; 1020 *gids = tmpgids; 1021 1022 /* 1023 * We need a copy of gids for the 1024 * auth_cache entry 1025 */ 1026 tmpgids = kmem_alloc(tmpngids * sizeof (gid_t), 1027 KM_NOSLEEP | KM_NORMALPRI); 1028 if (tmpgids != NULL) 1029 bcopy(*gids, tmpgids, 1030 tmpngids * sizeof (gid_t)); 1031 } 1032 1033 if (tmpgids != NULL || tmpngids == 0) { 1034 p->auth_srv_uid = tmpuid; 1035 p->auth_srv_gid = tmpgid; 1036 p->auth_srv_ngids = tmpngids; 1037 p->auth_srv_gids = tmpgids; 1038 1039 state = NFS_AUTH_FRESH; 1040 } 1041 } 1042 1043 /* 1044 * Set the auth_state and notify waiters. 1045 */ 1046 mutex_enter(&p->auth_lock); 1047 p->auth_state = state; 1048 cv_broadcast(&p->auth_cv); 1049 mutex_exit(&p->auth_lock); 1050 } else { 1051 uint_t nach; 1052 time_t refresh; 1053 1054 refresh = gethrestime_sec() - p->auth_freshness; 1055 1056 p->auth_time = gethrestime_sec(); 1057 1058 if (uid != NULL) 1059 *uid = p->auth_srv_uid; 1060 if (gid != NULL) 1061 *gid = p->auth_srv_gid; 1062 if (ngids != NULL && gids != NULL) { 1063 if ((*ngids = p->auth_srv_ngids) != 0) { 1064 size_t sz = *ngids * sizeof (gid_t); 1065 *gids = kmem_alloc(sz, KM_SLEEP); 1066 bcopy(p->auth_srv_gids, *gids, sz); 1067 } else { 1068 *gids = NULL; 1069 } 1070 } 1071 1072 access = p->auth_access; 1073 1074 if ((refresh > NFSAUTH_CACHE_REFRESH) && 1075 p->auth_state == NFS_AUTH_FRESH) { 1076 refreshq_auth_node_t *ran; 1077 uint_t nacr; 1078 1079 p->auth_state = NFS_AUTH_STALE; 1080 mutex_exit(&p->auth_lock); 1081 1082 nacr = atomic_inc_uint_nv(&nfsauth_cache_refresh); 1083 DTRACE_PROBE3(nfsauth__debug__cache__stale, 1084 struct exportinfo *, exi, 1085 struct auth_cache *, p, 1086 uint_t, nacr); 1087 1088 ran = kmem_alloc(sizeof (refreshq_auth_node_t), 1089 KM_SLEEP); 1090 ran->ran_auth = p; 1091 ran->ran_netid = strdup(svc_getnetid(req->rq_xprt)); 1092 1093 mutex_enter(&refreshq_lock); 1094 /* 1095 * We should not add a work queue 1096 * item if the thread is not 1097 * accepting them. 1098 */ 1099 if (refreshq_thread_state == REFRESHQ_THREAD_RUNNING) { 1100 refreshq_exi_node_t *ren; 1101 1102 /* 1103 * Is there an existing exi_list? 1104 */ 1105 for (ren = list_head(&refreshq_queue); 1106 ren != NULL; 1107 ren = list_next(&refreshq_queue, ren)) { 1108 if (ren->ren_exi == exi) { 1109 list_insert_tail( 1110 &ren->ren_authlist, ran); 1111 break; 1112 } 1113 } 1114 1115 if (ren == NULL) { 1116 ren = kmem_alloc( 1117 sizeof (refreshq_exi_node_t), 1118 KM_SLEEP); 1119 1120 exi_hold(exi); 1121 ren->ren_exi = exi; 1122 1123 list_create(&ren->ren_authlist, 1124 sizeof (refreshq_auth_node_t), 1125 offsetof(refreshq_auth_node_t, 1126 ran_node)); 1127 1128 list_insert_tail(&ren->ren_authlist, 1129 ran); 1130 list_insert_tail(&refreshq_queue, ren); 1131 } 1132 1133 cv_broadcast(&refreshq_cv); 1134 } else { 1135 strfree(ran->ran_netid); 1136 kmem_free(ran, sizeof (refreshq_auth_node_t)); 1137 } 1138 1139 mutex_exit(&refreshq_lock); 1140 } else { 1141 mutex_exit(&p->auth_lock); 1142 } 1143 1144 nach = atomic_inc_uint_nv(&nfsauth_cache_hit); 1145 DTRACE_PROBE2(nfsauth__debug__cache__hit, 1146 uint_t, nach, 1147 time_t, refresh); 1148 1149 kmem_free(addr.buf, addr.maxlen); 1150 } 1151 1152 return (access); 1153 1154 retrieve: 1155 crfree(ac.auth_clnt_cred); 1156 1157 /* 1158 * Retrieve the required data without caching. 1159 */ 1160 1161 ASSERT(p == NULL); 1162 1163 atomic_inc_uint(&nfsauth_cache_miss); 1164 1165 if (nfsauth_retrieve(exi, svc_getnetid(req->rq_xprt), flavor, &addr, 1166 &access, cr, &tmpuid, &tmpgid, &tmpngids, &tmpgids)) { 1167 if (uid != NULL) 1168 *uid = tmpuid; 1169 if (gid != NULL) 1170 *gid = tmpgid; 1171 if (ngids != NULL && gids != NULL) { 1172 *ngids = tmpngids; 1173 *gids = tmpgids; 1174 } else { 1175 kmem_free(tmpgids, tmpngids * sizeof (gid_t)); 1176 } 1177 } 1178 1179 kmem_free(addr.buf, addr.maxlen); 1180 1181 return (access); 1182 } 1183 1184 /* 1185 * Check if the requesting client has access to the filesystem with 1186 * a given nfs flavor number which is an explicitly shared flavor. 1187 */ 1188 int 1189 nfsauth4_secinfo_access(struct exportinfo *exi, struct svc_req *req, 1190 int flavor, int perm, cred_t *cr) 1191 { 1192 int access; 1193 1194 if (! (perm & M_4SEC_EXPORTED)) { 1195 return (NFSAUTH_DENIED); 1196 } 1197 1198 /* 1199 * Optimize if there are no lists 1200 */ 1201 if ((perm & (M_ROOT | M_NONE | M_MAP)) == 0) { 1202 perm &= ~M_4SEC_EXPORTED; 1203 if (perm == M_RO) 1204 return (NFSAUTH_RO); 1205 if (perm == M_RW) 1206 return (NFSAUTH_RW); 1207 } 1208 1209 access = nfsauth_cache_get(exi, req, flavor, cr, NULL, NULL, NULL, 1210 NULL); 1211 1212 return (access); 1213 } 1214 1215 int 1216 nfsauth_access(struct exportinfo *exi, struct svc_req *req, cred_t *cr, 1217 uid_t *uid, gid_t *gid, uint_t *ngids, gid_t **gids) 1218 { 1219 int access, mapaccess; 1220 struct secinfo *sp; 1221 int i, flavor, perm; 1222 int authnone_entry = -1; 1223 1224 /* 1225 * By default root is mapped to anonymous user. 1226 * This might get overriden later in nfsauth_cache_get(). 1227 */ 1228 if (crgetuid(cr) == 0) { 1229 if (uid != NULL) 1230 *uid = exi->exi_export.ex_anon; 1231 if (gid != NULL) 1232 *gid = exi->exi_export.ex_anon; 1233 } else { 1234 if (uid != NULL) 1235 *uid = crgetuid(cr); 1236 if (gid != NULL) 1237 *gid = crgetgid(cr); 1238 } 1239 1240 if (ngids != NULL) 1241 *ngids = 0; 1242 if (gids != NULL) 1243 *gids = NULL; 1244 1245 /* 1246 * Get the nfs flavor number from xprt. 1247 */ 1248 flavor = (int)(uintptr_t)req->rq_xprt->xp_cookie; 1249 1250 /* 1251 * First check the access restrictions on the filesystem. If 1252 * there are no lists associated with this flavor then there's no 1253 * need to make an expensive call to the nfsauth service or to 1254 * cache anything. 1255 */ 1256 1257 sp = exi->exi_export.ex_secinfo; 1258 for (i = 0; i < exi->exi_export.ex_seccnt; i++) { 1259 if (flavor != sp[i].s_secinfo.sc_nfsnum) { 1260 if (sp[i].s_secinfo.sc_nfsnum == AUTH_NONE) 1261 authnone_entry = i; 1262 continue; 1263 } 1264 break; 1265 } 1266 1267 mapaccess = 0; 1268 1269 if (i >= exi->exi_export.ex_seccnt) { 1270 /* 1271 * Flavor not found, but use AUTH_NONE if it exists 1272 */ 1273 if (authnone_entry == -1) 1274 return (NFSAUTH_DENIED); 1275 flavor = AUTH_NONE; 1276 mapaccess = NFSAUTH_MAPNONE; 1277 i = authnone_entry; 1278 } 1279 1280 /* 1281 * If the flavor is in the ex_secinfo list, but not an explicitly 1282 * shared flavor by the user, it is a result of the nfsv4 server 1283 * namespace setup. We will grant an RO permission similar for 1284 * a pseudo node except that this node is a shared one. 1285 * 1286 * e.g. flavor in (flavor) indicates that it is not explictly 1287 * shared by the user: 1288 * 1289 * / (sys, krb5) 1290 * | 1291 * export #share -o sec=sys (krb5) 1292 * | 1293 * secure #share -o sec=krb5 1294 * 1295 * In this case, when a krb5 request coming in to access 1296 * /export, RO permission is granted. 1297 */ 1298 if (!(sp[i].s_flags & M_4SEC_EXPORTED)) 1299 return (mapaccess | NFSAUTH_RO); 1300 1301 /* 1302 * Optimize if there are no lists. 1303 * We cannot optimize for AUTH_SYS with NGRPS (16) supplemental groups. 1304 */ 1305 perm = sp[i].s_flags; 1306 if ((perm & (M_ROOT | M_NONE | M_MAP)) == 0 && (ngroups_max <= NGRPS || 1307 flavor != AUTH_SYS || crgetngroups(cr) < NGRPS)) { 1308 perm &= ~M_4SEC_EXPORTED; 1309 if (perm == M_RO) 1310 return (mapaccess | NFSAUTH_RO); 1311 if (perm == M_RW) 1312 return (mapaccess | NFSAUTH_RW); 1313 } 1314 1315 access = nfsauth_cache_get(exi, req, flavor, cr, uid, gid, ngids, gids); 1316 1317 /* 1318 * For both NFSAUTH_DENIED and NFSAUTH_WRONGSEC we do not care about 1319 * the supplemental groups. 1320 */ 1321 if (access & NFSAUTH_DENIED || access & NFSAUTH_WRONGSEC) { 1322 if (ngids != NULL && gids != NULL) { 1323 kmem_free(*gids, *ngids * sizeof (gid_t)); 1324 *ngids = 0; 1325 *gids = NULL; 1326 } 1327 } 1328 1329 /* 1330 * Client's security flavor doesn't match with "ro" or 1331 * "rw" list. Try again using AUTH_NONE if present. 1332 */ 1333 if ((access & NFSAUTH_WRONGSEC) && (flavor != AUTH_NONE)) { 1334 /* 1335 * Have we already encountered AUTH_NONE ? 1336 */ 1337 if (authnone_entry != -1) { 1338 mapaccess = NFSAUTH_MAPNONE; 1339 access = nfsauth_cache_get(exi, req, AUTH_NONE, cr, 1340 NULL, NULL, NULL, NULL); 1341 } else { 1342 /* 1343 * Check for AUTH_NONE presence. 1344 */ 1345 for (; i < exi->exi_export.ex_seccnt; i++) { 1346 if (sp[i].s_secinfo.sc_nfsnum == AUTH_NONE) { 1347 mapaccess = NFSAUTH_MAPNONE; 1348 access = nfsauth_cache_get(exi, req, 1349 AUTH_NONE, cr, NULL, NULL, NULL, 1350 NULL); 1351 break; 1352 } 1353 } 1354 } 1355 } 1356 1357 if (access & NFSAUTH_DENIED) 1358 access = NFSAUTH_DENIED; 1359 1360 return (access | mapaccess); 1361 } 1362 1363 static void 1364 nfsauth_free_clnt_node(struct auth_cache_clnt *p) 1365 { 1366 void *cookie = NULL; 1367 struct auth_cache *node; 1368 1369 while ((node = avl_destroy_nodes(&p->authc_tree, &cookie)) != NULL) 1370 nfsauth_free_node(node); 1371 avl_destroy(&p->authc_tree); 1372 1373 kmem_free(p->authc_addr.buf, p->authc_addr.maxlen); 1374 rw_destroy(&p->authc_lock); 1375 1376 kmem_free(p, sizeof (*p)); 1377 } 1378 1379 static void 1380 nfsauth_free_node(struct auth_cache *p) 1381 { 1382 crfree(p->auth_clnt_cred); 1383 kmem_free(p->auth_srv_gids, p->auth_srv_ngids * sizeof (gid_t)); 1384 mutex_destroy(&p->auth_lock); 1385 cv_destroy(&p->auth_cv); 1386 kmem_cache_free(exi_cache_handle, p); 1387 } 1388 1389 /* 1390 * Free the nfsauth cache for a given export 1391 */ 1392 void 1393 nfsauth_cache_free(struct exportinfo *exi) 1394 { 1395 int i; 1396 1397 /* 1398 * The only way we got here was with an exi_rele, which means that no 1399 * auth cache entry is being refreshed. 1400 */ 1401 1402 for (i = 0; i < AUTH_TABLESIZE; i++) { 1403 avl_tree_t *tree = exi->exi_cache[i]; 1404 void *cookie = NULL; 1405 struct auth_cache_clnt *node; 1406 1407 while ((node = avl_destroy_nodes(tree, &cookie)) != NULL) 1408 nfsauth_free_clnt_node(node); 1409 } 1410 } 1411 1412 /* 1413 * Called by the kernel memory allocator when 1414 * memory is low. Free unused cache entries. 1415 * If that's not enough, the VM system will 1416 * call again for some more. 1417 */ 1418 /*ARGSUSED*/ 1419 void 1420 exi_cache_reclaim(void *cdrarg) 1421 { 1422 int i; 1423 struct exportinfo *exi; 1424 1425 rw_enter(&exported_lock, RW_READER); 1426 1427 for (i = 0; i < EXPTABLESIZE; i++) { 1428 for (exi = exptable[i]; exi; exi = exi->fid_hash.next) { 1429 exi_cache_trim(exi); 1430 } 1431 } 1432 1433 rw_exit(&exported_lock); 1434 1435 atomic_inc_uint(&nfsauth_cache_reclaim); 1436 } 1437 1438 void 1439 exi_cache_trim(struct exportinfo *exi) 1440 { 1441 struct auth_cache_clnt *c; 1442 struct auth_cache_clnt *nextc; 1443 struct auth_cache *p; 1444 struct auth_cache *next; 1445 int i; 1446 time_t stale_time; 1447 avl_tree_t *tree; 1448 1449 for (i = 0; i < AUTH_TABLESIZE; i++) { 1450 tree = exi->exi_cache[i]; 1451 stale_time = gethrestime_sec() - NFSAUTH_CACHE_TRIM; 1452 rw_enter(&exi->exi_cache_lock, RW_READER); 1453 1454 /* 1455 * Free entries that have not been 1456 * used for NFSAUTH_CACHE_TRIM seconds. 1457 */ 1458 for (c = avl_first(tree); c != NULL; c = AVL_NEXT(tree, c)) { 1459 /* 1460 * We are being called by the kmem subsystem to reclaim 1461 * memory so don't block if we can't get the lock. 1462 */ 1463 if (rw_tryenter(&c->authc_lock, RW_WRITER) == 0) { 1464 exi_cache_auth_reclaim_failed++; 1465 rw_exit(&exi->exi_cache_lock); 1466 return; 1467 } 1468 1469 for (p = avl_first(&c->authc_tree); p != NULL; 1470 p = next) { 1471 next = AVL_NEXT(&c->authc_tree, p); 1472 1473 ASSERT(p->auth_state != NFS_AUTH_INVALID); 1474 1475 mutex_enter(&p->auth_lock); 1476 1477 /* 1478 * We won't trim recently used and/or WAITING 1479 * entries. 1480 */ 1481 if (p->auth_time > stale_time || 1482 p->auth_state == NFS_AUTH_WAITING) { 1483 mutex_exit(&p->auth_lock); 1484 continue; 1485 } 1486 1487 DTRACE_PROBE1(nfsauth__debug__trim__state, 1488 auth_state_t, p->auth_state); 1489 1490 /* 1491 * STALE and REFRESHING entries needs to be 1492 * marked INVALID only because they are 1493 * referenced by some other structures or 1494 * threads. They will be freed later. 1495 */ 1496 if (p->auth_state == NFS_AUTH_STALE || 1497 p->auth_state == NFS_AUTH_REFRESHING) { 1498 p->auth_state = NFS_AUTH_INVALID; 1499 mutex_exit(&p->auth_lock); 1500 1501 avl_remove(&c->authc_tree, p); 1502 } else { 1503 mutex_exit(&p->auth_lock); 1504 1505 avl_remove(&c->authc_tree, p); 1506 nfsauth_free_node(p); 1507 } 1508 } 1509 rw_exit(&c->authc_lock); 1510 } 1511 1512 if (rw_tryupgrade(&exi->exi_cache_lock) == 0) { 1513 rw_exit(&exi->exi_cache_lock); 1514 exi_cache_clnt_reclaim_failed++; 1515 continue; 1516 } 1517 1518 for (c = avl_first(tree); c != NULL; c = nextc) { 1519 nextc = AVL_NEXT(tree, c); 1520 1521 if (avl_is_empty(&c->authc_tree) == B_FALSE) 1522 continue; 1523 1524 avl_remove(tree, c); 1525 1526 nfsauth_free_clnt_node(c); 1527 } 1528 1529 rw_exit(&exi->exi_cache_lock); 1530 } 1531 } 1532