xref: /openbmc/linux/fs/xfs/scrub/xfarray.h (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
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