bcachefs fixes for 6.14-rc4
Small stuff: - The fsck code for Hongbo's directory i_size patch was wrong, caught by transaction restart injection: we now have the CI running another test variant with restart injection enabled - Another fixup for reflink pointers to missing indirect extents: previous fix was for fsck code, this fixes the normal runtime paths - Another small srcu lock hold time fix, reported by jpsollie -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEKnAFLkS8Qha+jvQrE6szbY3KbnYFAme3OyoACgkQE6szbY3K bnaXTRAAuF+EL1MxMkyuIUEfTuAiE6wx26bf0C/pmgY/roALSY6lVFEnlbs2mpti 1z2uR4pnX06e27R9pDxzuSrkq12/+7ltuFQ6om/tgeGma+mwY0iLWClmhvj4U3Cw HX0sYseE56wQGRRv10qVA77sYyjum6Fevci02XplL+Qx4nl/BUabTF+3KnkgL4Tq LHFm70DsYItPdEW3a16mW+oiHpr35ADPcJX4UkvSU/QZd7WK5Ei+IVICsBkcsX52 CMxoWOxTlKRGRMbXD9kw2Oh6nliT0A/ErtYPIo/AJwFQVEqTloE2h/QotwkwRqzl MphypWZVX6umlJ7aq5fPhCRw9/UFwK9sv0/jY8TvkEQEuNi3+/5UbcumwYh6ZGVV pJS540sqoPQVTW/g6fxbEsUf+4/yTs3wawTlDlls/PKwj33s8fHDFvf4511kc9Wc mRAVcfwJelDmsEclELQsA2sZ4kUEQS90YZWLquozCU3L7TrfKiysUgONizBkVBtO PInTypH1uWlSZaacicozXmCJ/vBWC6JSliSz9HhSZQ0/KpSQNSX+IyCU9D+EMCtt WGMB9mQoyKyjThGgtecCxVNJi8c3Oe4Ll4Av21F+GXi0QPTt95G2hAVkX9gc3T4o DGKc9DRRPqShjgjImi7K3zRUH+BGaFiMWG8Q6PavPhZGAOMuiFM= =Yozy -----END PGP SIGNATURE----- Merge tag 'bcachefs-2025-02-20' of git://evilpiepirate.org/bcachefs Pull bcachefs fixes from Kent Overstreet: "Small stuff: - The fsck code for Hongbo's directory i_size patch was wrong, caught by transaction restart injection: we now have the CI running another test variant with restart injection enabled - Another fixup for reflink pointers to missing indirect extents: previous fix was for fsck code, this fixes the normal runtime paths - Another small srcu lock hold time fix, reported by jpsollie" * tag 'bcachefs-2025-02-20' of git://evilpiepirate.org/bcachefs: bcachefs: Fix srcu lock warning in btree_update_nodes_written() bcachefs: Fix bch2_indirect_extent_missing_error() bcachefs: Fix fsck directory i_size checking
This commit is contained in:
commit
bf0e5ed008
4 changed files with 42 additions and 58 deletions
|
@ -681,9 +681,11 @@ static void btree_update_nodes_written(struct btree_update *as)
|
|||
|
||||
b = as->old_nodes[i];
|
||||
|
||||
bch2_trans_begin(trans);
|
||||
btree_node_lock_nopath_nofail(trans, &b->c, SIX_LOCK_read);
|
||||
seq = b->data ? b->data->keys.seq : 0;
|
||||
six_unlock_read(&b->c.lock);
|
||||
bch2_trans_unlock_long(trans);
|
||||
|
||||
if (seq == as->old_nodes_seq[i])
|
||||
wait_on_bit_io(&b->flags, BTREE_NODE_write_in_flight_inner,
|
||||
|
|
|
@ -823,6 +823,7 @@ struct inode_walker_entry {
|
|||
struct bch_inode_unpacked inode;
|
||||
u32 snapshot;
|
||||
u64 count;
|
||||
u64 i_size;
|
||||
};
|
||||
|
||||
struct inode_walker {
|
||||
|
@ -910,8 +911,9 @@ found:
|
|||
if (k.k->p.snapshot != i->snapshot && !is_whiteout) {
|
||||
struct inode_walker_entry new = *i;
|
||||
|
||||
new.snapshot = k.k->p.snapshot;
|
||||
new.count = 0;
|
||||
new.snapshot = k.k->p.snapshot;
|
||||
new.count = 0;
|
||||
new.i_size = 0;
|
||||
|
||||
struct printbuf buf = PRINTBUF;
|
||||
bch2_bkey_val_to_text(&buf, c, k);
|
||||
|
@ -1116,37 +1118,6 @@ err:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int check_directory_size(struct btree_trans *trans,
|
||||
struct bch_inode_unpacked *inode_u,
|
||||
struct bkey_s_c inode_k, bool *write_inode)
|
||||
{
|
||||
struct btree_iter iter;
|
||||
struct bkey_s_c k;
|
||||
u64 new_size = 0;
|
||||
int ret;
|
||||
|
||||
for_each_btree_key_max_norestart(trans, iter, BTREE_ID_dirents,
|
||||
SPOS(inode_k.k->p.offset, 0, inode_k.k->p.snapshot),
|
||||
POS(inode_k.k->p.offset, U64_MAX),
|
||||
0, k, ret) {
|
||||
if (k.k->type != KEY_TYPE_dirent)
|
||||
continue;
|
||||
|
||||
struct bkey_s_c_dirent dirent = bkey_s_c_to_dirent(k);
|
||||
struct qstr name = bch2_dirent_get_name(dirent);
|
||||
|
||||
new_size += dirent_occupied_size(&name);
|
||||
}
|
||||
bch2_trans_iter_exit(trans, &iter);
|
||||
|
||||
if (!ret && inode_u->bi_size != new_size) {
|
||||
inode_u->bi_size = new_size;
|
||||
*write_inode = true;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int check_inode(struct btree_trans *trans,
|
||||
struct btree_iter *iter,
|
||||
struct bkey_s_c k,
|
||||
|
@ -1335,16 +1306,6 @@ static int check_inode(struct btree_trans *trans,
|
|||
u.bi_journal_seq = journal_cur_seq(&c->journal);
|
||||
do_update = true;
|
||||
}
|
||||
|
||||
if (S_ISDIR(u.bi_mode)) {
|
||||
ret = check_directory_size(trans, &u, k, &do_update);
|
||||
|
||||
fsck_err_on(ret,
|
||||
trans, directory_size_mismatch,
|
||||
"directory inode %llu:%u with the mismatch directory size",
|
||||
u.bi_inum, k.k->p.snapshot);
|
||||
ret = 0;
|
||||
}
|
||||
do_update:
|
||||
if (do_update) {
|
||||
ret = __bch2_fsck_write_inode(trans, &u);
|
||||
|
@ -2017,10 +1978,31 @@ fsck_err:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int check_subdir_count(struct btree_trans *trans, struct inode_walker *w)
|
||||
static int check_dir_i_size_notnested(struct btree_trans *trans, struct inode_walker *w)
|
||||
{
|
||||
struct bch_fs *c = trans->c;
|
||||
int ret = 0;
|
||||
|
||||
darray_for_each(w->inodes, i)
|
||||
if (fsck_err_on(i->inode.bi_size != i->i_size,
|
||||
trans, inode_dir_wrong_nlink,
|
||||
"directory %llu:%u with wrong i_size: got %llu, should be %llu",
|
||||
w->last_pos.inode, i->snapshot, i->inode.bi_size, i->i_size)) {
|
||||
i->inode.bi_size = i->i_size;
|
||||
ret = bch2_fsck_write_inode(trans, &i->inode);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
fsck_err:
|
||||
bch_err_fn(c, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int check_subdir_dirents_count(struct btree_trans *trans, struct inode_walker *w)
|
||||
{
|
||||
u32 restart_count = trans->restart_count;
|
||||
return check_subdir_count_notnested(trans, w) ?:
|
||||
check_dir_i_size_notnested(trans, w) ?:
|
||||
trans_was_restarted(trans, restart_count);
|
||||
}
|
||||
|
||||
|
@ -2367,7 +2349,7 @@ static int check_dirent(struct btree_trans *trans, struct btree_iter *iter,
|
|||
goto out;
|
||||
|
||||
if (dir->last_pos.inode != k.k->p.inode && dir->have_inodes) {
|
||||
ret = check_subdir_count(trans, dir);
|
||||
ret = check_subdir_dirents_count(trans, dir);
|
||||
if (ret)
|
||||
goto err;
|
||||
}
|
||||
|
@ -2457,9 +2439,11 @@ static int check_dirent(struct btree_trans *trans, struct btree_iter *iter,
|
|||
if (ret)
|
||||
goto err;
|
||||
|
||||
if (d.v->d_type == DT_DIR)
|
||||
for_each_visible_inode(c, s, dir, d.k->p.snapshot, i)
|
||||
for_each_visible_inode(c, s, dir, d.k->p.snapshot, i) {
|
||||
if (d.v->d_type == DT_DIR)
|
||||
i->count++;
|
||||
i->i_size += bkey_bytes(d.k);
|
||||
}
|
||||
out:
|
||||
err:
|
||||
fsck_err:
|
||||
|
|
|
@ -172,7 +172,7 @@ static int bch2_indirect_extent_missing_error(struct btree_trans *trans,
|
|||
bool should_commit)
|
||||
{
|
||||
if (REFLINK_P_ERROR(p.v))
|
||||
return -BCH_ERR_missing_indirect_extent;
|
||||
return 0;
|
||||
|
||||
struct bch_fs *c = trans->c;
|
||||
u64 live_start = REFLINK_P_IDX(p.v);
|
||||
|
@ -259,8 +259,6 @@ struct bkey_s_c bch2_lookup_indirect_extent(struct btree_trans *trans,
|
|||
return k;
|
||||
|
||||
if (unlikely(!bkey_extent_is_reflink_data(k.k))) {
|
||||
bch2_trans_iter_exit(trans, iter);
|
||||
|
||||
unsigned size = min((u64) k.k->size,
|
||||
REFLINK_P_IDX(p.v) + p.k->size + le32_to_cpu(p.v->back_pad) -
|
||||
reflink_offset);
|
||||
|
@ -268,14 +266,16 @@ struct bkey_s_c bch2_lookup_indirect_extent(struct btree_trans *trans,
|
|||
|
||||
int ret = bch2_indirect_extent_missing_error(trans, p, reflink_offset,
|
||||
k.k->p.offset, should_commit);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
bch2_trans_iter_exit(trans, iter);
|
||||
return bkey_s_c_err(ret);
|
||||
}
|
||||
} else if (unlikely(REFLINK_P_ERROR(p.v))) {
|
||||
bch2_trans_iter_exit(trans, iter);
|
||||
|
||||
int ret = bch2_indirect_extent_not_missing(trans, p, should_commit);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
bch2_trans_iter_exit(trans, iter);
|
||||
return bkey_s_c_err(ret);
|
||||
}
|
||||
}
|
||||
|
||||
*offset_into_extent = reflink_offset - bkey_start_offset(k.k);
|
||||
|
@ -300,7 +300,7 @@ static int trans_trigger_reflink_p_segment(struct btree_trans *trans,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (bkey_deleted(k.k)) {
|
||||
if (!bkey_refcount_c(k)) {
|
||||
if (!(flags & BTREE_TRIGGER_overwrite))
|
||||
ret = -BCH_ERR_missing_indirect_extent;
|
||||
goto next;
|
||||
|
@ -381,8 +381,6 @@ static s64 gc_trigger_reflink_p_segment(struct btree_trans *trans,
|
|||
not_found:
|
||||
if (flags & BTREE_TRIGGER_check_repair) {
|
||||
ret = bch2_indirect_extent_missing_error(trans, p, *idx, next_idx, false);
|
||||
if (ret == -BCH_ERR_missing_indirect_extent)
|
||||
ret = 0;
|
||||
if (ret)
|
||||
goto err;
|
||||
}
|
||||
|
|
|
@ -92,7 +92,7 @@
|
|||
BCH_FSCK_ERR_accounting_key_replicas_nr_devs_0, \
|
||||
BCH_FSCK_ERR_accounting_key_junk_at_end) \
|
||||
x(directory_size, \
|
||||
BIT_ULL(BCH_RECOVERY_PASS_check_inodes), \
|
||||
BIT_ULL(BCH_RECOVERY_PASS_check_dirents), \
|
||||
BCH_FSCK_ERR_directory_size_mismatch) \
|
||||
|
||||
#define DOWNGRADE_TABLE() \
|
||||
|
|
Loading…
Add table
Reference in a new issue