Update bcachefs sources to af2c94ff96a4 bcachefs: Fix FORTIFY_SOURCE warning in replicas.c
Some checks failed
build / bcachefs-tools-msrv (push) Has been cancelled
.deb build orchestrator / publish (push) Has been cancelled
.deb build orchestrator / source-only (push) Has been cancelled
.deb build orchestrator / obs (push) Has been cancelled
.deb build orchestrator / buildd (map[name:debian version:forky], map[build-arch:amd64 host-arch:amd64 machine-arch:amd64 runs-on:ubuntu-24.04]) (push) Has been cancelled
.deb build orchestrator / buildd (map[name:debian version:forky], map[build-arch:amd64 host-arch:ppc64el machine-arch:amd64 runs-on:ubuntu-24.04]) (push) Has been cancelled
.deb build orchestrator / buildd (map[name:debian version:forky], map[build-arch:arm64 host-arch:arm64 machine-arch:arm64 runs-on:ubuntu-24.04-arm]) (push) Has been cancelled
.deb build orchestrator / buildd (map[name:debian version:trixie], map[build-arch:amd64 host-arch:amd64 machine-arch:amd64 runs-on:ubuntu-24.04]) (push) Has been cancelled
.deb build orchestrator / buildd (map[name:debian version:trixie], map[build-arch:amd64 host-arch:ppc64el machine-arch:amd64 runs-on:ubuntu-24.04]) (push) Has been cancelled
.deb build orchestrator / buildd (map[name:debian version:trixie], map[build-arch:arm64 host-arch:arm64 machine-arch:arm64 runs-on:ubuntu-24.04-arm]) (push) Has been cancelled
.deb build orchestrator / buildd (map[name:debian version:unstable], map[build-arch:amd64 host-arch:amd64 machine-arch:amd64 runs-on:ubuntu-24.04]) (push) Has been cancelled
.deb build orchestrator / buildd (map[name:debian version:unstable], map[build-arch:amd64 host-arch:ppc64el machine-arch:amd64 runs-on:ubuntu-24.04]) (push) Has been cancelled
.deb build orchestrator / buildd (map[name:debian version:unstable], map[build-arch:arm64 host-arch:arm64 machine-arch:arm64 runs-on:ubuntu-24.04-arm]) (push) Has been cancelled
.deb build orchestrator / buildd (map[name:ubuntu version:plucky], map[build-arch:amd64 host-arch:amd64 machine-arch:amd64 runs-on:ubuntu-24.04]) (push) Has been cancelled
.deb build orchestrator / buildd (map[name:ubuntu version:plucky], map[build-arch:arm64 host-arch:arm64 machine-arch:arm64 runs-on:ubuntu-24.04-arm]) (push) Has been cancelled
.deb build orchestrator / buildd (map[name:ubuntu version:questing], map[build-arch:amd64 host-arch:amd64 machine-arch:amd64 runs-on:ubuntu-24.04]) (push) Has been cancelled
.deb build orchestrator / buildd (map[name:ubuntu version:questing], map[build-arch:arm64 host-arch:arm64 machine-arch:arm64 runs-on:ubuntu-24.04-arm]) (push) Has been cancelled
.deb build orchestrator / reprotest (push) Has been cancelled
Nix Flake actions / nix-matrix (push) Has been cancelled
Nix Flake actions / ${{ matrix.name }} (${{ matrix.system }}) (push) Has been cancelled

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
Kent Overstreet 2025-12-05 12:04:01 -05:00
parent d93ad5bbaa
commit 55833908f7
8 changed files with 147 additions and 181 deletions

View File

@ -1 +1 @@
656fe6ab62bd41321e90e1567e6bf9c3ea058633 af2c94ff96a44454a785878c6674fcf210c5a426

View File

