xref: /illumos-gate/usr/src/uts/common/idmap/idmap_cache.c (revision 051aabe6136ff13e81542a427e9693ffe1503525)
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 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * Windows to Solaris Identity Mapping kernel API
29  * This module provides the kernel cache.
30  */
31 
32 #pragma ident	"%Z%%M%	%I%	%E% SMI"
33 
34 
35 #include <sys/types.h>
36 #include <sys/avl.h>
37 #include <sys/systm.h>
38 #include <sys/sysmacros.h>
39 #include <sys/ksynch.h>
40 #include <sys/kidmap.h>
41 #include "idmap_prot.h"
42 #include "kidmap_priv.h"
43 
44 
45 /*
46  * External functions
47  */
48 extern	uintptr_t	space_fetch(char *key);
49 extern	int		space_store(char *key, uintptr_t ptr);
50 
51 
52 /*
53  * Internal definitions and functions
54  */
55 
56 #define	CACHE_UID_TRIGGER_SIZE	4096
57 #define	CACHE_GID_TRIGGER_SIZE	2048
58 #define	CACHE_PID_TRIGGER_SIZE \
59 	(CACHE_UID_TRIGGER_SIZE + CACHE_GID_TRIGGER_SIZE)
60 
61 
62 #define	UNDEF_UID	((uid_t)-1)
63 #define	UNDEF_GID	((gid_t)-1)
64 #define	UNDEF_ISUSER	(-1)
65 
66 #define	CACHE_PURGE_INTERVAL	(60 * 3)
67 #define	CACHE_TTL		(60 * 10)
68 
69 typedef struct sid_prefix_node {
70 	avl_node_t	avl_link;
71 	const char 	*sid_prefix;
72 } sid_prefix_node_t;
73 
74 
75 typedef struct sid2pid {
76 	avl_node_t	avl_link;
77 	const char 	*sid_prefix;
78 	uint32_t	rid;
79 	uid_t		uid;
80 	time_t		uid_ttl;
81 	gid_t		gid;
82 	time_t		gid_ttl;
83 	int		is_user;
84 } sid2pid_t;
85 
86 
87 typedef struct pid2sid {
88 	avl_node_t	avl_link;
89 	const char 	*sid_prefix;
90 	uint32_t	rid;
91 	uid_t		pid;
92 	time_t		ttl;
93 } pid2sid_t;
94 
95 
96 
97 
98 typedef int (*avl_comp_fn)(const void*, const void*);
99 
100 
101 struct sid_prefix_store {
102 	struct avl_tree	tree;
103 	krwlock_t	lock;
104 };
105 
106 struct sid_prefix_store *kidmap_sid_prefix_store = NULL;
107 
108 
109 
110 static void
111 kidmap_purge_sid2pid_avl(idmap_sid2pid_cache_t *cache, size_t limit);
112 
113 static void
114 kidmap_purge_pid2sid_avl(idmap_pid2sid_cache_t *cache, size_t limit);
115 
116 
117 /*
118  * kidmap_strdup() copied from uts/common/fs/sockfs/nl7c.c
119  */
120 static char *
121 kidmap_strdup(const char *s)
122 {
123 	int	len = strlen(s) + 1;
124 	char	*ret = kmem_alloc(len, KM_SLEEP);
125 
126 	bcopy(s, ret, len);
127 	return (ret);
128 }
129 
130 
131 static int
132 kidmap_compare_sid(const sid2pid_t *entry1, const sid2pid_t *entry2)
133 {
134 	int64_t comp = ((int64_t)entry2->rid) - ((int64_t)entry1->rid);
135 
136 	if (comp == 0)
137 		comp = strcmp(entry2->sid_prefix, entry1->sid_prefix);
138 
139 	if (comp < 0)
140 		comp = -1;
141 	else if (comp > 0)
142 		comp = 1;
143 
144 	return ((int)comp);
145 }
146 
147 
148 static int
149 kidmap_compare_pid(const pid2sid_t *entry1, const pid2sid_t *entry2)
150 {
151 	if (entry2->pid > entry1->pid)
152 		return (1);
153 	if (entry2->pid < entry1->pid)
154 		return (-1);
155 	return (0);
156 }
157 
158 
159 static int
160 kidmap_compare_sid_prefix(const sid_prefix_node_t *entry1,
161 			const sid_prefix_node_t *entry2)
162 {
163 	int comp;
164 
165 	comp = strcmp(entry2->sid_prefix, entry1->sid_prefix);
166 
167 	if (comp < 0)
168 		comp = -1;
169 	else if (comp > 0)
170 		comp = 1;
171 
172 	return (comp);
173 }
174 
175 
176 void
177 kidmap_cache_create(idmap_cache_t *cache)
178 {
179 	avl_create(&cache->sid2pid.tree, (avl_comp_fn)kidmap_compare_sid,
180 	    sizeof (sid2pid_t), offsetof(sid2pid_t, avl_link));
181 	mutex_init(&cache->sid2pid.mutex, NULL, MUTEX_DEFAULT, NULL);
182 	cache->sid2pid.purge_time = 0;
183 	cache->sid2pid.prev = NULL;
184 	cache->sid2pid.uid_num = 0;
185 	cache->sid2pid.gid_num = 0;
186 	cache->sid2pid.pid_num = 0;
187 
188 	avl_create(&cache->uid2sid.tree, (avl_comp_fn)kidmap_compare_pid,
189 	    sizeof (pid2sid_t), offsetof(pid2sid_t, avl_link));
190 	mutex_init(&cache->uid2sid.mutex, NULL, MUTEX_DEFAULT, NULL);
191 	cache->uid2sid.purge_time = 0;
192 	cache->uid2sid.prev = NULL;
193 
194 	avl_create(&cache->gid2sid.tree, (avl_comp_fn)kidmap_compare_pid,
195 	    sizeof (pid2sid_t), offsetof(pid2sid_t, avl_link));
196 	mutex_init(&cache->gid2sid.mutex, NULL, MUTEX_DEFAULT, NULL);
197 	cache->gid2sid.purge_time = 0;
198 	cache->gid2sid.prev = NULL;
199 }
200 
201 
202 void
203 kidmap_cache_delete(idmap_cache_t *cache)
204 {
205 	sid2pid_t *sid2pid;
206 	pid2sid_t *pid2sid;
207 	void *cookie;
208 
209 	cookie = NULL;
210 	while ((sid2pid = avl_destroy_nodes(&cache->sid2pid.tree, &cookie))
211 	    != NULL) {
212 		kmem_free(sid2pid, sizeof (sid2pid_t));
213 	}
214 	avl_destroy(&cache->sid2pid.tree);
215 	mutex_destroy(&cache->sid2pid.mutex);
216 
217 
218 	cookie = NULL;
219 	while ((pid2sid = avl_destroy_nodes(&cache->uid2sid.tree, &cookie))
220 	    != NULL) {
221 		kmem_free(pid2sid, sizeof (pid2sid_t));
222 	}
223 	avl_destroy(&cache->uid2sid.tree);
224 	mutex_destroy(&cache->uid2sid.mutex);
225 
226 
227 	cookie = NULL;
228 	while ((pid2sid = avl_destroy_nodes(&cache->gid2sid.tree, &cookie))
229 	    != NULL) {
230 		kmem_free(pid2sid, sizeof (pid2sid_t));
231 	}
232 	avl_destroy(&cache->gid2sid.tree);
233 	mutex_destroy(&cache->gid2sid.mutex);
234 }
235 
236 
237 void
238 kidmap_cache_get_data(idmap_cache_t *cache, size_t *uidbysid, size_t *gidbysid,
239 	size_t *pidbysid, size_t *sidbyuid, size_t *sidbygid)
240 {
241 	mutex_enter(&cache->sid2pid.mutex);
242 	*uidbysid = cache->sid2pid.uid_num;
243 	*gidbysid = cache->sid2pid.gid_num;
244 	*pidbysid = cache->sid2pid.pid_num;
245 	mutex_exit(&cache->sid2pid.mutex);
246 
247 	mutex_enter(&cache->uid2sid.mutex);
248 	*sidbyuid = avl_numnodes(&cache->uid2sid.tree);
249 	mutex_exit(&cache->uid2sid.mutex);
250 
251 	mutex_enter(&cache->gid2sid.mutex);
252 	*sidbygid = avl_numnodes(&cache->gid2sid.tree);
253 	mutex_exit(&cache->gid2sid.mutex);
254 }
255 
256 
257 void
258 kidmap_cache_purge(idmap_cache_t *cache)
259 {
260 	sid2pid_t *sid2pid;
261 	pid2sid_t *pid2sid;
262 	void *cookie;
263 
264 	mutex_enter(&cache->sid2pid.mutex);
265 	cookie = NULL;
266 	while ((sid2pid = avl_destroy_nodes(&cache->sid2pid.tree, &cookie))
267 	    != NULL) {
268 		kmem_free(sid2pid, sizeof (sid2pid_t));
269 	}
270 	avl_destroy(&cache->sid2pid.tree);
271 	avl_create(&cache->sid2pid.tree, (avl_comp_fn)kidmap_compare_sid,
272 	    sizeof (sid2pid_t), offsetof(sid2pid_t, avl_link));
273 	cache->sid2pid.purge_time = 0;
274 	cache->sid2pid.prev = NULL;
275 	cache->sid2pid.uid_num = 0;
276 	cache->sid2pid.gid_num = 0;
277 	cache->sid2pid.pid_num = 0;
278 	mutex_exit(&cache->sid2pid.mutex);
279 
280 
281 	mutex_enter(&cache->uid2sid.mutex);
282 	cookie = NULL;
283 	while ((pid2sid = avl_destroy_nodes(&cache->uid2sid.tree, &cookie))
284 	    != NULL) {
285 		kmem_free(pid2sid, sizeof (pid2sid_t));
286 	}
287 	avl_destroy(&cache->uid2sid.tree);
288 	avl_create(&cache->uid2sid.tree, (avl_comp_fn)kidmap_compare_pid,
289 	    sizeof (pid2sid_t), offsetof(pid2sid_t, avl_link));
290 	cache->uid2sid.purge_time = 0;
291 	cache->uid2sid.prev = NULL;
292 	mutex_exit(&cache->uid2sid.mutex);
293 
294 
295 	mutex_enter(&cache->gid2sid.mutex);
296 	cookie = NULL;
297 	while ((pid2sid = avl_destroy_nodes(&cache->gid2sid.tree, &cookie))
298 	    != NULL) {
299 		kmem_free(pid2sid, sizeof (pid2sid_t));
300 	}
301 	avl_destroy(&cache->gid2sid.tree);
302 	avl_create(&cache->gid2sid.tree, (avl_comp_fn)kidmap_compare_pid,
303 	    sizeof (pid2sid_t), offsetof(pid2sid_t, avl_link));
304 	cache->gid2sid.purge_time = 0;
305 	cache->gid2sid.prev = NULL;
306 	mutex_exit(&cache->gid2sid.mutex);
307 }
308 
309 
310 int
311 kidmap_cache_lookup_uidbysid(idmap_cache_t *cache, const char *sid_prefix,
312 			uint32_t rid, uid_t *uid)
313 {
314 	sid2pid_t	entry;
315 	sid2pid_t	*result;
316 	avl_index_t	where;
317 	int		status;
318 	time_t		now = gethrestime_sec();
319 
320 	entry.sid_prefix = sid_prefix;
321 	entry.rid = rid;
322 
323 	mutex_enter(&cache->sid2pid.mutex);
324 
325 	result = avl_find(&cache->sid2pid.tree, &entry, &where);
326 
327 	if (result && result->uid != UNDEF_UID && result->uid_ttl > now) {
328 		*uid = result->uid;
329 		status = IDMAP_SUCCESS;
330 	} else
331 		status = IDMAP_ERR_NOMAPPING;
332 
333 	mutex_exit(&cache->sid2pid.mutex);
334 
335 	return (status);
336 }
337 
338 
339 
340 int
341 kidmap_cache_lookup_gidbysid(idmap_cache_t *cache, const char *sid_prefix,
342 			uint32_t rid, gid_t *gid)
343 {
344 	sid2pid_t	entry;
345 	sid2pid_t	*result;
346 	avl_index_t	where;
347 	int		status;
348 	time_t		now = gethrestime_sec();
349 
350 	entry.sid_prefix = sid_prefix;
351 	entry.rid = rid;
352 
353 	mutex_enter(&cache->sid2pid.mutex);
354 
355 	result = avl_find(&cache->sid2pid.tree, &entry, &where);
356 
357 	if (result && result->gid != UNDEF_GID && result->gid_ttl > now) {
358 		*gid = result->gid;
359 		status = IDMAP_SUCCESS;
360 	} else
361 		status = IDMAP_ERR_NOMAPPING;
362 
363 	mutex_exit(&cache->sid2pid.mutex);
364 
365 	return (status);
366 }
367 
368 
369 
370 
371 int
372 kidmap_cache_lookup_pidbysid(idmap_cache_t *cache, const char *sid_prefix,
373 			uint32_t rid, uid_t *pid, int *is_user)
374 {
375 	sid2pid_t	entry;
376 	sid2pid_t	*result;
377 	avl_index_t	where;
378 	int		status;
379 	time_t		now = gethrestime_sec();
380 
381 	entry.sid_prefix = sid_prefix;
382 	entry.rid = rid;
383 
384 	mutex_enter(&cache->sid2pid.mutex);
385 
386 	result = avl_find(&cache->sid2pid.tree, &entry, &where);
387 
388 	if (result && result->is_user != UNDEF_ISUSER) {
389 		if (result->is_user && result->uid_ttl > now) {
390 			*pid = result->uid;
391 			*is_user = result->is_user;
392 			status = IDMAP_SUCCESS;
393 		} else if (!result->is_user && result->gid_ttl > now) {
394 			*pid = result->gid;
395 			*is_user = result->is_user;
396 			status = IDMAP_SUCCESS;
397 		} else
398 			status = IDMAP_ERR_NOMAPPING;
399 	} else
400 		status = IDMAP_ERR_NOMAPPING;
401 
402 	mutex_exit(&cache->sid2pid.mutex);
403 
404 	return (status);
405 }
406 
407 
408 
409 int
410 kidmap_cache_lookup_sidbyuid(idmap_cache_t *cache, const char **sid_prefix,
411 			uint32_t *rid, uid_t uid)
412 {
413 	pid2sid_t	entry;
414 	pid2sid_t	*result;
415 	avl_index_t	where;
416 	int		status;
417 	time_t		now = gethrestime_sec();
418 
419 	entry.pid = uid;
420 
421 	mutex_enter(&cache->uid2sid.mutex);
422 
423 	result = avl_find(&cache->uid2sid.tree, &entry, &where);
424 
425 	if (result && result->ttl > now) {
426 		*sid_prefix = result->sid_prefix;
427 		*rid = result->rid;
428 		status = IDMAP_SUCCESS;
429 	} else
430 		status = IDMAP_ERR_NOMAPPING;
431 
432 	mutex_exit(&cache->uid2sid.mutex);
433 
434 	return (status);
435 }
436 
437 int
438 kidmap_cache_lookup_sidbygid(idmap_cache_t *cache, const char **sid_prefix,
439 			uint32_t *rid, gid_t gid)
440 {
441 	pid2sid_t	entry;
442 	pid2sid_t	*result;
443 	avl_index_t	where;
444 	int		status;
445 	time_t		now = gethrestime_sec();
446 
447 	entry.pid = gid;
448 
449 	mutex_enter(&cache->gid2sid.mutex);
450 
451 	result = avl_find(&cache->gid2sid.tree, &entry, &where);
452 
453 	if (result && result->ttl > now) {
454 		*sid_prefix = result->sid_prefix;
455 		*rid = result->rid;
456 		status = IDMAP_SUCCESS;
457 	} else
458 		status = IDMAP_ERR_NOMAPPING;
459 
460 	mutex_exit(&cache->gid2sid.mutex);
461 
462 	return (status);
463 }
464 
465 
466 
467 
468 
469 void
470 kidmap_cache_add_sid2uid(idmap_cache_t *cache, const char *sid_prefix,
471 			uint32_t rid, uid_t uid, int direction)
472 
473 {
474 	avl_index_t	where;
475 	int		purge_required;
476 	time_t		ttl = CACHE_TTL + gethrestime_sec();
477 
478 
479 	if (direction == IDMAP_DIRECTION_BI ||
480 	    direction == IDMAP_DIRECTION_W2U) {
481 		sid2pid_t	find;
482 		sid2pid_t	*result;
483 		sid2pid_t	*new;
484 
485 		purge_required = FALSE;
486 		find.sid_prefix = sid_prefix;
487 		find.rid = rid;
488 
489 		mutex_enter(&cache->sid2pid.mutex);
490 		result = avl_find(&cache->sid2pid.tree, &find, &where);
491 
492 		if (result) {
493 			if (result->uid == UNDEF_UID)
494 				cache->sid2pid.uid_num++;
495 			result->uid = uid;
496 			result->uid_ttl = ttl;
497 		} else {
498 			new = kmem_alloc(sizeof (sid2pid_t), KM_SLEEP);
499 			new->sid_prefix = sid_prefix;
500 			new->rid = rid;
501 			new->uid = uid;
502 			new->uid_ttl = ttl;
503 			new->gid = UNDEF_GID;
504 			new->gid_ttl = 0;
505 			new->is_user = UNDEF_ISUSER; /* Unknown */
506 			cache->sid2pid.uid_num++;
507 
508 			avl_insert(&cache->sid2pid.tree, new, where);
509 
510 			if ((avl_numnodes(&cache->sid2pid.tree) >
511 			    CACHE_PID_TRIGGER_SIZE) &&
512 			    (cache->sid2pid.purge_time + CACHE_PURGE_INTERVAL <
513 			    gethrestime_sec()))
514 				purge_required = TRUE;
515 		}
516 
517 		mutex_exit(&cache->sid2pid.mutex);
518 
519 		if (purge_required)
520 			kidmap_purge_sid2pid_avl(&cache->sid2pid,
521 			    CACHE_PID_TRIGGER_SIZE);
522 	}
523 
524 	if (direction == IDMAP_DIRECTION_BI ||
525 	    direction == IDMAP_DIRECTION_U2W) {
526 		pid2sid_t	find;
527 		pid2sid_t	*result;
528 		pid2sid_t	*new;
529 
530 		purge_required = FALSE;
531 		find.pid = uid;
532 
533 		mutex_enter(&cache->uid2sid.mutex);
534 		result = avl_find(&cache->uid2sid.tree, &find, &where);
535 
536 		if (result) {
537 			result->sid_prefix = sid_prefix;
538 			result->rid = rid;
539 			result->ttl = ttl;
540 		} else {
541 			new = kmem_alloc(sizeof (pid2sid_t), KM_SLEEP);
542 			new->sid_prefix = sid_prefix;
543 			new->rid = rid;
544 			new->pid = uid;
545 			new->ttl = ttl;
546 
547 			avl_insert(&cache->uid2sid.tree, new, where);
548 
549 			if ((avl_numnodes(&cache->uid2sid.tree) >
550 			    CACHE_UID_TRIGGER_SIZE) &&
551 			    (cache->uid2sid.purge_time + CACHE_PURGE_INTERVAL <
552 			    gethrestime_sec()))
553 				purge_required = TRUE;
554 		}
555 		mutex_exit(&cache->uid2sid.mutex);
556 
557 		if (purge_required)
558 			kidmap_purge_pid2sid_avl(&cache->uid2sid,
559 			    CACHE_UID_TRIGGER_SIZE);
560 	}
561 }
562 
563 
564 
565 void
566 kidmap_cache_add_sid2gid(idmap_cache_t *cache, const char *sid_prefix,
567 			uint32_t rid, gid_t gid, int direction)
568 {
569 	avl_index_t	where;
570 	int		purge_required;
571 	time_t		ttl = CACHE_TTL + gethrestime_sec();
572 
573 
574 	if (direction == IDMAP_DIRECTION_BI ||
575 	    direction == IDMAP_DIRECTION_W2U) {
576 		sid2pid_t	find;
577 		sid2pid_t	*result;
578 		sid2pid_t	*new;
579 
580 		purge_required = FALSE;
581 		find.sid_prefix = sid_prefix;
582 		find.rid = rid;
583 
584 		mutex_enter(&cache->sid2pid.mutex);
585 		result = avl_find(&cache->sid2pid.tree, &find, &where);
586 
587 		if (result) {
588 			if (result->gid == UNDEF_GID)
589 				cache->sid2pid.gid_num++;
590 			result->gid = gid;
591 			result->gid_ttl = ttl;
592 		} else {
593 			new = kmem_alloc(sizeof (sid2pid_t), KM_SLEEP);
594 			new->sid_prefix = sid_prefix;
595 			new->rid = rid;
596 			new->uid = UNDEF_UID;
597 			new->uid_ttl = 0;
598 			new->gid = gid;
599 			new->gid_ttl = ttl;
600 			new->is_user = UNDEF_ISUSER; /* Unknown */
601 			cache->sid2pid.gid_num++;
602 
603 			avl_insert(&cache->sid2pid.tree, new, where);
604 
605 			if ((avl_numnodes(&cache->sid2pid.tree) >
606 			    CACHE_PID_TRIGGER_SIZE) &&
607 			    (cache->sid2pid.purge_time + CACHE_PURGE_INTERVAL <
608 			    gethrestime_sec()))
609 				purge_required = TRUE;
610 		}
611 		mutex_exit(&cache->sid2pid.mutex);
612 
613 		if (purge_required)
614 			kidmap_purge_sid2pid_avl(&cache->sid2pid,
615 			    CACHE_PID_TRIGGER_SIZE);
616 	}
617 
618 	if (direction == IDMAP_DIRECTION_BI ||
619 	    direction == IDMAP_DIRECTION_U2W) {
620 		pid2sid_t	find;
621 		pid2sid_t	*result;
622 		pid2sid_t	*new;
623 
624 		purge_required = FALSE;
625 		find.pid = gid;
626 
627 		mutex_enter(&cache->gid2sid.mutex);
628 		result = avl_find(&cache->gid2sid.tree, &find, &where);
629 
630 		if (result) {
631 			result->sid_prefix = sid_prefix;
632 			result->rid = rid;
633 			result->ttl = ttl;
634 		} else {
635 			new = kmem_alloc(sizeof (pid2sid_t), KM_SLEEP);
636 			new->sid_prefix = sid_prefix;
637 			new->rid = rid;
638 			new->pid = gid;
639 			new->ttl = ttl;
640 
641 			avl_insert(&cache->gid2sid.tree, new, where);
642 
643 			if ((avl_numnodes(&cache->gid2sid.tree) >
644 			    CACHE_GID_TRIGGER_SIZE) &&
645 			    (cache->gid2sid.purge_time + CACHE_PURGE_INTERVAL <
646 			    gethrestime_sec()))
647 				purge_required = TRUE;
648 		}
649 		mutex_exit(&cache->gid2sid.mutex);
650 
651 		if (purge_required)
652 			kidmap_purge_pid2sid_avl(&cache->gid2sid,
653 			    CACHE_GID_TRIGGER_SIZE);
654 	}
655 }
656 
657 
658 void
659 kidmap_cache_add_sid2pid(idmap_cache_t *cache, const char *sid_prefix,
660 			uint32_t rid, uid_t pid, int is_user, int direction)
661 {
662 	avl_index_t	where;
663 	int		purge_required;
664 	time_t		ttl = CACHE_TTL + gethrestime_sec();
665 
666 
667 	if (direction == IDMAP_DIRECTION_BI ||
668 	    direction == IDMAP_DIRECTION_W2U) {
669 		sid2pid_t	find;
670 		sid2pid_t	*result;
671 		sid2pid_t	*new;
672 
673 		purge_required = FALSE;
674 		find.sid_prefix = sid_prefix;
675 		find.rid = rid;
676 
677 		mutex_enter(&cache->sid2pid.mutex);
678 		result = avl_find(&cache->sid2pid.tree, &find, &where);
679 
680 		if (result) {
681 			if (result->is_user == UNDEF_ISUSER)
682 				cache->sid2pid.pid_num++;
683 			result->is_user = is_user;
684 			if (is_user) {
685 				if (result->uid == UNDEF_UID)
686 					cache->sid2pid.uid_num++;
687 				result->uid = pid;
688 				result->uid_ttl = ttl;
689 			} else {
690 				if (result->gid == UNDEF_GID)
691 					cache->sid2pid.gid_num++;
692 				result->gid = pid;
693 				result->gid_ttl = ttl;
694 			}
695 		} else {
696 			new = kmem_alloc(sizeof (sid2pid_t), KM_SLEEP);
697 			new->sid_prefix = sid_prefix;
698 			new->rid = rid;
699 			new->is_user = is_user;
700 			if (is_user) {
701 				new->uid = pid;
702 				new->uid_ttl = ttl;
703 				new->gid = UNDEF_GID;
704 				new->gid_ttl = 0;
705 				cache->sid2pid.uid_num++;
706 			} else {
707 				new->uid = UNDEF_UID;
708 				new->uid_ttl = 0;
709 				new->gid = pid;
710 				new->gid_ttl = ttl;
711 				cache->sid2pid.gid_num++;
712 			}
713 			cache->sid2pid.pid_num++;
714 
715 			avl_insert(&cache->sid2pid.tree, new, where);
716 
717 			if ((avl_numnodes(&cache->sid2pid.tree) >
718 			    CACHE_PID_TRIGGER_SIZE) &&
719 			    (cache->sid2pid.purge_time + CACHE_PURGE_INTERVAL <
720 			    gethrestime_sec()))
721 				purge_required = TRUE;
722 		}
723 		mutex_exit(&cache->sid2pid.mutex);
724 
725 		if (purge_required)
726 			kidmap_purge_sid2pid_avl(&cache->sid2pid,
727 			    CACHE_PID_TRIGGER_SIZE);
728 	}
729 
730 	if (direction == IDMAP_DIRECTION_BI ||
731 	    direction == IDMAP_DIRECTION_U2W) {
732 		pid2sid_t	find;
733 		pid2sid_t	*result;
734 		pid2sid_t	*new;
735 
736 		purge_required = FALSE;
737 		find.pid = pid;
738 		if (is_user) {
739 			mutex_enter(&cache->uid2sid.mutex);
740 			result = avl_find(&cache->uid2sid.tree, &find, &where);
741 
742 			if (result) {
743 				result->sid_prefix = sid_prefix;
744 				result->rid = rid;
745 				result->ttl = ttl;
746 			} else {
747 				new = kmem_alloc(sizeof (pid2sid_t), KM_SLEEP);
748 				new->sid_prefix = sid_prefix;
749 				new->rid = rid;
750 				new->pid = pid;
751 				new->ttl = ttl;
752 
753 				avl_insert(&cache->uid2sid.tree, new, where);
754 
755 				if ((avl_numnodes(&cache->uid2sid.tree) >
756 				    CACHE_UID_TRIGGER_SIZE) &&
757 				    (cache->uid2sid.purge_time +
758 				    CACHE_PURGE_INTERVAL <
759 				    gethrestime_sec()))
760 					purge_required = TRUE;
761 			}
762 			mutex_exit(&cache->uid2sid.mutex);
763 
764 			if (purge_required)
765 				kidmap_purge_pid2sid_avl(&cache->uid2sid,
766 				    CACHE_UID_TRIGGER_SIZE);
767 		} else {
768 			mutex_enter(&cache->gid2sid.mutex);
769 			result = avl_find(&cache->gid2sid.tree, &find, &where);
770 
771 			if (result) {
772 				result->sid_prefix = sid_prefix;
773 				result->rid = rid;
774 				result->ttl = ttl;
775 			} else {
776 				new = kmem_alloc(sizeof (pid2sid_t), KM_SLEEP);
777 				new->sid_prefix = sid_prefix;
778 				new->rid = rid;
779 				new->pid = pid;
780 				new->ttl = ttl;
781 
782 				avl_insert(&cache->gid2sid.tree, new, where);
783 
784 				if ((avl_numnodes(&cache->gid2sid.tree) >
785 				    CACHE_GID_TRIGGER_SIZE) &&
786 				    (cache->gid2sid.purge_time +
787 				    CACHE_PURGE_INTERVAL <
788 				    gethrestime_sec()))
789 					purge_required = TRUE;
790 
791 			}
792 			mutex_exit(&cache->gid2sid.mutex);
793 
794 			if (purge_required)
795 				kidmap_purge_pid2sid_avl(&cache->gid2sid,
796 				    CACHE_GID_TRIGGER_SIZE);
797 		}
798 	}
799 }
800 
801 
802 
803 
804 
805 static void
806 kidmap_purge_sid2pid_avl(idmap_sid2pid_cache_t *avl, size_t limit)
807 {
808 	time_t		now = gethrestime_sec();
809 	sid2pid_t	*curr;
810 	sid2pid_t	*prev;
811 	sid2pid_t	*start;
812 	int		last = FALSE;
813 
814 	mutex_enter(&avl->mutex);
815 	if (avl_numnodes(&avl->tree) <= limit) {
816 		mutex_exit(&avl->mutex);
817 		return;
818 	}
819 
820 	if (avl->prev == NULL)
821 		start = avl_first(&avl->tree);
822 	else
823 		start = avl->prev;
824 
825 	prev = start;
826 	curr = AVL_NEXT(&avl->tree, prev);
827 	if (curr == NULL)
828 		curr = avl_first(&avl->tree);
829 
830 	while (!last && avl_numnodes(&avl->tree) > limit) {
831 		if (curr == start)
832 			last = TRUE;
833 		if (curr->uid_ttl < now && curr->gid_ttl < now) {
834 			/* Old entry to remove */
835 			avl_remove(&avl->tree, curr);
836 			if (curr->uid != UNDEF_UID)
837 				avl->uid_num--;
838 			if (curr->gid != UNDEF_GID)
839 				avl->gid_num--;
840 			if (curr->is_user != UNDEF_ISUSER)
841 				avl->pid_num--;
842 			kmem_free(curr, sizeof (sid2pid_t));
843 			curr = AVL_NEXT(&avl->tree, prev);
844 			if (curr == NULL)
845 				curr = avl_first(&avl->tree);
846 			continue;
847 		}
848 		prev = curr;
849 		curr = AVL_NEXT(&avl->tree, curr);
850 		if (curr == NULL)
851 			curr = avl_first(&avl->tree);
852 	}
853 	avl->purge_time = now;
854 	avl->prev = prev;
855 
856 	mutex_exit(&avl->mutex);
857 }
858 
859 
860 static void
861 kidmap_purge_pid2sid_avl(idmap_pid2sid_cache_t *avl, size_t limit)
862 {
863 	time_t		now = gethrestime_sec();
864 	pid2sid_t	*curr;
865 	pid2sid_t	*prev = NULL;
866 	pid2sid_t	*start;
867 	int		last = FALSE;
868 
869 	mutex_enter(&avl->mutex);
870 	if (avl_numnodes(&avl->tree) <= limit) {
871 		mutex_exit(&avl->mutex);
872 		return;
873 	}
874 
875 	if (avl->prev == NULL)
876 		start = avl_first(&avl->tree);
877 	else
878 		start = avl->prev;
879 
880 	prev = start;
881 	curr = AVL_NEXT(&avl->tree, prev);
882 	if (curr == NULL)
883 		curr = avl_first(&avl->tree);
884 
885 	while (!last && avl_numnodes(&avl->tree) > limit) {
886 		if (curr == start)
887 			last = TRUE;
888 		if (curr->ttl < now) {
889 			/* Old entry to remove */
890 			avl_remove(&avl->tree, curr);
891 			kmem_free(curr, sizeof (pid2sid_t));
892 			curr = AVL_NEXT(&avl->tree, prev);
893 			if (curr == NULL)
894 				curr = avl_first(&avl->tree);
895 			continue;
896 		}
897 		prev = curr;
898 		curr = AVL_NEXT(&avl->tree, curr);
899 		if (curr == NULL)
900 			curr = avl_first(&avl->tree);
901 	}
902 	avl->purge_time = now;
903 	avl->prev = prev;
904 
905 	mutex_exit(&avl->mutex);
906 }
907 
908 
909 
910 
911 
912 void
913 kidmap_sid_prefix_store_init(void)
914 {
915 	kidmap_sid_prefix_store = (struct sid_prefix_store *)
916 	    space_fetch("SUNW,idmap_sid_prefix");
917 	if (kidmap_sid_prefix_store == NULL) {
918 		kidmap_sid_prefix_store = kmem_alloc(
919 		    sizeof (struct sid_prefix_store), KM_SLEEP);
920 		rw_init(&kidmap_sid_prefix_store->lock, NULL, RW_DRIVER, NULL);
921 		avl_create(&kidmap_sid_prefix_store->tree,
922 		    (avl_comp_fn)kidmap_compare_sid_prefix,
923 		    sizeof (sid_prefix_node_t),
924 		    offsetof(sid_prefix_node_t, avl_link));
925 		(void) space_store("SUNW,idmap_sid_prefix",
926 		    (uintptr_t)kidmap_sid_prefix_store);
927 	} else {
928 		/*
929 		 * The AVL comparison function must be re-initialised on
930 		 * re-load because may not be loaded into the same
931 		 * address space.
932 		 */
933 		kidmap_sid_prefix_store->tree.avl_compar =
934 		    (avl_comp_fn)kidmap_compare_sid_prefix;
935 	}
936 }
937 
938 
939 const char *
940 kidmap_find_sid_prefix(const char *sid_prefix) {
941 	sid_prefix_node_t 	find;
942 	sid_prefix_node_t	*result;
943 	sid_prefix_node_t 	*new;
944 	avl_index_t		where;
945 
946 	if (sid_prefix == NULL || *sid_prefix == '\0')
947 		return (NULL);
948 
949 	find.sid_prefix = sid_prefix;
950 
951 	rw_enter(&kidmap_sid_prefix_store->lock, RW_READER);
952 
953 	result = avl_find(&kidmap_sid_prefix_store->tree, &find, &where);
954 
955 	if (result) {
956 		rw_exit(&kidmap_sid_prefix_store->lock);
957 		return (result->sid_prefix);
958 	}
959 
960 	if (rw_tryupgrade(&kidmap_sid_prefix_store->lock) == 0) {
961 		/*
962 		 * Could not upgrade lock so release lock
963 		 * and acquire the write lock
964 		 */
965 		rw_exit(&kidmap_sid_prefix_store->lock);
966 		rw_enter(&kidmap_sid_prefix_store->lock, RW_WRITER);
967 
968 		result = avl_find(&kidmap_sid_prefix_store->tree,
969 			&find, &where);
970 		if (result) {
971 			rw_exit(&kidmap_sid_prefix_store->lock);
972 			return (result->sid_prefix);
973 		}
974 	}
975 
976 	new = kmem_alloc(sizeof (sid_prefix_node_t), KM_SLEEP);
977 	new->sid_prefix = kidmap_strdup(sid_prefix);
978 	avl_insert(&kidmap_sid_prefix_store->tree, new, where);
979 	rw_exit(&kidmap_sid_prefix_store->lock);
980 
981 	return (new->sid_prefix);
982 }
983