xref: /illumos-gate/usr/src/uts/common/idmap/idmap_cache.c (revision f998c95e3b7029fe5f7542e115f7474ddb8024d7)
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 2007 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_purge(idmap_cache_t *cache)
229 {
230 	entry_t *entry;
231 	void *cookie;
232 
233 	mutex_enter(&cache->uidbysid.mutex);
234 	cookie = NULL;
235 	while ((entry = avl_destroy_nodes(&cache->uidbysid.tree, &cookie))
236 	    != NULL) {
237 		kmem_free(entry, sizeof (entry_t));
238 	}
239 	avl_destroy(&cache->uidbysid.tree);
240 	avl_create(&cache->uidbysid.tree, (avl_comp_fn)kidmap_compare_sid,
241 	    sizeof (entry_t), offsetof(entry_t, avl_link));
242 	mutex_exit(&cache->uidbysid.mutex);
243 
244 	mutex_enter(&cache->gidbysid.mutex);
245 	cookie = NULL;
246 	while ((entry = avl_destroy_nodes(&cache->gidbysid.tree, &cookie))
247 	    != NULL) {
248 		kmem_free(entry, sizeof (entry_t));
249 	}
250 	avl_destroy(&cache->gidbysid.tree);
251 	avl_create(&cache->gidbysid.tree, (avl_comp_fn)kidmap_compare_sid,
252 	    sizeof (entry_t), offsetof(entry_t, avl_link));
253 	mutex_exit(&cache->gidbysid.mutex);
254 
255 	mutex_enter(&cache->pidbysid.mutex);
256 	cookie = NULL;
257 	while ((entry = avl_destroy_nodes(&cache->pidbysid.tree, &cookie))
258 	    != NULL) {
259 		kmem_free(entry, sizeof (entry_t));
260 	}
261 	avl_destroy(&cache->pidbysid.tree);
262 	avl_create(&cache->pidbysid.tree, (avl_comp_fn)kidmap_compare_sid,
263 	    sizeof (entry_t), offsetof(entry_t, avl_link));
264 	mutex_exit(&cache->pidbysid.mutex);
265 
266 	mutex_enter(&cache->sidbyuid.mutex);
267 	cookie = NULL;
268 	while ((entry = avl_destroy_nodes(&cache->sidbyuid.tree, &cookie))
269 	    != NULL) {
270 		kmem_free(entry, sizeof (entry_t));
271 	}
272 	avl_destroy(&cache->sidbyuid.tree);
273 	avl_create(&cache->sidbyuid.tree, (avl_comp_fn)kidmap_compare_pid,
274 	    sizeof (entry_t), offsetof(entry_t, avl_link));
275 	mutex_exit(&cache->sidbyuid.mutex);
276 
277 	mutex_enter(&cache->sidbygid.mutex);
278 	cookie = NULL;
279 	while ((entry = avl_destroy_nodes(&cache->sidbygid.tree, &cookie))
280 	    != NULL) {
281 		kmem_free(entry, sizeof (entry_t));
282 	}
283 	avl_destroy(&cache->sidbygid.tree);
284 	avl_create(&cache->sidbygid.tree, (avl_comp_fn)kidmap_compare_pid,
285 	    sizeof (entry_t), offsetof(entry_t, avl_link));
286 	mutex_exit(&cache->sidbygid.mutex);
287 }
288 
289 
290 int
291 kidmap_cache_lookup_uidbysid(idmap_cache_t *cache, const char *sid_prefix,
292 			uint32_t rid, uid_t *uid)
293 {
294 	entry_t		entry;
295 	entry_t		*result;
296 	avl_index_t	where;
297 	int		status;
298 	time_t		now = gethrestime_sec();
299 
300 	entry.sid_prefix = sid_prefix;
301 	entry.rid = rid;
302 
303 	mutex_enter(&cache->uidbysid.mutex);
304 
305 	result = avl_find(&cache->uidbysid.tree, &entry, &where);
306 
307 	if (result && result->ttl > now) {
308 		*uid = result->pid;
309 		status = IDMAP_SUCCESS;
310 	} else
311 		status = IDMAP_ERR_NOMAPPING;
312 
313 	mutex_exit(&cache->uidbysid.mutex);
314 
315 	return (status);
316 }
317 
318 
319 
320 int
321 kidmap_cache_lookup_gidbysid(idmap_cache_t *cache, const char *sid_prefix,
322 			uint32_t rid, gid_t *gid)
323 {
324 	entry_t		entry;
325 	entry_t		*result;
326 	avl_index_t	where;
327 	int		status;
328 	time_t		now = gethrestime_sec();
329 
330 	entry.sid_prefix = sid_prefix;
331 	entry.rid = rid;
332 
333 	mutex_enter(&cache->gidbysid.mutex);
334 
335 	result = avl_find(&cache->gidbysid.tree, &entry, &where);
336 
337 	if (result && result->ttl > now) {
338 		*gid = result->pid;
339 		status = IDMAP_SUCCESS;
340 	} else
341 		status = IDMAP_ERR_NOMAPPING;
342 
343 	mutex_exit(&cache->gidbysid.mutex);
344 
345 	return (status);
346 }
347 
348 
349 
350 
351 int
352 kidmap_cache_lookup_pidbysid(idmap_cache_t *cache, const char *sid_prefix,
353 			uint32_t rid, uid_t *pid, int *is_user)
354 {
355 	entry_t		entry;
356 	entry_t		*result;
357 	avl_index_t	where;
358 	int		status;
359 	time_t		now = gethrestime_sec();
360 
361 	entry.sid_prefix = sid_prefix;
362 	entry.rid = rid;
363 
364 	mutex_enter(&cache->pidbysid.mutex);
365 
366 	result = avl_find(&cache->pidbysid.tree, &entry, &where);
367 
368 	if (result && result->ttl > now) {
369 		*pid = result->pid;
370 		*is_user = result->is_user;
371 		status = IDMAP_SUCCESS;
372 	} else
373 		status = IDMAP_ERR_NOMAPPING;
374 
375 	mutex_exit(&cache->pidbysid.mutex);
376 
377 	return (status);
378 }
379 
380 
381 
382 int
383 kidmap_cache_lookup_sidbyuid(idmap_cache_t *cache, const char **sid_prefix,
384 			uint32_t *rid, uid_t uid)
385 {
386 	entry_t		entry;
387 	entry_t		*result;
388 	avl_index_t	where;
389 	int		status;
390 	time_t		now = gethrestime_sec();
391 
392 	entry.pid = uid;
393 
394 	mutex_enter(&cache->sidbyuid.mutex);
395 
396 	result = avl_find(&cache->sidbyuid.tree, &entry, &where);
397 
398 	if (result && result->ttl > now) {
399 		*sid_prefix = result->sid_prefix;
400 		*rid = result->rid;
401 		status = IDMAP_SUCCESS;
402 	} else
403 		status = IDMAP_ERR_NOMAPPING;
404 
405 	mutex_exit(&cache->sidbyuid.mutex);
406 
407 	return (status);
408 }
409 
410 int
411 kidmap_cache_lookup_sidbygid(idmap_cache_t *cache, const char **sid_prefix,
412 			uint32_t *rid, gid_t gid)
413 {
414 	entry_t		entry;
415 	entry_t		*result;
416 	avl_index_t	where;
417 	int		status;
418 	time_t		now = gethrestime_sec();
419 
420 	entry.pid = gid;
421 
422 	mutex_enter(&cache->sidbygid.mutex);
423 
424 	result = avl_find(&cache->sidbygid.tree, &entry, &where);
425 
426 	if (result && result->ttl > now) {
427 		*sid_prefix = result->sid_prefix;
428 		*rid = result->rid;
429 		status = IDMAP_SUCCESS;
430 	} else
431 		status = IDMAP_ERR_NOMAPPING;
432 
433 	mutex_exit(&cache->sidbygid.mutex);
434 
435 	return (status);
436 }
437 
438 
439 
440 
441 void
442 kidmap_cache_add_uidbysid(idmap_cache_t *cache, const char *sid_prefix,
443 			uint32_t rid, uid_t uid)
444 
445 {
446 	entry_t		find;
447 	entry_t		*result;
448 	entry_t		*new;
449 	avl_index_t	where;
450 	int		purge_required = FALSE;
451 	time_t		ttl = CACHE_TTL + gethrestime_sec();
452 
453 	find.sid_prefix = sid_prefix;
454 	find.rid = rid;
455 
456 	mutex_enter(&cache->uidbysid.mutex);
457 	result = avl_find(&cache->uidbysid.tree, &find, &where);
458 
459 	if (result) {
460 		result->pid = uid;
461 		result->ttl = ttl;
462 	} else {
463 		new = kmem_alloc(sizeof (entry_t), KM_SLEEP);
464 		new->pid = uid;
465 		new->sid_prefix = sid_prefix;
466 		new->rid = rid;
467 		new->ttl = ttl;
468 
469 		avl_insert(&cache->uidbysid.tree, new, where);
470 
471 		if ((avl_numnodes(&cache->uidbysid.tree) >
472 		    CACHE_TRIGGER_SIZE) &&
473 		    (cache->uidbysid.purge_time + CACHE_PURGE_INTERVAL <
474 		    gethrestime_sec()))
475 			purge_required = TRUE;
476 	}
477 
478 	mutex_exit(&cache->uidbysid.mutex);
479 
480 	if (purge_required)
481 		kidmap_cache_purge_avl(&cache->uidbysid);
482 }
483 
484 
485 void
486 kidmap_cache_add_gidbysid(idmap_cache_t *cache, const char *sid_prefix,
487 			uint32_t rid, gid_t gid)
488 
489 {
490 	entry_t		find;
491 	entry_t		*result;
492 	entry_t		*new;
493 	avl_index_t	where;
494 	int		purge_required = FALSE;
495 	time_t		ttl = CACHE_TTL + gethrestime_sec();
496 
497 	find.sid_prefix = sid_prefix;
498 	find.rid = rid;
499 
500 	mutex_enter(&cache->gidbysid.mutex);
501 	result = avl_find(&cache->gidbysid.tree, &find, &where);
502 
503 	if (result) {
504 		result->pid = gid;
505 		result->ttl = ttl;
506 	} else {
507 		new = kmem_alloc(sizeof (entry_t), KM_SLEEP);
508 		new->pid = gid;
509 		new->sid_prefix = sid_prefix;
510 		new->rid = rid;
511 		new->ttl = ttl;
512 
513 		avl_insert(&cache->gidbysid.tree, new, where);
514 
515 		if ((avl_numnodes(&cache->gidbysid.tree) >
516 		    CACHE_TRIGGER_SIZE) &&
517 		    (cache->gidbysid.purge_time + CACHE_PURGE_INTERVAL <
518 		    gethrestime_sec()))
519 			purge_required = TRUE;
520 	}
521 
522 	mutex_exit(&cache->gidbysid.mutex);
523 
524 	if (purge_required)
525 		kidmap_cache_purge_avl(&cache->gidbysid);
526 }
527 
528 void
529 kidmap_cache_add_pidbysid(idmap_cache_t *cache, const char *sid_prefix,
530 			uint32_t rid, uid_t pid, int is_user)
531 
532 {
533 	entry_t		find;
534 	entry_t		*result;
535 	entry_t		*new;
536 	avl_index_t	where;
537 	int		purge_required = FALSE;
538 	time_t		ttl = CACHE_TTL + gethrestime_sec();
539 
540 	find.sid_prefix = sid_prefix;
541 	find.rid = rid;
542 
543 	mutex_enter(&cache->pidbysid.mutex);
544 	result = avl_find(&cache->pidbysid.tree, &find, &where);
545 
546 	if (result) {
547 		result->pid = pid;
548 		result->is_user = is_user;
549 		result->ttl = ttl;
550 	} else {
551 		new = kmem_alloc(sizeof (entry_t), KM_SLEEP);
552 		new->pid = pid;
553 		new->is_user = is_user;
554 		new->sid_prefix = sid_prefix;
555 		new->rid = rid;
556 		new->ttl = ttl;
557 
558 		avl_insert(&cache->pidbysid.tree, new, where);
559 
560 		if ((avl_numnodes(&cache->pidbysid.tree) >
561 		    CACHE_TRIGGER_SIZE) &&
562 		    (cache->pidbysid.purge_time + CACHE_PURGE_INTERVAL <
563 		    gethrestime_sec()))
564 			purge_required = TRUE;
565 	}
566 
567 	mutex_exit(&cache->pidbysid.mutex);
568 
569 	if (purge_required)
570 		kidmap_cache_purge_avl(&cache->pidbysid);
571 }
572 
573 
574 
575 void
576 kidmap_cache_add_sidbyuid(idmap_cache_t *cache, const char *sid_prefix,
577 			uint32_t rid, uid_t uid)
578 {
579 	entry_t		find;
580 	entry_t		*result;
581 	entry_t		*new;
582 	avl_index_t	where;
583 	int		purge_required = FALSE;
584 	time_t		ttl = CACHE_TTL + gethrestime_sec();
585 
586 	find.pid = uid;
587 
588 	mutex_enter(&cache->sidbyuid.mutex);
589 	result = avl_find(&cache->sidbyuid.tree, &find, &where);
590 
591 	if (result) {
592 		result->sid_prefix = sid_prefix;
593 		result->rid = rid;
594 		result->ttl = ttl;
595 	} else {
596 		new = kmem_alloc(sizeof (entry_t), KM_SLEEP);
597 		new->pid = uid;
598 		new->sid_prefix = sid_prefix;
599 		new->rid = rid;
600 		new->ttl = ttl;
601 
602 		avl_insert(&cache->sidbyuid.tree, new, where);
603 		if ((avl_numnodes(&cache->sidbyuid.tree) >
604 		    CACHE_TRIGGER_SIZE) &&
605 		    (cache->sidbyuid.purge_time + CACHE_PURGE_INTERVAL <
606 		    gethrestime_sec()))
607 			purge_required = TRUE;
608 	}
609 
610 	mutex_exit(&cache->sidbyuid.mutex);
611 
612 	if (purge_required)
613 		kidmap_cache_purge_avl(&cache->sidbyuid);
614 }
615 
616 
617 void
618 kidmap_cache_add_sidbygid(idmap_cache_t *cache, const char *sid_prefix,
619 			uint32_t rid, gid_t gid)
620 {
621 	entry_t		find;
622 	entry_t		*result;
623 	entry_t		*new;
624 	avl_index_t	where;
625 	int		purge_required = FALSE;
626 	time_t		ttl = CACHE_TTL + gethrestime_sec();
627 
628 	find.pid = gid;
629 
630 	mutex_enter(&cache->sidbygid.mutex);
631 	result = avl_find(&cache->sidbygid.tree, &find, &where);
632 
633 	if (result) {
634 		result->sid_prefix = sid_prefix;
635 		result->rid = rid;
636 		result->ttl = ttl;
637 	} else {
638 		new = kmem_alloc(sizeof (entry_t), KM_SLEEP);
639 		new->pid = gid;
640 		new->sid_prefix = sid_prefix;
641 		new->rid = rid;
642 		new->ttl = ttl;
643 
644 		avl_insert(&cache->sidbygid.tree, new, where);
645 		if ((avl_numnodes(&cache->sidbygid.tree) >
646 		    CACHE_TRIGGER_SIZE) &&
647 		    (cache->sidbygid.purge_time + CACHE_PURGE_INTERVAL <
648 		    gethrestime_sec()))
649 			purge_required = TRUE;
650 	}
651 
652 	mutex_exit(&cache->sidbygid.mutex);
653 
654 	if (purge_required)
655 		kidmap_cache_purge_avl(&cache->sidbygid);
656 }
657 
658 
659 static void
660 kidmap_cache_purge_avl(idmap_avl_cache_t *cache)
661 {
662 	time_t		now = gethrestime_sec();
663 	entry_t		*curr;
664 	entry_t		*prev = NULL;
665 
666 	mutex_enter(&cache->mutex);
667 
668 	curr = avl_first(&cache->tree);
669 	while (curr != NULL) {
670 		if (curr->ttl < now) {
671 			/* Old entry to remove */
672 			avl_remove(&cache->tree, curr);
673 			curr = prev;
674 			if (curr == NULL) {
675 				/* We removed the first entery */
676 				curr = avl_first(&cache->tree);
677 				continue;
678 			}
679 		}
680 		prev = curr;
681 		curr = AVL_NEXT(&cache->tree, curr);
682 	}
683 	cache->purge_time = now;
684 
685 	mutex_exit(&cache->mutex);
686 }
687 
688 
689 void
690 kidmap_sid_prefix_store_init(void)
691 {
692 	kidmap_sid_prefix_store = (struct sid_prefix_store *)
693 	    space_fetch("SUNW,idmap_sid_prefix");
694 	if (kidmap_sid_prefix_store == NULL) {
695 		kidmap_sid_prefix_store = kmem_alloc(
696 		    sizeof (struct sid_prefix_store), KM_SLEEP);
697 		rw_init(&kidmap_sid_prefix_store->lock, NULL, RW_DRIVER, NULL);
698 		avl_create(&kidmap_sid_prefix_store->tree,
699 		    (avl_comp_fn)kidmap_compare_sid_prefix,
700 		    sizeof (sid_prefix_node_t),
701 		    offsetof(sid_prefix_node_t, avl_link));
702 		(void) space_store("SUNW,idmap_sid_prefix",
703 		    (uintptr_t)kidmap_sid_prefix_store);
704 	} else {
705 		/*
706 		 * The AVL comparison function must be re-initialised on
707 		 * re-load because may not be loaded into the same
708 		 * address space.
709 		 */
710 		kidmap_sid_prefix_store->tree.avl_compar =
711 		    (avl_comp_fn)kidmap_compare_sid_prefix;
712 	}
713 }
714 
715 
716 const char *
717 kidmap_find_sid_prefix(const char *sid_prefix) {
718 	sid_prefix_node_t 	find;
719 	sid_prefix_node_t	*result;
720 	sid_prefix_node_t 	*new;
721 	avl_index_t		where;
722 
723 	if (sid_prefix == NULL || *sid_prefix == '\0')
724 		return (NULL);
725 
726 	find.sid_prefix = sid_prefix;
727 
728 
729 	rw_enter(&kidmap_sid_prefix_store->lock, RW_READER);
730 
731 	result = avl_find(&kidmap_sid_prefix_store->tree, &find, &where);
732 
733 	if (result) {
734 		rw_exit(&kidmap_sid_prefix_store->lock);
735 		return (result->sid_prefix);
736 	}
737 
738 	if (rw_tryupgrade(&kidmap_sid_prefix_store->lock) == 0) {
739 		/*
740 		 * Could not upgrade lock so release lock
741 		 * and acquire the write lock
742 		 */
743 		rw_exit(&kidmap_sid_prefix_store->lock);
744 		rw_enter(&kidmap_sid_prefix_store->lock, RW_WRITER);
745 
746 		result = avl_find(&kidmap_sid_prefix_store->tree,
747 			&find, &where);
748 		if (result) {
749 			rw_exit(&kidmap_sid_prefix_store->lock);
750 			return (result->sid_prefix);
751 		}
752 	}
753 
754 	new = kmem_alloc(sizeof (sid_prefix_node_t), KM_SLEEP);
755 	new->sid_prefix = kidmap_strdup(sid_prefix);
756 	avl_insert(&kidmap_sid_prefix_store->tree, new, where);
757 	rw_exit(&kidmap_sid_prefix_store->lock);
758 
759 	return (new->sid_prefix);
760 }
761