Commit 6f519564 authored by Liu Bo's avatar Liu Bo Committed by Chris Mason

Btrfs: do not run snapshot-aware defragment on error

If something wrong happens in write endio, running snapshot-aware defragment
can end up with undefined results, maybe a crash, so we should avoid it.

In order to share similar code, this also adds a helper to free the struct for
snapshot-aware defrag.
Signed-off-by: default avatarLiu Bo <bo.li.liu@oracle.com>
Signed-off-by: default avatarJosef Bacik <jbacik@fusionio.com>
Signed-off-by: default avatarChris Mason <chris.mason@fusionio.com>
parent 269d040f
...@@ -2365,10 +2365,23 @@ static noinline int relink_extent_backref(struct btrfs_path *path, ...@@ -2365,10 +2365,23 @@ static noinline int relink_extent_backref(struct btrfs_path *path,
return ret; return ret;
} }
static void free_sa_defrag_extent(struct new_sa_defrag_extent *new)
{
struct old_sa_defrag_extent *old, *tmp;
if (!new)
return;
list_for_each_entry_safe(old, tmp, &new->head, list) {
list_del(&old->list);
kfree(old);
}
kfree(new);
}
static void relink_file_extents(struct new_sa_defrag_extent *new) static void relink_file_extents(struct new_sa_defrag_extent *new)
{ {
struct btrfs_path *path; struct btrfs_path *path;
struct old_sa_defrag_extent *old, *tmp;
struct sa_defrag_extent_backref *backref; struct sa_defrag_extent_backref *backref;
struct sa_defrag_extent_backref *prev = NULL; struct sa_defrag_extent_backref *prev = NULL;
struct inode *inode; struct inode *inode;
...@@ -2411,16 +2424,11 @@ static void relink_file_extents(struct new_sa_defrag_extent *new) ...@@ -2411,16 +2424,11 @@ static void relink_file_extents(struct new_sa_defrag_extent *new)
kfree(prev); kfree(prev);
btrfs_free_path(path); btrfs_free_path(path);
list_for_each_entry_safe(old, tmp, &new->head, list) {
list_del(&old->list);
kfree(old);
}
out: out:
free_sa_defrag_extent(new);
atomic_dec(&root->fs_info->defrag_running); atomic_dec(&root->fs_info->defrag_running);
wake_up(&root->fs_info->transaction_wait); wake_up(&root->fs_info->transaction_wait);
kfree(new);
} }
static struct new_sa_defrag_extent * static struct new_sa_defrag_extent *
...@@ -2430,7 +2438,7 @@ record_old_file_extents(struct inode *inode, ...@@ -2430,7 +2438,7 @@ record_old_file_extents(struct inode *inode,
struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_root *root = BTRFS_I(inode)->root;
struct btrfs_path *path; struct btrfs_path *path;
struct btrfs_key key; struct btrfs_key key;
struct old_sa_defrag_extent *old, *tmp; struct old_sa_defrag_extent *old;
struct new_sa_defrag_extent *new; struct new_sa_defrag_extent *new;
int ret; int ret;
...@@ -2478,7 +2486,7 @@ record_old_file_extents(struct inode *inode, ...@@ -2478,7 +2486,7 @@ record_old_file_extents(struct inode *inode,
if (slot >= btrfs_header_nritems(l)) { if (slot >= btrfs_header_nritems(l)) {
ret = btrfs_next_leaf(root, path); ret = btrfs_next_leaf(root, path);
if (ret < 0) if (ret < 0)
goto out_free_list; goto out_free_path;
else if (ret > 0) else if (ret > 0)
break; break;
continue; continue;
...@@ -2507,7 +2515,7 @@ record_old_file_extents(struct inode *inode, ...@@ -2507,7 +2515,7 @@ record_old_file_extents(struct inode *inode,
old = kmalloc(sizeof(*old), GFP_NOFS); old = kmalloc(sizeof(*old), GFP_NOFS);
if (!old) if (!old)
goto out_free_list; goto out_free_path;
offset = max(new->file_pos, key.offset); offset = max(new->file_pos, key.offset);
end = min(new->file_pos + new->len, key.offset + num_bytes); end = min(new->file_pos + new->len, key.offset + num_bytes);
...@@ -2529,15 +2537,10 @@ record_old_file_extents(struct inode *inode, ...@@ -2529,15 +2537,10 @@ record_old_file_extents(struct inode *inode,
return new; return new;
out_free_list:
list_for_each_entry_safe(old, tmp, &new->head, list) {
list_del(&old->list);
kfree(old);
}
out_free_path: out_free_path:
btrfs_free_path(path); btrfs_free_path(path);
out_kfree: out_kfree:
kfree(new); free_sa_defrag_extent(new);
return NULL; return NULL;
} }
...@@ -2708,8 +2711,14 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent) ...@@ -2708,8 +2711,14 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent)
btrfs_remove_ordered_extent(inode, ordered_extent); btrfs_remove_ordered_extent(inode, ordered_extent);
/* for snapshot-aware defrag */ /* for snapshot-aware defrag */
if (new) if (new) {
relink_file_extents(new); if (ret) {
free_sa_defrag_extent(new);
atomic_dec(&root->fs_info->defrag_running);
} else {
relink_file_extents(new);
}
}
/* once for us */ /* once for us */
btrfs_put_ordered_extent(ordered_extent); btrfs_put_ordered_extent(ordered_extent);
......
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