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

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
...@@ -485,20 +485,15 @@ u64 bch2_dirent_lookup(struct bch_fs *c, subvol_inum dir, ...@@ -485,20 +485,15 @@ u64 bch2_dirent_lookup(struct bch_fs *c, subvol_inum dir,
return ret; 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 btree_iter iter;
struct bkey_s_c k; struct bkey_s_c k;
u32 snapshot;
int ret; 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, for_each_btree_key_upto_norestart(trans, iter, BTREE_ID_dirents,
SPOS(dir.inum, 0, snapshot), SPOS(dir, 0, snapshot),
POS(dir.inum, U64_MAX), 0, k, ret) POS(dir, U64_MAX), 0, k, ret)
if (k.k->type == KEY_TYPE_dirent) { if (k.k->type == KEY_TYPE_dirent) {
ret = -ENOTEMPTY; ret = -ENOTEMPTY;
break; break;
...@@ -508,6 +503,14 @@ int bch2_empty_dir_trans(struct btree_trans *trans, subvol_inum dir) ...@@ -508,6 +503,14 @@ int bch2_empty_dir_trans(struct btree_trans *trans, subvol_inum dir)
return ret; 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) int bch2_readdir(struct bch_fs *c, subvol_inum inum, struct dir_context *ctx)
{ {
struct btree_trans *trans = bch2_trans_get(c); struct btree_trans *trans = bch2_trans_get(c);
......
...@@ -64,6 +64,7 @@ u64 bch2_dirent_lookup(struct bch_fs *, subvol_inum, ...@@ -64,6 +64,7 @@ u64 bch2_dirent_lookup(struct bch_fs *, subvol_inum,
const struct bch_hash_info *, const struct bch_hash_info *,
const struct qstr *, subvol_inum *); 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_empty_dir_trans(struct btree_trans *, subvol_inum);
int bch2_readdir(struct bch_fs *, subvol_inum, struct dir_context *); int bch2_readdir(struct bch_fs *, subvol_inum, struct dir_context *);
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "btree_update.h" #include "btree_update.h"
#include "buckets.h" #include "buckets.h"
#include "compress.h" #include "compress.h"
#include "dirent.h"
#include "error.h" #include "error.h"
#include "extents.h" #include "extents.h"
#include "extent_update.h" #include "extent_update.h"
...@@ -1093,11 +1094,15 @@ static int may_delete_deleted_inode(struct btree_trans *trans, ...@@ -1093,11 +1094,15 @@ static int may_delete_deleted_inode(struct btree_trans *trans,
if (ret) if (ret)
goto out; goto out;
if (fsck_err_on(S_ISDIR(inode.bi_mode), c, if (S_ISDIR(inode.bi_mode)) {
deleted_inode_is_dir, ret = bch2_empty_dir_snapshot(trans, pos.offset, pos.snapshot);
"directory %llu:%u in deleted_inodes btree", if (fsck_err_on(ret == -ENOTEMPTY, c, deleted_inode_is_dir,
pos.offset, pos.snapshot)) "non empty directory %llu:%u in deleted_inodes btree",
goto delete; pos.offset, pos.snapshot))
goto delete;
if (ret)
goto out;
}
if (fsck_err_on(!(inode.bi_flags & BCH_INODE_unlinked), c, if (fsck_err_on(!(inode.bi_flags & BCH_INODE_unlinked), c,
deleted_inode_not_unlinked, deleted_inode_not_unlinked,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment