Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+28 −19
Original line number Diff line number Diff line
@@ -2365,10 +2365,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;
@@ -2411,16 +2424,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 *
@@ -2430,7 +2438,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;

@@ -2478,7 +2486,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;
@@ -2507,7 +2515,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);
@@ -2529,15 +2537,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;
}

@@ -2708,8 +2711,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)
	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);