|
@@ -363,7 +363,7 @@ static noinline int btrfs_ioctl_fitrim(struct file *file, void __user *arg)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static noinline int create_subvol(struct btrfs_root *root,
|
|
|
+static noinline int create_subvol(struct inode *dir,
|
|
|
struct dentry *dentry,
|
|
|
char *name, int namelen,
|
|
|
u64 *async_transid,
|
|
@@ -374,32 +374,39 @@ static noinline int create_subvol(struct btrfs_root *root,
|
|
|
struct btrfs_root_item root_item;
|
|
|
struct btrfs_inode_item *inode_item;
|
|
|
struct extent_buffer *leaf;
|
|
|
+ struct btrfs_root *root = BTRFS_I(dir)->root;
|
|
|
struct btrfs_root *new_root;
|
|
|
- struct dentry *parent = dentry->d_parent;
|
|
|
- struct inode *dir;
|
|
|
+ struct btrfs_block_rsv block_rsv;
|
|
|
struct timespec cur_time = CURRENT_TIME;
|
|
|
int ret;
|
|
|
int err;
|
|
|
u64 objectid;
|
|
|
u64 new_dirid = BTRFS_FIRST_FREE_OBJECTID;
|
|
|
u64 index = 0;
|
|
|
+ u64 qgroup_reserved;
|
|
|
uuid_le new_uuid;
|
|
|
|
|
|
ret = btrfs_find_free_objectid(root->fs_info->tree_root, &objectid);
|
|
|
if (ret)
|
|
|
return ret;
|
|
|
|
|
|
- dir = parent->d_inode;
|
|
|
-
|
|
|
+ btrfs_init_block_rsv(&block_rsv, BTRFS_BLOCK_RSV_TEMP);
|
|
|
/*
|
|
|
- * 1 - inode item
|
|
|
- * 2 - refs
|
|
|
- * 1 - root item
|
|
|
- * 2 - dir items
|
|
|
+ * The same as the snapshot creation, please see the comment
|
|
|
+ * of create_snapshot().
|
|
|
*/
|
|
|
- trans = btrfs_start_transaction(root, 6);
|
|
|
- if (IS_ERR(trans))
|
|
|
- return PTR_ERR(trans);
|
|
|
+ ret = btrfs_subvolume_reserve_metadata(root, &block_rsv,
|
|
|
+ 7, &qgroup_reserved);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ trans = btrfs_start_transaction(root, 0);
|
|
|
+ if (IS_ERR(trans)) {
|
|
|
+ ret = PTR_ERR(trans);
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+ trans->block_rsv = &block_rsv;
|
|
|
+ trans->bytes_reserved = block_rsv.size;
|
|
|
|
|
|
ret = btrfs_qgroup_inherit(trans, root->fs_info, 0, objectid, inherit);
|
|
|
if (ret)
|
|
@@ -515,6 +522,8 @@ static noinline int create_subvol(struct btrfs_root *root,
|
|
|
BUG_ON(ret);
|
|
|
|
|
|
fail:
|
|
|
+ trans->block_rsv = NULL;
|
|
|
+ trans->bytes_reserved = 0;
|
|
|
if (async_transid) {
|
|
|
*async_transid = trans->transid;
|
|
|
err = btrfs_commit_transaction_async(trans, root, 1);
|
|
@@ -526,7 +535,8 @@ fail:
|
|
|
|
|
|
if (!ret)
|
|
|
d_instantiate(dentry, btrfs_lookup_dentry(dir, dentry));
|
|
|
-
|
|
|
+out:
|
|
|
+ btrfs_subvolume_release_metadata(root, &block_rsv, qgroup_reserved);
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
@@ -549,21 +559,31 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
|
|
|
|
|
|
btrfs_init_block_rsv(&pending_snapshot->block_rsv,
|
|
|
BTRFS_BLOCK_RSV_TEMP);
|
|
|
+ /*
|
|
|
+ * 1 - parent dir inode
|
|
|
+ * 2 - dir entries
|
|
|
+ * 1 - root item
|
|
|
+ * 2 - root ref/backref
|
|
|
+ * 1 - root of snapshot
|
|
|
+ */
|
|
|
+ ret = btrfs_subvolume_reserve_metadata(BTRFS_I(dir)->root,
|
|
|
+ &pending_snapshot->block_rsv, 7,
|
|
|
+ &pending_snapshot->qgroup_reserved);
|
|
|
+ if (ret)
|
|
|
+ goto out;
|
|
|
+
|
|
|
pending_snapshot->dentry = dentry;
|
|
|
pending_snapshot->root = root;
|
|
|
pending_snapshot->readonly = readonly;
|
|
|
pending_snapshot->dir = dir;
|
|
|
pending_snapshot->inherit = inherit;
|
|
|
|
|
|
- trans = btrfs_start_transaction(root->fs_info->extent_root, 6);
|
|
|
+ trans = btrfs_start_transaction(root, 0);
|
|
|
if (IS_ERR(trans)) {
|
|
|
ret = PTR_ERR(trans);
|
|
|
goto fail;
|
|
|
}
|
|
|
|
|
|
- ret = btrfs_snap_reserve_metadata(trans, pending_snapshot);
|
|
|
- BUG_ON(ret);
|
|
|
-
|
|
|
spin_lock(&root->fs_info->trans_lock);
|
|
|
list_add(&pending_snapshot->list,
|
|
|
&trans->transaction->pending_snapshots);
|
|
@@ -600,6 +620,10 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
|
|
|
d_instantiate(dentry, inode);
|
|
|
ret = 0;
|
|
|
fail:
|
|
|
+ btrfs_subvolume_release_metadata(BTRFS_I(dir)->root,
|
|
|
+ &pending_snapshot->block_rsv,
|
|
|
+ pending_snapshot->qgroup_reserved);
|
|
|
+out:
|
|
|
kfree(pending_snapshot);
|
|
|
return ret;
|
|
|
}
|
|
@@ -733,8 +757,8 @@ static noinline int btrfs_mksubvol(struct path *parent,
|
|
|
error = create_snapshot(snap_src, dir, dentry, name, namelen,
|
|
|
async_transid, readonly, inherit);
|
|
|
} else {
|
|
|
- error = create_subvol(BTRFS_I(dir)->root, dentry,
|
|
|
- name, namelen, async_transid, inherit);
|
|
|
+ error = create_subvol(dir, dentry, name, namelen,
|
|
|
+ async_transid, inherit);
|
|
|
}
|
|
|
if (!error)
|
|
|
fsnotify_mkdir(dir, dentry);
|