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