mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
xfarray: don't crash when sorting if array element crosses a folio
LOLLM points out that if an array element crosses a folio boundary,
xfile_get_folio returns a NULL folio pointer. If this happens,
si->folio is also set to NULL, and calling folio_pos/folio_address will
just crash the kernel. Teach this function to handle this condition by
falling back to reading the array element into scratchpad memory.
Cc: stable@vger.kernel.org # v6.6
Fixes: cf36f4f64c ("xfs: cache pages used for xfarray quicksort convergence")
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Assisted-by: LOLLM # finding obvious bugs
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
This commit is contained in:
parent
23067b4f98
commit
329750292e
|
|
@ -794,6 +794,46 @@ xfarray_sort_scan_done(
|
|||
si->folio = NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
xfarray_sort_load_folio(
|
||||
struct xfarray_sortinfo *si,
|
||||
xfarray_idx_t idx,
|
||||
loff_t idx_pos)
|
||||
{
|
||||
struct folio *folio;
|
||||
loff_t next_pos;
|
||||
|
||||
folio = xfile_get_folio(si->array->xfile, idx_pos, si->array->obj_size,
|
||||
XFILE_ALLOC);
|
||||
if (IS_ERR(folio))
|
||||
return PTR_ERR(folio);
|
||||
si->folio = folio;
|
||||
|
||||
/* No folio? Get the caller to read into the scratchpad. */
|
||||
if (!si->folio)
|
||||
return 0;
|
||||
|
||||
si->first_folio_idx = xfarray_idx(si->array,
|
||||
folio_pos(si->folio) + si->array->obj_size - 1);
|
||||
|
||||
next_pos = folio_next_pos(si->folio);
|
||||
si->last_folio_idx = xfarray_idx(si->array, next_pos - 1);
|
||||
if (xfarray_pos(si->array, si->last_folio_idx + 1) > next_pos)
|
||||
si->last_folio_idx--;
|
||||
|
||||
/*
|
||||
* If this folio still doesn't cover the desired element, it must cross
|
||||
* a folio boundary. Get the caller to read into the scratchpad.
|
||||
*/
|
||||
if (idx < si->first_folio_idx || idx > si->last_folio_idx) {
|
||||
xfarray_sort_scan_done(si);
|
||||
return 0;
|
||||
}
|
||||
|
||||
trace_xfarray_sort_scan(si, idx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Cache the folio backing the start of the given array element. If the array
|
||||
* element is contained entirely within the folio, return a pointer to the
|
||||
|
|
@ -819,33 +859,18 @@ xfarray_sort_scan(
|
|||
(idx < si->first_folio_idx || idx > si->last_folio_idx))
|
||||
xfarray_sort_scan_done(si);
|
||||
|
||||
/* Grab the first folio that backs this array element. */
|
||||
/* Grab the folio that backs this array element. */
|
||||
if (!si->folio) {
|
||||
struct folio *folio;
|
||||
loff_t next_pos;
|
||||
|
||||
folio = xfile_get_folio(si->array->xfile, idx_pos,
|
||||
si->array->obj_size, XFILE_ALLOC);
|
||||
if (IS_ERR(folio))
|
||||
return PTR_ERR(folio);
|
||||
si->folio = folio;
|
||||
|
||||
si->first_folio_idx = xfarray_idx(si->array,
|
||||
folio_pos(si->folio) + si->array->obj_size - 1);
|
||||
|
||||
next_pos = folio_next_pos(si->folio);
|
||||
si->last_folio_idx = xfarray_idx(si->array, next_pos - 1);
|
||||
if (xfarray_pos(si->array, si->last_folio_idx + 1) > next_pos)
|
||||
si->last_folio_idx--;
|
||||
|
||||
trace_xfarray_sort_scan(si, idx);
|
||||
error = xfarray_sort_load_folio(si, idx, idx_pos);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* If this folio still doesn't cover the desired element, it must cross
|
||||
* a folio boundary. Read into the scratchpad and we're done.
|
||||
* If we don't have a folio mapping the entire array element, read into
|
||||
* the scratchpad and we're done.
|
||||
*/
|
||||
if (idx < si->first_folio_idx || idx > si->last_folio_idx) {
|
||||
if (!si->folio) {
|
||||
void *temp = xfarray_scratch(si->array);
|
||||
|
||||
error = xfile_load(si->array->xfile, temp, si->array->obj_size,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user