2 * Copyright (C) 2016 Oracle. All Rights Reserved.
4 * Author: Darrick J. Wong <darrick.wong@oracle.com>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it would be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
26 # define dbg_printf(f, a...) do {printf(f, ## a); fflush(stdout); } while (0)
28 # define dbg_printf(f, a...)
32 * Slab Arrays and Bags
34 * The slab array is a dynamically growable linear array. Internally it
35 * maintains a list of slabs of increasing size; when a slab fills up, another
36 * is allocated. Each slab is sorted individually, which means that one must
37 * use an iterator to walk the entire logical array, sorted order or otherwise.
38 * Array items can neither be removed nor accessed randomly, since (at the
39 * moment) the only user of them (storing reverse mappings) doesn't need either
40 * piece. Pointers are not stable across sort operations.
42 * A bag is a collection of pointers. The bag can be added to or removed from
43 * arbitrarily, and the bag items can be iterated. Bags are used to process
44 * rmaps into refcount btree entries.
48 * Slabs -- each slab_hdr holds an array of items; when a slab_hdr fills up, we
49 * allocate a new one and add to that one. The slab object coordinates the
53 /* Each slab holds at least 4096 items */
54 #define MIN_SLAB_NR 4096
55 /* and cannot be larger than 128M */
56 #define MAX_SLAB_SIZE (128 * 1048576)
59 size_t sh_inuse
; /* items in use */
60 struct xfs_slab_hdr
*sh_next
; /* next slab hdr */
65 size_t s_item_sz
; /* item size */
66 size_t s_nr_slabs
; /* # of slabs */
67 size_t s_nr_items
; /* # of items */
68 struct xfs_slab_hdr
*s_first
; /* first slab header */
69 struct xfs_slab_hdr
*s_last
; /* last sh_next pointer */
73 * Slab cursors -- each slab_hdr_cursor tracks a slab_hdr; the slab_cursor
74 * tracks the slab_hdr_cursors. If a compare_fn is specified, the cursor
75 * returns objects in increasing order (if you've previously sorted the
76 * slabs with qsort_slab()). If compare_fn == NULL, it returns slab items
79 struct xfs_slab_hdr_cursor
{
80 struct xfs_slab_hdr
*hdr
; /* a slab header */
81 size_t loc
; /* where we are in the slab */
84 typedef int (*xfs_slab_compare_fn
)(const void *, const void *);
86 struct xfs_slab_cursor
{
87 size_t nr
; /* # of per-slab cursors */
88 struct xfs_slab
*slab
; /* pointer to the slab */
89 struct xfs_slab_hdr_cursor
*last_hcur
; /* last header we took from */
90 xfs_slab_compare_fn compare_fn
; /* compare items */
91 struct xfs_slab_hdr_cursor hcur
[0]; /* per-slab cursors */
95 * Bags -- each bag is an array of pointers items; when a bag fills up, we
98 #define MIN_BAG_SIZE 4096
100 size_t bg_nr
; /* number of pointers */
101 size_t bg_inuse
; /* number of slots in use */
102 void **bg_ptrs
; /* pointers */
104 #define BAG_SIZE(nr) (sizeof(struct xfs_bag) + ((nr) * sizeof(void *)))
105 #define BAG_END(bag) (&(bag)->bg_ptrs[(bag)->bg_nr])
108 * Create a slab to hold some objects of a particular size.
112 struct xfs_slab
**slab
,
115 struct xfs_slab
*ptr
;
117 ptr
= calloc(1, sizeof(struct xfs_slab
));
120 ptr
->s_item_sz
= item_size
;
132 struct xfs_slab
**slab
)
134 struct xfs_slab
*ptr
;
135 struct xfs_slab_hdr
*hdr
;
136 struct xfs_slab_hdr
*nhdr
;
153 struct xfs_slab
*slab
,
154 struct xfs_slab_hdr
*hdr
,
159 ASSERT(idx
< hdr
->sh_inuse
);
160 p
= (char *)(hdr
+ 1);
161 p
+= slab
->s_item_sz
* idx
;
166 * Add an item to the slab.
170 struct xfs_slab
*slab
,
173 struct xfs_slab_hdr
*hdr
;
177 if (!hdr
|| hdr
->sh_inuse
== hdr
->sh_nr
) {
180 n
= (hdr
? hdr
->sh_nr
* 2 : MIN_SLAB_NR
);
181 if (n
* slab
->s_item_sz
> MAX_SLAB_SIZE
)
182 n
= MAX_SLAB_SIZE
/ slab
->s_item_sz
;
183 hdr
= malloc(sizeof(struct xfs_slab_hdr
) + (n
* slab
->s_item_sz
));
190 slab
->s_last
->sh_next
= hdr
;
197 p
= slab_ptr(slab
, hdr
, hdr
->sh_inuse
- 1);
198 memcpy(p
, item
, slab
->s_item_sz
);
207 struct xfs_slab
*slab
;
208 struct xfs_slab_hdr
*hdr
;
209 int (*compare_fn
)(const void *, const void *);
214 struct workqueue
*wq
,
218 struct qsort_slab
*qs
= arg
;
220 qsort(slab_ptr(qs
->slab
, qs
->hdr
, 0), qs
->hdr
->sh_inuse
,
221 qs
->slab
->s_item_sz
, qs
->compare_fn
);
226 * Sort the items in the slab. Do not run this method if there are any
227 * cursors holding on to the slab.
231 struct xfs_slab
*slab
,
232 int (*compare_fn
)(const void *, const void *))
235 struct xfs_slab_hdr
*hdr
;
236 struct qsort_slab
*qs
;
239 * If we don't have that many slabs, we're probably better
240 * off skipping all the thread overhead.
242 if (slab
->s_nr_slabs
<= 4) {
245 qsort(slab_ptr(slab
, hdr
, 0), hdr
->sh_inuse
,
246 slab
->s_item_sz
, compare_fn
);
252 create_work_queue(&wq
, NULL
, libxfs_nproc());
255 qs
= malloc(sizeof(struct qsort_slab
));
258 qs
->compare_fn
= compare_fn
;
259 queue_work(&wq
, qsort_slab_helper
, 0, qs
);
262 destroy_work_queue(&wq
);
266 * init_slab_cursor() -- Create a slab cursor to iterate the slab items.
269 * @compare_fn: If specified, use this function to return items in ascending order.
270 * @cur: The new cursor.
274 struct xfs_slab
*slab
,
275 int (*compare_fn
)(const void *, const void *),
276 struct xfs_slab_cursor
**cur
)
278 struct xfs_slab_cursor
*c
;
279 struct xfs_slab_hdr_cursor
*hcur
;
280 struct xfs_slab_hdr
*hdr
;
282 c
= malloc(sizeof(struct xfs_slab_cursor
) +
283 (sizeof(struct xfs_slab_hdr_cursor
) * slab
->s_nr_slabs
));
286 c
->nr
= slab
->s_nr_slabs
;
288 c
->compare_fn
= compare_fn
;
290 hcur
= (struct xfs_slab_hdr_cursor
*)(c
+ 1);
303 * Free the slab cursor.
307 struct xfs_slab_cursor
**cur
)
316 * Return the smallest item in the slab, without advancing the iterator.
317 * The slabs must be sorted prior to the creation of the cursor.
321 struct xfs_slab_cursor
*cur
)
323 struct xfs_slab_hdr_cursor
*hcur
;
328 cur
->last_hcur
= NULL
;
330 /* no compare function; inorder traversal */
331 if (!cur
->compare_fn
) {
333 cur
->last_hcur
= &cur
->hcur
[0];
334 hcur
= cur
->last_hcur
;
335 while (hcur
< &cur
->hcur
[cur
->nr
] &&
336 hcur
->loc
>= hcur
->hdr
->sh_inuse
)
338 if (hcur
== &cur
->hcur
[cur
->nr
])
340 p
= slab_ptr(cur
->slab
, hcur
->hdr
, hcur
->loc
);
341 cur
->last_hcur
= hcur
;
345 /* otherwise return things in increasing order */
346 for (i
= 0, hcur
= &cur
->hcur
[i
]; i
< cur
->nr
; i
++, hcur
++) {
347 if (hcur
->loc
>= hcur
->hdr
->sh_inuse
)
349 q
= slab_ptr(cur
->slab
, hcur
->hdr
, hcur
->loc
);
350 if (!p
|| cur
->compare_fn(p
, q
) > 0) {
352 cur
->last_hcur
= hcur
;
360 * After a peek operation, advance the cursor.
364 struct xfs_slab_cursor
*cur
)
366 ASSERT(cur
->last_hcur
);
367 cur
->last_hcur
->loc
++;
371 * Retrieve the next item in the slab and advance the cursor.
375 struct xfs_slab_cursor
*cur
)
379 p
= peek_slab_cursor(cur
);
381 advance_slab_cursor(cur
);
386 * Return the number of items in the slab.
390 struct xfs_slab
*slab
)
392 return slab
->s_nr_items
;
396 * Create a bag to point to some objects.
400 struct xfs_bag
**bag
)
404 ptr
= calloc(1, sizeof(struct xfs_bag
));
407 ptr
->bg_ptrs
= calloc(MIN_BAG_SIZE
, sizeof(void *));
412 ptr
->bg_nr
= MIN_BAG_SIZE
;
418 * Free a bag of pointers.
422 struct xfs_bag
**bag
)
435 * Add an object to the pointer bag.
444 p
= &bag
->bg_ptrs
[bag
->bg_inuse
];
445 if (p
== BAG_END(bag
)) {
446 /* No free space, alloc more pointers */
450 x
= realloc(bag
->bg_ptrs
, nr
* sizeof(void *));
454 memset(BAG_END(bag
), 0, bag
->bg_nr
* sizeof(void *));
457 bag
->bg_ptrs
[bag
->bg_inuse
] = ptr
;
463 * Remove a pointer from a bag.
470 ASSERT(nr
< bag
->bg_inuse
);
471 memmove(&bag
->bg_ptrs
[nr
], &bag
->bg_ptrs
[nr
+ 1],
472 (bag
->bg_inuse
- nr
- 1) * sizeof(void *));
478 * Return the number of items in a bag.
484 return bag
->bg_inuse
;
488 * Return the nth item in a bag.
495 if (nr
>= bag
->bg_inuse
)
497 return bag
->bg_ptrs
[nr
];