Commit 1568ee7e authored by Guoju Fang's avatar Guoju Fang Committed by Jens Axboe

bcache: fix crashes stopping bcache device before read miss done

The bio from upper layer is considered completed when bio_complete()
returns. In most scenarios bio_complete() is called in search_free(),
but when read miss happens, the bio_compete() is called when backing
device reading completed, while the struct search is still in use until
cache inserting finished.

If someone stops the bcache device just then, the device may be closed
and released, but after cache inserting finished the struct search will
access a freed struct cached_dev.

This patch add the reference of bcache device before bio_complete() when
read miss happens, and put it after the search is not used.
Signed-off-by: default avatarGuoju Fang <fangguoju@gmail.com>
Signed-off-by: default avatarColy Li <colyli@suse.de>
Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent 0257c0ed
...@@ -706,14 +706,14 @@ static void search_free(struct closure *cl) ...@@ -706,14 +706,14 @@ static void search_free(struct closure *cl)
{ {
struct search *s = container_of(cl, struct search, cl); struct search *s = container_of(cl, struct search, cl);
atomic_dec(&s->d->c->search_inflight); atomic_dec(&s->iop.c->search_inflight);
if (s->iop.bio) if (s->iop.bio)
bio_put(s->iop.bio); bio_put(s->iop.bio);
bio_complete(s); bio_complete(s);
closure_debug_destroy(cl); closure_debug_destroy(cl);
mempool_free(s, &s->d->c->search); mempool_free(s, &s->iop.c->search);
} }
static inline struct search *search_alloc(struct bio *bio, static inline struct search *search_alloc(struct bio *bio,
...@@ -756,13 +756,13 @@ static void cached_dev_bio_complete(struct closure *cl) ...@@ -756,13 +756,13 @@ static void cached_dev_bio_complete(struct closure *cl)
struct search *s = container_of(cl, struct search, cl); struct search *s = container_of(cl, struct search, cl);
struct cached_dev *dc = container_of(s->d, struct cached_dev, disk); struct cached_dev *dc = container_of(s->d, struct cached_dev, disk);
search_free(cl);
cached_dev_put(dc); cached_dev_put(dc);
search_free(cl);
} }
/* Process reads */ /* Process reads */
static void cached_dev_cache_miss_done(struct closure *cl) static void cached_dev_read_error_done(struct closure *cl)
{ {
struct search *s = container_of(cl, struct search, cl); struct search *s = container_of(cl, struct search, cl);
...@@ -800,7 +800,22 @@ static void cached_dev_read_error(struct closure *cl) ...@@ -800,7 +800,22 @@ static void cached_dev_read_error(struct closure *cl)
closure_bio_submit(s->iop.c, bio, cl); closure_bio_submit(s->iop.c, bio, cl);
} }
continue_at(cl, cached_dev_cache_miss_done, NULL); continue_at(cl, cached_dev_read_error_done, NULL);
}
static void cached_dev_cache_miss_done(struct closure *cl)
{
struct search *s = container_of(cl, struct search, cl);
struct bcache_device *d = s->d;
if (s->iop.replace_collision)
bch_mark_cache_miss_collision(s->iop.c, s->d);
if (s->iop.bio)
bio_free_pages(s->iop.bio);
cached_dev_bio_complete(cl);
closure_put(&d->cl);
} }
static void cached_dev_read_done(struct closure *cl) static void cached_dev_read_done(struct closure *cl)
...@@ -833,6 +848,7 @@ static void cached_dev_read_done(struct closure *cl) ...@@ -833,6 +848,7 @@ static void cached_dev_read_done(struct closure *cl)
if (verify(dc) && s->recoverable && !s->read_dirty_data) if (verify(dc) && s->recoverable && !s->read_dirty_data)
bch_data_verify(dc, s->orig_bio); bch_data_verify(dc, s->orig_bio);
closure_get(&dc->disk.cl);
bio_complete(s); bio_complete(s);
if (s->iop.bio && if (s->iop.bio &&
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment