Skip to content

Commit 9b0d00a

Browse files
author
Kent Overstreet
committed
bcachefs: Refactor bch2_check_dirent_target()
Prep work for calling bch2_check_dirent_target() from bch2_lookup(). - Add an inline wrapper, if the target and backpointer match we can skip the function call. - We don't (yet?) want to remove the dirent we did the lookup from (when we find a directory or subvol with multiple valid dirents pointing to it), we can defer on that until later. For now, add an "are we in fsck?" parameter. Signed-off-by: Kent Overstreet <[email protected]>
1 parent 758ea4f commit 9b0d00a

File tree

4 files changed

+94
-68
lines changed

4 files changed

+94
-68
lines changed

fs/bcachefs/fsck.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2072,7 +2072,7 @@ static int check_dirent_to_subvol(struct btree_trans *trans, struct btree_iter *
20722072
goto err;
20732073
}
20742074

2075-
ret = bch2_check_dirent_target(trans, iter, d, &subvol_root);
2075+
ret = bch2_check_dirent_target(trans, iter, d, &subvol_root, true);
20762076
if (ret)
20772077
goto err;
20782078
out:
@@ -2165,7 +2165,7 @@ static int check_dirent(struct btree_trans *trans, struct btree_iter *iter,
21652165
}
21662166

21672167
darray_for_each(target->inodes, i) {
2168-
ret = bch2_check_dirent_target(trans, iter, d, &i->inode);
2168+
ret = bch2_check_dirent_target(trans, iter, d, &i->inode, true);
21692169
if (ret)
21702170
goto err;
21712171
}

fs/bcachefs/inode.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,7 @@ static inline bool bch2_inode_should_have_single_bp(struct bch_inode_unpacked *i
277277
bool inode_has_bp = inode->bi_dir || inode->bi_dir_offset;
278278

279279
return S_ISDIR(inode->bi_mode) ||
280+
inode->bi_subvol ||
280281
(!inode->bi_nlink && inode_has_bp);
281282
}
282283

fs/bcachefs/namei.c

