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