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

bcache: treat stale && dirty keys as bad keys

Stale && dirty keys can be produced in the follow way:
After writeback in write_dirty_finish(), dirty keys k1 will
replace by clean keys k2
==>ret = bch_btree_insert(dc->disk.c, &keys, NULL, &w->key);
==>btree_insert_fn(struct btree_op *b_op, struct btree *b)
==>static int bch_btree_insert_node(struct btree *b,
struct btree_op *op,
struct keylist *insert_keys,
atomic_t *journal_ref,
Then two steps:
A) update k1 to k2 in btree node memory;
bch_btree_insert_keys(b, op, insert_keys, replace_key)
B) Write the bset(contains k2) to cache disk by a 30s delay work
bch_btree_leaf_dirty(b, journal_ref).
But before the 30s delay work write the bset to cache device,
these things happened:
A) GC works, and reclaim the bucket k2 point to;
B) Allocator works, and invalidate the bucket k2 point to,
and increase the gen of the bucket, and place it into free_inc
fifo;
C) Until now, the 30s delay work still does not finish work,
so in the disk, the key still is k1, it is dirty and stale
(its gen is smaller than the gen of the bucket). and then the
machine power off suddenly happens;
D) When the machine power on again, after the btree reconstruction,
the stale dirty key appear.

In bch_extent_bad(), when expensive_debug_checks is off, it would
treat the dirty key as good even it is stale keys, and it would
cause bellow probelms:
A) In read_dirty() it would cause machine crash:
BUG_ON(ptr_stale(dc->disk.c, &w->key, 0));
B) It could be worse when reads hits stale dirty keys, it would
read old incorrect data.

This patch tolerate the existence of these stale && dirty keys,
and treat them as bad key in bch_extent_bad().

(Coly Li: fix indent which was modified by sender's email client)

Signed-off-by: Tang Junhui <tang.junhui.linux@gmail.com>
Cc: stable@vger.kernel.org
Signed-off-by: Coly Li <colyli@suse.de>
Signed-off-by: Jens Axboe <axboe@kernel.dk>

authored by

Tang Junhui and committed by
Jens Axboe
58ac3230 e8cf978d

+7 -6
+7 -6
drivers/md/bcache/extents.c
··· 538 538 { 539 539 struct btree *b = container_of(bk, struct btree, keys); 540 540 unsigned int i, stale; 541 + char buf[80]; 541 542 542 543 if (!KEY_PTRS(k) || 543 544 bch_extent_invalid(bk, k)) ··· 548 547 if (!ptr_available(b->c, k, i)) 549 548 return true; 550 549 551 - if (!expensive_debug_checks(b->c) && KEY_DIRTY(k)) 552 - return false; 553 - 554 550 for (i = 0; i < KEY_PTRS(k); i++) { 555 551 stale = ptr_stale(b->c, k, i); 552 + 553 + if (stale && KEY_DIRTY(k)) { 554 + bch_extent_to_text(buf, sizeof(buf), k); 555 + pr_info("stale dirty pointer, stale %u, key: %s", 556 + stale, buf); 557 + } 556 558 557 559 btree_bug_on(stale > BUCKET_GC_GEN_MAX, b, 558 560 "key too stale: %i, need_gc %u", 559 561 stale, b->c->need_gc); 560 - 561 - btree_bug_on(stale && KEY_DIRTY(k) && KEY_SIZE(k), 562 - b, "stale dirty pointer"); 563 562 564 563 if (stale) 565 564 return true;