#include "backpointers.h"
#include "btree_cache.h"
#include "btree_update.h"
+#include "btree_write_buffer.h"
#include "error.h"
#include <linux/mm.h>
struct bch_backpointer bp,
struct bkey_s_c orig_k,
struct bpos bucket_start,
- struct bpos bucket_end)
+ struct bpos bucket_end,
+ struct bpos *last_flushed_pos)
{
struct bch_fs *c = trans->c;
struct btree_iter alloc_iter, bp_iter = { NULL };
goto err;
if (bp_k.k->type != KEY_TYPE_backpointer ||
- memcmp(bkey_s_c_to_backpointer(bp_k).v, &bp, sizeof(bp)))
+ memcmp(bkey_s_c_to_backpointer(bp_k).v, &bp, sizeof(bp))) {
+ if (!bpos_eq(*last_flushed_pos, orig_k.k->p)) {
+ *last_flushed_pos = orig_k.k->p;
+ ret = bch2_btree_write_buffer_flush_sync(trans) ?:
+ -BCH_ERR_transaction_restart_write_buffer_flush;
+ goto out;
+ }
goto missing;
+ }
out:
err:
fsck_err:
printbuf_exit(&buf);
return ret;
missing:
+
prt_printf(&buf, "missing backpointer for btree=%s l=%u ",
bch2_btree_ids[bp.btree_id], bp.level);
bch2_bkey_val_to_text(&buf, c, orig_k);
static int check_extent_to_backpointers(struct btree_trans *trans,
struct btree_iter *iter,
struct bpos bucket_start,
- struct bpos bucket_end)
+ struct bpos bucket_end,
+ struct bpos *last_flushed_pos)
{
struct bch_fs *c = trans->c;
struct bkey_ptrs_c ptrs;
bch2_extent_ptr_to_bp(c, iter->btree_id, iter->path->level,
k, p, &bucket_pos, &bp);
- ret = check_bp_exists(trans, bucket_pos, bp, k, bucket_start, bucket_end);
+ ret = check_bp_exists(trans, bucket_pos, bp, k,
+ bucket_start, bucket_end,
+ last_flushed_pos);
if (ret)
return ret;
}
static int check_btree_root_to_backpointers(struct btree_trans *trans,
enum btree_id btree_id,
struct bpos bucket_start,
- struct bpos bucket_end)
+ struct bpos bucket_end,
+ struct bpos *last_flushed_pos)
{
struct bch_fs *c = trans->c;
struct btree_iter iter;
bch2_extent_ptr_to_bp(c, iter.btree_id, iter.path->level + 1,
k, p, &bucket_pos, &bp);
- ret = check_bp_exists(trans, bucket_pos, bp, k, bucket_start, bucket_end);
+ ret = check_bp_exists(trans, bucket_pos, bp, k,
+ bucket_start, bucket_end,
+ last_flushed_pos);
if (ret)
goto err;
}
{
struct btree_iter iter;
enum btree_id btree_id;
+ struct bpos last_flushed_pos = SPOS_MAX;
int ret = 0;
for (btree_id = 0; btree_id < BTREE_ID_NR; btree_id++) {
BTREE_INSERT_LAZY_RW|
BTREE_INSERT_NOFAIL,
check_extent_to_backpointers(trans, &iter,
- bucket_start, bucket_end));
+ bucket_start, bucket_end,
+ &last_flushed_pos));
if (ret)
break;
} while (!bch2_btree_iter_advance(&iter));
BTREE_INSERT_LAZY_RW|
BTREE_INSERT_NOFAIL,
check_btree_root_to_backpointers(trans, btree_id,
- bucket_start, bucket_end));
+ bucket_start, bucket_end,
+ &last_flushed_pos));
if (ret)
break;
}