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