Commit b0c0ea63 authored by David Sterba's avatar David Sterba

btrfs: allocate root item at snapshot ioctl time

The actual snapshot creation is delayed until transaction commit. If we
cannot get enough memory for the root item there, we have to fail the
whole transaction commit which is bad. So we'll allocate the memory at
the ioctl call and pass it along with the pending_snapshot struct. The
potential ENOMEM will be returned to the caller of snapshot ioctl.
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent a1ee7362
...@@ -659,6 +659,13 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir, ...@@ -659,6 +659,13 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
if (!pending_snapshot) if (!pending_snapshot)
return -ENOMEM; return -ENOMEM;
pending_snapshot->root_item = kzalloc(sizeof(struct btrfs_root_item),
GFP_NOFS);
if (!pending_snapshot->root_item) {
ret = -ENOMEM;
goto free_pending;
}
atomic_inc(&root->will_be_snapshoted); atomic_inc(&root->will_be_snapshoted);
smp_mb__after_atomic(); smp_mb__after_atomic();
btrfs_wait_for_no_snapshoting_writes(root); btrfs_wait_for_no_snapshoting_writes(root);
...@@ -738,6 +745,8 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir, ...@@ -738,6 +745,8 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
dec_and_free: dec_and_free:
if (atomic_dec_and_test(&root->will_be_snapshoted)) if (atomic_dec_and_test(&root->will_be_snapshoted))
wake_up_atomic_t(&root->will_be_snapshoted); wake_up_atomic_t(&root->will_be_snapshoted);
free_pending:
kfree(pending_snapshot->root_item);
kfree(pending_snapshot); kfree(pending_snapshot);
return ret; return ret;
......
...@@ -1325,11 +1325,8 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, ...@@ -1325,11 +1325,8 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
return 0; return 0;
} }
new_root_item = kmalloc(sizeof(*new_root_item), GFP_NOFS); ASSERT(pending->root_item);
if (!new_root_item) { new_root_item = pending->root_item;
pending->error = -ENOMEM;
goto root_item_alloc_fail;
}
pending->error = btrfs_find_free_objectid(tree_root, &objectid); pending->error = btrfs_find_free_objectid(tree_root, &objectid);
if (pending->error) if (pending->error)
...@@ -1562,7 +1559,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, ...@@ -1562,7 +1559,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
btrfs_clear_skip_qgroup(trans); btrfs_clear_skip_qgroup(trans);
no_free_objectid: no_free_objectid:
kfree(new_root_item); kfree(new_root_item);
root_item_alloc_fail: pending->root_item = NULL;
btrfs_free_path(path); btrfs_free_path(path);
return ret; return ret;
} }
......
...@@ -137,6 +137,7 @@ struct btrfs_pending_snapshot { ...@@ -137,6 +137,7 @@ struct btrfs_pending_snapshot {
struct dentry *dentry; struct dentry *dentry;
struct inode *dir; struct inode *dir;
struct btrfs_root *root; struct btrfs_root *root;
struct btrfs_root_item *root_item;
struct btrfs_root *snap; struct btrfs_root *snap;
struct btrfs_qgroup_inherit *inherit; struct btrfs_qgroup_inherit *inherit;
/* block reservation for the operation */ /* block reservation for the operation */
......
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