]> www.infradead.org Git - users/willy/pagecache.git/commitdiff
bcachefs: bch2_get_random_u64_below()
authorKent Overstreet <kent.overstreet@linux.dev>
Thu, 13 Mar 2025 15:16:28 +0000 (11:16 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Thu, 13 Mar 2025 16:40:22 +0000 (12:40 -0400)
steal the (clever) algorithm from get_random_u32_below()

this fixes a bug where we were passing roundup_pow_of_two() a 64 bit
number - we're squaring device latencies now:

[  +1.681698] ------------[ cut here ]------------
[  +0.000010] UBSAN: shift-out-of-bounds in ./include/linux/log2.h:57:13
[  +0.000011] shift exponent 64 is too large for 64-bit type 'long unsigned int'
[  +0.000011] CPU: 1 UID: 0 PID: 196 Comm: kworker/u32:13 Not tainted 6.14.0-rc6-dave+ #10
[  +0.000012] Hardware name: ASUS System Product Name/PRIME B460I-PLUS, BIOS 1301 07/13/2021
[  +0.000005] Workqueue: events_unbound __bch2_read_endio [bcachefs]
[  +0.000354] Call Trace:
[  +0.000005]  <TASK>
[  +0.000007]  dump_stack_lvl+0x5d/0x80
[  +0.000018]  ubsan_epilogue+0x5/0x30
[  +0.000008]  __ubsan_handle_shift_out_of_bounds.cold+0x61/0xe6
[  +0.000011]  bch2_rand_range.cold+0x17/0x20 [bcachefs]
[  +0.000231]  bch2_bkey_pick_read_device+0x547/0x920 [bcachefs]
[  +0.000229]  __bch2_read_extent+0x1e4/0x18e0 [bcachefs]
[  +0.000241]  ? bch2_btree_iter_peek_slot+0x3df/0x800 [bcachefs]
[  +0.000180]  ? bch2_read_retry_nodecode+0x270/0x330 [bcachefs]
[  +0.000230]  bch2_read_retry_nodecode+0x270/0x330 [bcachefs]
[  +0.000230]  bch2_rbio_retry+0x1fa/0x600 [bcachefs]
[  +0.000224]  ? bch2_printbuf_make_room+0x71/0xb0 [bcachefs]
[  +0.000243]  ? bch2_read_csum_err+0x4a4/0x610 [bcachefs]
[  +0.000278]  bch2_read_csum_err+0x4a4/0x610 [bcachefs]
[  +0.000227]  ? __bch2_read_endio+0x58b/0x870 [bcachefs]
[  +0.000220]  __bch2_read_endio+0x58b/0x870 [bcachefs]
[  +0.000268]  ? try_to_wake_up+0x31c/0x7f0
[  +0.000011]  ? process_one_work+0x176/0x330
[  +0.000008]  process_one_work+0x176/0x330
[  +0.000008]  worker_thread+0x252/0x390
[  +0.000008]  ? __pfx_worker_thread+0x10/0x10
[  +0.000006]  kthread+0xec/0x230
[  +0.000011]  ? __pfx_kthread+0x10/0x10
[  +0.000009]  ret_from_fork+0x31/0x50
[  +0.000009]  ? __pfx_kthread+0x10/0x10
[  +0.000008]  ret_from_fork_asm+0x1a/0x30
[  +0.000012]  </TASK>
[  +0.000046] ---[ end trace ]---

Reported-by: Roland Vet <vet.roland@protonmail.com>
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/extents.c
fs/bcachefs/util.c
fs/bcachefs/util.h

index 05d5f71a7ca9f6423f8f12162ae568ca2c150037..2d8042f853dcda23f377c5c44e6dfa80c84574c9 100644 (file)
@@ -99,7 +99,7 @@ static inline bool ptr_better(struct bch_fs *c,
 
                /* Pick at random, biased in favor of the faster device: */
 
-               return bch2_rand_range(l1 + l2) > l1;
+               return bch2_get_random_u64_below(l1 + l2) > l1;
        }
 
        if (bch2_force_reconstruct_read)
index e0a876cbaa6b78eda3f9fe5d718b4fd609193330..8e3ab4bf79a90628757f7abb1d66568656065250 100644 (file)
@@ -653,19 +653,24 @@ int bch2_bio_alloc_pages(struct bio *bio, size_t size, gfp_t gfp_mask)
        return 0;
 }
 
-size_t bch2_rand_range(size_t max)
+u64 bch2_get_random_u64_below(u64 ceil)
 {
-       size_t rand;
+       if (ceil <= U32_MAX)
+               return __get_random_u32_below(ceil);
 
-       if (!max)
-               return 0;
+       /* this is the same (clever) algorithm as in __get_random_u32_below() */
+       u64 rand = get_random_u64();
+       u64 mult = ceil * rand;
 
-       do {
-               rand = get_random_long();
-               rand &= roundup_pow_of_two(max) - 1;
-       } while (rand >= max);
+       if (unlikely(mult < ceil)) {
+               u64 bound = -ceil % ceil;
+               while (unlikely(mult < bound)) {
+                       rand = get_random_u64();
+                       mult = ceil * rand;
+               }
+       }
 
-       return rand;
+       return mul_u64_u64_shr(ceil, rand, 64);
 }
 
 void memcpy_to_bio(struct bio *dst, struct bvec_iter dst_iter, const void *src)
index e7c3541b38f3ff0df9d8fe0be372feabc383648d..f4a4783219d9d9e1319e5e40f797ef959138d9da 100644 (file)
@@ -401,7 +401,7 @@ do {                                                                        \
        _ret;                                                           \
 })
 
-size_t bch2_rand_range(size_t);
+u64 bch2_get_random_u64_below(u64);
 
 void memcpy_to_bio(struct bio *, struct bvec_iter, const void *);
 void memcpy_from_bio(void *, struct bio *, struct bvec_iter);