mirror of
https://github.com/torvalds/linux.git
synced 2026-06-01 02:53:36 +02:00
bcachefs: skip invisible entries in empty subvolume checking
When we are checking whether a subvolume is empty in the specified snapshot,
entries that do not belong to this subvolume should be skipped.
This fixes the following case:
$ bcachefs subvolume create ./sub
$ cd sub
$ bcachefs subvolume create ./sub2
$ bcachefs subvolume snapshot . ./snap
$ ls -a snap
. ..
$ rmdir snap
rmdir: failed to remove 'snap': Directory not empty
As Kent suggested, we pass 0 in may_delete_deleted_inode() to ignore subvols
in the subvol we are checking, because inode.bi_subvol is only set on
subvolume roots, and we can't go through every inode in the subvolume and
change bi_subvol when taking a snapshot. It makes the check less strict, but
that's ok, the rest of fsck will still catch it.
Signed-off-by: Guoyu Ou <benogy@gmail.com>
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
parent
067f244c9e
commit
0be5b38bce
|
|
@ -508,7 +508,7 @@ u64 bch2_dirent_lookup(struct bch_fs *c, subvol_inum dir,
|
|||
return ret;
|
||||
}
|
||||
|
||||
int bch2_empty_dir_snapshot(struct btree_trans *trans, u64 dir, u32 snapshot)
|
||||
int bch2_empty_dir_snapshot(struct btree_trans *trans, u64 dir, u32 subvol, u32 snapshot)
|
||||
{
|
||||
struct btree_iter iter;
|
||||
struct bkey_s_c k;
|
||||
|
|
@ -518,6 +518,9 @@ int bch2_empty_dir_snapshot(struct btree_trans *trans, u64 dir, u32 snapshot)
|
|||
SPOS(dir, 0, snapshot),
|
||||
POS(dir, U64_MAX), 0, k, ret)
|
||||
if (k.k->type == KEY_TYPE_dirent) {
|
||||
struct bkey_s_c_dirent d = bkey_s_c_to_dirent(k);
|
||||
if (d.v->d_type == DT_SUBVOL && le32_to_cpu(d.v->d_parent_subvol) != subvol)
|
||||
continue;
|
||||
ret = -ENOTEMPTY;
|
||||
break;
|
||||
}
|
||||
|
|
@ -531,7 +534,7 @@ 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);
|
||||
bch2_empty_dir_snapshot(trans, dir.inum, dir.subvol, snapshot);
|
||||
}
|
||||
|
||||
int bch2_readdir(struct bch_fs *c, subvol_inum inum, struct dir_context *ctx)
|
||||
|
|
|
|||
|
|
@ -69,7 +69,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_snapshot(struct btree_trans *, u64, u32, u32);
|
||||
int bch2_empty_dir_trans(struct btree_trans *, subvol_inum);
|
||||
int bch2_readdir(struct bch_fs *, subvol_inum, struct dir_context *);
|
||||
|
||||
|
|
|
|||
|
|
@ -1088,8 +1088,9 @@ static int may_delete_deleted_inode(struct btree_trans *trans,
|
|||
goto out;
|
||||
|
||||
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,
|
||||
ret = bch2_empty_dir_snapshot(trans, pos.offset, 0, pos.snapshot);
|
||||
if (fsck_err_on(bch2_err_matches(ret, ENOTEMPTY),
|
||||
c, deleted_inode_is_dir,
|
||||
"non empty directory %llu:%u in deleted_inodes btree",
|
||||
pos.offset, pos.snapshot))
|
||||
goto delete;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user