xfarray.h 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. /* SPDX-License-Identifier: GPL-2.0-or-later */
  2. /*
  3. * Copyright (C) 2021-2023 Oracle. All Rights Reserved.
  4. * Author: Darrick J. Wong <djwong@kernel.org>
  5. */
  6. #ifndef __XFS_SCRUB_XFARRAY_H__
  7. #define __XFS_SCRUB_XFARRAY_H__
  8. /* xfile array index type, along with cursor initialization */
  9. typedef uint64_t xfarray_idx_t;
  10. #define XFARRAY_NULLIDX ((__force xfarray_idx_t)-1ULL)
  11. #define XFARRAY_CURSOR_INIT ((__force xfarray_idx_t)0)
  12. /* Iterate each index of an xfile array. */
  13. #define foreach_xfarray_idx(array, idx) \
  14. for ((idx) = XFARRAY_CURSOR_INIT; \
  15. (idx) < xfarray_length(array); \
  16. (idx)++)
  17. struct xfarray {
  18. /* Underlying file that backs the array. */
  19. struct xfile *xfile;
  20. /* Number of array elements. */
  21. xfarray_idx_t nr;
  22. /* Maximum possible array size. */
  23. xfarray_idx_t max_nr;
  24. /* Number of unset slots in the array below @nr. */
  25. uint64_t unset_slots;
  26. /* Size of an array element. */
  27. size_t obj_size;
  28. /* log2 of array element size, if possible. */
  29. int obj_size_log;
  30. };
  31. int xfarray_create(const char *descr, unsigned long long required_capacity,
  32. size_t obj_size, struct xfarray **arrayp);
  33. void xfarray_destroy(struct xfarray *array);
  34. int xfarray_load(struct xfarray *array, xfarray_idx_t idx, void *ptr);
  35. int xfarray_unset(struct xfarray *array, xfarray_idx_t idx);
  36. int xfarray_store(struct xfarray *array, xfarray_idx_t idx, const void *ptr);
  37. int xfarray_store_anywhere(struct xfarray *array, const void *ptr);
  38. bool xfarray_element_is_null(struct xfarray *array, const void *ptr);
  39. void xfarray_truncate(struct xfarray *array);
  40. unsigned long long xfarray_bytes(struct xfarray *array);
  41. /*
  42. * Load an array element, but zero the buffer if there's no data because we
  43. * haven't stored to that array element yet.
  44. */
  45. static inline int
  46. xfarray_load_sparse(
  47. struct xfarray *array,
  48. uint64_t idx,
  49. void *rec)
  50. {
  51. int error = xfarray_load(array, idx, rec);
  52. if (error == -ENODATA) {
  53. memset(rec, 0, array->obj_size);
  54. return 0;
  55. }
  56. return error;
  57. }
  58. /* Append an element to the array. */
  59. static inline int xfarray_append(struct xfarray *array, const void *ptr)
  60. {
  61. return xfarray_store(array, array->nr, ptr);
  62. }
  63. uint64_t xfarray_length(struct xfarray *array);
  64. int xfarray_load_next(struct xfarray *array, xfarray_idx_t *idx, void *rec);
  65. /*
  66. * Iterate the non-null elements in a sparse xfarray. Callers should
  67. * initialize *idx to XFARRAY_CURSOR_INIT before the first call; on return, it
  68. * will be set to one more than the index of the record that was retrieved.
  69. * Returns 1 if a record was retrieved, 0 if there weren't any more records, or
  70. * a negative errno.
  71. */
  72. static inline int
  73. xfarray_iter(
  74. struct xfarray *array,
  75. xfarray_idx_t *idx,
  76. void *rec)
  77. {
  78. int ret = xfarray_load_next(array, idx, rec);
  79. if (ret == -ENODATA)
  80. return 0;
  81. if (ret == 0)
  82. return 1;
  83. return ret;
  84. }
  85. /* Declarations for xfile array sort functionality. */
  86. typedef cmp_func_t xfarray_cmp_fn;
  87. /* Perform an in-memory heapsort for small subsets. */
  88. #define XFARRAY_ISORT_SHIFT (4)
  89. #define XFARRAY_ISORT_NR (1U << XFARRAY_ISORT_SHIFT)
  90. /* Evalulate this many points to find the qsort pivot. */
  91. #define XFARRAY_QSORT_PIVOT_NR (9)
  92. struct xfarray_sortinfo {
  93. struct xfarray *array;
  94. /* Comparison function for the sort. */
  95. xfarray_cmp_fn cmp_fn;
  96. /* Maximum height of the partition stack. */
  97. uint8_t max_stack_depth;
  98. /* Current height of the partition stack. */
  99. int8_t stack_depth;
  100. /* Maximum stack depth ever used. */
  101. uint8_t max_stack_used;
  102. /* XFARRAY_SORT_* flags; see below. */
  103. unsigned int flags;
  104. /* next time we want to cond_resched() */
  105. struct xchk_relax relax;
  106. /* Cache a folio here for faster scanning for pivots */
  107. struct folio *folio;
  108. /* First array index in folio that is completely readable */
  109. xfarray_idx_t first_folio_idx;
  110. /* Last array index in folio that is completely readable */
  111. xfarray_idx_t last_folio_idx;
  112. #ifdef DEBUG
  113. /* Performance statistics. */
  114. uint64_t loads;
  115. uint64_t stores;
  116. uint64_t compares;
  117. uint64_t heapsorts;
  118. #endif
  119. /*
  120. * Extra bytes are allocated beyond the end of the structure to store
  121. * quicksort information. C does not permit multiple VLAs per struct,
  122. * so we document all of this in a comment.
  123. *
  124. * Pretend that we have a typedef for array records:
  125. *
  126. * typedef char[array->obj_size] xfarray_rec_t;
  127. *
  128. * First comes the quicksort partition stack:
  129. *
  130. * xfarray_idx_t lo[max_stack_depth];
  131. * xfarray_idx_t hi[max_stack_depth];
  132. *
  133. * union {
  134. *
  135. * If for a given subset we decide to use an in-memory sort, we use a
  136. * block of scratchpad records here to compare items:
  137. *
  138. * xfarray_rec_t scratch[ISORT_NR];
  139. *
  140. * Otherwise, we want to partition the records to partition the array.
  141. * We store the chosen pivot record at the start of the scratchpad area
  142. * and use the rest to sample some records to estimate the median.
  143. * The format of the qsort_pivot array enables us to use the kernel
  144. * heapsort function to place the median value in the middle.
  145. *
  146. * struct {
  147. * xfarray_rec_t pivot;
  148. * struct {
  149. * xfarray_rec_t rec; (rounded up to 8 bytes)
  150. * xfarray_idx_t idx;
  151. * } qsort_pivot[QSORT_PIVOT_NR];
  152. * };
  153. * }
  154. */
  155. };
  156. /* Sort can be interrupted by a fatal signal. */
  157. #define XFARRAY_SORT_KILLABLE (1U << 0)
  158. int xfarray_sort(struct xfarray *array, xfarray_cmp_fn cmp_fn,
  159. unsigned int flags);
  160. #endif /* __XFS_SCRUB_XFARRAY_H__ */