Skip to content

Commit

Permalink
Btrfs: do not run snapshot-aware defragment on error
Browse files Browse the repository at this point in the history
commit 6f51956 upstream.

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: Liu Bo <bo.li.liu@oracle.com>
Signed-off-by: Josef Bacik <jbacik@fusionio.com>
Signed-off-by: Chris Mason <chris.mason@fusionio.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Liu Bo authored and Greg Kroah-Hartman committed Dec 20, 2013
1 parent 9436cf9 commit f5749e3
Showing 1 changed file with 28 additions and 19 deletions.
47 changes: 28 additions & 19 deletions fs/btrfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -2419,10 +2419,23 @@ static noinline int relink_extent_backref(struct btrfs_path *path,
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)
{
struct btrfs_path *path;
struct old_sa_defrag_extent *old, *tmp;
struct sa_defrag_extent_backref *backref;
struct sa_defrag_extent_backref *prev = NULL;
struct inode *inode;
Expand Down Expand Up @@ -2465,16 +2478,11 @@ static void relink_file_extents(struct new_sa_defrag_extent *new)
kfree(prev);

btrfs_free_path(path);

list_for_each_entry_safe(old, tmp, &new->head, list) {
list_del(&old->list);
kfree(old);
}
out:
free_sa_defrag_extent(new);

atomic_dec(&root->fs_info->defrag_running);
wake_up(&root->fs_info->transaction_wait);

kfree(new);
}

static struct new_sa_defrag_extent *
Expand All @@ -2484,7 +2492,7 @@ record_old_file_extents(struct inode *inode,
struct btrfs_root *root = BTRFS_I(inode)->root;
struct btrfs_path *path;
struct btrfs_key key;
struct old_sa_defrag_extent *old, *tmp;
struct old_sa_defrag_extent *old;
struct new_sa_defrag_extent *new;
int ret;

Expand Down Expand Up @@ -2532,7 +2540,7 @@ record_old_file_extents(struct inode *inode,
if (slot >= btrfs_header_nritems(l)) {
ret = btrfs_next_leaf(root, path);
if (ret < 0)
goto out_free_list;
goto out_free_path;
else if (ret > 0)
break;
continue;
Expand Down Expand Up @@ -2561,7 +2569,7 @@ record_old_file_extents(struct inode *inode,

old = kmalloc(sizeof(*old), GFP_NOFS);
if (!old)
goto out_free_list;
goto out_free_path;

offset = max(new->file_pos, key.offset);
end = min(new->file_pos + new->len, key.offset + num_bytes);
Expand All @@ -2583,15 +2591,10 @@ record_old_file_extents(struct inode *inode,

return new;

out_free_list:
list_for_each_entry_safe(old, tmp, &new->head, list) {
list_del(&old->list);
kfree(old);
}
out_free_path:
btrfs_free_path(path);
out_kfree:
kfree(new);
free_sa_defrag_extent(new);
return NULL;
}

Expand Down Expand Up @@ -2743,8 +2746,14 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent)
btrfs_remove_ordered_extent(inode, ordered_extent);

/* for snapshot-aware defrag */
if (new)
relink_file_extents(new);
if (new) {
if (ret) {
free_sa_defrag_extent(new);
atomic_dec(&root->fs_info->defrag_running);
} else {
relink_file_extents(new);
}
}

/* once for us */
btrfs_put_ordered_extent(ordered_extent);
Expand Down

0 comments on commit f5749e3

Please sign in to comment.