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