diff options
author | Kent Overstreet <kmo@daterainc.com> | 2013-12-16 17:12:09 -0500 |
---|---|---|
committer | Kent Overstreet <kmo@daterainc.com> | 2013-12-16 17:22:58 -0500 |
commit | 6d3d1a9c542b19dff1c7d7c8354d0869e4655287 (patch) | |
tree | 92afafc81797f8ad6ed2548e25f9818f7f67a8d4 /drivers/md | |
parent | bf0a628a95dba7f983b6047cea695fb066fb2512 (diff) |
bcache: bugfix for race between moving_gc and bucket_invalidate
There is a possibility for a bucket to be invalidated by the allocator
while moving_gc was copying it's contents to another bucket, if the
bucket only held cached data. To prevent this moving checks for
a stale ptr (to an invalidated bucket), before and after reads.
It it finds one, it simply ignores moving that data. This only
affects bcache if the moving_gc was turned on, note that it's
off by default.
Signed-off-by: Nicholas Swenson <nks@daterainc.com>
Signed-off-by: Kent Overstreet <kmo@daterainc.com>
Diffstat (limited to 'drivers/md')
-rw-r--r-- | drivers/md/bcache/movinggc.c | 10 |
1 files changed, 10 insertions, 0 deletions
diff --git a/drivers/md/bcache/movinggc.c b/drivers/md/bcache/movinggc.c index 30f347d4e609..f2f0998c4a91 100644 --- a/drivers/md/bcache/movinggc.c +++ b/drivers/md/bcache/movinggc.c | |||
@@ -64,11 +64,16 @@ static void write_moving_finish(struct closure *cl) | |||
64 | 64 | ||
65 | static void read_moving_endio(struct bio *bio, int error) | 65 | static void read_moving_endio(struct bio *bio, int error) |
66 | { | 66 | { |
67 | struct bbio *b = container_of(bio, struct bbio, bio); | ||
67 | struct moving_io *io = container_of(bio->bi_private, | 68 | struct moving_io *io = container_of(bio->bi_private, |
68 | struct moving_io, cl); | 69 | struct moving_io, cl); |
69 | 70 | ||
70 | if (error) | 71 | if (error) |
71 | io->op.error = error; | 72 | io->op.error = error; |
73 | else if (!KEY_DIRTY(&b->key) && | ||
74 | ptr_stale(io->op.c, &b->key, 0)) { | ||
75 | io->op.error = -EINTR; | ||
76 | } | ||
72 | 77 | ||
73 | bch_bbio_endio(io->op.c, bio, error, "reading data to move"); | 78 | bch_bbio_endio(io->op.c, bio, error, "reading data to move"); |
74 | } | 79 | } |
@@ -140,6 +145,11 @@ static void read_moving(struct cache_set *c) | |||
140 | if (!w) | 145 | if (!w) |
141 | break; | 146 | break; |
142 | 147 | ||
148 | if (ptr_stale(c, &w->key, 0)) { | ||
149 | bch_keybuf_del(&c->moving_gc_keys, w); | ||
150 | continue; | ||
151 | } | ||
152 | |||
143 | io = kzalloc(sizeof(struct moving_io) + sizeof(struct bio_vec) | 153 | io = kzalloc(sizeof(struct moving_io) + sizeof(struct bio_vec) |
144 | * DIV_ROUND_UP(KEY_SIZE(&w->key), PAGE_SECTORS), | 154 | * DIV_ROUND_UP(KEY_SIZE(&w->key), PAGE_SECTORS), |
145 | GFP_KERNEL); | 155 | GFP_KERNEL); |