Commit 6d1980f0 authored by Kent Overstreet's avatar Kent Overstreet
Browse files

bcachefs: Fix deleted inode check for dirs



We could delete directories transactionally on rmdir()/unlink(), but we
don't; instead, like with regular files we wait for the VFS to call
evict().

That means that our check for directories in the deleted inodes btree is
wrong - the check should be for non-empty directories.

Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent e5972888
Loading
Loading
Loading
Loading
+11 −8
Original line number Diff line number Diff line
@@ -485,20 +485,15 @@ u64 bch2_dirent_lookup(struct bch_fs *c, subvol_inum dir,
	return ret;
}

int bch2_empty_dir_trans(struct btree_trans *trans, subvol_inum dir)
int bch2_empty_dir_snapshot(struct btree_trans *trans, u64 dir, u32 snapshot)
{
	struct btree_iter iter;
	struct bkey_s_c k;
	u32 snapshot;
	int ret;

	ret = bch2_subvolume_get_snapshot(trans, dir.subvol, &snapshot);
	if (ret)
		return ret;

	for_each_btree_key_upto_norestart(trans, iter, BTREE_ID_dirents,
			   SPOS(dir.inum, 0, snapshot),
			   POS(dir.inum, U64_MAX), 0, k, ret)
			   SPOS(dir, 0, snapshot),
			   POS(dir, U64_MAX), 0, k, ret)
		if (k.k->type == KEY_TYPE_dirent) {
			ret = -ENOTEMPTY;
			break;
@@ -508,6 +503,14 @@ int bch2_empty_dir_trans(struct btree_trans *trans, subvol_inum dir)
	return ret;
}

int bch2_empty_dir_trans(struct btree_trans *trans, subvol_inum dir)
{
	u32 snapshot;

	return bch2_subvolume_get_snapshot(trans, dir.subvol, &snapshot) ?:
		bch2_empty_dir_snapshot(trans, dir.inum, snapshot);
}

int bch2_readdir(struct bch_fs *c, subvol_inum inum, struct dir_context *ctx)
{
	struct btree_trans *trans = bch2_trans_get(c);
+1 −0
Original line number Diff line number Diff line
@@ -64,6 +64,7 @@ u64 bch2_dirent_lookup(struct bch_fs *, subvol_inum,
		       const struct bch_hash_info *,
		       const struct qstr *, subvol_inum *);

int bch2_empty_dir_snapshot(struct btree_trans *, u64, u32);
int bch2_empty_dir_trans(struct btree_trans *, subvol_inum);
int bch2_readdir(struct bch_fs *, subvol_inum, struct dir_context *);

+10 −5
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@
#include "btree_update.h"
#include "buckets.h"
#include "compress.h"
#include "dirent.h"
#include "error.h"
#include "extents.h"
#include "extent_update.h"
@@ -1093,11 +1094,15 @@ static int may_delete_deleted_inode(struct btree_trans *trans,
	if (ret)
		goto out;

	if (fsck_err_on(S_ISDIR(inode.bi_mode), c,
			deleted_inode_is_dir,
			"directory %llu:%u in deleted_inodes btree",
	if (S_ISDIR(inode.bi_mode)) {
		ret = bch2_empty_dir_snapshot(trans, pos.offset, pos.snapshot);
		if (fsck_err_on(ret == -ENOTEMPTY, c, deleted_inode_is_dir,
				"non empty directory %llu:%u in deleted_inodes btree",
				pos.offset, pos.snapshot))
			goto delete;
		if (ret)
			goto out;
	}

	if (fsck_err_on(!(inode.bi_flags & BCH_INODE_unlinked), c,
			deleted_inode_not_unlinked,