Lines changed: 67 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -659,17 +659,10 @@ int bch2_inum_to_path(struct btree_trans *trans, subvol_inum inum, struct printb
659659

660660
/* fsck */
661661

662-
static bool inode_points_to_dirent(struct bch_inode_unpacked *inode,
663-
struct bkey_s_c_dirent d)
664-
{
665-
return inode->bi_dir == d.k->p.inode &&
666-
inode->bi_dir_offset == d.k->p.offset;
667-
}
668-
669662
static int bch2_check_dirent_inode_dirent(struct btree_trans *trans,
670-
struct btree_iter *iter,
671-
struct bkey_s_c_dirent d,
672-
struct bch_inode_unpacked *target)
663+
struct bkey_s_c_dirent d,
664+
struct bch_inode_unpacked *target,
665+
bool in_fsck)
673666
{
674667
struct bch_fs *c = trans->c;
675668
struct printbuf buf = PRINTBUF;
@@ -725,52 +718,65 @@ static int bch2_check_dirent_inode_dirent(struct btree_trans *trans,
725718
bool backpointer_exists = !ret;
726719
ret = 0;
727720

728-
if (fsck_err_on(!backpointer_exists,
729-
trans, inode_wrong_backpointer,
730-
"inode %llu:%u has wrong backpointer:\n"
731-
"got %llu:%llu\n"
732-
"should be %llu:%llu",
733-
target->bi_inum, target->bi_snapshot,
734-
target->bi_dir,
735-
target->bi_dir_offset,
736-
d.k->p.inode,
737-
d.k->p.offset)) {
738-
target->bi_dir = d.k->p.inode;
739-
target->bi_dir_offset = d.k->p.offset;
740-
ret = __bch2_fsck_write_inode(trans, target);
741-
goto out;
742-
}
743-
744-
bch2_bkey_val_to_text(&buf, c, d.s_c);
745-
prt_newline(&buf);
746-
if (backpointer_exists)
721+
if (!backpointer_exists) {
722+
if (fsck_err(trans, inode_wrong_backpointer,
723+
"inode %llu:%u has wrong backpointer:\n"
724+
"got %llu:%llu\n"
725+
"should be %llu:%llu",
726+
target->bi_inum, target->bi_snapshot,
727+
target->bi_dir,
728+
target->bi_dir_offset,
729+
d.k->p.inode,
730+
d.k->p.offset)) {
731+
target->bi_dir = d.k->p.inode;
732+
target->bi_dir_offset = d.k->p.offset;
733+
ret = __bch2_fsck_write_inode(trans, target);
734+
}
735+
} else {
736+
bch2_bkey_val_to_text(&buf, c, d.s_c);
737+
prt_newline(&buf);
747738
bch2_bkey_val_to_text(&buf, c, bp_dirent.s_c);
748739

749-
if (fsck_err_on(backpointer_exists &&
750-
(S_ISDIR(target->bi_mode) ||
751-
target->bi_subvol),
752-
trans, inode_dir_multiple_links,
753-
"%s %llu:%u with multiple links\n%s",
754-
S_ISDIR(target->bi_mode) ? "directory" : "subvolume",
755-
target->bi_inum, target->bi_snapshot, buf.buf)) {
756-
ret = bch2_fsck_remove_dirent(trans, d.k->p);
757-
goto out;
758-
}
759-
760-
/*
761-
* hardlinked file with nlink 0:
762-
* We're just adjusting nlink here so check_nlinks() will pick
763-
* it up, it ignores inodes with nlink 0
764-
*/
765-
if (fsck_err_on(backpointer_exists && !target->bi_nlink,
766-
trans, inode_multiple_links_but_nlink_0,
767-
"inode %llu:%u type %s has multiple links but i_nlink 0\n%s",
768-
target->bi_inum, target->bi_snapshot, bch2_d_types[d.v->d_type], buf.buf)) {
769-
target->bi_nlink++;
770-
target->bi_flags &= ~BCH_INODE_unlinked;
771-
ret = __bch2_fsck_write_inode(trans, target);
772-
if (ret)
773-
goto err;
740+
if (S_ISDIR(target->bi_mode) || target->bi_subvol) {
741+
/*
742+
* XXX: verify connectivity of the other dirent
743+
* up to the root before removing this one
744+
*
745+
* Additionally, bch2_lookup would need to cope with the
746+
* dirent it found being removed - or should we remove
747+
* the other one, even though the inode points to it?
748+
*/
749+
if (in_fsck) {
750+
if (fsck_err(trans, inode_dir_multiple_links,
751+
"%s %llu:%u with multiple links\n%s",
752+
S_ISDIR(target->bi_mode) ? "directory" : "subvolume",
753+
target->bi_inum, target->bi_snapshot, buf.buf))
754+
ret = bch2_fsck_remove_dirent(trans, d.k->p);
755+
} else {
756+
bch2_fs_inconsistent(c,
757+
"%s %llu:%u with multiple links\n%s",
758+
S_ISDIR(target->bi_mode) ? "directory" : "subvolume",
759+
target->bi_inum, target->bi_snapshot, buf.buf);
760+
}
761+
762+
goto out;
763+
} else {
764+
/*
765+
* hardlinked file with nlink 0:
766+
* We're just adjusting nlink here so check_nlinks() will pick
767+
* it up, it ignores inodes with nlink 0
768+
*/
769+
if (fsck_err_on(!target->bi_nlink,
770+
trans, inode_multiple_links_but_nlink_0,
771+
"inode %llu:%u type %s has multiple links but i_nlink 0\n%s",
772+
target->bi_inum, target->bi_snapshot, bch2_d_types[d.v->d_type], buf.buf)) {
773+
target->bi_nlink++;
774+
target->bi_flags &= ~BCH_INODE_unlinked;
775+
ret = __bch2_fsck_write_inode(trans, target);
776+
if (ret)
777+
goto err;
778+
}
779+
}
774780
}
775781
out:
776782
err:
@@ -781,16 +787,17 @@ static int bch2_check_dirent_inode_dirent(struct btree_trans *trans,
781787
return ret;
782788
}
783789

784-
int bch2_check_dirent_target(struct btree_trans *trans,
785-
struct btree_iter *iter,
786-
struct bkey_s_c_dirent d,
787-
struct bch_inode_unpacked *target)
790+
int __bch2_check_dirent_target(struct btree_trans *trans,
791+
struct btree_iter *dirent_iter,
792+
struct bkey_s_c_dirent d,
793+
struct bch_inode_unpacked *target,
794+
bool in_fsck)
788795
{
789796
struct bch_fs *c = trans->c;
790797
struct printbuf buf = PRINTBUF;
791798
int ret = 0;
792799

793-
ret = bch2_check_dirent_inode_dirent(trans, iter, d, target);
800+
ret = bch2_check_dirent_inode_dirent(trans, d, target, in_fsck);
794801
if (ret)
795802
goto err;
796803

@@ -815,11 +822,9 @@ int bch2_check_dirent_target(struct btree_trans *trans,
815822
n->v.d_inum = cpu_to_le64(target->bi_inum);
816823
}
817824

818-
ret = bch2_trans_update(trans, iter, &n->k_i, 0);
825+
ret = bch2_trans_update(trans, dirent_iter, &n->k_i, 0);
819826
if (ret)
820827
goto err;
821-
822-
d = dirent_i_to_s_c(n);
823828
}
824829
err:
825830
fsck_err:

fs/bcachefs/namei.h

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,29 @@ bool bch2_reinherit_attrs(struct bch_inode_unpacked *,
4444

4545
int bch2_inum_to_path(struct btree_trans *, subvol_inum, struct printbuf *);
4646

47-
int bch2_check_dirent_target(struct btree_trans *,
48-
struct btree_iter *,
49-
struct bkey_s_c_dirent,
50-
struct bch_inode_unpacked *);
47+
int __bch2_check_dirent_target(struct btree_trans *,
48+
struct btree_iter *,
49+
struct bkey_s_c_dirent,
50+
struct bch_inode_unpacked *, bool);
51+
52+
static inline bool inode_points_to_dirent(struct bch_inode_unpacked *inode,
53+
struct bkey_s_c_dirent d)
54+
{
55+
return inode->bi_dir == d.k->p.inode &&
56+
inode->bi_dir_offset == d.k->p.offset;
57+
}
58+
59+
static inline int bch2_check_dirent_target(struct btree_trans *trans,
60+
struct btree_iter *dirent_iter,
61+
struct bkey_s_c_dirent d,
62+
struct bch_inode_unpacked *target,
63+
bool in_fsck)
64+
{
65+
if (likely(inode_points_to_dirent(target, d) &&
66+
d.v->d_type == inode_d_type(target)))
67+
return 0;
68+
69+
return __bch2_check_dirent_target(trans, dirent_iter, d, target, in_fsck);
70+
}
5171

5272
#endif /* _BCACHEFS_NAMEI_H */

0 commit comments

Comments
 (0)