@ -104,20 +104,33 @@ void bch2_dev_usage_to_text(struct printbuf *out,
prt_printf(out, "capacity\t%llu\r\n", ca->mi.nbuckets); prt_printf(out, "capacity\t%llu\r\n", ca->mi.nbuckets);
} }
struct ptrs_repair {
u8 drop;
u8 drop_stripe;
u8 reset_gen;
};
static inline int drop_this_ptr(struct ptrs_repair *r, unsigned ptr_bit)
{
r->drop |= ptr_bit;
return 0;
}
static int bch2_check_fix_ptr(struct btree_trans *trans, static int bch2_check_fix_ptr(struct btree_trans *trans,
struct bkey_s_c k, struct bkey_s_c k,
struct extent_ptr_decoded p, struct extent_ptr_decoded p,
const union bch_extent_entry *entry, const union bch_extent_entry *entry,
bool *do_update) struct ptrs_repair *r,
unsigned ptr_bit)
{ {
if (p.ptr.dev == BCH_SB_MEMBER_INVALID)
return 0;
struct bch_fs *c = trans->c; struct bch_fs *c = trans->c;
CLASS(printbuf, buf)(); CLASS(printbuf, buf)();
CLASS(bch2_dev_tryget_noerror, ca)(c, p.ptr.dev); CLASS(bch2_dev_tryget_noerror, ca)(c, p.ptr.dev);
if (!ca) { if (!ca) {
if (p.ptr.dev == BCH_SB_MEMBER_INVALID)
return 0;
if (test_bit(p.ptr.dev, c->devs_removed.d)) { if (test_bit(p.ptr.dev, c->devs_removed.d)) {
if (ret_fsck_err(trans, ptr_to_removed_device, if (ret_fsck_err(trans, ptr_to_removed_device,
"pointer to removed device %u\n" "pointer to removed device %u\n"
@ -125,7 +138,7 @@ static int bch2_check_fix_ptr(struct btree_trans *trans,
p.ptr.dev, p.ptr.dev,
(printbuf_reset(&buf), (printbuf_reset(&buf),
bch2_bkey_val_to_text(&buf, c, k), buf.buf))) bch2_bkey_val_to_text(&buf, c, k), buf.buf)))
*do_update = true; return drop_this_ptr(r, ptr_bit);
} else { } else {
if (ret_fsck_err(trans, ptr_to_invalid_device, if (ret_fsck_err(trans, ptr_to_invalid_device,
"pointer to missing device %u\n" "pointer to missing device %u\n"
@ -133,7 +146,7 @@ static int bch2_check_fix_ptr(struct btree_trans *trans,
p.ptr.dev, p.ptr.dev,
(printbuf_reset(&buf), (printbuf_reset(&buf),
bch2_bkey_val_to_text(&buf, c, k), buf.buf))) bch2_bkey_val_to_text(&buf, c, k), buf.buf)))
*do_update = true; return drop_this_ptr(r, ptr_bit);
} }
return 0; return 0;
} }
@ -146,7 +159,7 @@ static int bch2_check_fix_ptr(struct btree_trans *trans,
p.ptr.dev, p.ptr.dev,
(printbuf_reset(&buf), (printbuf_reset(&buf),
bch2_bkey_val_to_text(&buf, c, k), buf.buf))) bch2_bkey_val_to_text(&buf, c, k), buf.buf)))
*do_update = true; return drop_this_ptr(r, ptr_bit);
return 0; return 0;
} }
@ -161,14 +174,11 @@ static int bch2_check_fix_ptr(struct btree_trans *trans,
p.ptr.gen, p.ptr.gen,
(printbuf_reset(&buf), (printbuf_reset(&buf),
bch2_bkey_val_to_text(&buf, c, k), buf.buf))) { bch2_bkey_val_to_text(&buf, c, k), buf.buf))) {
if (!p.ptr.cached) { if (p.ptr.cached)
g->gen_valid = true; return drop_this_ptr(r, ptr_bit);
g->gen = p.ptr.gen;
} else { g->gen_valid = true;
/* this pointer will be dropped */ g->gen = p.ptr.gen;
*do_update = true;
return 0;
}
} }
/* g->gen_valid == true */ /* g->gen_valid == true */
@ -182,39 +192,38 @@ static int bch2_check_fix_ptr(struct btree_trans *trans,
p.ptr.gen, g->gen, p.ptr.gen, g->gen,
(printbuf_reset(&buf), (printbuf_reset(&buf),
bch2_bkey_val_to_text(&buf, c, k), buf.buf))) { bch2_bkey_val_to_text(&buf, c, k), buf.buf))) {
if (!p.ptr.cached && if (p.ptr.cached)
(g->data_type != BCH_DATA_btree || return drop_this_ptr(r, ptr_bit);
data_type == BCH_DATA_btree)) {
g->data_type = data_type;
g->stripe_sectors = 0;
g->dirty_sectors = 0;
g->cached_sectors = 0;
}
*do_update = true; /* XXX: if it's a data pointer, read it and see if it's good */
r->reset_gen |= ptr_bit;
} }
if (ret_fsck_err_on(gen_cmp(g->gen, p.ptr.gen) > BUCKET_GC_GEN_MAX, if (!p.ptr.cached) {
trans, ptr_gen_newer_than_bucket_gen, if (ret_fsck_err_on(gen_cmp(p.ptr.gen, g->gen) < 0,
"bucket %u:%zu gen %u data type %s: ptr gen %u too stale\n" trans, stale_dirty_ptr,
"while marking %s", "bucket %u:%zu data type %s stale dirty ptr: %u < %u\n"
p.ptr.dev, PTR_BUCKET_NR(ca, &p.ptr), g->gen, "while marking %s",
bch2_data_type_str(ptr_data_type(k.k, &p.ptr)), p.ptr.dev, PTR_BUCKET_NR(ca, &p.ptr),
p.ptr.gen, bch2_data_type_str(ptr_data_type(k.k, &p.ptr)),
(printbuf_reset(&buf), p.ptr.gen, g->gen,
bch2_bkey_val_to_text(&buf, c, k), buf.buf))) (printbuf_reset(&buf),
*do_update = true; bch2_bkey_val_to_text(&buf, c, k), buf.buf))) {
/* XXX: if it's a data pointer, read it and see if it's good */
if (ret_fsck_err_on(!p.ptr.cached && gen_cmp(p.ptr.gen, g->gen) < 0, r->reset_gen |= ptr_bit;
trans, stale_dirty_ptr, }
"bucket %u:%zu data type %s stale dirty ptr: %u < %u\n" } else {
"while marking %s", if (ret_fsck_err_on(gen_cmp(g->gen, p.ptr.gen) > BUCKET_GC_GEN_MAX,
p.ptr.dev, PTR_BUCKET_NR(ca, &p.ptr), trans, ptr_gen_newer_than_bucket_gen,
bch2_data_type_str(ptr_data_type(k.k, &p.ptr)), "bucket %u:%zu gen %u data type %s: ptr gen %u too stale\n"
p.ptr.gen, g->gen, "while marking %s",
(printbuf_reset(&buf), p.ptr.dev, PTR_BUCKET_NR(ca, &p.ptr), g->gen,
bch2_bkey_val_to_text(&buf, c, k), buf.buf))) bch2_data_type_str(ptr_data_type(k.k, &p.ptr)),
*do_update = true; p.ptr.gen,
(printbuf_reset(&buf),
bch2_bkey_val_to_text(&buf, c, k), buf.buf)))
return drop_this_ptr(r, ptr_bit);
}
if (data_type != BCH_DATA_btree && p.ptr.gen != g->gen) if (data_type != BCH_DATA_btree && p.ptr.gen != g->gen)
return 0; return 0;
@ -228,24 +237,23 @@ static int bch2_check_fix_ptr(struct btree_trans *trans,
bch2_data_type_str(data_type), bch2_data_type_str(data_type),
(printbuf_reset(&buf), (printbuf_reset(&buf),
bch2_bkey_val_to_text(&buf, c, k), buf.buf))) { bch2_bkey_val_to_text(&buf, c, k), buf.buf))) {
if (!p.ptr.cached && if (p.ptr.cached ||
data_type == BCH_DATA_btree) { data_type != BCH_DATA_btree)
switch (g->data_type) { return drop_this_ptr(r, ptr_bit);
case BCH_DATA_sb:
bch_err(c, "btree and superblock in the same bucket - cannot repair");
return bch_err_throw(c, fsck_repair_unimplemented);
case BCH_DATA_journal:
try(bch2_dev_journal_bucket_delete(ca, PTR_BUCKET_NR(ca, &p.ptr)));
break;
}
g->data_type = data_type; switch (g->data_type) {
g->stripe_sectors = 0; case BCH_DATA_sb:
g->dirty_sectors = 0; bch_err(c, "btree and superblock in the same bucket - cannot repair");
g->cached_sectors = 0; return bch_err_throw(c, fsck_repair_unimplemented);
} else { case BCH_DATA_journal:
*do_update = true; try(bch2_dev_journal_bucket_delete(ca, PTR_BUCKET_NR(ca, &p.ptr)));
break;
} }
g->data_type = data_type;
g->stripe_sectors = 0;
g->dirty_sectors = 0;
g->cached_sectors = 0;
} }
if (p.has_ec) { if (p.has_ec) {
@ -257,126 +265,67 @@ static int bch2_check_fix_ptr(struct btree_trans *trans,
"while marking %s", "while marking %s",
(u64) p.ec.idx, (u64) p.ec.idx,
(printbuf_reset(&buf), (printbuf_reset(&buf),
bch2_bkey_val_to_text(&buf, c, k), buf.buf))) bch2_bkey_val_to_text(&buf, c, k), buf.buf)) ||
*do_update = true; ret_fsck_err_on(m && m->alive && !bch2_ptr_matches_stripe_m(m, p),
if (ret_fsck_err_on(m && m->alive && !bch2_ptr_matches_stripe_m(m, p),
trans, ptr_to_incorrect_stripe, trans, ptr_to_incorrect_stripe,
"pointer does not match stripe %llu\n" "pointer does not match stripe %llu\n"
"while marking %s", "while marking %s",
(u64) p.ec.idx, (u64) p.ec.idx,
(printbuf_reset(&buf), (printbuf_reset(&buf),
bch2_bkey_val_to_text(&buf, c, k), buf.buf))) bch2_bkey_val_to_text(&buf, c, k), buf.buf)))
*do_update = true; r->drop_stripe |= ptr_bit;
} }
return 0; return 0;
} }
static bool should_drop_ptr(struct bch_fs *c, struct bkey_s_c k,
struct extent_ptr_decoded p,
const union bch_extent_entry *entry)
{
struct bch_dev *ca = bch2_dev_rcu_noerror(c, p.ptr.dev);
if (!ca)
return true;
struct bucket *g = PTR_GC_BUCKET(ca, &p.ptr);
enum bch_data_type data_type = bch2_bkey_ptr_data_type(k, p, entry);
if (p.ptr.cached) {
return !g->gen_valid || gen_cmp(p.ptr.gen, g->gen);
} else {
return gen_cmp(p.ptr.gen, g->gen) < 0 ||
gen_cmp(g->gen, p.ptr.gen) > BUCKET_GC_GEN_MAX ||
(g->data_type && g->data_type != data_type);
}
}
int bch2_check_fix_ptrs(struct btree_trans *trans, int bch2_check_fix_ptrs(struct btree_trans *trans,
enum btree_id btree, unsigned level, struct bkey_s_c k, enum btree_id btree, unsigned level, struct bkey_s_c k,
enum btree_iter_update_trigger_flags flags) enum btree_iter_update_trigger_flags flags)
{ {
struct bch_fs *c = trans->c; struct bch_fs *c = trans->c;
struct bkey_ptrs_c ptrs_c = bch2_bkey_ptrs_c(k);
const union bch_extent_entry *entry_c;
struct extent_ptr_decoded p = { 0 };
bool do_update = false;
CLASS(printbuf, buf)();
/* We don't yet do btree key updates correctly for when we're RW */ /* We don't yet do btree key updates correctly for when we're RW */
BUG_ON(test_bit(BCH_FS_rw, &c->flags)); BUG_ON(test_bit(BCH_FS_rw, &c->flags));
bkey_for_each_ptr_decode(k.k, ptrs_c, p, entry_c) struct ptrs_repair r = {};
try(bch2_check_fix_ptr(trans, k, p, entry_c, &do_update));
if (do_update) { struct bkey_ptrs_c ptrs_c = bch2_bkey_ptrs_c(k);
const union bch_extent_entry *entry_c;
struct extent_ptr_decoded p;
unsigned ptr_bit = 1;
bkey_for_each_ptr_decode(k.k, ptrs_c, p, entry_c) {
try(bch2_check_fix_ptr(trans, k, p, entry_c, &r, ptr_bit));
ptr_bit <<= 1;
}
if (r.drop ||
r.drop_stripe ||
r.reset_gen) {
struct bkey_i *new = struct bkey_i *new =
errptr_try(bch2_trans_kmalloc(trans, BKEY_EXTENT_U64s_MAX * sizeof(u64))); errptr_try(bch2_trans_kmalloc(trans, BKEY_EXTENT_U64s_MAX * sizeof(u64)));
bkey_reassemble(new, k); bkey_reassemble(new, k);
scoped_guard(rcu) struct bkey_ptrs ptrs = bch2_bkey_ptrs(bkey_i_to_s(new));
bch2_bkey_drop_ptrs(bkey_i_to_s(new), p, entry, if (r.reset_gen) {
!bch2_dev_exists(c, p.ptr.dev)); unsigned ptr_bit = 1;
guard(rcu)();
if (level) { bkey_for_each_ptr(ptrs, ptr) {
/* if (r.reset_gen & ptr_bit) {
* We don't want to drop btree node pointers - if the struct bch_dev *ca = bch2_dev_rcu(c, ptr->dev);
* btree node isn't there anymore, the read path will
* sort it out:
*/
struct bkey_ptrs ptrs = bch2_bkey_ptrs(bkey_i_to_s(new));
scoped_guard(rcu)
bkey_for_each_ptr(ptrs, ptr) {
struct bch_dev *ca = bch2_dev_rcu_noerror(c, ptr->dev);
if (ca) if (ca)
ptr->gen = PTR_GC_BUCKET(ca, ptr)->gen; ptr->gen = PTR_GC_BUCKET(ca, ptr)->gen;
} }
} else { ptr_bit <<= 1;
scoped_guard(rcu)
bch2_bkey_drop_ptrs(bkey_i_to_s(new), p, entry,
should_drop_ptr(c, bkey_i_to_s_c(new), p, entry));
struct bkey_ptrs ptrs;
union bch_extent_entry *entry;
again:
ptrs = bch2_bkey_ptrs(bkey_i_to_s(new));
bkey_extent_entry_for_each(ptrs, entry) {
if (extent_entry_type(entry) == BCH_EXTENT_ENTRY_stripe_ptr) {
struct gc_stripe *m = genradix_ptr(&c->ec.gc_stripes,
entry->stripe_ptr.idx);
union bch_extent_entry *next_ptr;
bkey_extent_entry_for_each_from(ptrs, next_ptr, entry)
if (extent_entry_type(next_ptr) == BCH_EXTENT_ENTRY_ptr)
goto found;
next_ptr = NULL;
found:
if (!next_ptr) {
bch_err(c, "aieee, found stripe ptr with no data ptr");
continue;
}
if (!m || !m->alive ||
!__bch2_ptr_matches_stripe(&m->ptrs[entry->stripe_ptr.block],
&next_ptr->ptr,
m->sectors)) {
bch2_bkey_extent_entry_drop(c, new, entry);
goto again;
}
}
} }
} }
if (0) { if (r.drop_stripe)
printbuf_reset(&buf); bch2_bkey_drop_ec_mask(c, new, r.drop_stripe);
bch2_bkey_val_to_text(&buf, c, k);
bch_info(c, "updated %s", buf.buf);
printbuf_reset(&buf); if (r.drop)
bch2_bkey_val_to_text(&buf, c, bkey_i_to_s_c(new)); bch2_bkey_drop_ptrs_mask(c, new, r.drop);
bch_info(c, "new key %s", buf.buf);
}
struct bch_inode_opts opts; struct bch_inode_opts opts;
try(bch2_bkey_get_io_opts(trans, NULL, k, &opts)); try(bch2_bkey_get_io_opts(trans, NULL, k, &opts));

View File

@ -313,9 +313,10 @@ cpu_replicas_add_entry(struct bch_fs *c,
cpu_replicas_entry(old, i), cpu_replicas_entry(old, i),
old->entry_size); old->entry_size);
memcpy(&cpu_replicas_entry(&new, old->nr)->e, unsafe_memcpy(&cpu_replicas_entry(&new, old->nr)->e,
new_entry, new_entry,
replicas_entry_bytes(new_entry)); replicas_entry_bytes(new_entry),
"embedded variable length struct");
bch2_cpu_replicas_sort(&new); bch2_cpu_replicas_sort(&new);
return new; return new;
@ -564,7 +565,8 @@ __bch2_sb_replicas_to_cpu_replicas(struct bch_sb_field_replicas *sb_r,
for_each_replicas_entry(sb_r, src) { for_each_replicas_entry(sb_r, src) {
struct bch_replicas_entry_cpu *dst = cpu_replicas_entry(cpu_r, idx++); struct bch_replicas_entry_cpu *dst = cpu_replicas_entry(cpu_r, idx++);
memcpy(&dst->e, src, replicas_entry_bytes(src)); unsafe_memcpy(&dst->e, src, replicas_entry_bytes(src),
"embedded variable length struct");
bch2_replicas_entry_sort(&dst->e); bch2_replicas_entry_sort(&dst->e);
} }

View File

@ -61,11 +61,9 @@ struct open_bucket {
struct ec_stripe_new *ec; struct ec_stripe_new *ec;
}; };
#define OPEN_BUCKET_LIST_MAX 15
struct open_buckets { struct open_buckets {
open_bucket_idx_t nr; open_bucket_idx_t nr;
open_bucket_idx_t v[OPEN_BUCKET_LIST_MAX]; open_bucket_idx_t v[BCH_BKEY_PTRS_MAX];
}; };
struct dev_stripe_state { struct dev_stripe_state {

View File

@ -116,6 +116,9 @@ int bch2_sb_members_v2_init(struct bch_fs *c)
DIV_ROUND_UP(sizeof(*mi2) + DIV_ROUND_UP(sizeof(*mi2) +
sizeof(struct bch_member) * c->sb.nr_devices, sizeof(struct bch_member) * c->sb.nr_devices,
sizeof(u64))); sizeof(u64)));
if (!mi2)
return bch_err_throw(c, ENOSPC_sb_members_v2);
mi1 = bch2_sb_field_get(c->disk_sb.sb, members_v1); mi1 = bch2_sb_field_get(c->disk_sb.sb, members_v1);
memcpy(&mi2->_members[0], &mi1->_members[0], memcpy(&mi2->_members[0], &mi1->_members[0],
BCH_MEMBER_V1_BYTES * c->sb.nr_devices); BCH_MEMBER_V1_BYTES * c->sb.nr_devices);

View File

@ -183,33 +183,37 @@ struct snapshot_t *bch2_snapshot_t_mut(struct bch_fs *c, u32 id)
return __snapshot_t_mut(c, id); return __snapshot_t_mut(c, id);
} }
void bch2_snapshot_to_text(struct printbuf *out, struct bch_fs *c, void bch2_snapshot_to_text(struct printbuf *out, struct bch_snapshot *s)
struct bkey_s_c k)
{ {
struct bkey_s_c_snapshot s = bkey_s_c_to_snapshot(k); if (BCH_SNAPSHOT_SUBVOL(s))
if (BCH_SNAPSHOT_SUBVOL(s.v))
prt_str(out, "subvol "); prt_str(out, "subvol ");
if (BCH_SNAPSHOT_WILL_DELETE(s.v)) if (BCH_SNAPSHOT_WILL_DELETE(s))
prt_str(out, "will_delete "); prt_str(out, "will_delete ");
if (BCH_SNAPSHOT_DELETED(s.v)) if (BCH_SNAPSHOT_DELETED(s))
prt_str(out, "deleted "); prt_str(out, "deleted ");
if (BCH_SNAPSHOT_NO_KEYS(s.v)) if (BCH_SNAPSHOT_NO_KEYS(s))
prt_str(out, "no_keys "); prt_str(out, "no_keys ");
prt_printf(out, "parent %10u children %10u %10u subvol %u tree %u", prt_printf(out, "parent %10u children %10u %10u subvol %u tree %u",
le32_to_cpu(s.v->parent), le32_to_cpu(s->parent),
le32_to_cpu(s.v->children[0]), le32_to_cpu(s->children[0]),
le32_to_cpu(s.v->children[1]), le32_to_cpu(s->children[1]),
le32_to_cpu(s.v->subvol), le32_to_cpu(s->subvol),
le32_to_cpu(s.v->tree)); le32_to_cpu(s->tree));
if (bkey_val_bytes(k.k) > offsetof(struct bch_snapshot, depth)) prt_printf(out, " depth %u skiplist %u %u %u",
prt_printf(out, " depth %u skiplist %u %u %u", le32_to_cpu(s->depth),
le32_to_cpu(s.v->depth), le32_to_cpu(s->skip[0]),
le32_to_cpu(s.v->skip[0]), le32_to_cpu(s->skip[1]),
le32_to_cpu(s.v->skip[1]), le32_to_cpu(s->skip[2]));
le32_to_cpu(s.v->skip[2])); }
void bch2_snapshot_key_to_text(struct printbuf *out, struct bch_fs *c,
struct bkey_s_c k)
{
struct bch_snapshot snapshot;
bkey_val_copy_pad(&snapshot, bkey_s_c_to_snapshot(k));
bch2_snapshot_to_text(out, &snapshot);
} }
int bch2_snapshot_validate(struct bch_fs *c, struct bkey_s_c k, int bch2_snapshot_validate(struct bch_fs *c, struct bkey_s_c k,

View File

@ -16,7 +16,8 @@ struct bkey_i_snapshot_tree *__bch2_snapshot_tree_create(struct btree_trans *);
int bch2_snapshot_tree_lookup(struct btree_trans *, u32, struct bch_snapshot_tree *); int bch2_snapshot_tree_lookup(struct btree_trans *, u32, struct bch_snapshot_tree *);
void bch2_snapshot_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c); void bch2_snapshot_to_text(struct printbuf *, struct bch_snapshot *);
void bch2_snapshot_key_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
int bch2_snapshot_validate(struct bch_fs *, struct bkey_s_c, int bch2_snapshot_validate(struct bch_fs *, struct bkey_s_c,
struct bkey_validate_context); struct bkey_validate_context);
int bch2_mark_snapshot(struct btree_trans *, enum btree_id, unsigned, int bch2_mark_snapshot(struct btree_trans *, enum btree_id, unsigned,
@ -25,7 +26,7 @@ int bch2_mark_snapshot(struct btree_trans *, enum btree_id, unsigned,
#define bch2_bkey_ops_snapshot ((struct bkey_ops) { \ #define bch2_bkey_ops_snapshot ((struct bkey_ops) { \
.key_validate = bch2_snapshot_validate, \ .key_validate = bch2_snapshot_validate, \
.val_to_text = bch2_snapshot_to_text, \ .val_to_text = bch2_snapshot_key_to_text, \
.trigger = bch2_mark_snapshot, \ .trigger = bch2_mark_snapshot, \
.min_val_size = 24, \ .min_val_size = 24, \
}) })

