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 (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
25 */
26
27 #include <sys/param.h>
28 #include <sys/types.h>
29 #include <sys/tzfile.h>
30 #include <sys/atomic.h>
31 #include <sys/time.h>
32 #include <sys/spl.h>
33 #include <sys/random.h>
34 #include <smbsrv/smb_kproto.h>
35 #include <smbsrv/smb_fsops.h>
36 #include <smbsrv/smbinfo.h>
37 #include <smbsrv/smb_xdr.h>
38 #include <smbsrv/smb_vops.h>
39 #include <smbsrv/smb_idmap.h>
40
41 #include <sys/sid.h>
42 #include <sys/priv_names.h>
43
44 static kmem_cache_t *smb_dtor_cache = NULL;
45
46 static boolean_t smb_avl_hold(smb_avl_t *);
47 static void smb_avl_rele(smb_avl_t *);
48
49 time_t tzh_leapcnt = 0;
50
51 struct tm
52 *smb_gmtime_r(time_t *clock, struct tm *result);
53
54 time_t
55 smb_timegm(struct tm *tm);
56
57 struct tm {
58 int tm_sec;
59 int tm_min;
60 int tm_hour;
61 int tm_mday;
62 int tm_mon;
63 int tm_year;
64 int tm_wday;
65 int tm_yday;
66 int tm_isdst;
67 };
68
69 static const int days_in_month[] = {
70 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
71 };
72
73 int
74 smb_ascii_or_unicode_strlen(struct smb_request *sr, char *str)
75 {
76 if (sr->session->dialect >= SMB_VERS_2_BASE ||
77 (sr->smb_flg2 & SMB_FLAGS2_UNICODE) != 0)
78 return (smb_wcequiv_strlen(str));
79 return (strlen(str));
80 }
81
82 int
83 smb_ascii_or_unicode_strlen_null(struct smb_request *sr, char *str)
84 {
85 if (sr->session->dialect >= SMB_VERS_2_BASE ||
86 (sr->smb_flg2 & SMB_FLAGS2_UNICODE) != 0)
87 return (smb_wcequiv_strlen(str) + 2);
88 return (strlen(str) + 1);
89 }
90
91 int
92 smb_ascii_or_unicode_null_len(struct smb_request *sr)
93 {
94 if (sr->session->dialect >= SMB_VERS_2_BASE ||
95 (sr->smb_flg2 & SMB_FLAGS2_UNICODE) != 0)
96 return (2);
97 return (1);
98 }
99
100 /*
101 *
102 * Convert old-style (DOS, LanMan) wildcard strings to NT style.
103 * This should ONLY happen to patterns that come from old clients,
104 * meaning dialect LANMAN2_1 etc. (dialect < NT_LM_0_12).
105 *
106 * ? is converted to >
107 * * is converted to < if it is followed by .
108 * . is converted to " if it is followed by ? or * or end of pattern
301 mutex_enter(&pool->id_mutex);
302 if ((pool->id_free_counter == 0) && smb_idpool_increment(pool)) {
303 mutex_exit(&pool->id_mutex);
304 return (-1);
305 }
306
307 i = pool->id_size;
308 while (i) {
309 bit = pool->id_bit;
310 bit_idx = pool->id_bit_idx;
311 byte = pool->id_pool[pool->id_idx];
312 while (bit) {
313 if (byte & bit) {
314 bit = bit << 1;
315 bit_idx++;
316 continue;
317 }
318 pool->id_pool[pool->id_idx] |= bit;
319 *id = (uint16_t)(pool->id_idx * 8 + (uint32_t)bit_idx);
320 pool->id_free_counter--;
321 pool->id_bit = bit;
322 pool->id_bit_idx = bit_idx;
323 mutex_exit(&pool->id_mutex);
324 return (0);
325 }
326 pool->id_bit = 1;
327 pool->id_bit_idx = 0;
328 pool->id_idx++;
329 pool->id_idx &= pool->id_idx_msk;
330 --i;
331 }
332 /*
333 * This section of code shouldn't be reached. If there are IDs
334 * available and none could be found there's a problem.
335 */
336 ASSERT(0);
337 mutex_exit(&pool->id_mutex);
338 return (-1);
339 }
340
341 /*
342 * smb_idpool_free
438 */
439 void
440 smb_llist_post(smb_llist_t *ll, void *object, smb_dtorproc_t dtorproc)
441 {
442 smb_dtor_t *dtor;
443
444 ASSERT((object != NULL) && (dtorproc != NULL));
445
446 dtor = kmem_cache_alloc(smb_dtor_cache, KM_SLEEP);
447 bzero(dtor, sizeof (smb_dtor_t));
448 dtor->dt_magic = SMB_DTOR_MAGIC;
449 dtor->dt_object = object;
450 dtor->dt_proc = dtorproc;
451
452 mutex_enter(&ll->ll_mutex);
453 list_insert_tail(&ll->ll_deleteq, dtor);
454 ++ll->ll_deleteq_count;
455 mutex_exit(&ll->ll_mutex);
456 }
457
458 /*
459 * Exit the list lock and process the delete queue.
460 */
461 void
462 smb_llist_exit(smb_llist_t *ll)
463 {
464 rw_exit(&ll->ll_lock);
465 smb_llist_flush(ll);
466 }
467
468 /*
469 * Flush the list delete queue. The mutex is dropped across the destructor
470 * call in case this leads to additional objects being posted to the delete
471 * queue.
472 */
473 void
474 smb_llist_flush(smb_llist_t *ll)
475 {
476 smb_dtor_t *dtor;
477
771 mutex_init(&rwx->rwx_mutex, NULL, MUTEX_DEFAULT, NULL);
772 rw_init(&rwx->rwx_lock, NULL, RW_DEFAULT, NULL);
773 }
774
775 /*
776 * smb_rwx_destroy
777 */
778 void
779 smb_rwx_destroy(
780 smb_rwx_t *rwx)
781 {
782 mutex_destroy(&rwx->rwx_mutex);
783 cv_destroy(&rwx->rwx_cv);
784 rw_destroy(&rwx->rwx_lock);
785 }
786
787 /*
788 * smb_rwx_rwexit
789 */
790 void
791 smb_rwx_rwexit(
792 smb_rwx_t *rwx)
793 {
794 if (rw_write_held(&rwx->rwx_lock)) {
795 ASSERT(rw_owner(&rwx->rwx_lock) == curthread);
796 mutex_enter(&rwx->rwx_mutex);
797 if (rwx->rwx_waiting) {
798 rwx->rwx_waiting = B_FALSE;
799 cv_broadcast(&rwx->rwx_cv);
800 }
801 mutex_exit(&rwx->rwx_mutex);
802 }
803 rw_exit(&rwx->rwx_lock);
804 }
805
806 /*
807 * smb_rwx_rwupgrade
808 */
809 krw_t
810 smb_rwx_rwupgrade(
811 smb_rwx_t *rwx)
812 {
813 if (rw_write_held(&rwx->rwx_lock)) {
814 ASSERT(rw_owner(&rwx->rwx_lock) == curthread);
815 return (RW_WRITER);
816 }
817 if (!rw_tryupgrade(&rwx->rwx_lock)) {
818 rw_exit(&rwx->rwx_lock);
819 rw_enter(&rwx->rwx_lock, RW_WRITER);
820 }
821 return (RW_READER);
822 }
823
824 /*
825 * smb_rwx_rwrestore
826 */
827 void
828 smb_rwx_rwdowngrade(
829 smb_rwx_t *rwx,
830 krw_t mode)
831 {
832 ASSERT(rw_write_held(&rwx->rwx_lock));
833 ASSERT(rw_owner(&rwx->rwx_lock) == curthread);
834
835 if (mode == RW_WRITER) {
836 return;
837 }
838 ASSERT(mode == RW_READER);
839 mutex_enter(&rwx->rwx_mutex);
840 if (rwx->rwx_waiting) {
841 rwx->rwx_waiting = B_FALSE;
842 cv_broadcast(&rwx->rwx_cv);
843 }
844 mutex_exit(&rwx->rwx_mutex);
845 rw_downgrade(&rwx->rwx_lock);
846 }
847
848 /*
849 * smb_rwx_wait
850 *
851 * This function assumes the smb_rwx lock was enter in RW_READER or RW_WRITER
852 * mode. It will:
853 *
854 * 1) release the lock and save its current mode.
855 * 2) wait until the condition variable is signaled. This can happen for
856 * 2 reasons: When a writer releases the lock or when the time out (if
857 * provided) expires.
858 * 3) re-acquire the lock in the mode saved in (1).
859 */
860 int
861 smb_rwx_rwwait(
862 smb_rwx_t *rwx,
863 clock_t timeout)
864 {
865 krw_t mode;
866 int rc = 1;
867
868 mutex_enter(&rwx->rwx_mutex);
869 rwx->rwx_waiting = B_TRUE;
870 mutex_exit(&rwx->rwx_mutex);
871
872 if (rw_write_held(&rwx->rwx_lock)) {
873 ASSERT(rw_owner(&rwx->rwx_lock) == curthread);
874 mode = RW_WRITER;
875 } else {
876 ASSERT(rw_read_held(&rwx->rwx_lock));
877 mode = RW_READER;
878 }
879 rw_exit(&rwx->rwx_lock);
880
881 mutex_enter(&rwx->rwx_mutex);
882 if (rwx->rwx_waiting) {
883 if (timeout == -1) {
884 cv_wait(&rwx->rwx_cv, &rwx->rwx_mutex);
885 } else {
886 rc = cv_reltimedwait(&rwx->rwx_cv, &rwx->rwx_mutex,
887 timeout, TR_CLOCK_TICK);
888 }
889 }
890 mutex_exit(&rwx->rwx_mutex);
891
892 rw_enter(&rwx->rwx_lock, mode);
893 return (rc);
894 }
895
896 /* smb_idmap_... moved to smb_idmap.c */
897
898 uint64_t
899 smb_time_unix_to_nt(timestruc_t *unix_time)
900 {
901 uint64_t nt_time;
902
903 if ((unix_time->tv_sec == 0) && (unix_time->tv_nsec == 0))
904 return (0);
905
906 nt_time = unix_time->tv_sec;
907 nt_time *= 10000000; /* seconds to 100ns */
908 nt_time += unix_time->tv_nsec / 100;
909 return (nt_time + NT_TIME_BIAS);
910 }
911
912 void
913 smb_time_nt_to_unix(uint64_t nt_time, timestruc_t *unix_time)
914 {
915 uint32_t seconds;
1705 }
1706
1707 void
1708 smb_threshold_exit(smb_cmd_threshold_t *ct)
1709 {
1710 mutex_enter(&ct->ct_mutex);
1711 ASSERT3U(ct->ct_active_cnt, >, 0);
1712 ct->ct_active_cnt--;
1713 if (ct->ct_blocked_cnt)
1714 cv_signal(&ct->ct_cond);
1715 mutex_exit(&ct->ct_mutex);
1716 }
1717
1718 void
1719 smb_threshold_wake_all(smb_cmd_threshold_t *ct)
1720 {
1721 mutex_enter(&ct->ct_mutex);
1722 ct->ct_threshold = 0;
1723 cv_broadcast(&ct->ct_cond);
1724 mutex_exit(&ct->ct_mutex);
1725 }
|
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 (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
25 */
26
27 #include <sys/param.h>
28 #include <sys/types.h>
29 #include <sys/tzfile.h>
30 #include <sys/atomic.h>
31 #include <sys/time.h>
32 #include <sys/spl.h>
33 #include <sys/random.h>
34 #include <smbsrv/smb_kproto.h>
35 #include <smbsrv/smb_fsops.h>
36 #include <smbsrv/smbinfo.h>
37 #include <smbsrv/smb_xdr.h>
38 #include <smbsrv/smb_vops.h>
39 #include <smbsrv/smb_idmap.h>
40
41 #include <sys/sid.h>
42 #include <sys/priv_names.h>
43 #include <sys/bitmap.h>
44
45 static kmem_cache_t *smb_dtor_cache = NULL;
46
47 static boolean_t smb_avl_hold(smb_avl_t *);
48 static void smb_avl_rele(smb_avl_t *);
49
50 time_t tzh_leapcnt = 0;
51
52 struct tm
53 *smb_gmtime_r(time_t *clock, struct tm *result);
54
55 time_t
56 smb_timegm(struct tm *tm);
57
58 struct tm {
59 int tm_sec;
60 int tm_min;
61 int tm_hour;
62 int tm_mday;
63 int tm_mon;
64 int tm_year;
65 int tm_wday;
66 int tm_yday;
67 int tm_isdst;
68 };
69
70 static const int days_in_month[] = {
71 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
72 };
73
74 /*
75 * Given a UTF-8 string (our internal form everywhere)
76 * return either the Unicode (UTF-16) length in bytes,
77 * or the OEM length in bytes. Which we return is
78 * determined by whether the client supports Unicode.
79 * This length does NOT include the null.
80 */
81 int
82 smb_ascii_or_unicode_strlen(struct smb_request *sr, char *str)
83 {
84 if (sr->session->dialect >= SMB_VERS_2_BASE ||
85 (sr->smb_flg2 & SMB_FLAGS2_UNICODE) != 0)
86 return (smb_wcequiv_strlen(str));
87 return (smb_sbequiv_strlen(str));
88 }
89
90 /*
91 * Given a UTF-8 string (our internal form everywhere)
92 * return either the Unicode (UTF-16) length in bytes,
93 * or the OEM length in bytes. Which we return is
94 * determined by whether the client supports Unicode.
95 * This length DOES include the null.
96 */
97 int
98 smb_ascii_or_unicode_strlen_null(struct smb_request *sr, char *str)
99 {
100 if (sr->session->dialect >= SMB_VERS_2_BASE ||
101 (sr->smb_flg2 & SMB_FLAGS2_UNICODE) != 0)
102 return (smb_wcequiv_strlen(str) + 2);
103 return (smb_sbequiv_strlen(str) + 1);
104 }
105
106 int
107 smb_ascii_or_unicode_null_len(struct smb_request *sr)
108 {
109 if (sr->session->dialect >= SMB_VERS_2_BASE ||
110 (sr->smb_flg2 & SMB_FLAGS2_UNICODE) != 0)
111 return (2);
112 return (1);
113 }
114
115 /*
116 *
117 * Convert old-style (DOS, LanMan) wildcard strings to NT style.
118 * This should ONLY happen to patterns that come from old clients,
119 * meaning dialect LANMAN2_1 etc. (dialect < NT_LM_0_12).
120 *
121 * ? is converted to >
122 * * is converted to < if it is followed by .
123 * . is converted to " if it is followed by ? or * or end of pattern
316 mutex_enter(&pool->id_mutex);
317 if ((pool->id_free_counter == 0) && smb_idpool_increment(pool)) {
318 mutex_exit(&pool->id_mutex);
319 return (-1);
320 }
321
322 i = pool->id_size;
323 while (i) {
324 bit = pool->id_bit;
325 bit_idx = pool->id_bit_idx;
326 byte = pool->id_pool[pool->id_idx];
327 while (bit) {
328 if (byte & bit) {
329 bit = bit << 1;
330 bit_idx++;
331 continue;
332 }
333 pool->id_pool[pool->id_idx] |= bit;
334 *id = (uint16_t)(pool->id_idx * 8 + (uint32_t)bit_idx);
335 pool->id_free_counter--;
336 /*
337 * Leave position at next bit to allocate,
338 * so we don't keep re-using the last in an
339 * alloc/free/alloc/free sequence. Doing
340 * that can confuse some SMB clients.
341 */
342 if (bit & 0x80) {
343 pool->id_bit = 1;
344 pool->id_bit_idx = 0;
345 pool->id_idx++;
346 pool->id_idx &= pool->id_idx_msk;
347 } else {
348 pool->id_bit = (bit << 1);
349 pool->id_bit_idx = bit_idx + 1;
350 /* keep id_idx */
351 }
352 mutex_exit(&pool->id_mutex);
353 return (0);
354 }
355 pool->id_bit = 1;
356 pool->id_bit_idx = 0;
357 pool->id_idx++;
358 pool->id_idx &= pool->id_idx_msk;
359 --i;
360 }
361 /*
362 * This section of code shouldn't be reached. If there are IDs
363 * available and none could be found there's a problem.
364 */
365 ASSERT(0);
366 mutex_exit(&pool->id_mutex);
367 return (-1);
368 }
369
370 /*
371 * smb_idpool_free
467 */
468 void
469 smb_llist_post(smb_llist_t *ll, void *object, smb_dtorproc_t dtorproc)
470 {
471 smb_dtor_t *dtor;
472
473 ASSERT((object != NULL) && (dtorproc != NULL));
474
475 dtor = kmem_cache_alloc(smb_dtor_cache, KM_SLEEP);
476 bzero(dtor, sizeof (smb_dtor_t));
477 dtor->dt_magic = SMB_DTOR_MAGIC;
478 dtor->dt_object = object;
479 dtor->dt_proc = dtorproc;
480
481 mutex_enter(&ll->ll_mutex);
482 list_insert_tail(&ll->ll_deleteq, dtor);
483 ++ll->ll_deleteq_count;
484 mutex_exit(&ll->ll_mutex);
485 }
486
487 void
488 smb_llist_enter(smb_llist_t *ll, krw_t mode)
489 {
490 rw_enter(&ll->ll_lock, mode);
491 }
492
493 /*
494 * Exit the list lock and process the delete queue.
495 */
496 void
497 smb_llist_exit(smb_llist_t *ll)
498 {
499 rw_exit(&ll->ll_lock);
500 smb_llist_flush(ll);
501 }
502
503 /*
504 * Flush the list delete queue. The mutex is dropped across the destructor
505 * call in case this leads to additional objects being posted to the delete
506 * queue.
507 */
508 void
509 smb_llist_flush(smb_llist_t *ll)
510 {
511 smb_dtor_t *dtor;
512
806 mutex_init(&rwx->rwx_mutex, NULL, MUTEX_DEFAULT, NULL);
807 rw_init(&rwx->rwx_lock, NULL, RW_DEFAULT, NULL);
808 }
809
810 /*
811 * smb_rwx_destroy
812 */
813 void
814 smb_rwx_destroy(
815 smb_rwx_t *rwx)
816 {
817 mutex_destroy(&rwx->rwx_mutex);
818 cv_destroy(&rwx->rwx_cv);
819 rw_destroy(&rwx->rwx_lock);
820 }
821
822 /*
823 * smb_rwx_rwexit
824 */
825 void
826 smb_rwx_rwenter(smb_rwx_t *rwx, krw_t mode)
827 {
828 rw_enter(&rwx->rwx_lock, mode);
829 }
830
831 /*
832 * smb_rwx_rwexit
833 */
834 void
835 smb_rwx_rwexit(
836 smb_rwx_t *rwx)
837 {
838 rw_exit(&rwx->rwx_lock);
839 }
840
841
842 /*
843 * smb_rwx_cvwait
844 *
845 * Wait on rwx->rw_cv, dropping the rw lock and retake after wakeup.
846 * Assumes the smb_rwx lock was entered in RW_READER or RW_WRITER
847 * mode. It will:
848 *
849 * 1) release the lock and save its current mode.
850 * 2) wait until the condition variable is signaled.
851 * 3) re-acquire the lock in the mode saved in (1).
852 *
853 * Lock order: rwlock, mutex
854 */
855 int
856 smb_rwx_cvwait(
857 smb_rwx_t *rwx,
858 clock_t timeout)
859 {
860 krw_t mode;
861 int rc = 1;
862
863 if (rw_write_held(&rwx->rwx_lock)) {
864 ASSERT(rw_owner(&rwx->rwx_lock) == curthread);
865 mode = RW_WRITER;
866 } else {
867 ASSERT(rw_read_held(&rwx->rwx_lock));
868 mode = RW_READER;
869 }
870
871 mutex_enter(&rwx->rwx_mutex);
872 rw_exit(&rwx->rwx_lock);
873
874 rwx->rwx_waiting = B_TRUE;
875 if (timeout == -1) {
876 cv_wait(&rwx->rwx_cv, &rwx->rwx_mutex);
877 } else {
878 rc = cv_reltimedwait(&rwx->rwx_cv, &rwx->rwx_mutex,
879 timeout, TR_CLOCK_TICK);
880 }
881 mutex_exit(&rwx->rwx_mutex);
882
883 rw_enter(&rwx->rwx_lock, mode);
884 return (rc);
885 }
886
887 /*
888 * smb_rwx_cvbcast
889 *
890 * Wake up threads waiting on rx_cv
891 * The rw lock may or may not be held.
892 * The mutex MUST NOT be held.
893 */
894 void
895 smb_rwx_cvbcast(smb_rwx_t *rwx)
896 {
897 mutex_enter(&rwx->rwx_mutex);
898 if (rwx->rwx_waiting) {
899 rwx->rwx_waiting = B_FALSE;
900 cv_broadcast(&rwx->rwx_cv);
901 }
902 mutex_exit(&rwx->rwx_mutex);
903 }
904
905 /* smb_idmap_... moved to smb_idmap.c */
906
907 uint64_t
908 smb_time_unix_to_nt(timestruc_t *unix_time)
909 {
910 uint64_t nt_time;
911
912 if ((unix_time->tv_sec == 0) && (unix_time->tv_nsec == 0))
913 return (0);
914
915 nt_time = unix_time->tv_sec;
916 nt_time *= 10000000; /* seconds to 100ns */
917 nt_time += unix_time->tv_nsec / 100;
918 return (nt_time + NT_TIME_BIAS);
919 }
920
921 void
922 smb_time_nt_to_unix(uint64_t nt_time, timestruc_t *unix_time)
923 {
924 uint32_t seconds;
1714 }
1715
1716 void
1717 smb_threshold_exit(smb_cmd_threshold_t *ct)
1718 {
1719 mutex_enter(&ct->ct_mutex);
1720 ASSERT3U(ct->ct_active_cnt, >, 0);
1721 ct->ct_active_cnt--;
1722 if (ct->ct_blocked_cnt)
1723 cv_signal(&ct->ct_cond);
1724 mutex_exit(&ct->ct_mutex);
1725 }
1726
1727 void
1728 smb_threshold_wake_all(smb_cmd_threshold_t *ct)
1729 {
1730 mutex_enter(&ct->ct_mutex);
1731 ct->ct_threshold = 0;
1732 cv_broadcast(&ct->ct_cond);
1733 mutex_exit(&ct->ct_mutex);
1734 }
1735
1736 /* taken from mod_hash_byptr */
1737 uint_t
1738 smb_hash_uint64(smb_hash_t *hash, uint64_t val)
1739 {
1740 uint64_t k = val >> hash->rshift;
1741 uint_t idx = ((uint_t)k) & (hash->num_buckets - 1);
1742
1743 return (idx);
1744 }
1745
1746 boolean_t
1747 smb_is_pow2(size_t n)
1748 {
1749 return ((n & (n - 1)) == 0);
1750 }
1751
1752 smb_hash_t *
1753 smb_hash_create(size_t elemsz, size_t link_offset,
1754 uint32_t num_buckets)
1755 {
1756 smb_hash_t *hash = kmem_alloc(sizeof (*hash), KM_SLEEP);
1757 int i;
1758
1759 if (!smb_is_pow2(num_buckets))
1760 num_buckets = 1 << highbit(num_buckets);
1761
1762 hash->rshift = highbit(elemsz);
1763 hash->num_buckets = num_buckets;
1764 hash->buckets = kmem_zalloc(num_buckets * sizeof (smb_bucket_t),
1765 KM_SLEEP);
1766 for (i = 0; i < num_buckets; i++)
1767 smb_llist_constructor(&hash->buckets[i].b_list, elemsz,
1768 link_offset);
1769 return (hash);
1770 }
1771
1772 void
1773 smb_hash_destroy(smb_hash_t *hash)
1774 {
1775 int i;
1776
1777 for (i = 0; i < hash->num_buckets; i++)
1778 smb_llist_destructor(&hash->buckets[i].b_list);
1779
1780 kmem_free(hash->buckets, hash->num_buckets * sizeof (smb_bucket_t));
1781 kmem_free(hash, sizeof (*hash));
1782 }
|