[PATCH] bcache: reserve a bucket generation for btree node freeing

Wale Zhang <[email protected]>
Newsgroups org.kernel.vger.linux-bcache,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
The allocator allows a bucket generation to advance until its distance
from last_gc reaches BUCKET_GC_GEN_MAX.  A bucket allocated for a btree
node can then be advanced once more by make_btree_freeing_key() when that
node is replaced.  That path does not go through can_inc_bucket_gen().

This can make the generation distance exceed BUCKET_GC_GEN_MAX.  It was
observed during journal replay when a btree split advanced the distance
from 96 to 97.  bch_inc_gen() warned and the subsequent btree scan
reported:

  key too stale: 97, need_gc 97

The cache set was then disabled.

Stop normal bucket invalidation one generation earlier.  The reserved
generation allows make_btree_freeing_key() to invalidate a btree node
without exceeding BUCKET_GC_GEN_MAX.  A bucket cannot need another such
increment before being reused, and reuse has to pass this check again.

The kernel log is as follow:
[   46.769015] ------------[ cut here ]------------
[   46.769023] WARNING: CPU: 14 PID: 3891 at drivers/md/bcache/alloc.c:81 bch_inc_gen+0x3f/0x50 [bcache]
[   46.769145] Modules linked in: bcache(E) dm_mod(E) ext4(E) crc16(E) jbd2(E) crc32c_cryptoapi(E) watchdog(E) squashfs(E) vfat(E) fat(E) overlay(E) raid10(E) raid456(E) async_raid6_recov(E) async_memcpy(E) async_pq(E) async_xor(E) xor(E) async_tx(E) raid6_pq(E) raid1(E) raid0(E) md_mod(E) quota_v2(E) quota_v1(E) quota_tree(E) loop(E) sd_mod(E) xhci_pci(E) nvme(E) ahci(E) xhci_hcd(E) nvme_core(E) libahci(E) libata(E) atlantic(E) nvme_keyring(E) nvme_auth(E) usbcore(E) scsi_mod(E)
[   46.769216] CPU: 14 UID: 0 PID: 3891 Comm: bcache Tainted: G S   U      E       6.18.15 #1 PREEMPT(lazy)
[   46.769222] Tainted: [S]=CPU_OUT_OF_SPEC, [U]=USER, [E]=UNSIGNED_MODULE
[   46.769223] Hardware name: MINI Pro/Default string, BIOS MINI Pro V1.1 20250806 08/06/2025
[   46.769225] RIP: 0010:bch_inc_gen+0x3f/0x50 [bcache]
[   46.769240] Code: 0f 89 c2 2a 56 07 0f b6 b1 22 06 00 00 40 38 f2 0f 42 d6 88 91 22 06 00 00 48 8b 17 80 ba 22 06 00 00 60 77 05 c3 cc cc cc cc <0f> 0b c3 cc cc cc cc 66 2e 0f 1f 84 00 00 00 00 00 90 90 90 90 90
[   46.769243] RSP: 0018:ffffcadc8ffdf590 EFLAGS: 00010202
[   46.769245] RAX: 0000000000000063 RBX: 000007ffffffffff RCX: ffff89da58600000
[   46.769247] RDX: ffff89da58600000 RSI: 0000000000000060 RDI: ffff89d8c14c8000
[   46.769249] RBP: 0000000000000002 R08: 0000000ae3a62aea R09: 0000000000000000
[   46.769250] R10: 0000000000000001 R11: 0000000000000000 R12: 0000000000000001
[   46.769252] R13: ffffcadc8ffdf658 R14: ffff89da820bb800 R15: ffffcadc8ffdf600
[   46.769254] FS:  00007f7222e26bc0(0000) GS:ffff89e854219000(0000) knlGS:0000000000000000
[   46.769256] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   46.769258] CR2: 00007f37b77fcde8 CR3: 0000000305c51006 CR4: 0000000000f72ef0
[   46.769260] PKRU: 55555554
[   46.769261] Call Trace:
[   46.769265]  <TASK>
[   46.769267]  make_btree_freeing_key+0xe3/0x120 [bcache]
[   46.769287]  btree_split+0x4b3/0x6c0 [bcache]
[   46.769304]  ? __pfx_closure_sync_fn+0x10/0x10
[   46.769312]  ? update_load_avg+0x7f/0x790
[   46.769319]  bch_btree_insert_node+0x2f6/0x3d0 [bcache]
[   46.769335]  ? __pfx_btree_insert_fn+0x10/0x10 [bcache]
[   46.769349]  btree_insert_fn+0x24/0x50 [bcache]
[   46.769364]  bch_btree_map_nodes_recurse+0x103/0x190 [bcache]
[   46.769379]  __bch_btree_map_nodes+0x1b7/0x1f0 [bcache]
[   46.769393]  ? __pfx_btree_insert_fn+0x10/0x10 [bcache]
[   46.769407]  bch_btree_insert+0xe3/0x160 [bcache]
[   46.769420]  ? __pfx_autoremove_wake_function+0x10/0x10
[   46.769425]  bch_journal_replay+0x131/0x290 [bcache]
[   46.769442]  ? ttwu_queue_wakelist+0xe0/0x100
[   46.769447]  ? try_to_wake_up+0x309/0x6e0
[   46.769451]  register_bcache+0x18b2/0x2000 [bcache]
[   46.769473]  kernfs_fop_write_iter+0x130/0x210
[   46.769480]  vfs_write+0x258/0x420
[   46.769486]  ksys_write+0x65/0xe0
[   46.769490]  do_syscall_64+0x84/0x810
[   46.769495]  ? next_uptodate_folio+0x85/0x2a0
[   46.769501]  ? percpu_counter_add_batch+0x4c/0x90
[   46.769504]  ? filemap_map_pages+0x64f/0x760
[   46.769509]  ? do_fault+0x2a2/0x5a0
[   46.769513]  ? __handle_mm_fault+0x943/0xfb0
[   46.769518]  ? count_memcg_events+0xb6/0x170
[   46.769523]  ? handle_mm_fault+0xb2/0x2b0
[   46.769526]  ? do_user_addr_fault+0x212/0x6a0
[   46.769531]  entry_SYSCALL_64_after_hwframe+0x76/0x7e
[   46.769535] RIP: 0033:0x7f7222f20350
[   46.769538] Code: 40 00 48 8b 15 b1 aa 0d 00 f7 d8 64 89 02 48 c7 c0 ff ff ff ff eb b7 0f 1f 00 80 3d 91 32 0e 00 00 74 17 b8 01 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 58 c3 0f 1f 80 00 00 00 00 48 83 ec 28 48 89
[   46.769540] RSP: 002b:00007ffec1502588 EFLAGS: 00000202 ORIG_RAX: 0000000000000001
[   46.769542] RAX: ffffffffffffffda RBX: 000000000000000a RCX: 00007f7222f20350
[   46.769543] RDX: 000000000000000a RSI: 000055b8694a3c00 RDI: 0000000000000003
[   46.769544] RBP: 000055b8694a3c00 R08: 00007f7222ffc2e0 R09: 0000000000000073
[   46.769546] R10: 0000000000000000 R11: 0000000000000202 R12: 000000000000000a
[   46.769547] R13: 00007ffec1502610 R14: 000000000000000a R15: 00007f7222ff79e0
[   46.769549]  </TASK>
[   46.769550] ---[ end trace 0000000000000000 ]---
[   46.777982] bcache: bch_journal_replay() journal replay done, 4 keys in 3 entries, seq 75283
[   46.809306] bcache: register_cache() registered cache device dm-1
[   46.820987] bcache: register_bdev() registered backing device dm-3
[   46.850260] bcache: bch_cache_set_error() error on b2f0a7d0-0c65-44e6-8ea7-c2b2d66324ad: key too stale: 97, need_gc 97, disabling caching
[   46.850268] CPU: 4 UID: 0 PID: 4171 Comm: bch_dirtcnt[3] Tainted: G S   U  W   E       6.18.15 #1 PREEMPT(lazy)
[   46.850270] Tainted: [S]=CPU_OUT_OF_SPEC, [U]=USER, [W]=WARN, [E]=UNSIGNED_MODULE
[   46.850271] Hardware name: MINI Pro/Default string, BIOS MINI Pro V1.1 20250806 08/06/2025
[   46.850272] Call Trace:
[   46.850274]  <TASK>
[   46.850277]  dump_stack_lvl+0x64/0x80
[   46.850286]  bch_extent_bad+0x11e/0x170 [bcache]
[   46.850299]  ? __pfx_bch_ptr_bad+0x10/0x10 [bcache]
[   46.850305]  bch_btree_iter_next_filter+0x1b0/0x2e0 [bcache]
[   46.850311]  bch_btree_map_keys_recurse+0x7d/0x190 [bcache]
[   46.850317]  ? __pfx_sectors_dirty_init_fn+0x10/0x10 [bcache]
[   46.850324]  ? sched_balance_update_blocked_averages+0x5f8/0x710
[   46.850328]  ? bch_btree_node_get.part.0+0x1f6/0x2e0 [bcache]
[   46.850333]  ? __pfx_up_read+0x10/0x10
[   46.850335]  bch_root_node_dirty_init+0xdc/0x170 [bcache]
[   46.850342]  ? __pfx_autoremove_wake_function+0x10/0x10
[   46.850343]  bch_dirty_init_thread+0x11a/0x150 [bcache]
[   46.850349]  ? __pfx_bch_dirty_init_thread+0x10/0x10 [bcache]
[   46.850354]  kthread+0xfe/0x240
[   46.850356]  ? __pfx_kthread+0x10/0x10
[   46.850357]  ? __pfx_kthread+0x10/0x10
[   46.850357]  ret_from_fork+0x1cc/0x200
[   46.850360]  ? __pfx_kthread+0x10/0x10
[   46.850360]  ret_from_fork_asm+0x1a/0x30
[   46.850363]  </TASK>
[   46.851013] Buffer I/O error on dev bcache0, logical block 0, async page read
[   46.851027] ldm_validate_partition_table(): Disk read failed.
[   46.851032] Buffer I/O error on dev bcache0, logical block 0, async page read
[   46.851033] Dev bcache0: unable to read RDB block 0
[   46.851037] Buffer I/O error on dev bcache0, logical block 3, async page read
[   46.851039]  bcache0: unable to read partition table
[   46.851155] bcache: bch_cached_dev_attach() Caching dm-3 as bcache0 on set b2f0a7d0-0c65-44e6-8ea7-c2b2d66324ad
[   46.851296] bcache: conditional_stop_bcache_device() stop_when_cache_set_failed of bcache0 is "auto" and cache is dirty, stop it to avoid potential data corruption.
[   46.856117] bcache: cached_dev_detach_finish() Caching disabled for dm-3
[   46.881268] bcache: bcache_device_free() bcache0 stopped
[   47.089287] bcache: cache_set_free() Cache set b2f0a7d0-0c65-44e6-8ea7-c2b2d66324ad unregistered

Signed-off-by: Wale Zhang <[email protected]>
---
 drivers/md/bcache/alloc.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/md/bcache/alloc.c b/drivers/md/bcache/alloc.c
index 3ec240ec685d..460a6eed59ff 100644
--- a/drivers/md/bcache/alloc.c
+++ b/drivers/md/bcache/alloc.c
@@ -120,7 +120,12 @@ void bch_rescale_priorities(struct cache_set *c, int sectors)
 
 static inline bool can_inc_bucket_gen(struct bucket *b)
 {
-	return bucket_gc_gen(b) < BUCKET_GC_GEN_MAX;
+	/*
+	 * A bucket may be allocated for a btree node. When the node is freed,
+	 * make_btree_freeing_key() increments the bucket generation once more
+	 * without going through this check. Leave room for that increment.
+	 */
+	return bucket_gc_gen(b) < BUCKET_GC_GEN_MAX - 1;
 }
 
 bool bch_can_invalidate_bucket(struct cache *ca, struct bucket *b)
-- 
2.47.3
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.