summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2015-08-21 00:32:20 -0800
committerKent Overstreet <kent.overstreet@gmail.com>2016-10-07 09:21:25 -0800
commitad6d9b7d545817af82f635659ca720377caab230 (patch)
tree5af37c3c1a75c88273151172d5b803b53d40874c
parentc429d08d9667437f9cbb711c1072b6ea40a96053 (diff)
bcache: don't overrun buffer in bch_data_insert()
Need to drop old stale pointers before adding new ones Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
-rw-r--r--drivers/md/bcache/extents.c43
-rw-r--r--drivers/md/bcache/extents.h1
-rw-r--r--drivers/md/bcache/request.c5
3 files changed, 29 insertions, 20 deletions
diff --git a/drivers/md/bcache/extents.c b/drivers/md/bcache/extents.c
index 0ad774f66193..43b855d42fe9 100644
--- a/drivers/md/bcache/extents.c
+++ b/drivers/md/bcache/extents.c
@@ -102,14 +102,6 @@ static bool should_drop_ptr(struct cache_set *c, const struct bkey *k,
ptr_stale(c, ca, k, ptr);
}
-static unsigned PTR_TIER(struct cache_set *c, const struct bkey *k,
- unsigned ptr)
-{
- unsigned dev = PTR_DEV(k, ptr);
-
- return dev < c->sb.nr_in_set ? CACHE_TIER(&c->members[dev]) : UINT_MAX;
-}
-
unsigned bch_extent_nr_ptrs_after_normalize(struct cache_set *c,
const struct bkey *k)
{
@@ -127,16 +119,9 @@ unsigned bch_extent_nr_ptrs_after_normalize(struct cache_set *c,
return ret;
}
-bool bch_extent_normalize(struct cache_set *c, struct bkey *k)
+void bch_extent_drop_stale(struct cache_set *c, struct bkey *k)
{
unsigned i = 0;
- bool swapped;
-
- if (!KEY_SIZE(k)) {
- bch_set_extent_ptrs(k, 0);
- SET_KEY_DELETED(k, true);
- return true;
- }
rcu_read_lock();
@@ -149,6 +134,30 @@ bool bch_extent_normalize(struct cache_set *c, struct bkey *k)
} else
i++;
+ rcu_read_unlock();
+}
+
+static unsigned PTR_TIER(struct cache_set *c, const struct bkey *k,
+ unsigned ptr)
+{
+ unsigned dev = PTR_DEV(k, ptr);
+
+ return dev < c->sb.nr_in_set ? CACHE_TIER(&c->members[dev]) : UINT_MAX;
+}
+
+bool bch_extent_normalize(struct cache_set *c, struct bkey *k)
+{
+ unsigned i;
+ bool swapped;
+
+ if (!KEY_SIZE(k)) {
+ bch_set_extent_ptrs(k, 0);
+ SET_KEY_DELETED(k, true);
+ return true;
+ }
+
+ bch_extent_drop_stale(c, k);
+
/* Bubble sort pointers by tier, lowest (fastest) tier first */
do {
swapped = false;
@@ -160,8 +169,6 @@ bool bch_extent_normalize(struct cache_set *c, struct bkey *k)
}
} while (swapped);
- rcu_read_unlock();
-
if (!bch_extent_ptrs(k))
SET_KEY_DELETED(k, true);
diff --git a/drivers/md/bcache/extents.h b/drivers/md/bcache/extents.h
index 0912064a4e07..e4bb64accc6b 100644
--- a/drivers/md/bcache/extents.h
+++ b/drivers/md/bcache/extents.h
@@ -25,6 +25,7 @@ struct cache *bch_extent_pick_ptr(struct cache_set *, const struct bkey *,
unsigned bch_extent_nr_ptrs_after_normalize(struct cache_set *,
const struct bkey *);
+void bch_extent_drop_stale(struct cache_set *, struct bkey *);
bool bch_extent_normalize(struct cache_set *, struct bkey *);
static inline unsigned bch_extent_ptrs(const struct bkey *k)
diff --git a/drivers/md/bcache/request.c b/drivers/md/bcache/request.c
index f05a73dfdcbd..08f82223c0ef 100644
--- a/drivers/md/bcache/request.c
+++ b/drivers/md/bcache/request.c
@@ -318,11 +318,12 @@ static void bch_data_insert_start(struct closure *cl)
(KEY_CSUM(&op->insert_key) ? 1 : 0)))
continue_at(cl, bch_data_insert_keys, op->c->wq);
- memset(ptrs_to_write, 0, sizeof(ptrs_to_write));
-
k = op->insert_keys.top;
bkey_copy(k, &op->insert_key);
+ bch_extent_drop_stale(op->c, k);
+ memset(ptrs_to_write, 0, sizeof(ptrs_to_write));
+
b = op->moving_gc
? bch_gc_alloc_sectors(op->c, k, ptrs_to_write, cl)
: bch_alloc_sectors(op->c, k, op->write_point, op->tier,