xfarray: don't allow users to unset in the middle of an array

Now that we've merged online repair and removed some clunky parts of the
original online checking code, the only user of xfarray_unset is the
free space btree repair code, and it only needs to be able to remove
records from the end of the array.  Let's remove all the code that
handles "unset" array elements that are not at the end, because we can
just reduce the array element count.

Remove the "store anywhere" function because it was only ever used by
the callers who used unset to remove elements in the middle of the
array.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
This commit is contained in:
Darrick J. Wong 2026-09-22 22:59:57 -07:00 committed by Carlos Maiolino
parent 329750292e
commit 3a94b91aef
4 changed files with 15 additions and 114 deletions

View File

@ -1973,8 +1973,7 @@ provide loading and storing of array elements at arbitrary array indices.
Gaps are defined to be null records, and null records are defined to be a
sequence of all zero bytes.
Null records are detected by calling ``xfarray_element_is_null``.
They are created either by calling ``xfarray_unset`` to null out an existing
record or by never storing anything to an array index.
They are created by never storing anything to an array index.
The second type of caller handles records that are not indexed by position
and do not require multiple updates to a record.
@ -1991,9 +1990,7 @@ The typical use case here is constructing space extent reference counts from
reverse mapping information.
Records can be put in the bag in any order, they can be removed from the bag
at any time, and uniqueness of records is left to callers.
The ``xfarray_store_anywhere`` function is used to insert a record in any
null record slot in the bag; and the ``xfarray_unset`` function removes a
record from the bag.
Note: Bags are now implemented with in-memory btrees for faster access.
Iterating Array Elements
^^^^^^^^^^^^^^^^^^^^^^^^
@ -2643,11 +2640,7 @@ generate refcount information from reverse mapping records.
refcount record associating the block number range that we just walked to
the size of the bag.
The bag-like structure in this case is a type 2 xfarray as discussed in the
:ref:`xfarray access patterns<xfarray_access_patterns>` section.
Reverse mappings are added to the bag using ``xfarray_store_anywhere`` and
removed via ``xfarray_unset``.
Bag members are examined through ``xfarray_iter`` loops.
The bag-like structure in this case is an in-memory btree.
Case Study: Rebuilding File Fork Mapping Indices
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View File

@ -517,7 +517,7 @@ xrep_abt_reserve_space(
* records (but doesn't break the sorting order), so we must
* go around the loop once more to re-run _bload_init.
*/
error = xfarray_unset(ra->free_records, record_nr);
error = xfarray_trim(ra->free_records, 1);
if (error)
break;
ra->nr_real_records--;

View File

@ -140,55 +140,20 @@ xfarray_load(
xfarray_pos(array, idx));
}
/* Is this array element potentially unset? */
static inline bool
xfarray_is_unset(
struct xfarray *array,
loff_t pos)
{
void *temp = xfarray_scratch(array);
int error;
if (array->unset_slots == 0)
return false;
error = xfile_load(array->xfile, temp, array->obj_size, pos);
if (!error && xfarray_element_is_null(array, temp))
return true;
return false;
}
/*
* Unset an array element. If @idx is the last element in the array, the
* array will be truncated. Otherwise, the entry will be zeroed.
*/
/* Remove the elements at the end of an array. */
int
xfarray_unset(
struct xfarray *array,
xfarray_idx_t idx)
xfarray_trim(
struct xfarray *array,
unsigned long long nr)
{
void *temp = xfarray_scratch(array);
loff_t pos = xfarray_pos(array, idx);
int error;
loff_t new_eof;
if (idx >= array->nr)
if (nr > array->nr)
return -ENODATA;
if (idx == array->nr - 1) {
array->nr--;
return 0;
}
if (xfarray_is_unset(array, pos))
return 0;
memset(temp, 0, array->obj_size);
error = xfile_store(array->xfile, temp, array->obj_size, pos);
if (error)
return error;
array->unset_slots++;
array->nr -= nr;
new_eof = xfarray_pos(array, array->nr);
xfile_discard(array->xfile, new_eof, MAX_LFS_FILESIZE - new_eof);
return 0;
}
@ -227,43 +192,6 @@ xfarray_element_is_null(
return !memchr_inv(ptr, 0, array->obj_size);
}
/*
* Store an element anywhere in the array that is unset. If there are no
* unset slots, append the element to the array.
*/
int
xfarray_store_anywhere(
struct xfarray *array,
const void *ptr)
{
void *temp = xfarray_scratch(array);
loff_t endpos = xfarray_pos(array, array->nr);
loff_t pos;
int error;
/* Find an unset slot to put it in. */
for (pos = 0;
pos < endpos && array->unset_slots > 0;
pos += array->obj_size) {
error = xfile_load(array->xfile, temp, array->obj_size,
pos);
if (error || !xfarray_element_is_null(array, temp))
continue;
error = xfile_store(array->xfile, ptr, array->obj_size,
pos);
if (error)
return error;
array->unset_slots--;
return 0;
}
/* No unset slots found; attach it on the end. */
array->unset_slots = 0;
return xfarray_append(array, ptr);
}
/* Return length of array. */
uint64_t
xfarray_length(
@ -677,26 +605,10 @@ xfarray_qsort_pivot(
/* Load the selected xfarray records into the pivot array. */
for (i = 0; i < XFARRAY_QSORT_PIVOT_NR; i++) {
xfarray_idx_t idx;
recp = xfarray_pivot_array_rec(parray, pivot_rec_sz, i);
idxp = xfarray_pivot_array_idx(parray, pivot_rec_sz, i);
/* No unset records; load directly into the array. */
if (likely(si->array->unset_slots == 0)) {
error = xfarray_sort_load(si, *idxp, recp);
if (error)
return error;
continue;
}
/*
* Load non-null records into the scratchpad without changing
* the xfarray_idx_t in the pivot array.
*/
idx = *idxp;
xfarray_sort_bump_loads(si);
error = xfarray_load_next(si->array, &idx, recp);
error = xfarray_sort_load(si, *idxp, recp);
if (error)
return error;
}

View File

@ -27,9 +27,6 @@ struct xfarray {
/* Maximum possible array size. */
xfarray_idx_t max_nr;
/* Number of unset slots in the array below @nr. */
uint64_t unset_slots;
/* Size of an array element. */
size_t obj_size;
@ -41,9 +38,8 @@ int xfarray_create(const char *descr, unsigned long long required_capacity,
size_t obj_size, struct xfarray **arrayp);
void xfarray_destroy(struct xfarray *array);
int xfarray_load(struct xfarray *array, xfarray_idx_t idx, void *ptr);
int xfarray_unset(struct xfarray *array, xfarray_idx_t idx);
int xfarray_trim(struct xfarray *array, unsigned long long nr);
int xfarray_store(struct xfarray *array, xfarray_idx_t idx, const void *ptr);
int xfarray_store_anywhere(struct xfarray *array, const void *ptr);
bool xfarray_element_is_null(struct xfarray *array, const void *ptr);
void xfarray_truncate(struct xfarray *array);
unsigned long long xfarray_bytes(struct xfarray *array);