]> git.hungrycats.org Git - linux/commitdiff
btrfs: allocate root item at snapshot ioctl time
authorDavid Sterba <dsterba@suse.com>
Tue, 10 Nov 2015 17:54:00 +0000 (18:54 +0100)
committerZygo Blaxell <zblaxell@thirteen.furryterror.org>
Sat, 16 Jan 2016 03:36:24 +0000 (22:36 -0500)
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>
(cherry picked from commit b0c0ea6338d5018e02d27c5315084fb1a5d099f6)

fs/btrfs/ioctl.c
fs/btrfs/transaction.c
fs/btrfs/transaction.h

index dd6b18cb840e358cda799deedd3a281cb1bd2ed9..0f103c4ea4071ec5015f40c038c657ebced0f3a9 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 5c716c782ad879a98e6be26b9650eaae5e39c171..61e11892b560471cf951259b2c2729fbf17e74d2 100644 (file)
@@ -1360,11 +1360,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)
@@ -1584,7 +1581,7 @@ dir_item_existed:
        trans->bytes_reserved = 0;
 no_free_objectid:
        kfree(new_root_item);
-root_item_alloc_fail:
+       pending->root_item = NULL;
        btrfs_free_path(path);
        return ret;
 }
index fd861fe87a24d30d9389533ffd0bab75f57a89f8..c0137cc3664d20030261b292b6aafd7687cd4574 100644 (file)
@@ -136,6 +136,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 */