diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2015-11-29 21:47:01 -0500 |
---|---|---|
committer | Jens Axboe <axboe@fb.com> | 2015-12-30 22:23:16 -0500 |
commit | 627ccd20b4ad3ba836472468208e2ac4dfadbf03 (patch) | |
tree | a784e113c005e53ba3d86f27c3f9a0c59bd55de6 | |
parent | 8d16ce540c94c9d366eb36fc91b7154d92d6397b (diff) |
bcache: Change refill_dirty() to always scan entire disk if necessary
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>
-rw-r--r-- | drivers/md/bcache/writeback.c | 37 |
1 files changed, 30 insertions, 7 deletions
diff --git a/drivers/md/bcache/writeback.c b/drivers/md/bcache/writeback.c index b23f88d9f18c..b9346cd9cda1 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, | |||
323 | 323 | ||
324 | static bool dirty_pred(struct keybuf *buf, struct bkey *k) | 324 | static bool dirty_pred(struct keybuf *buf, struct bkey *k) |
325 | { | 325 | { |
326 | struct cached_dev *dc = container_of(buf, struct cached_dev, writeback_keys); | ||
327 | |||
328 | BUG_ON(KEY_INODE(k) != dc->disk.id); | ||
329 | |||
326 | return KEY_DIRTY(k); | 330 | return KEY_DIRTY(k); |
327 | } | 331 | } |
328 | 332 | ||
@@ -372,11 +376,24 @@ next: | |||
372 | } | 376 | } |
373 | } | 377 | } |
374 | 378 | ||
379 | /* | ||
380 | * Returns true if we scanned the entire disk | ||
381 | */ | ||
375 | static bool refill_dirty(struct cached_dev *dc) | 382 | static bool refill_dirty(struct cached_dev *dc) |
376 | { | 383 | { |
377 | struct keybuf *buf = &dc->writeback_keys; | 384 | struct keybuf *buf = &dc->writeback_keys; |
385 | struct bkey start = KEY(dc->disk.id, 0, 0); | ||
378 | struct bkey end = KEY(dc->disk.id, MAX_KEY_OFFSET, 0); | 386 | struct bkey end = KEY(dc->disk.id, MAX_KEY_OFFSET, 0); |
379 | bool searched_from_start = false; | 387 | struct bkey start_pos; |
388 | |||
389 | /* | ||
390 | * make sure keybuf pos is inside the range for this disk - at bringup | ||
391 | * we might not be attached yet so this disk's inode nr isn't | ||
392 | * initialized then | ||
393 | */ | ||
394 | if (bkey_cmp(&buf->last_scanned, &start) < 0 || | ||
395 | bkey_cmp(&buf->last_scanned, &end) > 0) | ||
396 | buf->last_scanned = start; | ||
380 | 397 | ||
381 | if (dc->partial_stripes_expensive) { | 398 | if (dc->partial_stripes_expensive) { |
382 | refill_full_stripes(dc); | 399 | refill_full_stripes(dc); |
@@ -384,14 +401,20 @@ static bool refill_dirty(struct cached_dev *dc) | |||
384 | return false; | 401 | return false; |
385 | } | 402 | } |
386 | 403 | ||
387 | if (bkey_cmp(&buf->last_scanned, &end) >= 0) { | 404 | start_pos = buf->last_scanned; |
388 | buf->last_scanned = KEY(dc->disk.id, 0, 0); | ||
389 | searched_from_start = true; | ||
390 | } | ||
391 | |||
392 | bch_refill_keybuf(dc->disk.c, buf, &end, dirty_pred); | 405 | bch_refill_keybuf(dc->disk.c, buf, &end, dirty_pred); |
393 | 406 | ||
394 | return bkey_cmp(&buf->last_scanned, &end) >= 0 && searched_from_start; | 407 | if (bkey_cmp(&buf->last_scanned, &end) < 0) |
408 | return false; | ||
409 | |||
410 | /* | ||
411 | * If we get to the end start scanning again from the beginning, and | ||
412 | * only scan up to where we initially started scanning from: | ||
413 | */ | ||
414 | buf->last_scanned = start; | ||
415 | bch_refill_keybuf(dc->disk.c, buf, &start_pos, dirty_pred); | ||
416 | |||
417 | return bkey_cmp(&buf->last_scanned, &start_pos) >= 0; | ||
395 | } | 418 | } |
396 | 419 | ||
397 | static int bch_writeback_thread(void *arg) | 420 | static int bch_writeback_thread(void *arg) |