Commit d39881d2 authored by Kent Overstreet's avatar Kent Overstreet

bcachefs: add check for missing fragmentation in check_alloc_to_lru_ref()

We need to make sure we're not missing any fragmenation entries in the
LRU BTREE after repairing ALLOC BTREE

Also, use the new bch2_btree_write_buffer_maybe_flush() helper; this was
only working without it before since bucket invalidation (usually)
wasn't happening while fsck was running.
Co-developed-by: default avatarDaniel Hill <daniel@gluo.nz>
Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent 92e1c29a
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include "alloc_background.h" #include "alloc_background.h"
#include "alloc_foreground.h" #include "alloc_foreground.h"
#include "backpointers.h" #include "backpointers.h"
#include "bkey_buf.h"
#include "btree_cache.h" #include "btree_cache.h"
#include "btree_io.h" #include "btree_io.h"
#include "btree_key_cache.h" #include "btree_key_cache.h"
...@@ -1553,13 +1554,13 @@ int bch2_check_alloc_info(struct bch_fs *c) ...@@ -1553,13 +1554,13 @@ int bch2_check_alloc_info(struct bch_fs *c)
} }
static int bch2_check_alloc_to_lru_ref(struct btree_trans *trans, static int bch2_check_alloc_to_lru_ref(struct btree_trans *trans,
struct btree_iter *alloc_iter) struct btree_iter *alloc_iter,
struct bkey_buf *last_flushed)
{ {
struct bch_fs *c = trans->c; struct bch_fs *c = trans->c;
struct btree_iter lru_iter;
struct bch_alloc_v4 a_convert; struct bch_alloc_v4 a_convert;
const struct bch_alloc_v4 *a; const struct bch_alloc_v4 *a;
struct bkey_s_c alloc_k, lru_k; struct bkey_s_c alloc_k;
struct printbuf buf = PRINTBUF; struct printbuf buf = PRINTBUF;
int ret; int ret;
...@@ -1573,6 +1574,14 @@ static int bch2_check_alloc_to_lru_ref(struct btree_trans *trans, ...@@ -1573,6 +1574,14 @@ static int bch2_check_alloc_to_lru_ref(struct btree_trans *trans,
a = bch2_alloc_to_v4(alloc_k, &a_convert); a = bch2_alloc_to_v4(alloc_k, &a_convert);
if (a->fragmentation_lru) {
ret = bch2_lru_check_set(trans, BCH_LRU_FRAGMENTATION_START,
a->fragmentation_lru,
alloc_k, last_flushed);
if (ret)
return ret;
}
if (a->data_type != BCH_DATA_cached) if (a->data_type != BCH_DATA_cached)
return 0; return 0;
...@@ -1597,41 +1606,30 @@ static int bch2_check_alloc_to_lru_ref(struct btree_trans *trans, ...@@ -1597,41 +1606,30 @@ static int bch2_check_alloc_to_lru_ref(struct btree_trans *trans,
a = &a_mut->v; a = &a_mut->v;
} }
lru_k = bch2_bkey_get_iter(trans, &lru_iter, BTREE_ID_lru, ret = bch2_lru_check_set(trans, alloc_k.k->p.inode, a->io_time[READ],
lru_pos(alloc_k.k->p.inode, alloc_k, last_flushed);
bucket_to_u64(alloc_k.k->p),
a->io_time[READ]), 0);
ret = bkey_err(lru_k);
if (ret)
return ret;
if (fsck_err_on(lru_k.k->type != KEY_TYPE_set, c,
alloc_key_to_missing_lru_entry,
"missing lru entry\n"
" %s",
(printbuf_reset(&buf),
bch2_bkey_val_to_text(&buf, c, alloc_k), buf.buf))) {
ret = bch2_lru_set(trans,
alloc_k.k->p.inode,
bucket_to_u64(alloc_k.k->p),
a->io_time[READ]);
if (ret) if (ret)
goto err; goto err;
}
err: err:
fsck_err: fsck_err:
bch2_trans_iter_exit(trans, &lru_iter);
printbuf_exit(&buf); printbuf_exit(&buf);
return ret; return ret;
} }
int bch2_check_alloc_to_lru_refs(struct bch_fs *c) int bch2_check_alloc_to_lru_refs(struct bch_fs *c)
{ {
struct bkey_buf last_flushed;
bch2_bkey_buf_init(&last_flushed);
bkey_init(&last_flushed.k->k);
int ret = bch2_trans_run(c, int ret = bch2_trans_run(c,
for_each_btree_key_commit(trans, iter, BTREE_ID_alloc, for_each_btree_key_commit(trans, iter, BTREE_ID_alloc,
POS_MIN, BTREE_ITER_prefetch, k, POS_MIN, BTREE_ITER_prefetch, k,
NULL, NULL, BCH_TRANS_COMMIT_no_enospc, NULL, NULL, BCH_TRANS_COMMIT_no_enospc,
bch2_check_alloc_to_lru_ref(trans, &iter))); bch2_check_alloc_to_lru_ref(trans, &iter, &last_flushed)));
bch2_bkey_buf_exit(&last_flushed, c);
bch_err_fn(c, ret); bch_err_fn(c, ret);
return ret; return ret;
} }
......
...@@ -77,6 +77,45 @@ static const char * const bch2_lru_types[] = { ...@@ -77,6 +77,45 @@ static const char * const bch2_lru_types[] = {
NULL NULL
}; };
int bch2_lru_check_set(struct btree_trans *trans,
u16 lru_id, u64 time,
struct bkey_s_c referring_k,
struct bkey_buf *last_flushed)
{
struct bch_fs *c = trans->c;
struct printbuf buf = PRINTBUF;
struct btree_iter lru_iter;
struct bkey_s_c lru_k =
bch2_bkey_get_iter(trans, &lru_iter, BTREE_ID_lru,
lru_pos(lru_id,
bucket_to_u64(referring_k.k->p),
time), 0);
int ret = bkey_err(lru_k);
if (ret)
return ret;
if (lru_k.k->type != KEY_TYPE_set) {
ret = bch2_btree_write_buffer_maybe_flush(trans, referring_k, last_flushed);
if (ret)
goto err;
if (fsck_err(c, alloc_key_to_missing_lru_entry,
"missing %s lru entry\n"
" %s",
bch2_lru_types[lru_type(lru_k)],
(bch2_bkey_val_to_text(&buf, c, referring_k), buf.buf))) {
ret = bch2_lru_set(trans, lru_id, bucket_to_u64(referring_k.k->p), time);
if (ret)
goto err;
}
}
err:
fsck_err:
bch2_trans_iter_exit(trans, &lru_iter);
printbuf_exit(&buf);
return ret;
}
static int bch2_check_lru_key(struct btree_trans *trans, static int bch2_check_lru_key(struct btree_trans *trans,
struct btree_iter *lru_iter, struct btree_iter *lru_iter,
struct bkey_s_c lru_k, struct bkey_s_c lru_k,
......
...@@ -61,6 +61,9 @@ int bch2_lru_del(struct btree_trans *, u16, u64, u64); ...@@ -61,6 +61,9 @@ int bch2_lru_del(struct btree_trans *, u16, u64, u64);
int bch2_lru_set(struct btree_trans *, u16, u64, u64); int bch2_lru_set(struct btree_trans *, u16, u64, u64);
int bch2_lru_change(struct btree_trans *, u16, u64, u64, u64); int bch2_lru_change(struct btree_trans *, u16, u64, u64, u64);
struct bkey_buf;
int bch2_lru_check_set(struct btree_trans *, u16, u64, struct bkey_s_c, struct bkey_buf *);
int bch2_check_lrus(struct bch_fs *); int bch2_check_lrus(struct bch_fs *);
#endif /* _BCACHEFS_LRU_H */ #endif /* _BCACHEFS_LRU_H */
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