btrfs: allocate root item at snapshot ioctl time
authorDavid Sterba <dsterba@suse.com>
Tue, 10 Nov 2015 17:54:00 +0000 (18:54 +0100)
committerDavid Sterba <dsterba@suse.com>
Thu, 7 Jan 2016 14:20:54 +0000 (15:20 +0100)
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: David Sterba <dsterba@suse.com>
fs/btrfs/ioctl.c
fs/btrfs/transaction.c
fs/btrfs/transaction.h

index fa25091e10abca15b9dba318e61fc9850e51a319..27fc660b0ff33e12f1e739af5daa48fa65dcc5da 100644 (file)
@@ -659,6 +659,13 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
        if (!pending_snapshot)
                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);
        smp_mb__after_atomic();
        btrfs_wait_for_no_snapshoting_writes(root);
@@ -738,6 +745,8 @@ fail:
 dec_and_free:
        if (atomic_dec_and_test(&root->will_be_snapshoted))
                wake_up_atomic_t(&root->will_be_snapshoted);
+free_pending:
+       kfree(pending_snapshot->root_item);
        kfree(pending_snapshot);
 
        return ret;
index be8eae80ff6572608a478610f9c2b16f3bcb1871..2074106122d9ab5b2c8d6074eb7f7624000b4cd8 100644 (file)
@@ -1325,11 +1325,8 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
                return 0;
        }
 
-       new_root_item = kmalloc(sizeof(*new_root_item), GFP_NOFS);
-       if (!new_root_item) {
-               pending->error = -ENOMEM;
-               goto root_item_alloc_fail;
-       }
+       ASSERT(pending->root_item);
+       new_root_item = pending->root_item;
 
        pending->error = btrfs_find_free_objectid(tree_root, &objectid);
        if (pending->error)
@@ -1562,7 +1559,7 @@ clear_skip_qgroup:
        btrfs_clear_skip_qgroup(trans);
 no_free_objectid:
        kfree(new_root_item);
-root_item_alloc_fail:
+       pending->root_item = NULL;
        btrfs_free_path(path);
        return ret;
 }
index 64c8221b6165bb7a6b786ac74e1833f2b93a197b..b6f9a3c944685136c72f7d8bd0a76e3809f8047a 100644 (file)
@@ -137,6 +137,7 @@ struct btrfs_pending_snapshot {
        struct dentry *dentry;
        struct inode *dir;
        struct btrfs_root *root;
+       struct btrfs_root_item *root_item;
        struct btrfs_root *snap;
        struct btrfs_qgroup_inherit *inherit;
        /* block reservation for the operation */