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 <sbehr...@giantdisaster.de>
> ---
>  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 majord...@vger.kernel.org
> 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 majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to