On Tue, May 14, 2013 at 11:36:56AM +0200, Stefan Behrens wrote:
> When a new subvolume or snapshot is created, a new UUID item is added
> to the UUID tree. Such items are removed when the subvolume is deleted.
> The ioctl to set the received subvolume UUID is also touched and will
> now also add this received UUID into the UUID tree together with the
> ID of the subvolume. The latter is also done when read-only snapshots
> are created which inherit all the send/receive information from the
> parent subvolume.
>
> User mode programs use the BTRFS_IOC_TREE_SEARCH ioctl to search and
> read in the UUID tree.
>
> Signed-off-by: Stefan Behrens <sbehrens@xxxxxxxxxxxxxxxx>
> ---
> fs/btrfs/ctree.h | 1 +
> fs/btrfs/ioctl.c | 74 +++++++++++++++++++++++++++++++++++++++++++-------
> fs/btrfs/transaction.c | 19 ++++++++++++-
> 3 files changed, 83 insertions(+), 11 deletions(-)
>
> diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
> index 6f9d760..73d797c 100644
> --- a/fs/btrfs/ctree.h
> +++ b/fs/btrfs/ctree.h
> @@ -3634,6 +3634,7 @@ extern const struct dentry_operations btrfs_dentry_operations;
> long btrfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
> void btrfs_update_iflags(struct inode *inode);
> void btrfs_inherit_iflags(struct inode *inode, struct inode *dir);
> +int btrfs_is_empty_uuid(u8 *uuid);
> int btrfs_defrag_file(struct inode *inode, struct file *file,
> struct btrfs_ioctl_defrag_range_args *range,
> u64 newer_than, unsigned long max_pages);
> diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
> index b2537c7..47bef5a 100644
> --- a/fs/btrfs/ioctl.c
> +++ b/fs/btrfs/ioctl.c
> @@ -363,6 +363,13 @@ static noinline int btrfs_ioctl_fitrim(struct file *file, void __user *arg)
> return 0;
> }
>
> +int btrfs_is_empty_uuid(u8 *uuid)
> +{
> + static char empty_uuid[BTRFS_UUID_SIZE] = {0};
> +
> + return !memcmp(uuid, empty_uuid, BTRFS_UUID_SIZE);
> +}
> +
> static noinline int create_subvol(struct inode *dir,
> struct dentry *dentry,
> char *name, int namelen,
> @@ -396,7 +403,7 @@ static noinline int create_subvol(struct inode *dir,
> * of create_snapshot().
> */
> ret = btrfs_subvolume_reserve_metadata(root, &block_rsv,
> - 7, &qgroup_reserved);
> + 8, &qgroup_reserved);
> if (ret)
> return ret;
>
> @@ -518,9 +525,13 @@ static noinline int create_subvol(struct inode *dir,
> ret = btrfs_add_root_ref(trans, root->fs_info->tree_root,
> objectid, root->root_key.objectid,
> btrfs_ino(dir), index, name, namelen);
> -
> BUG_ON(ret);
>
This uuid_root will not use trans->block_rsv but empty_rsv since it does not set
ref_cow, so you don't need to add one more to block_rsv, and same for
the below cases.
thanks,
liubo
> + ret = btrfs_insert_uuid_subvol_item(trans, root->fs_info->uuid_root,
> + root_item.uuid, objectid);
> + if (ret)
> + btrfs_abort_transaction(trans, root, ret);
> +
> fail:
> trans->block_rsv = NULL;
> trans->bytes_reserved = 0;
> @@ -567,9 +578,10 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
> * 1 - root item
> * 2 - root ref/backref
> * 1 - root of snapshot
> + * 1 - UUID item
> */
> ret = btrfs_subvolume_reserve_metadata(BTRFS_I(dir)->root,
> - &pending_snapshot->block_rsv, 7,
> + &pending_snapshot->block_rsv, 8,
> &pending_snapshot->qgroup_reserved);
> if (ret)
> goto out;
> @@ -2207,6 +2219,27 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
> goto out_end_trans;
> }
> }
> +
> + ret = btrfs_del_uuid_subvol_item(trans, root->fs_info->uuid_root,
> + dest->root_item.uuid,
> + dest->root_key.objectid);
> + if (ret && ret != -ENOENT) {
> + btrfs_abort_transaction(trans, root, ret);
> + err = ret;
> + goto out_end_trans;
> + }
> + if (!btrfs_is_empty_uuid(dest->root_item.received_uuid)) {
> + ret = btrfs_del_uuid_received_subvol_item(trans,
> + root->fs_info->uuid_root,
> + dest->root_item.received_uuid,
> + dest->root_key.objectid);
> + if (ret && ret != -ENOENT) {
> + btrfs_abort_transaction(trans, root, ret);
> + err = ret;
> + goto out_end_trans;
> + }
> + }
> +
> out_end_trans:
> trans->block_rsv = NULL;
> trans->bytes_reserved = 0;
> @@ -2418,7 +2451,6 @@ static long btrfs_ioctl_dev_info(struct btrfs_root *root, void __user *arg)
> struct btrfs_fs_devices *fs_devices = root->fs_info->fs_devices;
> int ret = 0;
> char *s_uuid = NULL;
> - char empty_uuid[BTRFS_UUID_SIZE] = {0};
>
> if (!capable(CAP_SYS_ADMIN))
> return -EPERM;
> @@ -2427,7 +2459,7 @@ static long btrfs_ioctl_dev_info(struct btrfs_root *root, void __user *arg)
> if (IS_ERR(di_args))
> return PTR_ERR(di_args);
>
> - if (memcmp(empty_uuid, di_args->uuid, BTRFS_UUID_SIZE) != 0)
> + if (!btrfs_is_empty_uuid(di_args->uuid))
> s_uuid = di_args->uuid;
>
> mutex_lock(&fs_devices->device_list_mutex);
> @@ -3952,6 +3984,7 @@ static long btrfs_ioctl_set_received_subvol(struct file *file,
> struct btrfs_trans_handle *trans;
> struct timespec ct = CURRENT_TIME;
> int ret = 0;
> + int received_uuid_changed;
>
> ret = mnt_want_write_file(file);
> if (ret < 0)
> @@ -3981,7 +4014,11 @@ static long btrfs_ioctl_set_received_subvol(struct file *file,
> goto out;
> }
>
> - trans = btrfs_start_transaction(root, 1);
> + /*
> + * 1 - root item
> + * 2 - uuid items (received uuid + subvol uuid)
> + */
> + trans = btrfs_start_transaction(root, 3);
> if (IS_ERR(trans)) {
> ret = PTR_ERR(trans);
> trans = NULL;
> @@ -3992,6 +4029,14 @@ static long btrfs_ioctl_set_received_subvol(struct file *file,
> sa->rtime.sec = ct.tv_sec;
> sa->rtime.nsec = ct.tv_nsec;
>
> + received_uuid_changed = memcmp(root_item->received_uuid, sa->uuid,
> + BTRFS_UUID_SIZE);
> + if (received_uuid_changed &&
> + !btrfs_is_empty_uuid(root_item->received_uuid))
> + btrfs_del_uuid_received_subvol_item(trans,
> + root->fs_info->uuid_root,
> + root_item->received_uuid,
> + root->root_key.objectid);
> memcpy(root_item->received_uuid, sa->uuid, BTRFS_UUID_SIZE);
> btrfs_set_root_stransid(root_item, sa->stransid);
> btrfs_set_root_rtransid(root_item, sa->rtransid);
> @@ -4004,12 +4049,21 @@ static long btrfs_ioctl_set_received_subvol(struct file *file,
> &root->root_key, &root->root_item);
> if (ret < 0) {
> btrfs_end_transaction(trans, root);
> - trans = NULL;
> goto out;
> - } else {
> - ret = btrfs_commit_transaction(trans, root);
> - if (ret < 0)
> + }
> + if (received_uuid_changed && !btrfs_is_empty_uuid(sa->uuid)) {
> + ret = btrfs_insert_uuid_received_subvol_item(
> + trans, root->fs_info->uuid_root, sa->uuid,
> + root->root_key.objectid);
> + if (ret < 0 && ret != -EEXIST) {
> + btrfs_abort_transaction(trans, root, ret);
> goto out;
> + }
> + }
> + ret = btrfs_commit_transaction(trans, root);
> + if (ret < 0) {
> + btrfs_abort_transaction(trans, root, ret);
> + goto out;
> }
>
> ret = copy_to_user(arg, sa, sizeof(*sa));
> diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
> index 0544587..a3d92b3 100644
> --- a/fs/btrfs/transaction.c
> +++ b/fs/btrfs/transaction.c
> @@ -1263,8 +1263,25 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
> dentry->d_name.len * 2);
> parent_inode->i_mtime = parent_inode->i_ctime = CURRENT_TIME;
> ret = btrfs_update_inode_fallback(trans, parent_root, parent_inode);
> - if (ret)
> + if (ret) {
> + btrfs_abort_transaction(trans, root, ret);
> + goto fail;
> + }
> + ret = btrfs_insert_uuid_subvol_item(trans, fs_info->uuid_root,
> + new_uuid.b, objectid);
> + if (ret) {
> btrfs_abort_transaction(trans, root, ret);
> + goto fail;
> + }
> + if (!btrfs_is_empty_uuid(new_root_item->received_uuid)) {
> + ret = btrfs_insert_uuid_received_subvol_item(
> + trans, fs_info->uuid_root, new_root_item->received_uuid,
> + objectid);
> + if (ret && ret != -EEXIST) {
> + btrfs_abort_transaction(trans, root, ret);
> + goto fail;
> + }
> + }
> fail:
> pending->error = ret;
> dir_item_existed:
> --
> 1.8.2.2
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html