Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

lib/sort.c: add _nonatomic() variants with cond_resched()

bcachefs calls sort() during recovery to sort all keys it found in the
journal, and this may be very large - gigabytes on large machines.

This has been causing "task blocked" warnings, so needs a
cond_resched().

[kent.overstreet@linux.dev: fix kerneldoc]
Link: https://lkml.kernel.org/r/cgsr5a447pxqomc4gvznsp5yroqmif4omd7o5lsr2swifjhoic@yzjjrx2bvrq7
Link: https://lkml.kernel.org/r/20250326152606.2594920-1-kent.overstreet@linux.dev
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
Cc: Kuan-Wei Chiu <visitorckw@gmail.com>
Cc: Stephen Rothwell <sfr@canb.auug.org.au>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Kent Overstreet and committed by
Andrew Morton
e2a33a2a c8b6d5dd

+90 -31
+11
include/linux/sort.h
··· 13 13 cmp_func_t cmp_func, 14 14 swap_func_t swap_func); 15 15 16 + /* Versions that periodically call cond_resched(): */ 17 + 18 + void sort_r_nonatomic(void *base, size_t num, size_t size, 19 + cmp_r_func_t cmp_func, 20 + swap_r_func_t swap_func, 21 + const void *priv); 22 + 23 + void sort_nonatomic(void *base, size_t num, size_t size, 24 + cmp_func_t cmp_func, 25 + swap_func_t swap_func); 26 + 16 27 #endif
+79 -31
lib/sort.c
··· 186 186 return i / 2; 187 187 } 188 188 189 - /** 190 - * sort_r - sort an array of elements 191 - * @base: pointer to data to sort 192 - * @num: number of elements 193 - * @size: size of each element 194 - * @cmp_func: pointer to comparison function 195 - * @swap_func: pointer to swap function or NULL 196 - * @priv: third argument passed to comparison function 197 - * 198 - * This function does a heapsort on the given array. You may provide 199 - * a swap_func function if you need to do something more than a memory 200 - * copy (e.g. fix up pointers or auxiliary data), but the built-in swap 201 - * avoids a slow retpoline and so is significantly faster. 202 - * 203 - * The comparison function must adhere to specific mathematical 204 - * properties to ensure correct and stable sorting: 205 - * - Antisymmetry: cmp_func(a, b) must return the opposite sign of 206 - * cmp_func(b, a). 207 - * - Transitivity: if cmp_func(a, b) <= 0 and cmp_func(b, c) <= 0, then 208 - * cmp_func(a, c) <= 0. 209 - * 210 - * Sorting time is O(n log n) both on average and worst-case. While 211 - * quicksort is slightly faster on average, it suffers from exploitable 212 - * O(n*n) worst-case behavior and extra memory requirements that make 213 - * it less suitable for kernel use. 214 - */ 215 - void sort_r(void *base, size_t num, size_t size, 216 - cmp_r_func_t cmp_func, 217 - swap_r_func_t swap_func, 218 - const void *priv) 189 + #include <linux/sched.h> 190 + 191 + static void __sort_r(void *base, size_t num, size_t size, 192 + cmp_r_func_t cmp_func, 193 + swap_r_func_t swap_func, 194 + const void *priv, 195 + bool may_schedule) 219 196 { 220 197 /* pre-scale counters for performance */ 221 198 size_t n = num * size, a = (num/2) * size; ··· 263 286 b = parent(b, lsbit, size); 264 287 do_swap(base + b, base + c, size, swap_func, priv); 265 288 } 289 + 290 + if (may_schedule) 291 + cond_resched(); 266 292 } 267 293 268 294 n -= size; ··· 273 293 if (n == size * 2 && do_cmp(base, base + size, cmp_func, priv) > 0) 274 294 do_swap(base, base + size, size, swap_func, priv); 275 295 } 296 + 297 + /** 298 + * sort_r - sort an array of elements 299 + * @base: pointer to data to sort 300 + * @num: number of elements 301 + * @size: size of each element 302 + * @cmp_func: pointer to comparison function 303 + * @swap_func: pointer to swap function or NULL 304 + * @priv: third argument passed to comparison function 305 + * 306 + * This function does a heapsort on the given array. You may provide 307 + * a swap_func function if you need to do something more than a memory 308 + * copy (e.g. fix up pointers or auxiliary data), but the built-in swap 309 + * avoids a slow retpoline and so is significantly faster. 310 + * 311 + * The comparison function must adhere to specific mathematical 312 + * properties to ensure correct and stable sorting: 313 + * - Antisymmetry: cmp_func(a, b) must return the opposite sign of 314 + * cmp_func(b, a). 315 + * - Transitivity: if cmp_func(a, b) <= 0 and cmp_func(b, c) <= 0, then 316 + * cmp_func(a, c) <= 0. 317 + * 318 + * Sorting time is O(n log n) both on average and worst-case. While 319 + * quicksort is slightly faster on average, it suffers from exploitable 320 + * O(n*n) worst-case behavior and extra memory requirements that make 321 + * it less suitable for kernel use. 322 + */ 323 + void sort_r(void *base, size_t num, size_t size, 324 + cmp_r_func_t cmp_func, 325 + swap_r_func_t swap_func, 326 + const void *priv) 327 + { 328 + __sort_r(base, num, size, cmp_func, swap_func, priv, false); 329 + } 276 330 EXPORT_SYMBOL(sort_r); 331 + 332 + /** 333 + * sort_r_nonatomic - sort an array of elements, with cond_resched 334 + * @base: pointer to data to sort 335 + * @num: number of elements 336 + * @size: size of each element 337 + * @cmp_func: pointer to comparison function 338 + * @swap_func: pointer to swap function or NULL 339 + * @priv: third argument passed to comparison function 340 + * 341 + * Same as sort_r, but preferred for larger arrays as it does a periodic 342 + * cond_resched(). 343 + */ 344 + void sort_r_nonatomic(void *base, size_t num, size_t size, 345 + cmp_r_func_t cmp_func, 346 + swap_r_func_t swap_func, 347 + const void *priv) 348 + { 349 + __sort_r(base, num, size, cmp_func, swap_func, priv, true); 350 + } 351 + EXPORT_SYMBOL(sort_r_nonatomic); 277 352 278 353 void sort(void *base, size_t num, size_t size, 279 354 cmp_func_t cmp_func, ··· 339 304 .swap = swap_func, 340 305 }; 341 306 342 - return sort_r(base, num, size, _CMP_WRAPPER, SWAP_WRAPPER, &w); 307 + return __sort_r(base, num, size, _CMP_WRAPPER, SWAP_WRAPPER, &w, false); 343 308 } 344 309 EXPORT_SYMBOL(sort); 310 + 311 + void sort_nonatomic(void *base, size_t num, size_t size, 312 + cmp_func_t cmp_func, 313 + swap_func_t swap_func) 314 + { 315 + struct wrapper w = { 316 + .cmp = cmp_func, 317 + .swap = swap_func, 318 + }; 319 + 320 + return __sort_r(base, num, size, _CMP_WRAPPER, SWAP_WRAPPER, &w, true); 321 + } 322 + EXPORT_SYMBOL(sort_nonatomic);