13934e8ebSDarrick J. Wong /* SPDX-License-Identifier: GPL-2.0-or-later */
23934e8ebSDarrick J. Wong /*
33934e8ebSDarrick J. Wong * Copyright (C) 2021-2023 Oracle. All Rights Reserved.
43934e8ebSDarrick J. Wong * Author: Darrick J. Wong <djwong@kernel.org>
53934e8ebSDarrick J. Wong */
63934e8ebSDarrick J. Wong #ifndef __XFS_SCRUB_XFARRAY_H__
73934e8ebSDarrick J. Wong #define __XFS_SCRUB_XFARRAY_H__
83934e8ebSDarrick J. Wong
93934e8ebSDarrick J. Wong /* xfile array index type, along with cursor initialization */
103934e8ebSDarrick J. Wong typedef uint64_t xfarray_idx_t;
113934e8ebSDarrick J. Wong #define XFARRAY_CURSOR_INIT ((__force xfarray_idx_t)0)
123934e8ebSDarrick J. Wong
133934e8ebSDarrick J. Wong /* Iterate each index of an xfile array. */
143934e8ebSDarrick J. Wong #define foreach_xfarray_idx(array, idx) \
153934e8ebSDarrick J. Wong for ((idx) = XFARRAY_CURSOR_INIT; \
163934e8ebSDarrick J. Wong (idx) < xfarray_length(array); \
173934e8ebSDarrick J. Wong (idx)++)
183934e8ebSDarrick J. Wong
193934e8ebSDarrick J. Wong struct xfarray {
203934e8ebSDarrick J. Wong /* Underlying file that backs the array. */
213934e8ebSDarrick J. Wong struct xfile *xfile;
223934e8ebSDarrick J. Wong
233934e8ebSDarrick J. Wong /* Number of array elements. */
243934e8ebSDarrick J. Wong xfarray_idx_t nr;
253934e8ebSDarrick J. Wong
263934e8ebSDarrick J. Wong /* Maximum possible array size. */
273934e8ebSDarrick J. Wong xfarray_idx_t max_nr;
283934e8ebSDarrick J. Wong
293934e8ebSDarrick J. Wong /* Number of unset slots in the array below @nr. */
303934e8ebSDarrick J. Wong uint64_t unset_slots;
313934e8ebSDarrick J. Wong
323934e8ebSDarrick J. Wong /* Size of an array element. */
333934e8ebSDarrick J. Wong size_t obj_size;
343934e8ebSDarrick J. Wong
353934e8ebSDarrick J. Wong /* log2 of array element size, if possible. */
363934e8ebSDarrick J. Wong int obj_size_log;
373934e8ebSDarrick J. Wong };
383934e8ebSDarrick J. Wong
393934e8ebSDarrick J. Wong int xfarray_create(const char *descr, unsigned long long required_capacity,
403934e8ebSDarrick J. Wong size_t obj_size, struct xfarray **arrayp);
413934e8ebSDarrick J. Wong void xfarray_destroy(struct xfarray *array);
423934e8ebSDarrick J. Wong int xfarray_load(struct xfarray *array, xfarray_idx_t idx, void *ptr);
433934e8ebSDarrick J. Wong int xfarray_unset(struct xfarray *array, xfarray_idx_t idx);
443934e8ebSDarrick J. Wong int xfarray_store(struct xfarray *array, xfarray_idx_t idx, const void *ptr);
453934e8ebSDarrick J. Wong int xfarray_store_anywhere(struct xfarray *array, const void *ptr);
463934e8ebSDarrick J. Wong bool xfarray_element_is_null(struct xfarray *array, const void *ptr);
473934e8ebSDarrick J. Wong
483934e8ebSDarrick J. Wong /* Append an element to the array. */
xfarray_append(struct xfarray * array,const void * ptr)493934e8ebSDarrick J. Wong static inline int xfarray_append(struct xfarray *array, const void *ptr)
503934e8ebSDarrick J. Wong {
513934e8ebSDarrick J. Wong return xfarray_store(array, array->nr, ptr);
523934e8ebSDarrick J. Wong }
533934e8ebSDarrick J. Wong
543934e8ebSDarrick J. Wong uint64_t xfarray_length(struct xfarray *array);
553934e8ebSDarrick J. Wong int xfarray_load_next(struct xfarray *array, xfarray_idx_t *idx, void *rec);
563934e8ebSDarrick J. Wong
57232ea052SDarrick J. Wong /* Declarations for xfile array sort functionality. */
58232ea052SDarrick J. Wong
59232ea052SDarrick J. Wong typedef cmp_func_t xfarray_cmp_fn;
60232ea052SDarrick J. Wong
61c390c645SDarrick J. Wong /* Perform an in-memory heapsort for small subsets. */
62c390c645SDarrick J. Wong #define XFARRAY_ISORT_SHIFT (4)
63c390c645SDarrick J. Wong #define XFARRAY_ISORT_NR (1U << XFARRAY_ISORT_SHIFT)
64c390c645SDarrick J. Wong
65*764018caSDarrick J. Wong /* Evalulate this many points to find the qsort pivot. */
66*764018caSDarrick J. Wong #define XFARRAY_QSORT_PIVOT_NR (9)
67*764018caSDarrick J. Wong
68232ea052SDarrick J. Wong struct xfarray_sortinfo {
69232ea052SDarrick J. Wong struct xfarray *array;
70232ea052SDarrick J. Wong
71232ea052SDarrick J. Wong /* Comparison function for the sort. */
72232ea052SDarrick J. Wong xfarray_cmp_fn cmp_fn;
73232ea052SDarrick J. Wong
74232ea052SDarrick J. Wong /* Maximum height of the partition stack. */
75232ea052SDarrick J. Wong uint8_t max_stack_depth;
76232ea052SDarrick J. Wong
77232ea052SDarrick J. Wong /* Current height of the partition stack. */
78232ea052SDarrick J. Wong int8_t stack_depth;
79232ea052SDarrick J. Wong
80232ea052SDarrick J. Wong /* Maximum stack depth ever used. */
81232ea052SDarrick J. Wong uint8_t max_stack_used;
82232ea052SDarrick J. Wong
83232ea052SDarrick J. Wong /* XFARRAY_SORT_* flags; see below. */
84232ea052SDarrick J. Wong unsigned int flags;
85232ea052SDarrick J. Wong
86e5b46c75SDarrick J. Wong /* Cache a page here for faster access. */
87e5b46c75SDarrick J. Wong struct xfile_page xfpage;
88e5b46c75SDarrick J. Wong void *page_kaddr;
89e5b46c75SDarrick J. Wong
90232ea052SDarrick J. Wong #ifdef DEBUG
91232ea052SDarrick J. Wong /* Performance statistics. */
92232ea052SDarrick J. Wong uint64_t loads;
93232ea052SDarrick J. Wong uint64_t stores;
94232ea052SDarrick J. Wong uint64_t compares;
95c390c645SDarrick J. Wong uint64_t heapsorts;
96232ea052SDarrick J. Wong #endif
97232ea052SDarrick J. Wong /*
98232ea052SDarrick J. Wong * Extra bytes are allocated beyond the end of the structure to store
99232ea052SDarrick J. Wong * quicksort information. C does not permit multiple VLAs per struct,
100232ea052SDarrick J. Wong * so we document all of this in a comment.
101232ea052SDarrick J. Wong *
102232ea052SDarrick J. Wong * Pretend that we have a typedef for array records:
103232ea052SDarrick J. Wong *
104232ea052SDarrick J. Wong * typedef char[array->obj_size] xfarray_rec_t;
105232ea052SDarrick J. Wong *
106232ea052SDarrick J. Wong * First comes the quicksort partition stack:
107232ea052SDarrick J. Wong *
108232ea052SDarrick J. Wong * xfarray_idx_t lo[max_stack_depth];
109232ea052SDarrick J. Wong * xfarray_idx_t hi[max_stack_depth];
110232ea052SDarrick J. Wong *
111232ea052SDarrick J. Wong * union {
112232ea052SDarrick J. Wong *
113c390c645SDarrick J. Wong * If for a given subset we decide to use an in-memory sort, we use a
114c390c645SDarrick J. Wong * block of scratchpad records here to compare items:
115232ea052SDarrick J. Wong *
116c390c645SDarrick J. Wong * xfarray_rec_t scratch[ISORT_NR];
117232ea052SDarrick J. Wong *
118232ea052SDarrick J. Wong * Otherwise, we want to partition the records to partition the array.
119*764018caSDarrick J. Wong * We store the chosen pivot record at the start of the scratchpad area
120*764018caSDarrick J. Wong * and use the rest to sample some records to estimate the median.
121*764018caSDarrick J. Wong * The format of the qsort_pivot array enables us to use the kernel
122*764018caSDarrick J. Wong * heapsort function to place the median value in the middle.
123232ea052SDarrick J. Wong *
124*764018caSDarrick J. Wong * struct {
125232ea052SDarrick J. Wong * xfarray_rec_t pivot;
126*764018caSDarrick J. Wong * struct {
127*764018caSDarrick J. Wong * xfarray_rec_t rec; (rounded up to 8 bytes)
128*764018caSDarrick J. Wong * xfarray_idx_t idx;
129*764018caSDarrick J. Wong * } qsort_pivot[QSORT_PIVOT_NR];
130*764018caSDarrick J. Wong * };
131232ea052SDarrick J. Wong * }
132232ea052SDarrick J. Wong */
133232ea052SDarrick J. Wong };
134232ea052SDarrick J. Wong
135232ea052SDarrick J. Wong /* Sort can be interrupted by a fatal signal. */
136232ea052SDarrick J. Wong #define XFARRAY_SORT_KILLABLE (1U << 0)
137232ea052SDarrick J. Wong
138232ea052SDarrick J. Wong int xfarray_sort(struct xfarray *array, xfarray_cmp_fn cmp_fn,
139232ea052SDarrick J. Wong unsigned int flags);
140232ea052SDarrick J. Wong
1413934e8ebSDarrick J. Wong #endif /* __XFS_SCRUB_XFARRAY_H__ */
142