Skip to content

Commit c72def5

Browse files
author
Kent Overstreet
committed
bcachefs: Run check_dirents second time if required
If we move a key backwards, we'll need a second pass to run the rest of the fsck checks. Signed-off-by: Kent Overstreet <[email protected]>
1 parent a4907d7 commit c72def5

File tree

4 files changed

+49
-27
lines changed

4 files changed

+49
-27
lines changed

fs/bcachefs/dirent.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -705,8 +705,9 @@ int bch2_readdir(struct bch_fs *c, subvol_inum inum,
705705

706706
subvol_inum target;
707707

708+
bool need_second_pass = false;
708709
int ret2 = bch2_str_hash_check_key(trans, NULL, &bch2_dirent_hash_desc,
709-
hash_info, &iter, k) ?:
710+
hash_info, &iter, k, &need_second_pass) ?:
710711
bch2_dirent_read_target(trans, inum, dirent, &target);
711712
if (ret2 > 0)
712713
continue;

fs/bcachefs/fsck.c

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2141,7 +2141,8 @@ static int check_dirent(struct btree_trans *trans, struct btree_iter *iter,
21412141
struct bch_hash_info *hash_info,
21422142
struct inode_walker *dir,
21432143
struct inode_walker *target,
2144-
struct snapshots_seen *s)
2144+
struct snapshots_seen *s,
2145+
bool *need_second_pass)
21452146
{
21462147
struct bch_fs *c = trans->c;
21472148
struct inode_walker_entry *i;
@@ -2183,7 +2184,8 @@ static int check_dirent(struct btree_trans *trans, struct btree_iter *iter,
21832184
*hash_info = bch2_hash_info_init(c, &i->inode);
21842185
dir->first_this_inode = false;
21852186

2186-
ret = bch2_str_hash_check_key(trans, s, &bch2_dirent_hash_desc, hash_info, iter, k);
2187+
ret = bch2_str_hash_check_key(trans, s, &bch2_dirent_hash_desc, hash_info,
2188+
iter, k, need_second_pass);
21872189
if (ret < 0)
21882190
goto err;
21892191
if (ret) {
@@ -2228,7 +2230,8 @@ static int check_dirent(struct btree_trans *trans, struct btree_iter *iter,
22282230
STR_HASH_must_create) ?:
22292231
bch2_trans_commit(trans, NULL, NULL, BCH_TRANS_COMMIT_no_enospc);
22302232

2231-
/* might need another check_dirents pass */
2233+
if (dir_offset < k.k->p.offset)
2234+
*need_second_pass = true;
22322235
goto out;
22332236
}
22342237

@@ -2296,7 +2299,6 @@ static int check_dirent(struct btree_trans *trans, struct btree_iter *iter,
22962299
err:
22972300
fsck_err:
22982301
printbuf_exit(&buf);
2299-
bch_err_fn(c, ret);
23002302
return ret;
23012303
}
23022304

@@ -2310,17 +2312,30 @@ int bch2_check_dirents(struct bch_fs *c)
23102312
struct inode_walker target = inode_walker_init();
23112313
struct snapshots_seen s;
23122314
struct bch_hash_info hash_info;
2315+
bool need_second_pass = false, did_second_pass = false;
23132316

23142317
snapshots_seen_init(&s);
2315-
2318+
again:
23162319
int ret = bch2_trans_run(c,
23172320
for_each_btree_key_commit(trans, iter, BTREE_ID_dirents,
23182321
POS(BCACHEFS_ROOT_INO, 0),
23192322
BTREE_ITER_prefetch|BTREE_ITER_all_snapshots, k,
23202323
NULL, NULL, BCH_TRANS_COMMIT_no_enospc,
2321-
check_dirent(trans, &iter, k, &hash_info, &dir, &target, &s)) ?:
2324+
check_dirent(trans, &iter, k, &hash_info, &dir, &target, &s,
2325+
&need_second_pass)) ?:
23222326
check_subdir_count_notnested(trans, &dir));
23232327

2328+
if (!ret && need_second_pass && !did_second_pass) {
2329+
bch_info(c, "check_dirents requires second pass");
2330+
swap(did_second_pass, need_second_pass);
2331+
goto again;
2332+
}
2333+
2334+
if (!ret && need_second_pass) {
2335+
bch_err(c, "dirents not repairing");
2336+
ret = -EINVAL;
2337+
}
2338+
23242339
snapshots_seen_exit(&s);
23252340
inode_walker_exit(&dir);
23262341
inode_walker_exit(&target);
@@ -2334,16 +2349,14 @@ static int check_xattr(struct btree_trans *trans, struct btree_iter *iter,
23342349
struct inode_walker *inode)
23352350
{
23362351
struct bch_fs *c = trans->c;
2337-
struct inode_walker_entry *i;
2338-
int ret;
23392352

2340-
ret = bch2_check_key_has_snapshot(trans, iter, k);
2353+
int ret = bch2_check_key_has_snapshot(trans, iter, k);
23412354
if (ret < 0)
23422355
return ret;
23432356
if (ret)
23442357
return 0;
23452358

2346-
i = walk_inode(trans, inode, k);
2359+
struct inode_walker_entry *i = walk_inode(trans, inode, k);
23472360
ret = PTR_ERR_OR_ZERO(i);
23482361
if (ret)
23492362
return ret;
@@ -2359,9 +2372,9 @@ static int check_xattr(struct btree_trans *trans, struct btree_iter *iter,
23592372
*hash_info = bch2_hash_info_init(c, &i->inode);
23602373
inode->first_this_inode = false;
23612374

2362-
ret = bch2_str_hash_check_key(trans, NULL, &bch2_xattr_hash_desc, hash_info, iter, k);
2363-
bch_err_fn(c, ret);
2364-
return ret;
2375+
bool need_second_pass = false;
2376+
return bch2_str_hash_check_key(trans, NULL, &bch2_xattr_hash_desc, hash_info,
2377+
iter, k, &need_second_pass);
23652378
}
23662379

23672380
/*

fs/bcachefs/str_hash.c

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ static noinline int fsck_rename_dirent(struct btree_trans *trans,
3535
struct snapshots_seen *s,
3636
const struct bch_hash_desc desc,
3737
struct bch_hash_info *hash_info,
38-
struct bkey_s_c_dirent old)
38+
struct bkey_s_c_dirent old,
39+
bool *updated_before_k_pos)
3940
{
4041
struct qstr old_name = bch2_dirent_get_name(old);
4142
struct bkey_i_dirent *new = bch2_trans_kmalloc(trans, bkey_bytes(old.k) + 32);
@@ -62,16 +63,15 @@ static noinline int fsck_rename_dirent(struct btree_trans *trans,
6263
old.k->p.snapshot, &new->k_i,
6364
BTREE_UPDATE_internal_snapshot_node);
6465
if (ret && !bch2_err_matches(ret, EEXIST))
65-
goto err;
66-
if (!ret)
6766
break;
67+
if (!ret) {
68+
if (bpos_lt(new->k.p, old.k->p))
69+
*updated_before_k_pos = true;
70+
break;
71+
}
6872
}
6973

70-
if (ret)
71-
goto err;
72-
73-
ret = bch2_fsck_update_backpointers(trans, s, desc, hash_info, &new->k_i);
74-
err:
74+
ret = ret ?: bch2_fsck_update_backpointers(trans, s, desc, hash_info, &new->k_i);
7575
bch_err_fn(trans->c, ret);
7676
return ret;
7777
}
@@ -230,7 +230,8 @@ int __bch2_str_hash_check_key(struct btree_trans *trans,
230230
struct snapshots_seen *s,
231231
const struct bch_hash_desc *desc,
232232
struct bch_hash_info *hash_info,
233-
struct btree_iter *k_iter, struct bkey_s_c hash_k)
233+
struct btree_iter *k_iter, struct bkey_s_c hash_k,
234+
bool *updated_before_k_pos)
234235
{
235236
struct bch_fs *c = trans->c;
236237
struct btree_iter iter = {};
@@ -310,6 +311,9 @@ int __bch2_str_hash_check_key(struct btree_trans *trans,
310311
if (k.k)
311312
goto duplicate_entries;
312313

314+
if (bpos_lt(new->k.p, k.k->p))
315+
*updated_before_k_pos = true;
316+
313317
ret = bch2_insert_snapshot_whiteouts(trans, desc->btree_id,
314318
k_iter->pos, new->k.p) ?:
315319
bch2_hash_delete_at(trans, *desc, hash_info, k_iter,
@@ -345,7 +349,8 @@ int __bch2_str_hash_check_key(struct btree_trans *trans,
345349
ret = bch2_hash_delete_at(trans, *desc, hash_info, &iter, 0);
346350
break;
347351
case 2:
348-
ret = fsck_rename_dirent(trans, s, *desc, hash_info, bkey_s_c_to_dirent(hash_k)) ?:
352+
ret = fsck_rename_dirent(trans, s, *desc, hash_info, bkey_s_c_to_dirent(hash_k),
353+
updated_before_k_pos) ?:
349354
bch2_hash_delete_at(trans, *desc, hash_info, k_iter, 0);
350355
goto out;
351356
}

fs/bcachefs/str_hash.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -402,21 +402,24 @@ int __bch2_str_hash_check_key(struct btree_trans *,
402402
struct snapshots_seen *,
403403
const struct bch_hash_desc *,
404404
struct bch_hash_info *,
405-
struct btree_iter *, struct bkey_s_c);
405+
struct btree_iter *, struct bkey_s_c,
406+
bool *);
406407

407408
static inline int bch2_str_hash_check_key(struct btree_trans *trans,
408409
struct snapshots_seen *s,
409410
const struct bch_hash_desc *desc,
410411
struct bch_hash_info *hash_info,
411-
struct btree_iter *k_iter, struct bkey_s_c hash_k)
412+
struct btree_iter *k_iter, struct bkey_s_c hash_k,
413+
bool *updated_before_k_pos)
412414
{
413415
if (hash_k.k->type != desc->key_type)
414416
return 0;
415417

416418
if (likely(desc->hash_bkey(hash_info, hash_k) == hash_k.k->p.offset))
417419
return 0;
418420

419-
return __bch2_str_hash_check_key(trans, s, desc, hash_info, k_iter, hash_k);
421+
return __bch2_str_hash_check_key(trans, s, desc, hash_info, k_iter, hash_k,
422+
updated_before_k_pos);
420423
}
421424

422425
#endif /* _BCACHEFS_STR_HASH_H */

0 commit comments

Comments
 (0)