diff options
author | Eric Wheeler <git@linux.ewheeler.net> | 2016-02-26 17:39:06 -0500 |
---|---|---|
committer | Jens Axboe <axboe@fb.com> | 2016-03-08 11:17:30 -0500 |
commit | 07cc6ef8edc47f8b4fc1e276d31127a0a5863d4d (patch) | |
tree | f70c53b8aa72129040a75222086ed6590d63bd3e /drivers/md | |
parent | 08095e70783f1d8296f858d37a9e1878f5da0623 (diff) |
bcache: fix race of writeback thread starting before complete initialization
The bch_writeback_thread might BUG_ON in read_dirty() if
dc->sb==BDEV_STATE_DIRTY and bch_sectors_dirty_init has not yet completed
its related initialization. This patch downs the dc->writeback_lock until
after initialization is complete, thus preventing bch_writeback_thread
from proceeding prematurely.
See this thread:
http://thread.gmane.org/gmane.linux.kernel.bcache.devel/3453
Signed-off-by: Eric Wheeler <bcache@linux.ewheeler.net>
Tested-by: Marc MERLIN <marc@merlins.org>
Cc: <stable@vger.kernel.org>
Signed-off-by: Jens Axboe <axboe@fb.com>
Diffstat (limited to 'drivers/md')
-rw-r--r-- | drivers/md/bcache/super.c | 9 |
1 files changed, 8 insertions, 1 deletions
diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index 8d0ead98eb6e..b411c73bfeb3 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c | |||
@@ -1015,8 +1015,12 @@ int bch_cached_dev_attach(struct cached_dev *dc, struct cache_set *c) | |||
1015 | */ | 1015 | */ |
1016 | atomic_set(&dc->count, 1); | 1016 | atomic_set(&dc->count, 1); |
1017 | 1017 | ||
1018 | if (bch_cached_dev_writeback_start(dc)) | 1018 | /* Block writeback thread, but spawn it */ |
1019 | down_write(&dc->writeback_lock); | ||
1020 | if (bch_cached_dev_writeback_start(dc)) { | ||
1021 | up_write(&dc->writeback_lock); | ||
1019 | return -ENOMEM; | 1022 | return -ENOMEM; |
1023 | } | ||
1020 | 1024 | ||
1021 | if (BDEV_STATE(&dc->sb) == BDEV_STATE_DIRTY) { | 1025 | if (BDEV_STATE(&dc->sb) == BDEV_STATE_DIRTY) { |
1022 | bch_sectors_dirty_init(dc); | 1026 | bch_sectors_dirty_init(dc); |
@@ -1028,6 +1032,9 @@ int bch_cached_dev_attach(struct cached_dev *dc, struct cache_set *c) | |||
1028 | bch_cached_dev_run(dc); | 1032 | bch_cached_dev_run(dc); |
1029 | bcache_device_link(&dc->disk, c, "bdev"); | 1033 | bcache_device_link(&dc->disk, c, "bdev"); |
1030 | 1034 | ||
1035 | /* Allow the writeback thread to proceed */ | ||
1036 | up_write(&dc->writeback_lock); | ||
1037 | |||
1031 | pr_info("Caching %s as %s on set %pU", | 1038 | pr_info("Caching %s as %s on set %pU", |
1032 | bdevname(dc->bdev, buf), dc->disk.disk->disk_name, | 1039 | bdevname(dc->bdev, buf), dc->disk.disk->disk_name, |
1033 | dc->disk.c->sb.set_uuid); | 1040 | dc->disk.c->sb.set_uuid); |