summaryrefslogtreecommitdiff
path: root/libbcachefs/alloc_background.c
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2022-04-06 14:13:15 -0400
committerKent Overstreet <kent.overstreet@gmail.com>2022-04-06 14:13:15 -0400
commit790ca9522a96efe321aae36fb0d7f4e437110b0f (patch)
tree06b208f7671ee218bcaa11876a7fb37f1806f3d7 /libbcachefs/alloc_background.c
parent498874fdb71973c1856f35414bd607e58be16790 (diff)
Update bcachefs sources to e027cf9aa0 fixup! bcachefs: Defer checking of alloc -> lru refs until after RW
Diffstat (limited to 'libbcachefs/alloc_background.c')
-rw-r--r--libbcachefs/alloc_background.c342
1 files changed, 193 insertions, 149 deletions
diff --git a/libbcachefs/alloc_background.c b/libbcachefs/alloc_background.c
index e8a34ecc..6d6798ae 100644
--- a/libbcachefs/alloc_background.c
+++ b/libbcachefs/alloc_background.c
@@ -302,71 +302,57 @@ static unsigned bch_alloc_v1_val_u64s(const struct bch_alloc *a)
return DIV_ROUND_UP(bytes, sizeof(u64));
}
-const char *bch2_alloc_v1_invalid(const struct bch_fs *c, struct bkey_s_c k)
+int bch2_alloc_v1_invalid(const struct bch_fs *c, struct bkey_s_c k,
+ int rw, struct printbuf *err)
{
struct bkey_s_c_alloc a = bkey_s_c_to_alloc(k);
- if (k.k->p.inode >= c->sb.nr_devices ||
- !c->devs[k.k->p.inode])
- return "invalid device";
-
/* allow for unknown fields */
- if (bkey_val_u64s(a.k) < bch_alloc_v1_val_u64s(a.v))
- return "incorrect value size";
+ if (bkey_val_u64s(a.k) < bch_alloc_v1_val_u64s(a.v)) {
+ pr_buf(err, "incorrect value size (%zu < %u)",
+ bkey_val_u64s(a.k), bch_alloc_v1_val_u64s(a.v));
+ return -EINVAL;
+ }
- return NULL;
+ return 0;
}
-const char *bch2_alloc_v2_invalid(const struct bch_fs *c, struct bkey_s_c k)
+int bch2_alloc_v2_invalid(const struct bch_fs *c, struct bkey_s_c k,
+ int rw, struct printbuf *err)
{
struct bkey_alloc_unpacked u;
- if (k.k->p.inode >= c->sb.nr_devices ||
- !c->devs[k.k->p.inode])
- return "invalid device";
-
- if (bch2_alloc_unpack_v2(&u, k))
- return "unpack error";
+ if (bch2_alloc_unpack_v2(&u, k)) {
+ pr_buf(err, "unpack error");
+ return -EINVAL;
+ }
- return NULL;
+ return 0;
}
-const char *bch2_alloc_v3_invalid(const struct bch_fs *c, struct bkey_s_c k)
+int bch2_alloc_v3_invalid(const struct bch_fs *c, struct bkey_s_c k,
+ int rw, struct printbuf *err)
{
struct bkey_alloc_unpacked u;
- struct bch_dev *ca;
-
- if (k.k->p.inode >= c->sb.nr_devices ||
- !c->devs[k.k->p.inode])
- return "invalid device";
-
- ca = bch_dev_bkey_exists(c, k.k->p.inode);
-
- if (k.k->p.offset < ca->mi.first_bucket ||
- k.k->p.offset >= ca->mi.nbuckets)
- return "invalid bucket";
- if (bch2_alloc_unpack_v3(&u, k))
- return "unpack error";
+ if (bch2_alloc_unpack_v3(&u, k)) {
+ pr_buf(err, "unpack error");
+ return -EINVAL;
+ }
- return NULL;
+ return 0;
}
-const char *bch2_alloc_v4_invalid(const struct bch_fs *c, struct bkey_s_c k)
+int bch2_alloc_v4_invalid(const struct bch_fs *c, struct bkey_s_c k,
+ int rw, struct printbuf *err)
{
- struct bch_dev *ca;
-
- if (k.k->p.inode >= c->sb.nr_devices ||
- !c->devs[k.k->p.inode])
- return "invalid device";
-
- ca = bch_dev_bkey_exists(c, k.k->p.inode);
-
- if (k.k->p.offset < ca->mi.first_bucket ||
- k.k->p.offset >= ca->mi.nbuckets)
- return "invalid bucket";
+ if (bkey_val_bytes(k.k) != sizeof(struct bch_alloc_v4)) {
+ pr_buf(err, "bad val size (%zu != %zu)",
+ bkey_val_bytes(k.k), sizeof(struct bch_alloc_v4));
+ return -EINVAL;
+ }
- return NULL;
+ return 0;
}
void bch2_alloc_v4_swab(struct bkey_s k)
@@ -562,7 +548,8 @@ static int bch2_check_alloc_key(struct btree_trans *trans,
struct btree_iter *alloc_iter)
{
struct bch_fs *c = trans->c;
- struct btree_iter discard_iter, freespace_iter, lru_iter;
+ struct bch_dev *ca;
+ struct btree_iter discard_iter, freespace_iter;
struct bch_alloc_v4 a;
unsigned discard_key_type, freespace_key_type;
struct bkey_s_c alloc_k, k;
@@ -578,7 +565,16 @@ static int bch2_check_alloc_key(struct btree_trans *trans,
if (ret)
return ret;
+ if (fsck_err_on(!bch2_dev_bucket_exists(c, alloc_k.k->p), c,
+ "alloc key for invalid device or bucket"))
+ return bch2_btree_delete_at(trans, alloc_iter, 0);
+
+ ca = bch_dev_bkey_exists(c, alloc_k.k->p.inode);
+ if (!ca->mi.freespace_initialized)
+ return 0;
+
bch2_alloc_to_v4(alloc_k, &a);
+
discard_key_type = bucket_state(a) == BUCKET_need_discard
? KEY_TYPE_set : 0;
freespace_key_type = bucket_state(a) == BUCKET_free
@@ -588,8 +584,6 @@ static int bch2_check_alloc_key(struct btree_trans *trans,
alloc_k.k->p, 0);
bch2_trans_iter_init(trans, &freespace_iter, BTREE_ID_freespace,
alloc_freespace_pos(alloc_k.k->p, a), 0);
- bch2_trans_iter_init(trans, &lru_iter, BTREE_ID_lru,
- POS(alloc_k.k->p.inode, a.io_time[READ]), 0);
k = bch2_btree_iter_peek_slot(&discard_iter);
ret = bkey_err(k);
@@ -613,8 +607,7 @@ static int bch2_check_alloc_key(struct btree_trans *trans,
update->k.type = discard_key_type;
update->k.p = discard_iter.pos;
- ret = bch2_trans_update(trans, &discard_iter, update, 0) ?:
- bch2_trans_commit(trans, NULL, NULL, 0);
+ ret = bch2_trans_update(trans, &discard_iter, update, 0);
if (ret)
goto err;
}
@@ -643,65 +636,12 @@ static int bch2_check_alloc_key(struct btree_trans *trans,
update->k.p = freespace_iter.pos;
bch2_key_resize(&update->k, 1);
- ret = bch2_trans_update(trans, &freespace_iter, update, 0) ?:
- bch2_trans_commit(trans, NULL, NULL, 0);
+ ret = bch2_trans_update(trans, &freespace_iter, update, 0);
if (ret)
goto err;
}
-
- if (bucket_state(a) == BUCKET_cached) {
- k = bch2_btree_iter_peek_slot(&lru_iter);
- ret = bkey_err(k);
- if (ret)
- goto err;
-
- if (fsck_err_on(!a.io_time[READ], c,
- "cached bucket with read_time 0\n"
- " %s",
- (printbuf_reset(&buf),
- bch2_bkey_val_to_text(&buf, c, alloc_k), buf.buf)) ||
- fsck_err_on(k.k->type != KEY_TYPE_lru ||
- le64_to_cpu(bkey_s_c_to_lru(k).v->idx) != alloc_k.k->p.offset, c,
- "incorrect/missing lru entry\n"
- " %s\n"
- " %s",
- (printbuf_reset(&buf),
- bch2_bkey_val_to_text(&buf, c, alloc_k), buf.buf),
- (bch2_bkey_val_to_text(&buf2, c, k), buf2.buf))) {
- u64 read_time = a.io_time[READ];
-
- if (!a.io_time[READ])
- a.io_time[READ] = atomic64_read(&c->io_clock[READ].now);
-
- ret = bch2_lru_change(trans,
- alloc_k.k->p.inode,
- alloc_k.k->p.offset,
- 0, &a.io_time[READ]);
- if (ret)
- goto err;
-
- if (a.io_time[READ] != read_time) {
- struct bkey_i_alloc_v4 *a_mut =
- bch2_alloc_to_v4_mut(trans, alloc_k);
- ret = PTR_ERR_OR_ZERO(a_mut);
- if (ret)
- goto err;
-
- a_mut->v.io_time[READ] = a.io_time[READ];
- ret = bch2_trans_update(trans, alloc_iter,
- &a_mut->k_i, BTREE_TRIGGER_NORUN);
- if (ret)
- goto err;
- }
-
- ret = bch2_trans_commit(trans, NULL, NULL, 0);
- if (ret)
- goto err;
- }
- }
err:
fsck_err:
- bch2_trans_iter_exit(trans, &lru_iter);
bch2_trans_iter_exit(trans, &freespace_iter);
bch2_trans_iter_exit(trans, &discard_iter);
printbuf_exit(&buf2);
@@ -709,21 +649,8 @@ fsck_err:
return ret;
}
-static inline bool bch2_dev_bucket_exists(struct bch_fs *c, struct bpos pos)
-{
- struct bch_dev *ca;
-
- if (pos.inode >= c->sb.nr_devices || !c->devs[pos.inode])
- return false;
-
- ca = bch_dev_bkey_exists(c, pos.inode);
- return pos.offset >= ca->mi.first_bucket &&
- pos.offset < ca->mi.nbuckets;
-}
-
-static int bch2_check_freespace_key(struct btree_trans *trans,
- struct btree_iter *freespace_iter,
- bool initial)
+static int bch2_check_discard_freespace_key(struct btree_trans *trans,
+ struct btree_iter *iter)
{
struct bch_fs *c = trans->c;
struct btree_iter alloc_iter;
@@ -732,10 +659,13 @@ static int bch2_check_freespace_key(struct btree_trans *trans,
u64 genbits;
struct bpos pos;
struct bkey_i *update;
+ enum bucket_state state = iter->btree_id == BTREE_ID_need_discard
+ ? BUCKET_need_discard
+ : BUCKET_free;
struct printbuf buf = PRINTBUF;
int ret;
- freespace_k = bch2_btree_iter_peek(freespace_iter);
+ freespace_k = bch2_btree_iter_peek(iter);
if (!freespace_k.k)
return 1;
@@ -743,15 +673,16 @@ static int bch2_check_freespace_key(struct btree_trans *trans,
if (ret)
return ret;
- pos = freespace_iter->pos;
+ pos = iter->pos;
pos.offset &= ~(~0ULL << 56);
- genbits = freespace_iter->pos.offset & (~0ULL << 56);
+ genbits = iter->pos.offset & (~0ULL << 56);
bch2_trans_iter_init(trans, &alloc_iter, BTREE_ID_alloc, pos, 0);
if (fsck_err_on(!bch2_dev_bucket_exists(c, pos), c,
- "%llu:%llu set in freespace btree but device or bucket does not exist",
- pos.inode, pos.offset))
+ "%llu:%llu set in %s btree but device or bucket does not exist",
+ pos.inode, pos.offset,
+ bch2_btree_ids[iter->btree_id]))
goto delete;
k = bch2_btree_iter_peek_slot(&alloc_iter);
@@ -761,11 +692,13 @@ static int bch2_check_freespace_key(struct btree_trans *trans,
bch2_alloc_to_v4(k, &a);
- if (fsck_err_on(bucket_state(a) != BUCKET_free ||
- genbits != alloc_freespace_genbits(a), c,
- "%s\n incorrectly set in freespace index (free %u, genbits %llu should be %llu)",
+ if (fsck_err_on(bucket_state(a) != state ||
+ (state == BUCKET_free &&
+ genbits != alloc_freespace_genbits(a)), c,
+ "%s\n incorrectly set in %s index (free %u, genbits %llu should be %llu)",
(bch2_bkey_val_to_text(&buf, c, k), buf.buf),
- bucket_state(a) == BUCKET_free,
+ bch2_btree_ids[iter->btree_id],
+ bucket_state(a) == state,
genbits >> 56, alloc_freespace_genbits(a) >> 56))
goto delete;
out:
@@ -775,46 +708,54 @@ fsck_err:
printbuf_exit(&buf);
return ret;
delete:
- update = bch2_trans_kmalloc(trans, sizeof(*update));
- ret = PTR_ERR_OR_ZERO(update);
- if (ret)
- goto err;
+ if (iter->btree_id == BTREE_ID_freespace) {
+ /* should probably add a helper for deleting extents */
+ update = bch2_trans_kmalloc(trans, sizeof(*update));
+ ret = PTR_ERR_OR_ZERO(update);
+ if (ret)
+ goto err;
- bkey_init(&update->k);
- update->k.p = freespace_iter->pos;
- bch2_key_resize(&update->k, 1);
+ bkey_init(&update->k);
+ update->k.p = iter->pos;
+ bch2_key_resize(&update->k, 1);
- ret = bch2_trans_update(trans, freespace_iter, update, 0) ?:
- bch2_trans_commit(trans, NULL, NULL, 0);
+ ret = bch2_trans_update(trans, iter, update, 0);
+ } else {
+ ret = bch2_btree_delete_at(trans, iter, 0);
+ }
goto out;
}
-int bch2_check_alloc_info(struct bch_fs *c, bool initial)
+int bch2_check_alloc_info(struct bch_fs *c)
{
struct btree_trans trans;
struct btree_iter iter;
struct bkey_s_c k;
- int ret = 0, last_dev = -1;
+ int ret = 0;
bch2_trans_init(&trans, c, 0, 0);
for_each_btree_key(&trans, iter, BTREE_ID_alloc, POS_MIN,
BTREE_ITER_PREFETCH, k, ret) {
- if (k.k->p.inode != last_dev) {
- struct bch_dev *ca = bch_dev_bkey_exists(c, k.k->p.inode);
-
- if (!ca->mi.freespace_initialized) {
- bch2_btree_iter_set_pos(&iter, POS(k.k->p.inode + 1, 0));
- continue;
- }
+ ret = __bch2_trans_do(&trans, NULL, NULL, 0,
+ bch2_check_alloc_key(&trans, &iter));
+ if (ret)
+ break;
+ }
+ bch2_trans_iter_exit(&trans, &iter);
- last_dev = k.k->p.inode;
- }
+ if (ret)
+ goto err;
+ bch2_trans_iter_init(&trans, &iter, BTREE_ID_need_discard, POS_MIN,
+ BTREE_ITER_PREFETCH);
+ while (1) {
ret = __bch2_trans_do(&trans, NULL, NULL, 0,
- bch2_check_alloc_key(&trans, &iter));
+ bch2_check_discard_freespace_key(&trans, &iter));
if (ret)
break;
+
+ bch2_btree_iter_set_pos(&iter, bpos_nosnap_successor(iter.pos));
}
bch2_trans_iter_exit(&trans, &iter);
@@ -825,7 +766,7 @@ int bch2_check_alloc_info(struct bch_fs *c, bool initial)
BTREE_ITER_PREFETCH);
while (1) {
ret = __bch2_trans_do(&trans, NULL, NULL, 0,
- bch2_check_freespace_key(&trans, &iter, initial));
+ bch2_check_discard_freespace_key(&trans, &iter));
if (ret)
break;
@@ -837,6 +778,109 @@ err:
return ret < 0 ? ret : 0;
}
+static int bch2_check_alloc_to_lru_ref(struct btree_trans *trans,
+ struct btree_iter *alloc_iter)
+{
+ struct bch_fs *c = trans->c;
+ struct btree_iter lru_iter;
+ struct bch_alloc_v4 a;
+ struct bkey_s_c alloc_k, k;
+ struct printbuf buf = PRINTBUF;
+ struct printbuf buf2 = PRINTBUF;
+ int ret;
+
+ alloc_k = bch2_btree_iter_peek(alloc_iter);
+ if (!alloc_k.k)
+ return 0;
+
+ ret = bkey_err(alloc_k);
+ if (ret)
+ return ret;
+
+ bch2_alloc_to_v4(alloc_k, &a);
+
+ if (bucket_state(a) != BUCKET_cached)
+ return 0;
+
+ bch2_trans_iter_init(trans, &lru_iter, BTREE_ID_lru,
+ POS(alloc_k.k->p.inode, a.io_time[READ]), 0);
+
+ k = bch2_btree_iter_peek_slot(&lru_iter);
+ ret = bkey_err(k);
+ if (ret)
+ goto err;
+
+ if (fsck_err_on(!a.io_time[READ], c,
+ "cached bucket with read_time 0\n"
+ " %s",
+ (printbuf_reset(&buf),
+ bch2_bkey_val_to_text(&buf, c, alloc_k), buf.buf)) ||
+ fsck_err_on(k.k->type != KEY_TYPE_lru ||
+ le64_to_cpu(bkey_s_c_to_lru(k).v->idx) != alloc_k.k->p.offset, c,
+ "incorrect/missing lru entry\n"
+ " %s\n"
+ " %s",
+ (printbuf_reset(&buf),
+ bch2_bkey_val_to_text(&buf, c, alloc_k), buf.buf),
+ (bch2_bkey_val_to_text(&buf2, c, k), buf2.buf))) {
+ u64 read_time = a.io_time[READ];
+
+ if (!a.io_time[READ])
+ a.io_time[READ] = atomic64_read(&c->io_clock[READ].now);
+
+ ret = bch2_lru_change(trans,
+ alloc_k.k->p.inode,
+ alloc_k.k->p.offset,
+ 0, &a.io_time[READ]);
+ if (ret)
+ goto err;
+
+ if (a.io_time[READ] != read_time) {
+ struct bkey_i_alloc_v4 *a_mut =
+ bch2_alloc_to_v4_mut(trans, alloc_k);
+ ret = PTR_ERR_OR_ZERO(a_mut);
+ if (ret)
+ goto err;
+
+ a_mut->v.io_time[READ] = a.io_time[READ];
+ ret = bch2_trans_update(trans, alloc_iter,
+ &a_mut->k_i, BTREE_TRIGGER_NORUN);
+ if (ret)
+ goto err;
+ }
+ }
+err:
+fsck_err:
+ bch2_trans_iter_exit(trans, &lru_iter);
+ printbuf_exit(&buf2);
+ printbuf_exit(&buf);
+ return ret;
+}
+
+int bch2_check_alloc_to_lru_refs(struct bch_fs *c)
+{
+ struct btree_trans trans;
+ struct btree_iter iter;
+ struct bkey_s_c k;
+ int ret = 0;
+
+ bch2_trans_init(&trans, c, 0, 0);
+
+ for_each_btree_key(&trans, iter, BTREE_ID_alloc, POS_MIN,
+ BTREE_ITER_PREFETCH, k, ret) {
+ ret = __bch2_trans_do(&trans, NULL, NULL,
+ BTREE_INSERT_NOFAIL|
+ BTREE_INSERT_LAZY_RW,
+ bch2_check_alloc_to_lru_ref(&trans, &iter));
+ if (ret)
+ break;
+ }
+ bch2_trans_iter_exit(&trans, &iter);
+
+ bch2_trans_exit(&trans);
+ return ret < 0 ? ret : 0;
+}
+
static int bch2_clear_need_discard(struct btree_trans *trans, struct bpos pos,
struct bch_dev *ca, bool *discard_done)
{