]> 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@serenity.furryterror.org>
Tue, 19 Jan 2016 05:30:46 +0000 (00:30 -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)
(cherry picked from commit b6e581a7ad2a965960f8b9fe76066fc954258dbe)

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

index bb6437f78ba849428e3e6e472092ac21bf00bbeb..8f3f0f7b5b7f7c68ff57e2e7fdc7e919637cbf91 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 ec9e3b704b4853355ebf4c7e006d5159b69a530b..ff10082096e20696f37eefe798c88afa37e07058 100644 (file)
@@ -1366,11 +1366,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)
@@ -1603,7 +1600,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 6e755658f0aef00784719edbc27db2ec996547b4..93487babed77140ce64c15ea84eded1ff1c3c5ae 100644 (file)
@@ -138,6 +138,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 */