92 lines
2.9 KiB
Diff
92 lines
2.9 KiB
Diff
From: Kent Overstreet <kent.overstreet@gmail.com>
|
|
Date: Sun, 29 Nov 2015 18:47:01 -0800
|
|
Subject: [8/8] bcache: Change refill_dirty() to always scan entire disk if
|
|
necessary
|
|
Origin: https://git.kernel.org/cgit/linux/kernel/git/axboe/linux-block.git/commit?id=627ccd20b4ad3ba836472468208e2ac4dfadbf03
|
|
|
|
Previously, it would only scan the entire disk if it was starting from
|
|
the very start of the disk - i.e. if the previous scan got to the end.
|
|
|
|
This was broken by refill_full_stripes(), which updates last_scanned so
|
|
that refill_dirty was never triggering the searched_from_start path.
|
|
|
|
But if we change refill_dirty() to always scan the entire disk if
|
|
necessary, regardless of what last_scanned was, the code gets cleaner
|
|
and we fix that bug too.
|
|
|
|
Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
|
|
Cc: stable@vger.kernel.org
|
|
Signed-off-by: Jens Axboe <axboe@fb.com>
|
|
---
|
|
drivers/md/bcache/writeback.c | 37 ++++++++++++++++++++++++++++++-------
|
|
1 file changed, 30 insertions(+), 7 deletions(-)
|
|
|
|
diff --git a/drivers/md/bcache/writeback.c b/drivers/md/bcache/writeback.c
|
|
index b23f88d..b9346cd 100644
|
|
--- a/drivers/md/bcache/writeback.c
|
|
+++ b/drivers/md/bcache/writeback.c
|
|
@@ -323,6 +323,10 @@ void bcache_dev_sectors_dirty_add(struct cache_set *c, unsigned inode,
|
|
|
|
static bool dirty_pred(struct keybuf *buf, struct bkey *k)
|
|
{
|
|
+ struct cached_dev *dc = container_of(buf, struct cached_dev, writeback_keys);
|
|
+
|
|
+ BUG_ON(KEY_INODE(k) != dc->disk.id);
|
|
+
|
|
return KEY_DIRTY(k);
|
|
}
|
|
|
|
@@ -372,11 +376,24 @@ next:
|
|
}
|
|
}
|
|
|
|
+/*
|
|
+ * Returns true if we scanned the entire disk
|
|
+ */
|
|
static bool refill_dirty(struct cached_dev *dc)
|
|
{
|
|
struct keybuf *buf = &dc->writeback_keys;
|
|
+ struct bkey start = KEY(dc->disk.id, 0, 0);
|
|
struct bkey end = KEY(dc->disk.id, MAX_KEY_OFFSET, 0);
|
|
- bool searched_from_start = false;
|
|
+ struct bkey start_pos;
|
|
+
|
|
+ /*
|
|
+ * make sure keybuf pos is inside the range for this disk - at bringup
|
|
+ * we might not be attached yet so this disk's inode nr isn't
|
|
+ * initialized then
|
|
+ */
|
|
+ if (bkey_cmp(&buf->last_scanned, &start) < 0 ||
|
|
+ bkey_cmp(&buf->last_scanned, &end) > 0)
|
|
+ buf->last_scanned = start;
|
|
|
|
if (dc->partial_stripes_expensive) {
|
|
refill_full_stripes(dc);
|
|
@@ -384,14 +401,20 @@ static bool refill_dirty(struct cached_dev *dc)
|
|
return false;
|
|
}
|
|
|
|
- if (bkey_cmp(&buf->last_scanned, &end) >= 0) {
|
|
- buf->last_scanned = KEY(dc->disk.id, 0, 0);
|
|
- searched_from_start = true;
|
|
- }
|
|
-
|
|
+ start_pos = buf->last_scanned;
|
|
bch_refill_keybuf(dc->disk.c, buf, &end, dirty_pred);
|
|
|
|
- return bkey_cmp(&buf->last_scanned, &end) >= 0 && searched_from_start;
|
|
+ if (bkey_cmp(&buf->last_scanned, &end) < 0)
|
|
+ return false;
|
|
+
|
|
+ /*
|
|
+ * If we get to the end start scanning again from the beginning, and
|
|
+ * only scan up to where we initially started scanning from:
|
|
+ */
|
|
+ buf->last_scanned = start;
|
|
+ bch_refill_keybuf(dc->disk.c, buf, &start_pos, dirty_pred);
|
|
+
|
|
+ return bkey_cmp(&buf->last_scanned, &start_pos) >= 0;
|
|
}
|
|
|
|
static int bch_writeback_thread(void *arg)
|