9075 Improve ZFS pool import/load process and corrupted pool recovery
[unleashed.git] / usr / src / uts / common / idmap / idmap_cache.c
blob184dd0ebe47b62b5f2b1a924889db33064a663bf
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * Windows to Solaris Identity Mapping kernel API
29 * This module provides the kernel cache.
33 #include <sys/types.h>
34 #include <sys/avl.h>
35 #include <sys/systm.h>
36 #include <sys/sysmacros.h>
37 #include <sys/ksynch.h>
38 #include <sys/kidmap.h>
39 #include <rpcsvc/idmap_prot.h>
40 #include "kidmap_priv.h"
44 * External functions
46 extern uintptr_t space_fetch(char *key);
47 extern int space_store(char *key, uintptr_t ptr);
51 * Internal definitions and functions
54 #define CACHE_UID_TRIGGER_SIZE 4096
55 #define CACHE_GID_TRIGGER_SIZE 2048
56 #define CACHE_PID_TRIGGER_SIZE \
57 (CACHE_UID_TRIGGER_SIZE + CACHE_GID_TRIGGER_SIZE)
60 #define UNDEF_UID ((uid_t)-1)
61 #define UNDEF_GID ((gid_t)-1)
62 #define UNDEF_ISUSER (-1)
64 #define CACHE_PURGE_INTERVAL (60 * 3)
65 #define CACHE_TTL (60 * 10)
69 #define list_insert(head, ele)\
70 do {\
71 (ele)->flink = (head)->flink;\
72 (head)->flink = (ele);\
73 (ele)->blink = (ele)->flink->blink;\
74 (ele)->flink->blink = (ele);\
75 } while (0)
79 #define list_remove(ele)\
80 do {\
81 (ele)->flink->blink = (ele)->blink;\
82 (ele)->blink->flink = (ele)->flink;\
83 } while (0)
86 #define list_move(head, ele) \
87 do {\
88 if ((head)->flink != (ele)) {\
89 list_remove(ele);\
90 list_insert(head, ele);\
92 } while (0)
95 typedef struct sid_prefix_node {
96 avl_node_t avl_link;
97 const char *sid_prefix;
98 } sid_prefix_node_t;
101 typedef int (*avl_comp_fn)(const void*, const void*);
104 struct sid_prefix_store {
105 struct avl_tree tree;
106 krwlock_t lock;
109 struct sid_prefix_store *kidmap_sid_prefix_store = NULL;
113 static void
114 kidmap_purge_sid2pid_cache(idmap_sid2pid_cache_t *cache, size_t limit);
116 static void
117 kidmap_purge_pid2sid_cache(idmap_pid2sid_cache_t *cache, size_t limit);
121 * kidmap_strdup() copied from uts/common/fs/sockfs/nl7c.c
123 static char *
124 kidmap_strdup(const char *s)
126 int len = strlen(s) + 1;
127 char *ret = kmem_alloc(len, KM_SLEEP);
129 bcopy(s, ret, len);
130 return (ret);
134 static int
135 kidmap_compare_sid(const sid2pid_t *entry1, const sid2pid_t *entry2)
137 int64_t comp = ((int64_t)entry2->rid) - ((int64_t)entry1->rid);
139 if (comp == 0)
140 comp = strcmp(entry2->sid_prefix, entry1->sid_prefix);
142 if (comp < 0)
143 comp = -1;
144 else if (comp > 0)
145 comp = 1;
147 return ((int)comp);
151 static int
152 kidmap_compare_pid(const pid2sid_t *entry1, const pid2sid_t *entry2)
154 if (entry2->pid > entry1->pid)
155 return (1);
156 if (entry2->pid < entry1->pid)
157 return (-1);
158 return (0);
162 static int
163 kidmap_compare_sid_prefix(const sid_prefix_node_t *entry1,
164 const sid_prefix_node_t *entry2)
166 int comp;
168 comp = strcmp(entry2->sid_prefix, entry1->sid_prefix);
170 if (comp < 0)
171 comp = -1;
172 else if (comp > 0)
173 comp = 1;
175 return (comp);
179 void
180 kidmap_cache_create(idmap_cache_t *cache)
182 avl_create(&cache->sid2pid.tree, (avl_comp_fn)kidmap_compare_sid,
183 sizeof (sid2pid_t), offsetof(sid2pid_t, avl_link));
184 mutex_init(&cache->sid2pid.mutex, NULL, MUTEX_DEFAULT, NULL);
185 cache->sid2pid.purge_time = 0;
186 cache->sid2pid.head.flink = &cache->sid2pid.head;
187 cache->sid2pid.head.blink = &cache->sid2pid.head;
188 cache->sid2pid.uid_num = 0;
189 cache->sid2pid.gid_num = 0;
190 cache->sid2pid.pid_num = 0;
192 avl_create(&cache->uid2sid.tree, (avl_comp_fn)kidmap_compare_pid,
193 sizeof (pid2sid_t), offsetof(pid2sid_t, avl_link));
194 mutex_init(&cache->uid2sid.mutex, NULL, MUTEX_DEFAULT, NULL);
195 cache->uid2sid.purge_time = 0;
196 cache->uid2sid.head.flink = &cache->uid2sid.head;
197 cache->uid2sid.head.blink = &cache->uid2sid.head;
199 avl_create(&cache->gid2sid.tree, (avl_comp_fn)kidmap_compare_pid,
200 sizeof (pid2sid_t), offsetof(pid2sid_t, avl_link));
201 mutex_init(&cache->gid2sid.mutex, NULL, MUTEX_DEFAULT, NULL);
202 cache->gid2sid.purge_time = 0;
203 cache->gid2sid.head.flink = &cache->gid2sid.head;
204 cache->gid2sid.head.blink = &cache->gid2sid.head;
208 void
209 kidmap_cache_delete(idmap_cache_t *cache)
211 sid2pid_t *sid2pid;
212 pid2sid_t *pid2sid;
213 void *cookie;
215 cookie = NULL;
216 while ((sid2pid = avl_destroy_nodes(&cache->sid2pid.tree, &cookie))
217 != NULL) {
218 kmem_free(sid2pid, sizeof (sid2pid_t));
220 avl_destroy(&cache->sid2pid.tree);
221 mutex_destroy(&cache->sid2pid.mutex);
224 cookie = NULL;
225 while ((pid2sid = avl_destroy_nodes(&cache->uid2sid.tree, &cookie))
226 != NULL) {
227 kmem_free(pid2sid, sizeof (pid2sid_t));
229 avl_destroy(&cache->uid2sid.tree);
230 mutex_destroy(&cache->uid2sid.mutex);
233 cookie = NULL;
234 while ((pid2sid = avl_destroy_nodes(&cache->gid2sid.tree, &cookie))
235 != NULL) {
236 kmem_free(pid2sid, sizeof (pid2sid_t));
238 avl_destroy(&cache->gid2sid.tree);
239 mutex_destroy(&cache->gid2sid.mutex);
243 void
244 kidmap_cache_get_data(idmap_cache_t *cache, size_t *uidbysid, size_t *gidbysid,
245 size_t *pidbysid, size_t *sidbyuid, size_t *sidbygid)
247 mutex_enter(&cache->sid2pid.mutex);
248 *uidbysid = cache->sid2pid.uid_num;
249 *gidbysid = cache->sid2pid.gid_num;
250 *pidbysid = cache->sid2pid.pid_num;
251 mutex_exit(&cache->sid2pid.mutex);
253 mutex_enter(&cache->uid2sid.mutex);
254 *sidbyuid = avl_numnodes(&cache->uid2sid.tree);
255 mutex_exit(&cache->uid2sid.mutex);
257 mutex_enter(&cache->gid2sid.mutex);
258 *sidbygid = avl_numnodes(&cache->gid2sid.tree);
259 mutex_exit(&cache->gid2sid.mutex);
263 void
264 kidmap_cache_purge(idmap_cache_t *cache)
266 sid2pid_t *sid2pid;
267 pid2sid_t *pid2sid;
268 void *cookie;
270 mutex_enter(&cache->sid2pid.mutex);
271 cookie = NULL;
272 while ((sid2pid = avl_destroy_nodes(&cache->sid2pid.tree, &cookie))
273 != NULL) {
274 kmem_free(sid2pid, sizeof (sid2pid_t));
276 avl_destroy(&cache->sid2pid.tree);
277 avl_create(&cache->sid2pid.tree, (avl_comp_fn)kidmap_compare_sid,
278 sizeof (sid2pid_t), offsetof(sid2pid_t, avl_link));
279 cache->sid2pid.purge_time = 0;
280 cache->sid2pid.head.flink = &cache->sid2pid.head;
281 cache->sid2pid.head.blink = &cache->sid2pid.head;
282 cache->sid2pid.uid_num = 0;
283 cache->sid2pid.gid_num = 0;
284 cache->sid2pid.pid_num = 0;
285 mutex_exit(&cache->sid2pid.mutex);
288 mutex_enter(&cache->uid2sid.mutex);
289 cookie = NULL;
290 while ((pid2sid = avl_destroy_nodes(&cache->uid2sid.tree, &cookie))
291 != NULL) {
292 kmem_free(pid2sid, sizeof (pid2sid_t));
294 avl_destroy(&cache->uid2sid.tree);
295 avl_create(&cache->uid2sid.tree, (avl_comp_fn)kidmap_compare_pid,
296 sizeof (pid2sid_t), offsetof(pid2sid_t, avl_link));
297 cache->uid2sid.purge_time = 0;
298 cache->uid2sid.head.flink = &cache->uid2sid.head;
299 cache->uid2sid.head.blink = &cache->uid2sid.head;
300 mutex_exit(&cache->uid2sid.mutex);
303 mutex_enter(&cache->gid2sid.mutex);
304 cookie = NULL;
305 while ((pid2sid = avl_destroy_nodes(&cache->gid2sid.tree, &cookie))
306 != NULL) {
307 kmem_free(pid2sid, sizeof (pid2sid_t));
309 avl_destroy(&cache->gid2sid.tree);
310 avl_create(&cache->gid2sid.tree, (avl_comp_fn)kidmap_compare_pid,
311 sizeof (pid2sid_t), offsetof(pid2sid_t, avl_link));
312 cache->gid2sid.purge_time = 0;
313 cache->gid2sid.head.flink = &cache->gid2sid.head;
314 cache->gid2sid.head.blink = &cache->gid2sid.head;
315 mutex_exit(&cache->gid2sid.mutex);
320 kidmap_cache_lookup_uidbysid(idmap_cache_t *cache, const char *sid_prefix,
321 uint32_t rid, uid_t *uid)
323 sid2pid_t entry;
324 sid2pid_t *result;
325 avl_index_t where;
326 int status = IDMAP_ERR_NOMAPPING;
327 time_t now = gethrestime_sec();
329 entry.sid_prefix = sid_prefix;
330 entry.rid = rid;
332 mutex_enter(&cache->sid2pid.mutex);
334 result = avl_find(&cache->sid2pid.tree, &entry, &where);
335 if (result != NULL) {
336 list_move(&cache->sid2pid.head, result);
337 if (result->uid != UNDEF_UID && result->uid_ttl > now) {
338 *uid = result->uid;
339 status = IDMAP_SUCCESS;
343 mutex_exit(&cache->sid2pid.mutex);
345 return (status);
350 kidmap_cache_lookup_gidbysid(idmap_cache_t *cache, const char *sid_prefix,
351 uint32_t rid, gid_t *gid)
353 sid2pid_t entry;
354 sid2pid_t *result;
355 avl_index_t where;
356 int status = IDMAP_ERR_NOMAPPING;
357 time_t now = gethrestime_sec();
359 entry.sid_prefix = sid_prefix;
360 entry.rid = rid;
362 mutex_enter(&cache->sid2pid.mutex);
364 result = avl_find(&cache->sid2pid.tree, &entry, &where);
365 if (result != NULL) {
366 list_move(&cache->sid2pid.head, result);
367 if (result->gid != UNDEF_GID && result->gid_ttl > now) {
368 *gid = result->gid;
369 status = IDMAP_SUCCESS;
373 mutex_exit(&cache->sid2pid.mutex);
375 return (status);
380 kidmap_cache_lookup_pidbysid(idmap_cache_t *cache, const char *sid_prefix,
381 uint32_t rid, uid_t *pid, int *is_user)
383 sid2pid_t entry;
384 sid2pid_t *result;
385 avl_index_t where;
386 int status = IDMAP_ERR_NOMAPPING;
387 time_t now = gethrestime_sec();
389 entry.sid_prefix = sid_prefix;
390 entry.rid = rid;
392 mutex_enter(&cache->sid2pid.mutex);
394 result = avl_find(&cache->sid2pid.tree, &entry, &where);
395 if (result != NULL) {
396 list_move(&cache->sid2pid.head, result);
397 if (result->is_user != UNDEF_ISUSER) {
398 if (result->is_user && result->uid_ttl > now) {
399 *pid = result->uid;
400 *is_user = result->is_user;
401 status = IDMAP_SUCCESS;
402 } else if (!result->is_user && result->gid_ttl > now) {
403 *pid = result->gid;
404 *is_user = result->is_user;
405 status = IDMAP_SUCCESS;
410 mutex_exit(&cache->sid2pid.mutex);
412 return (status);
418 kidmap_cache_lookup_sidbyuid(idmap_cache_t *cache, const char **sid_prefix,
419 uint32_t *rid, uid_t uid)
421 pid2sid_t entry;
422 pid2sid_t *result;
423 avl_index_t where;
424 int status = IDMAP_ERR_NOMAPPING;
425 time_t now = gethrestime_sec();
427 entry.pid = uid;
429 mutex_enter(&cache->uid2sid.mutex);
431 result = avl_find(&cache->uid2sid.tree, &entry, &where);
432 if (result != NULL) {
433 list_move(&cache->uid2sid.head, result);
434 if (result->ttl > now) {
435 *sid_prefix = result->sid_prefix;
436 *rid = result->rid;
437 status = IDMAP_SUCCESS;
441 mutex_exit(&cache->uid2sid.mutex);
443 return (status);
448 kidmap_cache_lookup_sidbygid(idmap_cache_t *cache, const char **sid_prefix,
449 uint32_t *rid, gid_t gid)
451 pid2sid_t entry;
452 pid2sid_t *result;
453 avl_index_t where;
454 int status = IDMAP_ERR_NOMAPPING;
455 time_t now = gethrestime_sec();
457 entry.pid = gid;
459 mutex_enter(&cache->gid2sid.mutex);
461 result = avl_find(&cache->gid2sid.tree, &entry, &where);
462 if (result != NULL) {
463 list_move(&cache->gid2sid.head, result);
464 if (result->ttl > now) {
465 *sid_prefix = result->sid_prefix;
466 *rid = result->rid;
467 status = IDMAP_SUCCESS;
471 mutex_exit(&cache->gid2sid.mutex);
473 return (status);
477 void
478 kidmap_cache_add_sid2uid(idmap_cache_t *cache, const char *sid_prefix,
479 uint32_t rid, uid_t uid, int direction)
482 avl_index_t where;
483 time_t ttl = CACHE_TTL + gethrestime_sec();
486 if (direction == IDMAP_DIRECTION_BI ||
487 direction == IDMAP_DIRECTION_W2U) {
488 sid2pid_t find;
489 sid2pid_t *result;
490 sid2pid_t *new;
492 find.sid_prefix = sid_prefix;
493 find.rid = rid;
495 mutex_enter(&cache->sid2pid.mutex);
497 result = avl_find(&cache->sid2pid.tree, &find, &where);
498 if (result) {
499 if (result->uid == UNDEF_UID)
500 cache->sid2pid.uid_num++;
501 result->uid = uid;
502 result->uid_ttl = ttl;
503 } else {
504 new = kmem_alloc(sizeof (sid2pid_t), KM_SLEEP);
505 new->sid_prefix = sid_prefix;
506 new->rid = rid;
507 new->uid = uid;
508 new->uid_ttl = ttl;
509 new->gid = UNDEF_GID;
510 new->gid_ttl = 0;
511 new->is_user = UNDEF_ISUSER; /* Unknown */
512 cache->sid2pid.uid_num++;
514 list_insert(&cache->sid2pid.head, new);
515 avl_insert(&cache->sid2pid.tree, new, where);
518 if ((avl_numnodes(&cache->sid2pid.tree) >
519 CACHE_PID_TRIGGER_SIZE) &&
520 (cache->sid2pid.purge_time + CACHE_PURGE_INTERVAL <
521 gethrestime_sec()))
522 kidmap_purge_sid2pid_cache(&cache->sid2pid,
523 CACHE_PID_TRIGGER_SIZE);
525 mutex_exit(&cache->sid2pid.mutex);
528 if (direction == IDMAP_DIRECTION_BI ||
529 direction == IDMAP_DIRECTION_U2W) {
530 pid2sid_t find;
531 pid2sid_t *result;
532 pid2sid_t *new;
534 find.pid = uid;
536 mutex_enter(&cache->uid2sid.mutex);
538 result = avl_find(&cache->uid2sid.tree, &find, &where);
539 if (result) {
540 result->sid_prefix = sid_prefix;
541 result->rid = rid;
542 result->ttl = ttl;
543 } else {
544 new = kmem_alloc(sizeof (pid2sid_t), KM_SLEEP);
545 new->sid_prefix = sid_prefix;
546 new->rid = rid;
547 new->pid = uid;
548 new->ttl = ttl;
550 list_insert(&cache->uid2sid.head, new);
551 avl_insert(&cache->uid2sid.tree, new, where);
554 if ((avl_numnodes(&cache->uid2sid.tree) >
555 CACHE_UID_TRIGGER_SIZE) &&
556 (cache->uid2sid.purge_time + CACHE_PURGE_INTERVAL <
557 gethrestime_sec()))
558 kidmap_purge_pid2sid_cache(&cache->uid2sid,
559 CACHE_UID_TRIGGER_SIZE);
561 mutex_exit(&cache->uid2sid.mutex);
567 void
568 kidmap_cache_add_sid2gid(idmap_cache_t *cache, const char *sid_prefix,
569 uint32_t rid, gid_t gid, int direction)
571 avl_index_t where;
572 time_t ttl = CACHE_TTL + gethrestime_sec();
575 if (direction == IDMAP_DIRECTION_BI ||
576 direction == IDMAP_DIRECTION_W2U) {
577 sid2pid_t find;
578 sid2pid_t *result;
579 sid2pid_t *new;
581 find.sid_prefix = sid_prefix;
582 find.rid = rid;
584 mutex_enter(&cache->sid2pid.mutex);
586 result = avl_find(&cache->sid2pid.tree, &find, &where);
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++;
603 list_insert(&cache->sid2pid.head, new);
604 avl_insert(&cache->sid2pid.tree, new, where);
607 if ((avl_numnodes(&cache->sid2pid.tree) >
608 CACHE_PID_TRIGGER_SIZE) &&
609 (cache->sid2pid.purge_time + CACHE_PURGE_INTERVAL <
610 gethrestime_sec()))
611 kidmap_purge_sid2pid_cache(&cache->sid2pid,
612 CACHE_PID_TRIGGER_SIZE);
614 mutex_exit(&cache->sid2pid.mutex);
617 if (direction == IDMAP_DIRECTION_BI ||
618 direction == IDMAP_DIRECTION_U2W) {
619 pid2sid_t find;
620 pid2sid_t *result;
621 pid2sid_t *new;
623 find.pid = gid;
625 mutex_enter(&cache->gid2sid.mutex);
627 result = avl_find(&cache->gid2sid.tree, &find, &where);
628 if (result) {
629 result->sid_prefix = sid_prefix;
630 result->rid = rid;
631 result->ttl = ttl;
632 } else {
633 new = kmem_alloc(sizeof (pid2sid_t), KM_SLEEP);
634 new->sid_prefix = sid_prefix;
635 new->rid = rid;
636 new->pid = gid;
637 new->ttl = ttl;
639 list_insert(&cache->gid2sid.head, new);
640 avl_insert(&cache->gid2sid.tree, new, where);
643 if ((avl_numnodes(&cache->gid2sid.tree) >
644 CACHE_GID_TRIGGER_SIZE) &&
645 (cache->gid2sid.purge_time + CACHE_PURGE_INTERVAL <
646 gethrestime_sec()))
647 kidmap_purge_pid2sid_cache(&cache->gid2sid,
648 CACHE_GID_TRIGGER_SIZE);
650 mutex_exit(&cache->gid2sid.mutex);
655 void
656 kidmap_cache_add_sid2pid(idmap_cache_t *cache, const char *sid_prefix,
657 uint32_t rid, uid_t pid, int is_user, int direction)
659 avl_index_t where;
660 time_t ttl = CACHE_TTL + gethrestime_sec();
663 if (direction == IDMAP_DIRECTION_BI ||
664 direction == IDMAP_DIRECTION_W2U) {
665 sid2pid_t find;
666 sid2pid_t *result;
667 sid2pid_t *new;
669 find.sid_prefix = sid_prefix;
670 find.rid = rid;
672 mutex_enter(&cache->sid2pid.mutex);
674 result = avl_find(&cache->sid2pid.tree, &find, &where);
675 if (result) {
676 if (result->is_user == UNDEF_ISUSER)
677 cache->sid2pid.pid_num++;
678 result->is_user = is_user;
679 if (is_user) {
680 if (result->uid == UNDEF_UID)
681 cache->sid2pid.uid_num++;
682 result->uid = pid;
683 result->uid_ttl = ttl;
684 } else {
685 if (result->gid == UNDEF_GID)
686 cache->sid2pid.gid_num++;
687 result->gid = pid;
688 result->gid_ttl = ttl;
690 } else {
691 new = kmem_alloc(sizeof (sid2pid_t), KM_SLEEP);
692 new->sid_prefix = sid_prefix;
693 new->rid = rid;
694 new->is_user = is_user;
695 if (is_user) {
696 new->uid = pid;
697 new->uid_ttl = ttl;
698 new->gid = UNDEF_GID;
699 new->gid_ttl = 0;
700 cache->sid2pid.uid_num++;
701 } else {
702 new->uid = UNDEF_UID;
703 new->uid_ttl = 0;
704 new->gid = pid;
705 new->gid_ttl = ttl;
706 cache->sid2pid.gid_num++;
708 cache->sid2pid.pid_num++;
710 list_insert(&cache->sid2pid.head, new);
711 avl_insert(&cache->sid2pid.tree, new, where);
714 if ((avl_numnodes(&cache->sid2pid.tree) >
715 CACHE_PID_TRIGGER_SIZE) &&
716 (cache->sid2pid.purge_time + CACHE_PURGE_INTERVAL <
717 gethrestime_sec()))
718 kidmap_purge_sid2pid_cache(&cache->sid2pid,
719 CACHE_PID_TRIGGER_SIZE);
721 mutex_exit(&cache->sid2pid.mutex);
724 if (direction == IDMAP_DIRECTION_BI ||
725 direction == IDMAP_DIRECTION_U2W) {
726 pid2sid_t find;
727 pid2sid_t *result;
728 pid2sid_t *new;
730 find.pid = pid;
731 if (is_user) {
732 mutex_enter(&cache->uid2sid.mutex);
734 result = avl_find(&cache->uid2sid.tree, &find, &where);
735 if (result) {
736 result->sid_prefix = sid_prefix;
737 result->rid = rid;
738 result->ttl = ttl;
739 } else {
740 new = kmem_alloc(sizeof (pid2sid_t), KM_SLEEP);
741 new->sid_prefix = sid_prefix;
742 new->rid = rid;
743 new->pid = pid;
744 new->ttl = ttl;
746 list_insert(&cache->uid2sid.head, new);
747 avl_insert(&cache->uid2sid.tree, new, where);
750 if ((avl_numnodes(&cache->uid2sid.tree) >
751 CACHE_UID_TRIGGER_SIZE) &&
752 (cache->uid2sid.purge_time +
753 CACHE_PURGE_INTERVAL <
754 gethrestime_sec()))
755 kidmap_purge_pid2sid_cache(&cache->uid2sid,
756 CACHE_UID_TRIGGER_SIZE);
758 mutex_exit(&cache->uid2sid.mutex);
759 } else {
760 mutex_enter(&cache->gid2sid.mutex);
762 result = avl_find(&cache->gid2sid.tree, &find, &where);
763 if (result) {
764 result->sid_prefix = sid_prefix;
765 result->rid = rid;
766 result->ttl = ttl;
767 } else {
768 new = kmem_alloc(sizeof (pid2sid_t), KM_SLEEP);
769 new->sid_prefix = sid_prefix;
770 new->rid = rid;
771 new->pid = pid;
772 new->ttl = ttl;
774 list_insert(&cache->gid2sid.head, new);
775 avl_insert(&cache->gid2sid.tree, new, where);
778 if ((avl_numnodes(&cache->gid2sid.tree) >
779 CACHE_GID_TRIGGER_SIZE) &&
780 (cache->gid2sid.purge_time +
781 CACHE_PURGE_INTERVAL < gethrestime_sec()))
782 kidmap_purge_pid2sid_cache(&cache->gid2sid,
783 CACHE_GID_TRIGGER_SIZE);
785 mutex_exit(&cache->gid2sid.mutex);
794 static void
795 kidmap_purge_sid2pid_cache(idmap_sid2pid_cache_t *cache, size_t limit)
797 time_t now = gethrestime_sec();
798 sid2pid_t *item;
800 while (avl_numnodes(&cache->tree) > limit) {
801 /* Remove least recently used */
802 item = cache->head.blink;
803 list_remove(item);
804 avl_remove(&cache->tree, item);
805 if (item->uid != UNDEF_UID)
806 cache->uid_num--;
807 if (item->gid != UNDEF_GID)
808 cache->gid_num--;
809 if (item->is_user != UNDEF_ISUSER)
810 cache->pid_num--;
811 kmem_free(item, sizeof (sid2pid_t));
813 cache->purge_time = now;
817 static void
818 kidmap_purge_pid2sid_cache(idmap_pid2sid_cache_t *cache, size_t limit)
820 time_t now = gethrestime_sec();
821 pid2sid_t *item;
823 while (avl_numnodes(&cache->tree) > limit) {
824 /* Remove least recently used */
825 item = cache->head.blink;
826 list_remove(item);
827 avl_remove(&cache->tree, item);
828 kmem_free(item, sizeof (pid2sid_t));
830 cache->purge_time = now;
834 void
835 kidmap_sid_prefix_store_init(void)
837 kidmap_sid_prefix_store = (struct sid_prefix_store *)
838 space_fetch("SUNW,idmap_sid_prefix");
839 if (kidmap_sid_prefix_store == NULL) {
840 kidmap_sid_prefix_store = kmem_alloc(
841 sizeof (struct sid_prefix_store), KM_SLEEP);
842 rw_init(&kidmap_sid_prefix_store->lock, NULL, RW_DRIVER, NULL);
843 avl_create(&kidmap_sid_prefix_store->tree,
844 (avl_comp_fn)kidmap_compare_sid_prefix,
845 sizeof (sid_prefix_node_t),
846 offsetof(sid_prefix_node_t, avl_link));
847 (void) space_store("SUNW,idmap_sid_prefix",
848 (uintptr_t)kidmap_sid_prefix_store);
849 } else {
851 * The AVL comparison function must be re-initialised on
852 * re-load because may not be loaded into the same
853 * address space.
855 kidmap_sid_prefix_store->tree.avl_compar =
856 (avl_comp_fn)kidmap_compare_sid_prefix;
861 const char *
862 kidmap_find_sid_prefix(const char *sid_prefix) {
863 sid_prefix_node_t find;
864 sid_prefix_node_t *result;
865 sid_prefix_node_t *new;
866 avl_index_t where;
868 if (sid_prefix == NULL || *sid_prefix == '\0')
869 return (NULL);
871 find.sid_prefix = sid_prefix;
873 rw_enter(&kidmap_sid_prefix_store->lock, RW_READER);
875 result = avl_find(&kidmap_sid_prefix_store->tree, &find, &where);
877 if (result) {
878 rw_exit(&kidmap_sid_prefix_store->lock);
879 return (result->sid_prefix);
882 if (rw_tryupgrade(&kidmap_sid_prefix_store->lock) == 0) {
884 * Could not upgrade lock so release lock
885 * and acquire the write lock
887 rw_exit(&kidmap_sid_prefix_store->lock);
888 rw_enter(&kidmap_sid_prefix_store->lock, RW_WRITER);
890 result = avl_find(&kidmap_sid_prefix_store->tree,
891 &find, &where);
892 if (result) {
893 rw_exit(&kidmap_sid_prefix_store->lock);
894 return (result->sid_prefix);
898 new = kmem_alloc(sizeof (sid_prefix_node_t), KM_SLEEP);
899 new->sid_prefix = kidmap_strdup(sid_prefix);
900 avl_insert(&kidmap_sid_prefix_store->tree, new, where);
901 rw_exit(&kidmap_sid_prefix_store->lock);
903 return (new->sid_prefix);