1eda14cbcSMatt Macy /* 2eda14cbcSMatt Macy * CDDL HEADER START 3eda14cbcSMatt Macy * 4eda14cbcSMatt Macy * This file and its contents are supplied under the terms of the 5eda14cbcSMatt Macy * Common Development and Distribution License ("CDDL"), version 1.0. 6eda14cbcSMatt Macy * You may only use this file in accordance with the terms of version 7eda14cbcSMatt Macy * 1.0 of the CDDL. 8eda14cbcSMatt Macy * 9eda14cbcSMatt Macy * A full copy of the text of the CDDL should have accompanied this 10eda14cbcSMatt Macy * source. A copy of the CDDL is also available via the Internet at 11eda14cbcSMatt Macy * http://www.illumos.org/license/CDDL. 12eda14cbcSMatt Macy * 13eda14cbcSMatt Macy * CDDL HEADER END 14eda14cbcSMatt Macy */ 15eda14cbcSMatt Macy /* 16eda14cbcSMatt Macy * Copyright (c) 2013, 2017 by Delphix. All rights reserved. 17eda14cbcSMatt Macy */ 18eda14cbcSMatt Macy 19eda14cbcSMatt Macy #include <sys/zfs_context.h> 20eda14cbcSMatt Macy #include <sys/multilist.h> 21eda14cbcSMatt Macy #include <sys/trace_zfs.h> 22eda14cbcSMatt Macy 23eda14cbcSMatt Macy /* needed for spa_get_random() */ 24eda14cbcSMatt Macy #include <sys/spa.h> 25eda14cbcSMatt Macy 26eda14cbcSMatt Macy /* 27eda14cbcSMatt Macy * This overrides the number of sublists in each multilist_t, which defaults 28eda14cbcSMatt Macy * to the number of CPUs in the system (see multilist_create()). 29eda14cbcSMatt Macy */ 30eda14cbcSMatt Macy int zfs_multilist_num_sublists = 0; 31eda14cbcSMatt Macy 32eda14cbcSMatt Macy /* 33eda14cbcSMatt Macy * Given the object contained on the list, return a pointer to the 34eda14cbcSMatt Macy * object's multilist_node_t structure it contains. 35eda14cbcSMatt Macy */ 36eda14cbcSMatt Macy #ifdef ZFS_DEBUG 37eda14cbcSMatt Macy static multilist_node_t * 38eda14cbcSMatt Macy multilist_d2l(multilist_t *ml, void *obj) 39eda14cbcSMatt Macy { 40eda14cbcSMatt Macy return ((multilist_node_t *)((char *)obj + ml->ml_offset)); 41eda14cbcSMatt Macy } 42eda14cbcSMatt Macy #endif 43eda14cbcSMatt Macy 44eda14cbcSMatt Macy /* 45eda14cbcSMatt Macy * Initialize a new mutlilist using the parameters specified. 46eda14cbcSMatt Macy * 47eda14cbcSMatt Macy * - 'size' denotes the size of the structure containing the 48eda14cbcSMatt Macy * multilist_node_t. 49eda14cbcSMatt Macy * - 'offset' denotes the byte offset of the mutlilist_node_t within 50eda14cbcSMatt Macy * the structure that contains it. 51eda14cbcSMatt Macy * - 'num' specifies the number of internal sublists to create. 52eda14cbcSMatt Macy * - 'index_func' is used to determine which sublist to insert into 53eda14cbcSMatt Macy * when the multilist_insert() function is called; as well as which 54eda14cbcSMatt Macy * sublist to remove from when multilist_remove() is called. The 55eda14cbcSMatt Macy * requirements this function must meet, are the following: 56eda14cbcSMatt Macy * 57eda14cbcSMatt Macy * - It must always return the same value when called on the same 58eda14cbcSMatt Macy * object (to ensure the object is removed from the list it was 59eda14cbcSMatt Macy * inserted into). 60eda14cbcSMatt Macy * 61eda14cbcSMatt Macy * - It must return a value in the range [0, number of sublists). 62eda14cbcSMatt Macy * The multilist_get_num_sublists() function may be used to 63eda14cbcSMatt Macy * determine the number of sublists in the multilist. 64eda14cbcSMatt Macy * 65eda14cbcSMatt Macy * Also, in order to reduce internal contention between the sublists 66eda14cbcSMatt Macy * during insertion and removal, this function should choose evenly 67eda14cbcSMatt Macy * between all available sublists when inserting. This isn't a hard 68eda14cbcSMatt Macy * requirement, but a general rule of thumb in order to garner the 69eda14cbcSMatt Macy * best multi-threaded performance out of the data structure. 70eda14cbcSMatt Macy */ 71*3ff01b23SMartin Matuska static void 72*3ff01b23SMartin Matuska multilist_create_impl(multilist_t *ml, size_t size, size_t offset, 73eda14cbcSMatt Macy unsigned int num, multilist_sublist_index_func_t *index_func) 74eda14cbcSMatt Macy { 75eda14cbcSMatt Macy ASSERT3U(size, >, 0); 76eda14cbcSMatt Macy ASSERT3U(size, >=, offset + sizeof (multilist_node_t)); 77eda14cbcSMatt Macy ASSERT3U(num, >, 0); 78eda14cbcSMatt Macy ASSERT3P(index_func, !=, NULL); 79eda14cbcSMatt Macy 80eda14cbcSMatt Macy ml->ml_offset = offset; 81eda14cbcSMatt Macy ml->ml_num_sublists = num; 82eda14cbcSMatt Macy ml->ml_index_func = index_func; 83eda14cbcSMatt Macy 84eda14cbcSMatt Macy ml->ml_sublists = kmem_zalloc(sizeof (multilist_sublist_t) * 85eda14cbcSMatt Macy ml->ml_num_sublists, KM_SLEEP); 86eda14cbcSMatt Macy 87eda14cbcSMatt Macy ASSERT3P(ml->ml_sublists, !=, NULL); 88eda14cbcSMatt Macy 89eda14cbcSMatt Macy for (int i = 0; i < ml->ml_num_sublists; i++) { 90eda14cbcSMatt Macy multilist_sublist_t *mls = &ml->ml_sublists[i]; 91eda14cbcSMatt Macy mutex_init(&mls->mls_lock, NULL, MUTEX_NOLOCKDEP, NULL); 92eda14cbcSMatt Macy list_create(&mls->mls_list, size, offset); 93eda14cbcSMatt Macy } 94eda14cbcSMatt Macy } 95eda14cbcSMatt Macy 96eda14cbcSMatt Macy /* 977877fdebSMatt Macy * Allocate a new multilist, using the default number of sublists (the number 987877fdebSMatt Macy * of CPUs, or at least 4, or the tunable zfs_multilist_num_sublists). Note 997877fdebSMatt Macy * that the multilists do not expand if more CPUs are hot-added. In that case, 1007877fdebSMatt Macy * we will have less fanout than boot_ncpus, but we don't want to always 1017877fdebSMatt Macy * reserve the RAM necessary to create the extra slots for additional CPUs up 1027877fdebSMatt Macy * front, and dynamically adding them is a complex task. 103eda14cbcSMatt Macy */ 104*3ff01b23SMartin Matuska void 105*3ff01b23SMartin Matuska multilist_create(multilist_t *ml, size_t size, size_t offset, 106eda14cbcSMatt Macy multilist_sublist_index_func_t *index_func) 107eda14cbcSMatt Macy { 108eda14cbcSMatt Macy int num_sublists; 109eda14cbcSMatt Macy 110eda14cbcSMatt Macy if (zfs_multilist_num_sublists > 0) { 111eda14cbcSMatt Macy num_sublists = zfs_multilist_num_sublists; 112eda14cbcSMatt Macy } else { 113eda14cbcSMatt Macy num_sublists = MAX(boot_ncpus, 4); 114eda14cbcSMatt Macy } 115eda14cbcSMatt Macy 116*3ff01b23SMartin Matuska multilist_create_impl(ml, size, offset, num_sublists, index_func); 117eda14cbcSMatt Macy } 118eda14cbcSMatt Macy 119eda14cbcSMatt Macy /* 120eda14cbcSMatt Macy * Destroy the given multilist object, and free up any memory it holds. 121eda14cbcSMatt Macy */ 122eda14cbcSMatt Macy void 123eda14cbcSMatt Macy multilist_destroy(multilist_t *ml) 124eda14cbcSMatt Macy { 125eda14cbcSMatt Macy ASSERT(multilist_is_empty(ml)); 126eda14cbcSMatt Macy 127eda14cbcSMatt Macy for (int i = 0; i < ml->ml_num_sublists; i++) { 128eda14cbcSMatt Macy multilist_sublist_t *mls = &ml->ml_sublists[i]; 129eda14cbcSMatt Macy 130eda14cbcSMatt Macy ASSERT(list_is_empty(&mls->mls_list)); 131eda14cbcSMatt Macy 132eda14cbcSMatt Macy list_destroy(&mls->mls_list); 133eda14cbcSMatt Macy mutex_destroy(&mls->mls_lock); 134eda14cbcSMatt Macy } 135eda14cbcSMatt Macy 136eda14cbcSMatt Macy ASSERT3P(ml->ml_sublists, !=, NULL); 137eda14cbcSMatt Macy kmem_free(ml->ml_sublists, 138eda14cbcSMatt Macy sizeof (multilist_sublist_t) * ml->ml_num_sublists); 139eda14cbcSMatt Macy 140eda14cbcSMatt Macy ml->ml_num_sublists = 0; 141eda14cbcSMatt Macy ml->ml_offset = 0; 142*3ff01b23SMartin Matuska ml->ml_sublists = NULL; 143eda14cbcSMatt Macy } 144eda14cbcSMatt Macy 145eda14cbcSMatt Macy /* 146eda14cbcSMatt Macy * Insert the given object into the multilist. 147eda14cbcSMatt Macy * 148eda14cbcSMatt Macy * This function will insert the object specified into the sublist 149eda14cbcSMatt Macy * determined using the function given at multilist creation time. 150eda14cbcSMatt Macy * 151eda14cbcSMatt Macy * The sublist locks are automatically acquired if not already held, to 152eda14cbcSMatt Macy * ensure consistency when inserting and removing from multiple threads. 153eda14cbcSMatt Macy */ 154eda14cbcSMatt Macy void 155eda14cbcSMatt Macy multilist_insert(multilist_t *ml, void *obj) 156eda14cbcSMatt Macy { 157eda14cbcSMatt Macy unsigned int sublist_idx = ml->ml_index_func(ml, obj); 158eda14cbcSMatt Macy multilist_sublist_t *mls; 159eda14cbcSMatt Macy boolean_t need_lock; 160eda14cbcSMatt Macy 161eda14cbcSMatt Macy DTRACE_PROBE3(multilist__insert, multilist_t *, ml, 162eda14cbcSMatt Macy unsigned int, sublist_idx, void *, obj); 163eda14cbcSMatt Macy 164eda14cbcSMatt Macy ASSERT3U(sublist_idx, <, ml->ml_num_sublists); 165eda14cbcSMatt Macy 166eda14cbcSMatt Macy mls = &ml->ml_sublists[sublist_idx]; 167eda14cbcSMatt Macy 168eda14cbcSMatt Macy /* 169eda14cbcSMatt Macy * Note: Callers may already hold the sublist lock by calling 170eda14cbcSMatt Macy * multilist_sublist_lock(). Here we rely on MUTEX_HELD() 171eda14cbcSMatt Macy * returning TRUE if and only if the current thread holds the 172eda14cbcSMatt Macy * lock. While it's a little ugly to make the lock recursive in 173eda14cbcSMatt Macy * this way, it works and allows the calling code to be much 174eda14cbcSMatt Macy * simpler -- otherwise it would have to pass around a flag 175eda14cbcSMatt Macy * indicating that it already has the lock. 176eda14cbcSMatt Macy */ 177eda14cbcSMatt Macy need_lock = !MUTEX_HELD(&mls->mls_lock); 178eda14cbcSMatt Macy 179eda14cbcSMatt Macy if (need_lock) 180eda14cbcSMatt Macy mutex_enter(&mls->mls_lock); 181eda14cbcSMatt Macy 182eda14cbcSMatt Macy ASSERT(!multilist_link_active(multilist_d2l(ml, obj))); 183eda14cbcSMatt Macy 184eda14cbcSMatt Macy multilist_sublist_insert_head(mls, obj); 185eda14cbcSMatt Macy 186eda14cbcSMatt Macy if (need_lock) 187eda14cbcSMatt Macy mutex_exit(&mls->mls_lock); 188eda14cbcSMatt Macy } 189eda14cbcSMatt Macy 190eda14cbcSMatt Macy /* 191eda14cbcSMatt Macy * Remove the given object from the multilist. 192eda14cbcSMatt Macy * 193eda14cbcSMatt Macy * This function will remove the object specified from the sublist 194eda14cbcSMatt Macy * determined using the function given at multilist creation time. 195eda14cbcSMatt Macy * 196eda14cbcSMatt Macy * The necessary sublist locks are automatically acquired, to ensure 197eda14cbcSMatt Macy * consistency when inserting and removing from multiple threads. 198eda14cbcSMatt Macy */ 199eda14cbcSMatt Macy void 200eda14cbcSMatt Macy multilist_remove(multilist_t *ml, void *obj) 201eda14cbcSMatt Macy { 202eda14cbcSMatt Macy unsigned int sublist_idx = ml->ml_index_func(ml, obj); 203eda14cbcSMatt Macy multilist_sublist_t *mls; 204eda14cbcSMatt Macy boolean_t need_lock; 205eda14cbcSMatt Macy 206eda14cbcSMatt Macy DTRACE_PROBE3(multilist__remove, multilist_t *, ml, 207eda14cbcSMatt Macy unsigned int, sublist_idx, void *, obj); 208eda14cbcSMatt Macy 209eda14cbcSMatt Macy ASSERT3U(sublist_idx, <, ml->ml_num_sublists); 210eda14cbcSMatt Macy 211eda14cbcSMatt Macy mls = &ml->ml_sublists[sublist_idx]; 212eda14cbcSMatt Macy /* See comment in multilist_insert(). */ 213eda14cbcSMatt Macy need_lock = !MUTEX_HELD(&mls->mls_lock); 214eda14cbcSMatt Macy 215eda14cbcSMatt Macy if (need_lock) 216eda14cbcSMatt Macy mutex_enter(&mls->mls_lock); 217eda14cbcSMatt Macy 218eda14cbcSMatt Macy ASSERT(multilist_link_active(multilist_d2l(ml, obj))); 219eda14cbcSMatt Macy 220eda14cbcSMatt Macy multilist_sublist_remove(mls, obj); 221eda14cbcSMatt Macy 222eda14cbcSMatt Macy if (need_lock) 223eda14cbcSMatt Macy mutex_exit(&mls->mls_lock); 224eda14cbcSMatt Macy } 225eda14cbcSMatt Macy 226eda14cbcSMatt Macy /* 227eda14cbcSMatt Macy * Check to see if this multilist object is empty. 228eda14cbcSMatt Macy * 229eda14cbcSMatt Macy * This will return TRUE if it finds all of the sublists of this 230eda14cbcSMatt Macy * multilist to be empty, and FALSE otherwise. Each sublist lock will be 231eda14cbcSMatt Macy * automatically acquired as necessary. 232eda14cbcSMatt Macy * 233eda14cbcSMatt Macy * If concurrent insertions and removals are occurring, the semantics 234eda14cbcSMatt Macy * of this function become a little fuzzy. Instead of locking all 235eda14cbcSMatt Macy * sublists for the entire call time of the function, each sublist is 236eda14cbcSMatt Macy * only locked as it is individually checked for emptiness. Thus, it's 237eda14cbcSMatt Macy * possible for this function to return TRUE with non-empty sublists at 238eda14cbcSMatt Macy * the time the function returns. This would be due to another thread 239eda14cbcSMatt Macy * inserting into a given sublist, after that specific sublist was check 240eda14cbcSMatt Macy * and deemed empty, but before all sublists have been checked. 241eda14cbcSMatt Macy */ 242eda14cbcSMatt Macy int 243eda14cbcSMatt Macy multilist_is_empty(multilist_t *ml) 244eda14cbcSMatt Macy { 245eda14cbcSMatt Macy for (int i = 0; i < ml->ml_num_sublists; i++) { 246eda14cbcSMatt Macy multilist_sublist_t *mls = &ml->ml_sublists[i]; 247eda14cbcSMatt Macy /* See comment in multilist_insert(). */ 248eda14cbcSMatt Macy boolean_t need_lock = !MUTEX_HELD(&mls->mls_lock); 249eda14cbcSMatt Macy 250eda14cbcSMatt Macy if (need_lock) 251eda14cbcSMatt Macy mutex_enter(&mls->mls_lock); 252eda14cbcSMatt Macy 253eda14cbcSMatt Macy if (!list_is_empty(&mls->mls_list)) { 254eda14cbcSMatt Macy if (need_lock) 255eda14cbcSMatt Macy mutex_exit(&mls->mls_lock); 256eda14cbcSMatt Macy 257eda14cbcSMatt Macy return (FALSE); 258eda14cbcSMatt Macy } 259eda14cbcSMatt Macy 260eda14cbcSMatt Macy if (need_lock) 261eda14cbcSMatt Macy mutex_exit(&mls->mls_lock); 262eda14cbcSMatt Macy } 263eda14cbcSMatt Macy 264eda14cbcSMatt Macy return (TRUE); 265eda14cbcSMatt Macy } 266eda14cbcSMatt Macy 267eda14cbcSMatt Macy /* Return the number of sublists composing this multilist */ 268eda14cbcSMatt Macy unsigned int 269eda14cbcSMatt Macy multilist_get_num_sublists(multilist_t *ml) 270eda14cbcSMatt Macy { 271eda14cbcSMatt Macy return (ml->ml_num_sublists); 272eda14cbcSMatt Macy } 273eda14cbcSMatt Macy 274eda14cbcSMatt Macy /* Return a randomly selected, valid sublist index for this multilist */ 275eda14cbcSMatt Macy unsigned int 276eda14cbcSMatt Macy multilist_get_random_index(multilist_t *ml) 277eda14cbcSMatt Macy { 278eda14cbcSMatt Macy return (spa_get_random(ml->ml_num_sublists)); 279eda14cbcSMatt Macy } 280eda14cbcSMatt Macy 281eda14cbcSMatt Macy /* Lock and return the sublist specified at the given index */ 282eda14cbcSMatt Macy multilist_sublist_t * 283eda14cbcSMatt Macy multilist_sublist_lock(multilist_t *ml, unsigned int sublist_idx) 284eda14cbcSMatt Macy { 285eda14cbcSMatt Macy multilist_sublist_t *mls; 286eda14cbcSMatt Macy 287eda14cbcSMatt Macy ASSERT3U(sublist_idx, <, ml->ml_num_sublists); 288eda14cbcSMatt Macy mls = &ml->ml_sublists[sublist_idx]; 289eda14cbcSMatt Macy mutex_enter(&mls->mls_lock); 290eda14cbcSMatt Macy 291eda14cbcSMatt Macy return (mls); 292eda14cbcSMatt Macy } 293eda14cbcSMatt Macy 294eda14cbcSMatt Macy /* Lock and return the sublist that would be used to store the specified obj */ 295eda14cbcSMatt Macy multilist_sublist_t * 296eda14cbcSMatt Macy multilist_sublist_lock_obj(multilist_t *ml, void *obj) 297eda14cbcSMatt Macy { 298eda14cbcSMatt Macy return (multilist_sublist_lock(ml, ml->ml_index_func(ml, obj))); 299eda14cbcSMatt Macy } 300eda14cbcSMatt Macy 301eda14cbcSMatt Macy void 302eda14cbcSMatt Macy multilist_sublist_unlock(multilist_sublist_t *mls) 303eda14cbcSMatt Macy { 304eda14cbcSMatt Macy mutex_exit(&mls->mls_lock); 305eda14cbcSMatt Macy } 306eda14cbcSMatt Macy 307eda14cbcSMatt Macy /* 308eda14cbcSMatt Macy * We're allowing any object to be inserted into this specific sublist, 309eda14cbcSMatt Macy * but this can lead to trouble if multilist_remove() is called to 310eda14cbcSMatt Macy * remove this object. Specifically, if calling ml_index_func on this 311eda14cbcSMatt Macy * object returns an index for sublist different than what is passed as 312eda14cbcSMatt Macy * a parameter here, any call to multilist_remove() with this newly 313eda14cbcSMatt Macy * inserted object is undefined! (the call to multilist_remove() will 314eda14cbcSMatt Macy * remove the object from a list that it isn't contained in) 315eda14cbcSMatt Macy */ 316eda14cbcSMatt Macy void 317eda14cbcSMatt Macy multilist_sublist_insert_head(multilist_sublist_t *mls, void *obj) 318eda14cbcSMatt Macy { 319eda14cbcSMatt Macy ASSERT(MUTEX_HELD(&mls->mls_lock)); 320eda14cbcSMatt Macy list_insert_head(&mls->mls_list, obj); 321eda14cbcSMatt Macy } 322eda14cbcSMatt Macy 323eda14cbcSMatt Macy /* please see comment above multilist_sublist_insert_head */ 324eda14cbcSMatt Macy void 325eda14cbcSMatt Macy multilist_sublist_insert_tail(multilist_sublist_t *mls, void *obj) 326eda14cbcSMatt Macy { 327eda14cbcSMatt Macy ASSERT(MUTEX_HELD(&mls->mls_lock)); 328eda14cbcSMatt Macy list_insert_tail(&mls->mls_list, obj); 329eda14cbcSMatt Macy } 330eda14cbcSMatt Macy 331eda14cbcSMatt Macy /* 332eda14cbcSMatt Macy * Move the object one element forward in the list. 333eda14cbcSMatt Macy * 334eda14cbcSMatt Macy * This function will move the given object forward in the list (towards 335eda14cbcSMatt Macy * the head) by one object. So, in essence, it will swap its position in 336eda14cbcSMatt Macy * the list with its "prev" pointer. If the given object is already at the 337eda14cbcSMatt Macy * head of the list, it cannot be moved forward any more than it already 338eda14cbcSMatt Macy * is, so no action is taken. 339eda14cbcSMatt Macy * 340eda14cbcSMatt Macy * NOTE: This function **must not** remove any object from the list other 341eda14cbcSMatt Macy * than the object given as the parameter. This is relied upon in 342eda14cbcSMatt Macy * arc_evict_state_impl(). 343eda14cbcSMatt Macy */ 344eda14cbcSMatt Macy void 345eda14cbcSMatt Macy multilist_sublist_move_forward(multilist_sublist_t *mls, void *obj) 346eda14cbcSMatt Macy { 347eda14cbcSMatt Macy void *prev = list_prev(&mls->mls_list, obj); 348eda14cbcSMatt Macy 349eda14cbcSMatt Macy ASSERT(MUTEX_HELD(&mls->mls_lock)); 350eda14cbcSMatt Macy ASSERT(!list_is_empty(&mls->mls_list)); 351eda14cbcSMatt Macy 352eda14cbcSMatt Macy /* 'obj' must be at the head of the list, nothing to do */ 353eda14cbcSMatt Macy if (prev == NULL) 354eda14cbcSMatt Macy return; 355eda14cbcSMatt Macy 356eda14cbcSMatt Macy list_remove(&mls->mls_list, obj); 357eda14cbcSMatt Macy list_insert_before(&mls->mls_list, prev, obj); 358eda14cbcSMatt Macy } 359eda14cbcSMatt Macy 360eda14cbcSMatt Macy void 361eda14cbcSMatt Macy multilist_sublist_remove(multilist_sublist_t *mls, void *obj) 362eda14cbcSMatt Macy { 363eda14cbcSMatt Macy ASSERT(MUTEX_HELD(&mls->mls_lock)); 364eda14cbcSMatt Macy list_remove(&mls->mls_list, obj); 365eda14cbcSMatt Macy } 366eda14cbcSMatt Macy 367eda14cbcSMatt Macy int 368eda14cbcSMatt Macy multilist_sublist_is_empty(multilist_sublist_t *mls) 369eda14cbcSMatt Macy { 370eda14cbcSMatt Macy ASSERT(MUTEX_HELD(&mls->mls_lock)); 371eda14cbcSMatt Macy return (list_is_empty(&mls->mls_list)); 372eda14cbcSMatt Macy } 373eda14cbcSMatt Macy 374eda14cbcSMatt Macy int 375eda14cbcSMatt Macy multilist_sublist_is_empty_idx(multilist_t *ml, unsigned int sublist_idx) 376eda14cbcSMatt Macy { 377eda14cbcSMatt Macy multilist_sublist_t *mls; 378eda14cbcSMatt Macy int empty; 379eda14cbcSMatt Macy 380eda14cbcSMatt Macy ASSERT3U(sublist_idx, <, ml->ml_num_sublists); 381eda14cbcSMatt Macy mls = &ml->ml_sublists[sublist_idx]; 382eda14cbcSMatt Macy ASSERT(!MUTEX_HELD(&mls->mls_lock)); 383eda14cbcSMatt Macy mutex_enter(&mls->mls_lock); 384eda14cbcSMatt Macy empty = list_is_empty(&mls->mls_list); 385eda14cbcSMatt Macy mutex_exit(&mls->mls_lock); 386eda14cbcSMatt Macy return (empty); 387eda14cbcSMatt Macy } 388eda14cbcSMatt Macy 389eda14cbcSMatt Macy void * 390eda14cbcSMatt Macy multilist_sublist_head(multilist_sublist_t *mls) 391eda14cbcSMatt Macy { 392eda14cbcSMatt Macy ASSERT(MUTEX_HELD(&mls->mls_lock)); 393eda14cbcSMatt Macy return (list_head(&mls->mls_list)); 394eda14cbcSMatt Macy } 395eda14cbcSMatt Macy 396eda14cbcSMatt Macy void * 397eda14cbcSMatt Macy multilist_sublist_tail(multilist_sublist_t *mls) 398eda14cbcSMatt Macy { 399eda14cbcSMatt Macy ASSERT(MUTEX_HELD(&mls->mls_lock)); 400eda14cbcSMatt Macy return (list_tail(&mls->mls_list)); 401eda14cbcSMatt Macy } 402eda14cbcSMatt Macy 403eda14cbcSMatt Macy void * 404eda14cbcSMatt Macy multilist_sublist_next(multilist_sublist_t *mls, void *obj) 405eda14cbcSMatt Macy { 406eda14cbcSMatt Macy ASSERT(MUTEX_HELD(&mls->mls_lock)); 407eda14cbcSMatt Macy return (list_next(&mls->mls_list, obj)); 408eda14cbcSMatt Macy } 409eda14cbcSMatt Macy 410eda14cbcSMatt Macy void * 411eda14cbcSMatt Macy multilist_sublist_prev(multilist_sublist_t *mls, void *obj) 412eda14cbcSMatt Macy { 413eda14cbcSMatt Macy ASSERT(MUTEX_HELD(&mls->mls_lock)); 414eda14cbcSMatt Macy return (list_prev(&mls->mls_list, obj)); 415eda14cbcSMatt Macy } 416eda14cbcSMatt Macy 417eda14cbcSMatt Macy void 418eda14cbcSMatt Macy multilist_link_init(multilist_node_t *link) 419eda14cbcSMatt Macy { 420eda14cbcSMatt Macy list_link_init(link); 421eda14cbcSMatt Macy } 422eda14cbcSMatt Macy 423eda14cbcSMatt Macy int 424eda14cbcSMatt Macy multilist_link_active(multilist_node_t *link) 425eda14cbcSMatt Macy { 426eda14cbcSMatt Macy return (list_link_active(link)); 427eda14cbcSMatt Macy } 428eda14cbcSMatt Macy 429eda14cbcSMatt Macy /* BEGIN CSTYLED */ 430eda14cbcSMatt Macy ZFS_MODULE_PARAM(zfs, zfs_, multilist_num_sublists, INT, ZMOD_RW, 431eda14cbcSMatt Macy "Number of sublists used in each multilist"); 432eda14cbcSMatt Macy /* END CSTYLED */ 433