xref: /titanic_52/usr/src/uts/common/idmap/idmap_cache.c (revision b9bd317cda1afb3a01f4812de73e8cec888cbbd7)
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_TRIGGER_SIZE	4096
57 #define	CACHE_PURGE_INTERVAL	(60 * 3)
58 #define	CACHE_TTL		(60 * 10)
59 
60 typedef struct sid_prefix_node {
61 	avl_node_t	avl_link;
62 	const char 	*sid_prefix;
63 } sid_prefix_node_t;
64 
65 
66 typedef struct entry {
67 	avl_node_t	avl_link;
68 	const char 	*sid_prefix;
69 	uint32_t	rid;
70 	uid_t		pid;
71 	int		is_user;
72 	time_t		ttl;
73 } entry_t;
74 
75 typedef int (*avl_comp_fn)(const void*, const void*);
76 
77 
78 struct sid_prefix_store {
79 	struct avl_tree	tree;
80 	krwlock_t	lock;
81 };
82 
83 struct sid_prefix_store *kidmap_sid_prefix_store = NULL;
84 
85 
86 
87 static void
88 kidmap_cache_purge_avl(idmap_avl_cache_t *cache);
89 
90 /*
91  * kidmap_strdup() copied from uts/common/fs/sockfs/nl7c.c
92  */
93 static char *
94 kidmap_strdup(const char *s)
95 {
96 	int	len = strlen(s) + 1;
97 	char	*ret = kmem_alloc(len, KM_SLEEP);
98 
99 	bcopy(s, ret, len);
100 	return (ret);
101 }
102 
103 
104 static int
105 kidmap_compare_sid(const entry_t *entry1, const entry_t *entry2)
106 {
107 	int64_t comp = ((int64_t)entry2->rid) - ((int64_t)entry1->rid);
108 
109 	if (comp == 0)
110 		comp = strcmp(entry2->sid_prefix, entry1->sid_prefix);
111 
112 	if (comp < 0)
113 		comp = -1;
114 	else if (comp > 0)
115 		comp = 1;
116 
117 	return ((int)comp);
118 }
119 
120 
121 static int
122 kidmap_compare_pid(const entry_t *entry1, const entry_t *entry2)
123 {
124 	if (entry2->pid > entry1->pid)
125 		return (1);
126 	if (entry2->pid < entry1->pid)
127 		return (-1);
128 	return (0);
129 }
130 
131 
132 static int
133 kidmap_compare_sid_prefix(const sid_prefix_node_t *entry1,
134 			const sid_prefix_node_t *entry2)
135 {
136 	int comp;
137 
138 	comp = strcmp(entry2->sid_prefix, entry1->sid_prefix);
139 
140 	if (comp < 0)
141 		comp = -1;
142 	else if (comp > 0)
143 		comp = 1;
144 
145 	return (comp);
146 }
147 
148 
149 void
150 kidmap_cache_create(idmap_cache_t *cache)
151 {
152 	avl_create(&cache->uidbysid.tree, (avl_comp_fn)kidmap_compare_sid,
153 	    sizeof (entry_t), offsetof(entry_t, avl_link));
154 	mutex_init(&cache->uidbysid.mutex, NULL, MUTEX_DEFAULT, NULL);
155 	cache->uidbysid.purge_time = 0;
156 
157 	avl_create(&cache->gidbysid.tree, (avl_comp_fn)kidmap_compare_sid,
158 	    sizeof (entry_t), offsetof(entry_t, avl_link));
159 	mutex_init(&cache->gidbysid.mutex, NULL, MUTEX_DEFAULT, NULL);
160 	cache->gidbysid.purge_time = 0;
161 
162 	avl_create(&cache->pidbysid.tree, (avl_comp_fn)kidmap_compare_sid,
163 	    sizeof (entry_t), offsetof(entry_t, avl_link));
164 	mutex_init(&cache->pidbysid.mutex, NULL, MUTEX_DEFAULT, NULL);
165 	cache->pidbysid.purge_time = 0;
166 
167 	avl_create(&cache->sidbyuid.tree, (avl_comp_fn)kidmap_compare_pid,
168 	    sizeof (entry_t), offsetof(entry_t, avl_link));
169 	mutex_init(&cache->sidbyuid.mutex, NULL, MUTEX_DEFAULT, NULL);
170 	cache->sidbyuid.purge_time = 0;
171 
172 	avl_create(&cache->sidbygid.tree, (avl_comp_fn)kidmap_compare_pid,
173 	    sizeof (entry_t), offsetof(entry_t, avl_link));
174 	mutex_init(&cache->sidbygid.mutex, NULL, MUTEX_DEFAULT, NULL);
175 	cache->sidbygid.purge_time = 0;
176 }
177 
178 
179 void
180 kidmap_cache_delete(idmap_cache_t *cache)
181 {
182 	entry_t *entry;
183 	void *cookie;
184 
185 	cookie = NULL;
186 	while ((entry = avl_destroy_nodes(&cache->uidbysid.tree, &cookie))
187 	    != NULL) {
188 		kmem_free(entry, sizeof (entry_t));
189 	}
190 	avl_destroy(&cache->uidbysid.tree);
191 	mutex_destroy(&cache->uidbysid.mutex);
192 
193 	cookie = NULL;
194 	while ((entry = avl_destroy_nodes(&cache->gidbysid.tree, &cookie))
195 	    != NULL) {
196 		kmem_free(entry, sizeof (entry_t));
197 	}
198 	avl_destroy(&cache->gidbysid.tree);
199 	mutex_destroy(&cache->gidbysid.mutex);
200 
201 	cookie = NULL;
202 	while ((entry = avl_destroy_nodes(&cache->pidbysid.tree, &cookie))
203 	    != NULL) {
204 		kmem_free(entry, sizeof (entry_t));
205 	}
206 	avl_destroy(&cache->pidbysid.tree);
207 	mutex_destroy(&cache->pidbysid.mutex);
208 
209 	cookie = NULL;
210 	while ((entry = avl_destroy_nodes(&cache->sidbyuid.tree, &cookie))
211 	    != NULL) {
212 		kmem_free(entry, sizeof (entry_t));
213 	}
214 	avl_destroy(&cache->sidbyuid.tree);
215 	mutex_destroy(&cache->sidbyuid.mutex);
216 
217 	cookie = NULL;
218 	while ((entry = avl_destroy_nodes(&cache->sidbygid.tree, &cookie))
219 	    != NULL) {
220 		kmem_free(entry, sizeof (entry_t));
221 	}
222 	avl_destroy(&cache->sidbygid.tree);
223 	mutex_destroy(&cache->sidbygid.mutex);
224 }
225 
226 
227 void
228 kidmap_cache_get_data(idmap_cache_t *cache, size_t *uidbysid, size_t *gidbysid,
229 	size_t *pidbysid, size_t *sidbyuid, size_t *sidbygid)
230 {
231 	mutex_enter(&cache->uidbysid.mutex);
232 	*uidbysid = avl_numnodes(&cache->uidbysid.tree);
233 	mutex_exit(&cache->uidbysid.mutex);
234 
235 	mutex_enter(&cache->gidbysid.mutex);
236 	*gidbysid = avl_numnodes(&cache->gidbysid.tree);
237 	mutex_exit(&cache->gidbysid.mutex);
238 
239 	mutex_enter(&cache->pidbysid.mutex);
240 	*pidbysid = avl_numnodes(&cache->pidbysid.tree);
241 	mutex_exit(&cache->pidbysid.mutex);
242 
243 	mutex_enter(&cache->sidbyuid.mutex);
244 	*sidbyuid = avl_numnodes(&cache->sidbyuid.tree);
245 	mutex_exit(&cache->sidbyuid.mutex);
246 
247 	mutex_enter(&cache->sidbygid.mutex);
248 	*sidbygid = avl_numnodes(&cache->sidbygid.tree);
249 	mutex_exit(&cache->sidbygid.mutex);
250 }
251 
252 
253 void
254 kidmap_cache_purge(idmap_cache_t *cache)
255 {
256 	entry_t *entry;
257 	void *cookie;
258 
259 	mutex_enter(&cache->uidbysid.mutex);
260 	cookie = NULL;
261 	while ((entry = avl_destroy_nodes(&cache->uidbysid.tree, &cookie))
262 	    != NULL) {
263 		kmem_free(entry, sizeof (entry_t));
264 	}
265 	avl_destroy(&cache->uidbysid.tree);
266 	avl_create(&cache->uidbysid.tree, (avl_comp_fn)kidmap_compare_sid,
267 	    sizeof (entry_t), offsetof(entry_t, avl_link));
268 	mutex_exit(&cache->uidbysid.mutex);
269 
270 	mutex_enter(&cache->gidbysid.mutex);
271 	cookie = NULL;
272 	while ((entry = avl_destroy_nodes(&cache->gidbysid.tree, &cookie))
273 	    != NULL) {
274 		kmem_free(entry, sizeof (entry_t));
275 	}
276 	avl_destroy(&cache->gidbysid.tree);
277 	avl_create(&cache->gidbysid.tree, (avl_comp_fn)kidmap_compare_sid,
278 	    sizeof (entry_t), offsetof(entry_t, avl_link));
279 	mutex_exit(&cache->gidbysid.mutex);
280 
281 	mutex_enter(&cache->pidbysid.mutex);
282 	cookie = NULL;
283 	while ((entry = avl_destroy_nodes(&cache->pidbysid.tree, &cookie))
284 	    != NULL) {
285 		kmem_free(entry, sizeof (entry_t));
286 	}
287 	avl_destroy(&cache->pidbysid.tree);
288 	avl_create(&cache->pidbysid.tree, (avl_comp_fn)kidmap_compare_sid,
289 	    sizeof (entry_t), offsetof(entry_t, avl_link));
290 	mutex_exit(&cache->pidbysid.mutex);
291 
292 	mutex_enter(&cache->sidbyuid.mutex);
293 	cookie = NULL;
294 	while ((entry = avl_destroy_nodes(&cache->sidbyuid.tree, &cookie))
295 	    != NULL) {
296 		kmem_free(entry, sizeof (entry_t));
297 	}
298 	avl_destroy(&cache->sidbyuid.tree);
299 	avl_create(&cache->sidbyuid.tree, (avl_comp_fn)kidmap_compare_pid,
300 	    sizeof (entry_t), offsetof(entry_t, avl_link));
301 	mutex_exit(&cache->sidbyuid.mutex);
302 
303 	mutex_enter(&cache->sidbygid.mutex);
304 	cookie = NULL;
305 	while ((entry = avl_destroy_nodes(&cache->sidbygid.tree, &cookie))
306 	    != NULL) {
307 		kmem_free(entry, sizeof (entry_t));
308 	}
309 	avl_destroy(&cache->sidbygid.tree);
310 	avl_create(&cache->sidbygid.tree, (avl_comp_fn)kidmap_compare_pid,
311 	    sizeof (entry_t), offsetof(entry_t, avl_link));
312 	mutex_exit(&cache->sidbygid.mutex);
313 }
314 
315 
316 int
317 kidmap_cache_lookup_uidbysid(idmap_cache_t *cache, const char *sid_prefix,
318 			uint32_t rid, uid_t *uid)
319 {
320 	entry_t		entry;
321 	entry_t		*result;
322 	avl_index_t	where;
323 	int		status;
324 	time_t		now = gethrestime_sec();
325 
326 	entry.sid_prefix = sid_prefix;
327 	entry.rid = rid;
328 
329 	mutex_enter(&cache->uidbysid.mutex);
330 
331 	result = avl_find(&cache->uidbysid.tree, &entry, &where);
332 
333 	if (result && result->ttl > now) {
334 		*uid = result->pid;
335 		status = IDMAP_SUCCESS;
336 	} else
337 		status = IDMAP_ERR_NOMAPPING;
338 
339 	mutex_exit(&cache->uidbysid.mutex);
340 
341 	return (status);
342 }
343 
344 
345 
346 int
347 kidmap_cache_lookup_gidbysid(idmap_cache_t *cache, const char *sid_prefix,
348 			uint32_t rid, gid_t *gid)
349 {
350 	entry_t		entry;
351 	entry_t		*result;
352 	avl_index_t	where;
353 	int		status;
354 	time_t		now = gethrestime_sec();
355 
356 	entry.sid_prefix = sid_prefix;
357 	entry.rid = rid;
358 
359 	mutex_enter(&cache->gidbysid.mutex);
360 
361 	result = avl_find(&cache->gidbysid.tree, &entry, &where);
362 
363 	if (result && result->ttl > now) {
364 		*gid = result->pid;
365 		status = IDMAP_SUCCESS;
366 	} else
367 		status = IDMAP_ERR_NOMAPPING;
368 
369 	mutex_exit(&cache->gidbysid.mutex);
370 
371 	return (status);
372 }
373 
374 
375 
376 
377 int
378 kidmap_cache_lookup_pidbysid(idmap_cache_t *cache, const char *sid_prefix,
379 			uint32_t rid, uid_t *pid, int *is_user)
380 {
381 	entry_t		entry;
382 	entry_t		*result;
383 	avl_index_t	where;
384 	int		status;
385 	time_t		now = gethrestime_sec();
386 
387 	entry.sid_prefix = sid_prefix;
388 	entry.rid = rid;
389 
390 	mutex_enter(&cache->pidbysid.mutex);
391 
392 	result = avl_find(&cache->pidbysid.tree, &entry, &where);
393 
394 	if (result && result->ttl > now) {
395 		*pid = result->pid;
396 		*is_user = result->is_user;
397 		status = IDMAP_SUCCESS;
398 	} else
399 		status = IDMAP_ERR_NOMAPPING;
400 
401 	mutex_exit(&cache->pidbysid.mutex);
402 
403 	return (status);
404 }
405 
406 
407 
408 int
409 kidmap_cache_lookup_sidbyuid(idmap_cache_t *cache, const char **sid_prefix,
410 			uint32_t *rid, uid_t uid)
411 {
412 	entry_t		entry;
413 	entry_t		*result;
414 	avl_index_t	where;
415 	int		status;
416 	time_t		now = gethrestime_sec();
417 
418 	entry.pid = uid;
419 
420 	mutex_enter(&cache->sidbyuid.mutex);
421 
422 	result = avl_find(&cache->sidbyuid.tree, &entry, &where);
423 
424 	if (result && result->ttl > now) {
425 		*sid_prefix = result->sid_prefix;
426 		*rid = result->rid;
427 		status = IDMAP_SUCCESS;
428 	} else
429 		status = IDMAP_ERR_NOMAPPING;
430 
431 	mutex_exit(&cache->sidbyuid.mutex);
432 
433 	return (status);
434 }
435 
436 int
437 kidmap_cache_lookup_sidbygid(idmap_cache_t *cache, const char **sid_prefix,
438 			uint32_t *rid, gid_t gid)
439 {
440 	entry_t		entry;
441 	entry_t		*result;
442 	avl_index_t	where;
443 	int		status;
444 	time_t		now = gethrestime_sec();
445 
446 	entry.pid = gid;
447 
448 	mutex_enter(&cache->sidbygid.mutex);
449 
450 	result = avl_find(&cache->sidbygid.tree, &entry, &where);
451 
452 	if (result && result->ttl > now) {
453 		*sid_prefix = result->sid_prefix;
454 		*rid = result->rid;
455 		status = IDMAP_SUCCESS;
456 	} else
457 		status = IDMAP_ERR_NOMAPPING;
458 
459 	mutex_exit(&cache->sidbygid.mutex);
460 
461 	return (status);
462 }
463 
464 
465 
466 
467 void
468 kidmap_cache_add_uidbysid(idmap_cache_t *cache, const char *sid_prefix,
469 			uint32_t rid, uid_t uid)
470 
471 {
472 	entry_t		find;
473 	entry_t		*result;
474 	entry_t		*new;
475 	avl_index_t	where;
476 	int		purge_required = FALSE;
477 	time_t		ttl = CACHE_TTL + gethrestime_sec();
478 
479 	find.sid_prefix = sid_prefix;
480 	find.rid = rid;
481 
482 	mutex_enter(&cache->uidbysid.mutex);
483 	result = avl_find(&cache->uidbysid.tree, &find, &where);
484 
485 	if (result) {
486 		result->pid = uid;
487 		result->ttl = ttl;
488 	} else {
489 		new = kmem_alloc(sizeof (entry_t), KM_SLEEP);
490 		new->pid = uid;
491 		new->sid_prefix = sid_prefix;
492 		new->rid = rid;
493 		new->ttl = ttl;
494 
495 		avl_insert(&cache->uidbysid.tree, new, where);
496 
497 		if ((avl_numnodes(&cache->uidbysid.tree) >
498 		    CACHE_TRIGGER_SIZE) &&
499 		    (cache->uidbysid.purge_time + CACHE_PURGE_INTERVAL <
500 		    gethrestime_sec()))
501 			purge_required = TRUE;
502 	}
503 
504 	mutex_exit(&cache->uidbysid.mutex);
505 
506 	if (purge_required)
507 		kidmap_cache_purge_avl(&cache->uidbysid);
508 }
509 
510 
511 void
512 kidmap_cache_add_gidbysid(idmap_cache_t *cache, const char *sid_prefix,
513 			uint32_t rid, gid_t gid)
514 
515 {
516 	entry_t		find;
517 	entry_t		*result;
518 	entry_t		*new;
519 	avl_index_t	where;
520 	int		purge_required = FALSE;
521 	time_t		ttl = CACHE_TTL + gethrestime_sec();
522 
523 	find.sid_prefix = sid_prefix;
524 	find.rid = rid;
525 
526 	mutex_enter(&cache->gidbysid.mutex);
527 	result = avl_find(&cache->gidbysid.tree, &find, &where);
528 
529 	if (result) {
530 		result->pid = gid;
531 		result->ttl = ttl;
532 	} else {
533 		new = kmem_alloc(sizeof (entry_t), KM_SLEEP);
534 		new->pid = gid;
535 		new->sid_prefix = sid_prefix;
536 		new->rid = rid;
537 		new->ttl = ttl;
538 
539 		avl_insert(&cache->gidbysid.tree, new, where);
540 
541 		if ((avl_numnodes(&cache->gidbysid.tree) >
542 		    CACHE_TRIGGER_SIZE) &&
543 		    (cache->gidbysid.purge_time + CACHE_PURGE_INTERVAL <
544 		    gethrestime_sec()))
545 			purge_required = TRUE;
546 	}
547 
548 	mutex_exit(&cache->gidbysid.mutex);
549 
550 	if (purge_required)
551 		kidmap_cache_purge_avl(&cache->gidbysid);
552 }
553 
554 void
555 kidmap_cache_add_pidbysid(idmap_cache_t *cache, const char *sid_prefix,
556 			uint32_t rid, uid_t pid, int is_user)
557 
558 {
559 	entry_t		find;
560 	entry_t		*result;
561 	entry_t		*new;
562 	avl_index_t	where;
563 	int		purge_required = FALSE;
564 	time_t		ttl = CACHE_TTL + gethrestime_sec();
565 
566 	find.sid_prefix = sid_prefix;
567 	find.rid = rid;
568 
569 	mutex_enter(&cache->pidbysid.mutex);
570 	result = avl_find(&cache->pidbysid.tree, &find, &where);
571 
572 	if (result) {
573 		result->pid = pid;
574 		result->is_user = is_user;
575 		result->ttl = ttl;
576 	} else {
577 		new = kmem_alloc(sizeof (entry_t), KM_SLEEP);
578 		new->pid = pid;
579 		new->is_user = is_user;
580 		new->sid_prefix = sid_prefix;
581 		new->rid = rid;
582 		new->ttl = ttl;
583 
584 		avl_insert(&cache->pidbysid.tree, new, where);
585 
586 		if ((avl_numnodes(&cache->pidbysid.tree) >
587 		    CACHE_TRIGGER_SIZE) &&
588 		    (cache->pidbysid.purge_time + CACHE_PURGE_INTERVAL <
589 		    gethrestime_sec()))
590 			purge_required = TRUE;
591 	}
592 
593 	mutex_exit(&cache->pidbysid.mutex);
594 
595 	if (purge_required)
596 		kidmap_cache_purge_avl(&cache->pidbysid);
597 }
598 
599 
600 
601 void
602 kidmap_cache_add_sidbyuid(idmap_cache_t *cache, const char *sid_prefix,
603 			uint32_t rid, uid_t uid)
604 {
605 	entry_t		find;
606 	entry_t		*result;
607 	entry_t		*new;
608 	avl_index_t	where;
609 	int		purge_required = FALSE;
610 	time_t		ttl = CACHE_TTL + gethrestime_sec();
611 
612 	find.pid = uid;
613 
614 	mutex_enter(&cache->sidbyuid.mutex);
615 	result = avl_find(&cache->sidbyuid.tree, &find, &where);
616 
617 	if (result) {
618 		result->sid_prefix = sid_prefix;
619 		result->rid = rid;
620 		result->ttl = ttl;
621 	} else {
622 		new = kmem_alloc(sizeof (entry_t), KM_SLEEP);
623 		new->pid = uid;
624 		new->sid_prefix = sid_prefix;
625 		new->rid = rid;
626 		new->ttl = ttl;
627 
628 		avl_insert(&cache->sidbyuid.tree, new, where);
629 		if ((avl_numnodes(&cache->sidbyuid.tree) >
630 		    CACHE_TRIGGER_SIZE) &&
631 		    (cache->sidbyuid.purge_time + CACHE_PURGE_INTERVAL <
632 		    gethrestime_sec()))
633 			purge_required = TRUE;
634 	}
635 
636 	mutex_exit(&cache->sidbyuid.mutex);
637 
638 	if (purge_required)
639 		kidmap_cache_purge_avl(&cache->sidbyuid);
640 }
641 
642 
643 void
644 kidmap_cache_add_sidbygid(idmap_cache_t *cache, const char *sid_prefix,
645 			uint32_t rid, gid_t gid)
646 {
647 	entry_t		find;
648 	entry_t		*result;
649 	entry_t		*new;
650 	avl_index_t	where;
651 	int		purge_required = FALSE;
652 	time_t		ttl = CACHE_TTL + gethrestime_sec();
653 
654 	find.pid = gid;
655 
656 	mutex_enter(&cache->sidbygid.mutex);
657 	result = avl_find(&cache->sidbygid.tree, &find, &where);
658 
659 	if (result) {
660 		result->sid_prefix = sid_prefix;
661 		result->rid = rid;
662 		result->ttl = ttl;
663 	} else {
664 		new = kmem_alloc(sizeof (entry_t), KM_SLEEP);
665 		new->pid = gid;
666 		new->sid_prefix = sid_prefix;
667 		new->rid = rid;
668 		new->ttl = ttl;
669 
670 		avl_insert(&cache->sidbygid.tree, new, where);
671 		if ((avl_numnodes(&cache->sidbygid.tree) >
672 		    CACHE_TRIGGER_SIZE) &&
673 		    (cache->sidbygid.purge_time + CACHE_PURGE_INTERVAL <
674 		    gethrestime_sec()))
675 			purge_required = TRUE;
676 	}
677 
678 	mutex_exit(&cache->sidbygid.mutex);
679 
680 	if (purge_required)
681 		kidmap_cache_purge_avl(&cache->sidbygid);
682 }
683 
684 
685 static void
686 kidmap_cache_purge_avl(idmap_avl_cache_t *cache)
687 {
688 	time_t		now = gethrestime_sec();
689 	entry_t		*curr;
690 	entry_t		*prev = NULL;
691 
692 	mutex_enter(&cache->mutex);
693 
694 	curr = avl_first(&cache->tree);
695 	while (curr != NULL) {
696 		if (curr->ttl < now) {
697 			/* Old entry to remove */
698 			avl_remove(&cache->tree, curr);
699 			kmem_free(curr, sizeof (entry_t));
700 			curr = prev;
701 			if (curr == NULL) {
702 				/* We removed the first entery */
703 				curr = avl_first(&cache->tree);
704 				continue;
705 			}
706 		}
707 		prev = curr;
708 		curr = AVL_NEXT(&cache->tree, curr);
709 	}
710 	cache->purge_time = now;
711 
712 	mutex_exit(&cache->mutex);
713 }
714 
715 
716 void
717 kidmap_sid_prefix_store_init(void)
718 {
719 	kidmap_sid_prefix_store = (struct sid_prefix_store *)
720 	    space_fetch("SUNW,idmap_sid_prefix");
721 	if (kidmap_sid_prefix_store == NULL) {
722 		kidmap_sid_prefix_store = kmem_alloc(
723 		    sizeof (struct sid_prefix_store), KM_SLEEP);
724 		rw_init(&kidmap_sid_prefix_store->lock, NULL, RW_DRIVER, NULL);
725 		avl_create(&kidmap_sid_prefix_store->tree,
726 		    (avl_comp_fn)kidmap_compare_sid_prefix,
727 		    sizeof (sid_prefix_node_t),
728 		    offsetof(sid_prefix_node_t, avl_link));
729 		(void) space_store("SUNW,idmap_sid_prefix",
730 		    (uintptr_t)kidmap_sid_prefix_store);
731 	} else {
732 		/*
733 		 * The AVL comparison function must be re-initialised on
734 		 * re-load because may not be loaded into the same
735 		 * address space.
736 		 */
737 		kidmap_sid_prefix_store->tree.avl_compar =
738 		    (avl_comp_fn)kidmap_compare_sid_prefix;
739 	}
740 }
741 
742 
743 const char *
744 kidmap_find_sid_prefix(const char *sid_prefix) {
745 	sid_prefix_node_t 	find;
746 	sid_prefix_node_t	*result;
747 	sid_prefix_node_t 	*new;
748 	avl_index_t		where;
749 
750 	if (sid_prefix == NULL || *sid_prefix == '\0')
751 		return (NULL);
752 
753 	find.sid_prefix = sid_prefix;
754 
755 
756 	rw_enter(&kidmap_sid_prefix_store->lock, RW_READER);
757 
758 	result = avl_find(&kidmap_sid_prefix_store->tree, &find, &where);
759 
760 	if (result) {
761 		rw_exit(&kidmap_sid_prefix_store->lock);
762 		return (result->sid_prefix);
763 	}
764 
765 	if (rw_tryupgrade(&kidmap_sid_prefix_store->lock) == 0) {
766 		/*
767 		 * Could not upgrade lock so release lock
768 		 * and acquire the write lock
769 		 */
770 		rw_exit(&kidmap_sid_prefix_store->lock);
771 		rw_enter(&kidmap_sid_prefix_store->lock, RW_WRITER);
772 
773 		result = avl_find(&kidmap_sid_prefix_store->tree,
774 			&find, &where);
775 		if (result) {
776 			rw_exit(&kidmap_sid_prefix_store->lock);
777 			return (result->sid_prefix);
778 		}
779 	}
780 
781 	new = kmem_alloc(sizeof (sid_prefix_node_t), KM_SLEEP);
782 	new->sid_prefix = kidmap_strdup(sid_prefix);
783 	avl_insert(&kidmap_sid_prefix_store->tree, new, where);
784 	rw_exit(&kidmap_sid_prefix_store->lock);
785 
786 	return (new->sid_prefix);
787 }
788