| From 627ccd20b4ad3ba836472468208e2ac4dfadbf03 Mon Sep 17 00:00:00 2001 |
| From: Kent Overstreet <kent.overstreet@gmail.com> |
| Date: Sun, 29 Nov 2015 18:47:01 -0800 |
| Subject: bcache: Change refill_dirty() to always scan entire disk if necessary |
| |
| From: Kent Overstreet <kent.overstreet@gmail.com> |
| |
| commit 627ccd20b4ad3ba836472468208e2ac4dfadbf03 upstream. |
| |
| 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> |
| Signed-off-by: Jens Axboe <axboe@fb.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/md/bcache/writeback.c | 37 ++++++++++++++++++++++++++++++------- |
| 1 file changed, 30 insertions(+), 7 deletions(-) |
| |
| --- a/drivers/md/bcache/writeback.c |
| +++ b/drivers/md/bcache/writeback.c |
| @@ -323,6 +323,10 @@ void bcache_dev_sectors_dirty_add(struct |
| |
| 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_d |
| 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) |