Commit bbc3a0b1 authored by Kent Overstreet's avatar Kent Overstreet
Browse files

bcachefs: fsck: Fix check_directory_structure when no check_dirents



check_directory_structure runs after check_dirents, so it expects that
it won't see any inodes with missing backpointers - normally.

But online fsck can't run check_dirents yet, or the user might only be
running a specific pass, so we need to be careful that this isn't an
error. If an inode is unreachable, that's handled by a separate pass.

Also, add a new 'bch2_inode_has_backpointer()' helper, since we were
doing this inconsistently.

Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent e1f0e1a4
Loading
Loading
Loading
Loading
+13 −5
Original line number Diff line number Diff line
@@ -327,7 +327,8 @@ static inline bool inode_should_reattach(struct bch_inode_unpacked *inode)
	    (inode->bi_flags & BCH_INODE_has_child_snapshot))
		return false;

	return !inode->bi_dir && !(inode->bi_flags & BCH_INODE_unlinked);
	return !bch2_inode_has_backpointer(inode) &&
		!(inode->bi_flags & BCH_INODE_unlinked);
}

static int maybe_delete_dirent(struct btree_trans *trans, struct bpos d_pos, u32 snapshot)
@@ -514,7 +515,7 @@ static struct bkey_s_c_dirent dirent_get_by_pos(struct btree_trans *trans,
static int remove_backpointer(struct btree_trans *trans,
			      struct bch_inode_unpacked *inode)
{
	if (!inode->bi_dir)
	if (!bch2_inode_has_backpointer(inode))
		return 0;

	u32 snapshot = inode->bi_snapshot;
@@ -1165,13 +1166,14 @@ static int check_inode(struct btree_trans *trans,
	if (ret)
		goto err;

	if (u.bi_dir || u.bi_dir_offset) {
	if (bch2_inode_has_backpointer(&u)) {
		ret = check_inode_dirent_inode(trans, &u, &do_update);
		if (ret)
			goto err;
	}

	if (fsck_err_on(u.bi_dir && (u.bi_flags & BCH_INODE_unlinked),
	if (fsck_err_on(bch2_inode_has_backpointer(&u) &&
			(u.bi_flags & BCH_INODE_unlinked),
			trans, inode_unlinked_but_has_dirent,
			"inode unlinked but has dirent\n%s",
			(printbuf_reset(&buf),
@@ -2751,7 +2753,13 @@ static int check_path_loop(struct btree_trans *trans, struct bkey_s_c inode_k)
	if (ret)
		return ret;

	while (!inode.bi_subvol) {
	/*
	 * If we're running full fsck, check_dirents() will have already ran,
	 * and we shouldn't see any missing backpointers here - otherwise that's
	 * handled separately, by check_unreachable_inodes
	 */
	while (!inode.bi_subvol &&
	       bch2_inode_has_backpointer(&inode)) {
		struct btree_iter dirent_iter;
		struct bkey_s_c_dirent d;

+5 −0
Original line number Diff line number Diff line
@@ -254,6 +254,11 @@ static inline bool bch2_inode_casefold(struct bch_fs *c, const struct bch_inode_
		: c->opts.casefold;
}

static inline bool bch2_inode_has_backpointer(const struct bch_inode_unpacked *bi)
{
	return bi->bi_dir || bi->bi_dir_offset;
}

/* i_nlink: */

static inline unsigned nlink_bias(umode_t mode)
+1 −2
Original line number Diff line number Diff line
@@ -734,8 +734,7 @@ static int bch2_check_dirent_inode_dirent(struct btree_trans *trans,
	if (inode_points_to_dirent(target, d))
		return 0;

	if (!target->bi_dir &&
	    !target->bi_dir_offset) {
	if (!bch2_inode_has_backpointer(target)) {
		fsck_err_on(S_ISDIR(target->bi_mode),
			    trans, inode_dir_missing_backpointer,
			    "directory with missing backpointer\n%s",