View File

@ -100,7 +100,8 @@ static int check_subvol(struct btree_trans *trans,
subvol_children_iter.pos.inode, subvol_children_iter.pos.offset, subvol_children_iter.pos.inode, subvol_children_iter.pos.offset,
(printbuf_reset(&buf), (printbuf_reset(&buf),
bch2_bkey_val_to_text(&buf, c, k), buf.buf))) { bch2_bkey_val_to_text(&buf, c, k), buf.buf))) {
try(bch2_btree_bit_mod(trans, BTREE_ID_subvolume_children, subvol_children_iter.pos, true)); try(bch2_btree_bit_mod(trans, BTREE_ID_subvolume_children,
subvol_children_iter.pos, true));
} }
} }
@ -111,9 +112,17 @@ static int check_subvol(struct btree_trans *trans,
if (!ret) { if (!ret) {
if (fsck_err_on(inode.bi_subvol != k.k->p.offset, if (fsck_err_on(inode.bi_subvol != k.k->p.offset,
trans, subvol_root_wrong_bi_subvol, trans, subvol_root_wrong_bi_subvol,
"subvol root %llu:%u has wrong bi_subvol field: got %u, should be %llu", "subvol root %llu:%u has wrong bi_subvol field: got %u, should be %llu\n%s",
inode.bi_inum, inode.bi_snapshot, inode.bi_inum, inode.bi_snapshot,
inode.bi_subvol, k.k->p.offset)) { inode.bi_subvol, k.k->p.offset,
(printbuf_reset(&buf),
bch2_bkey_val_to_text(&buf, c, k),
prt_newline(&buf),
prt_printf(&buf, "snapshot %u: ", snapid),
bch2_snapshot_to_text(&buf, &snapshot),
prt_newline(&buf),
bch2_inode_unpacked_to_text(&buf, &inode),
buf.buf))) {
inode.bi_subvol = k.k->p.offset; inode.bi_subvol = k.k->p.offset;
inode.bi_snapshot = le32_to_cpu(subvol.snapshot); inode.bi_snapshot = le32_to_cpu(subvol.snapshot);
try(__bch2_fsck_write_inode(trans, &inode)); try(__bch2_fsck_write_inode(trans, &inode));