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