diff options
author | Arne Jansen <sensille@gmx.net> | 2011-12-14 20:12:02 -0500 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2011-12-15 10:50:37 -0500 |
commit | f8e9e0b07be0464e12366631da3da73a1a62449c (patch) | |
tree | 3950d7dfe50186637b0bcca0d38943a64c9dff8c | |
parent | 39fb26c398ddf8d7794a85e896cfe1a42e55524b (diff) |
btrfs: keep orphans for subvolume deletion
Since we have the free space caches, btrfs_orphan_cleanup also runs for
the tree_root. Unfortunately this also cleans up the orphans used to mark
subvol deletions in progress.
Currently if a subvol deletion gets interrupted twice by umount/mount, the
deletion will not be continued and the space permanently lost, though it
would be possible to write a tool to recover those lost subvol deletions.
This patch checks if the orphan belongs to a subvol (dead root) and skips
the deletion.
Signed-off-by: Arne Jansen <sensille@gmx.net>
Signed-off-by: Chris Mason <chris.mason@oracle.com>
-rw-r--r-- | fs/btrfs/inode.c | 32 |
1 files changed, 32 insertions, 0 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index f1c4bceed072..4a31493d97ac 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -2158,6 +2158,38 @@ int btrfs_orphan_cleanup(struct btrfs_root *root) | |||
2158 | if (ret && ret != -ESTALE) | 2158 | if (ret && ret != -ESTALE) |
2159 | goto out; | 2159 | goto out; |
2160 | 2160 | ||
2161 | if (ret == -ESTALE && root == root->fs_info->tree_root) { | ||
2162 | struct btrfs_root *dead_root; | ||
2163 | struct btrfs_fs_info *fs_info = root->fs_info; | ||
2164 | int is_dead_root = 0; | ||
2165 | |||
2166 | /* | ||
2167 | * this is an orphan in the tree root. Currently these | ||
2168 | * could come from 2 sources: | ||
2169 | * a) a snapshot deletion in progress | ||
2170 | * b) a free space cache inode | ||
2171 | * We need to distinguish those two, as the snapshot | ||
2172 | * orphan must not get deleted. | ||
2173 | * find_dead_roots already ran before us, so if this | ||
2174 | * is a snapshot deletion, we should find the root | ||
2175 | * in the dead_roots list | ||
2176 | */ | ||
2177 | spin_lock(&fs_info->trans_lock); | ||
2178 | list_for_each_entry(dead_root, &fs_info->dead_roots, | ||
2179 | root_list) { | ||
2180 | if (dead_root->root_key.objectid == | ||
2181 | found_key.objectid) { | ||
2182 | is_dead_root = 1; | ||
2183 | break; | ||
2184 | } | ||
2185 | } | ||
2186 | spin_unlock(&fs_info->trans_lock); | ||
2187 | if (is_dead_root) { | ||
2188 | /* prevent this orphan from being found again */ | ||
2189 | key.offset = found_key.objectid - 1; | ||
2190 | continue; | ||
2191 | } | ||
2192 | } | ||
2161 | /* | 2193 | /* |
2162 | * Inode is already gone but the orphan item is still there, | 2194 | * Inode is already gone but the orphan item is still there, |
2163 | * kill the orphan item. | 2195 | * kill the orphan item. |