summaryrefslogtreecommitdiff
path: root/drivers/md
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/md')
-rw-r--r--drivers/md/bcache/request.c108
1 files changed, 46 insertions, 62 deletions
diff --git a/drivers/md/bcache/request.c b/drivers/md/bcache/request.c
index 854743e85e76..de3fc76ffcfc 100644
--- a/drivers/md/bcache/request.c
+++ b/drivers/md/bcache/request.c
@@ -663,86 +663,70 @@ static void bch_cache_read_endio(struct bio *bio, int error)
bch_bbio_endio(s->op.c, bio, error, "reading from cache");
}
-static int submit_partial_cache_miss(struct btree *b, struct search *s,
- struct bkey *k)
-{
- struct bio *bio = &s->bio.bio;
- int ret = MAP_CONTINUE;
-
- do {
- unsigned sectors = INT_MAX;
-
- if (KEY_INODE(k) == s->op.inode) {
- if (KEY_START(k) <= bio->bi_sector)
- break;
-
- sectors = min_t(uint64_t, sectors,
- KEY_START(k) - bio->bi_sector);
- }
-
- ret = s->d->cache_miss(b, s, bio, sectors);
- } while (ret == MAP_CONTINUE);
-
- return ret;
-}
-
/*
* Read from a single key, handling the initial cache miss if the key starts in
* the middle of the bio
*/
-static int submit_partial_cache_hit(struct btree_op *op, struct btree *b,
- struct bkey *k)
+static int cache_lookup_fn(struct btree_op *op, struct btree *b, struct bkey *k)
{
struct search *s = container_of(op, struct search, op);
- struct bio *bio = &s->bio.bio;
+ struct bio *n, *bio = &s->bio.bio;
+ struct bkey *bio_key;
unsigned ptr;
- struct bio *n;
- int ret = submit_partial_cache_miss(b, s, k);
- if (ret != MAP_CONTINUE || !KEY_SIZE(k))
- return ret;
+ if (bkey_cmp(k, &KEY(op->inode, bio->bi_sector, 0)) <= 0)
+ return MAP_CONTINUE;
+
+ if (KEY_INODE(k) != s->op.inode ||
+ KEY_START(k) > bio->bi_sector) {
+ unsigned bio_sectors = bio_sectors(bio);
+ unsigned sectors = KEY_INODE(k) == s->op.inode
+ ? min_t(uint64_t, INT_MAX,
+ KEY_START(k) - bio->bi_sector)
+ : INT_MAX;
+
+ int ret = s->d->cache_miss(b, s, bio, sectors);
+ if (ret != MAP_CONTINUE)
+ return ret;
+
+ /* if this was a complete miss we shouldn't get here */
+ BUG_ON(bio_sectors <= sectors);
+ }
+
+ if (!KEY_SIZE(k))
+ return MAP_CONTINUE;
/* XXX: figure out best pointer - for multiple cache devices */
ptr = 0;
PTR_BUCKET(b->c, k, ptr)->prio = INITIAL_PRIO;
- while (ret == MAP_CONTINUE &&
- KEY_INODE(k) == op->inode &&
- bio->bi_sector < KEY_OFFSET(k)) {
- struct bkey *bio_key;
- sector_t sector = PTR_OFFSET(k, ptr) +
- (bio->bi_sector - KEY_START(k));
- unsigned sectors = min_t(uint64_t, INT_MAX,
- KEY_OFFSET(k) - bio->bi_sector);
-
- n = bch_bio_split(bio, sectors, GFP_NOIO, s->d->bio_split);
- if (n == bio)
- ret = MAP_DONE;
-
- bio_key = &container_of(n, struct bbio, bio)->key;
+ n = bch_bio_split(bio, min_t(uint64_t, INT_MAX,
+ KEY_OFFSET(k) - bio->bi_sector),
+ GFP_NOIO, s->d->bio_split);
- /*
- * The bucket we're reading from might be reused while our bio
- * is in flight, and we could then end up reading the wrong
- * data.
- *
- * We guard against this by checking (in cache_read_endio()) if
- * the pointer is stale again; if so, we treat it as an error
- * and reread from the backing device (but we don't pass that
- * error up anywhere).
- */
+ bio_key = &container_of(n, struct bbio, bio)->key;
+ bch_bkey_copy_single_ptr(bio_key, k, ptr);
- bch_bkey_copy_single_ptr(bio_key, k, ptr);
- SET_PTR_OFFSET(bio_key, 0, sector);
+ bch_cut_front(&KEY(s->op.inode, n->bi_sector, 0), bio_key);
+ bch_cut_back(&KEY(s->op.inode, bio_end_sector(n), 0), bio_key);
- n->bi_end_io = bch_cache_read_endio;
- n->bi_private = &s->cl;
+ n->bi_end_io = bch_cache_read_endio;
+ n->bi_private = &s->cl;
- __bch_submit_bbio(n, b->c);
- }
+ /*
+ * The bucket we're reading from might be reused while our bio
+ * is in flight, and we could then end up reading the wrong
+ * data.
+ *
+ * We guard against this by checking (in cache_read_endio()) if
+ * the pointer is stale again; if so, we treat it as an error
+ * and reread from the backing device (but we don't pass that
+ * error up anywhere).
+ */
- return ret;
+ __bch_submit_bbio(n, b->c);
+ return n == bio ? MAP_DONE : MAP_CONTINUE;
}
static void cache_lookup(struct closure *cl)
@@ -753,7 +737,7 @@ static void cache_lookup(struct closure *cl)
int ret = bch_btree_map_keys(op, op->c,
&KEY(op->inode, bio->bi_sector, 0),
- submit_partial_cache_hit, 1);
+ cache_lookup_fn, MAP_END_KEY);
if (ret == -EAGAIN)
continue_at(cl, cache_lookup, bcache_wq);