aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/ioctl.c
diff options
context:
space:
mode:
authorStefan Behrens <sbehrens@giantdisaster.de>2013-08-15 11:11:20 -0400
committerChris Mason <chris.mason@fusionio.com>2013-09-01 08:15:55 -0400
commitdd5f9615fc5c5e8d3751aab3a17b92768fb1ce70 (patch)
tree9b7ad64c2761200e7713ee55e5d667e1b57d0e6b /fs/btrfs/ioctl.c
parentf7a81ea4cc6bdb51d8267d2f3ff485f0b4070074 (diff)
Btrfs: maintain subvolume items in the UUID tree
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@giantdisaster.de> Signed-off-by: Josef Bacik <jbacik@fusionio.com> Signed-off-by: Chris Mason <chris.mason@fusionio.com>
Diffstat (limited to 'fs/btrfs/ioctl.c')
-rw-r--r--fs/btrfs/ioctl.c76
1 files changed, 66 insertions, 10 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 82fb11a361c4..8e75249282c2 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -367,6 +367,13 @@ static noinline int btrfs_ioctl_fitrim(struct file *file, void __user *arg)
367 return 0; 367 return 0;
368} 368}
369 369
370int btrfs_is_empty_uuid(u8 *uuid)
371{
372 static char empty_uuid[BTRFS_UUID_SIZE] = {0};
373
374 return !memcmp(uuid, empty_uuid, BTRFS_UUID_SIZE);
375}
376
370static noinline int create_subvol(struct inode *dir, 377static noinline int create_subvol(struct inode *dir,
371 struct dentry *dentry, 378 struct dentry *dentry,
372 char *name, int namelen, 379 char *name, int namelen,
@@ -400,7 +407,7 @@ static noinline int create_subvol(struct inode *dir,
400 * of create_snapshot(). 407 * of create_snapshot().
401 */ 408 */
402 ret = btrfs_subvolume_reserve_metadata(root, &block_rsv, 409 ret = btrfs_subvolume_reserve_metadata(root, &block_rsv,
403 7, &qgroup_reserved, false); 410 8, &qgroup_reserved, false);
404 if (ret) 411 if (ret)
405 return ret; 412 return ret;
406 413
@@ -522,9 +529,14 @@ static noinline int create_subvol(struct inode *dir,
522 ret = btrfs_add_root_ref(trans, root->fs_info->tree_root, 529 ret = btrfs_add_root_ref(trans, root->fs_info->tree_root,
523 objectid, root->root_key.objectid, 530 objectid, root->root_key.objectid,
524 btrfs_ino(dir), index, name, namelen); 531 btrfs_ino(dir), index, name, namelen);
525
526 BUG_ON(ret); 532 BUG_ON(ret);
527 533
534 ret = btrfs_uuid_tree_add(trans, root->fs_info->uuid_root,
535 root_item.uuid, BTRFS_UUID_KEY_SUBVOL,
536 objectid);
537 if (ret)
538 btrfs_abort_transaction(trans, root, ret);
539
528fail: 540fail:
529 trans->block_rsv = NULL; 541 trans->block_rsv = NULL;
530 trans->bytes_reserved = 0; 542 trans->bytes_reserved = 0;
@@ -577,9 +589,10 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
577 * 1 - root item 589 * 1 - root item
578 * 2 - root ref/backref 590 * 2 - root ref/backref
579 * 1 - root of snapshot 591 * 1 - root of snapshot
592 * 1 - UUID item
580 */ 593 */
581 ret = btrfs_subvolume_reserve_metadata(BTRFS_I(dir)->root, 594 ret = btrfs_subvolume_reserve_metadata(BTRFS_I(dir)->root,
582 &pending_snapshot->block_rsv, 7, 595 &pending_snapshot->block_rsv, 8,
583 &pending_snapshot->qgroup_reserved, 596 &pending_snapshot->qgroup_reserved,
584 false); 597 false);
585 if (ret) 598 if (ret)
@@ -2235,6 +2248,27 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
2235 goto out_end_trans; 2248 goto out_end_trans;
2236 } 2249 }
2237 } 2250 }
2251
2252 ret = btrfs_uuid_tree_rem(trans, root->fs_info->uuid_root,
2253 dest->root_item.uuid, BTRFS_UUID_KEY_SUBVOL,
2254 dest->root_key.objectid);
2255 if (ret && ret != -ENOENT) {
2256 btrfs_abort_transaction(trans, root, ret);
2257 err = ret;
2258 goto out_end_trans;
2259 }
2260 if (!btrfs_is_empty_uuid(dest->root_item.received_uuid)) {
2261 ret = btrfs_uuid_tree_rem(trans, root->fs_info->uuid_root,
2262 dest->root_item.received_uuid,
2263 BTRFS_UUID_KEY_RECEIVED_SUBVOL,
2264 dest->root_key.objectid);
2265 if (ret && ret != -ENOENT) {
2266 btrfs_abort_transaction(trans, root, ret);
2267 err = ret;
2268 goto out_end_trans;
2269 }
2270 }
2271
2238out_end_trans: 2272out_end_trans:
2239 trans->block_rsv = NULL; 2273 trans->block_rsv = NULL;
2240 trans->bytes_reserved = 0; 2274 trans->bytes_reserved = 0;
@@ -2446,7 +2480,6 @@ static long btrfs_ioctl_dev_info(struct btrfs_root *root, void __user *arg)
2446 struct btrfs_fs_devices *fs_devices = root->fs_info->fs_devices; 2480 struct btrfs_fs_devices *fs_devices = root->fs_info->fs_devices;
2447 int ret = 0; 2481 int ret = 0;
2448 char *s_uuid = NULL; 2482 char *s_uuid = NULL;
2449 char empty_uuid[BTRFS_UUID_SIZE] = {0};
2450 2483
2451 if (!capable(CAP_SYS_ADMIN)) 2484 if (!capable(CAP_SYS_ADMIN))
2452 return -EPERM; 2485 return -EPERM;
@@ -2455,7 +2488,7 @@ static long btrfs_ioctl_dev_info(struct btrfs_root *root, void __user *arg)
2455 if (IS_ERR(di_args)) 2488 if (IS_ERR(di_args))
2456 return PTR_ERR(di_args); 2489 return PTR_ERR(di_args);
2457 2490
2458 if (memcmp(empty_uuid, di_args->uuid, BTRFS_UUID_SIZE) != 0) 2491 if (!btrfs_is_empty_uuid(di_args->uuid))
2459 s_uuid = di_args->uuid; 2492 s_uuid = di_args->uuid;
2460 2493
2461 mutex_lock(&fs_devices->device_list_mutex); 2494 mutex_lock(&fs_devices->device_list_mutex);
@@ -4292,6 +4325,7 @@ static long btrfs_ioctl_set_received_subvol(struct file *file,
4292 struct btrfs_trans_handle *trans; 4325 struct btrfs_trans_handle *trans;
4293 struct timespec ct = CURRENT_TIME; 4326 struct timespec ct = CURRENT_TIME;
4294 int ret = 0; 4327 int ret = 0;
4328 int received_uuid_changed;
4295 4329
4296 ret = mnt_want_write_file(file); 4330 ret = mnt_want_write_file(file);
4297 if (ret < 0) 4331 if (ret < 0)
@@ -4321,7 +4355,11 @@ static long btrfs_ioctl_set_received_subvol(struct file *file,
4321 goto out; 4355 goto out;
4322 } 4356 }
4323 4357
4324 trans = btrfs_start_transaction(root, 1); 4358 /*
4359 * 1 - root item
4360 * 2 - uuid items (received uuid + subvol uuid)
4361 */
4362 trans = btrfs_start_transaction(root, 3);
4325 if (IS_ERR(trans)) { 4363 if (IS_ERR(trans)) {
4326 ret = PTR_ERR(trans); 4364 ret = PTR_ERR(trans);
4327 trans = NULL; 4365 trans = NULL;
@@ -4332,6 +4370,14 @@ static long btrfs_ioctl_set_received_subvol(struct file *file,
4332 sa->rtime.sec = ct.tv_sec; 4370 sa->rtime.sec = ct.tv_sec;
4333 sa->rtime.nsec = ct.tv_nsec; 4371 sa->rtime.nsec = ct.tv_nsec;
4334 4372
4373 received_uuid_changed = memcmp(root_item->received_uuid, sa->uuid,
4374 BTRFS_UUID_SIZE);
4375 if (received_uuid_changed &&
4376 !btrfs_is_empty_uuid(root_item->received_uuid))
4377 btrfs_uuid_tree_rem(trans, root->fs_info->uuid_root,
4378 root_item->received_uuid,
4379 BTRFS_UUID_KEY_RECEIVED_SUBVOL,
4380 root->root_key.objectid);
4335 memcpy(root_item->received_uuid, sa->uuid, BTRFS_UUID_SIZE); 4381 memcpy(root_item->received_uuid, sa->uuid, BTRFS_UUID_SIZE);
4336 btrfs_set_root_stransid(root_item, sa->stransid); 4382 btrfs_set_root_stransid(root_item, sa->stransid);
4337 btrfs_set_root_rtransid(root_item, sa->rtransid); 4383 btrfs_set_root_rtransid(root_item, sa->rtransid);
@@ -4344,12 +4390,22 @@ static long btrfs_ioctl_set_received_subvol(struct file *file,
4344 &root->root_key, &root->root_item); 4390 &root->root_key, &root->root_item);
4345 if (ret < 0) { 4391 if (ret < 0) {
4346 btrfs_end_transaction(trans, root); 4392 btrfs_end_transaction(trans, root);
4347 trans = NULL;
4348 goto out; 4393 goto out;
4349 } else { 4394 }
4350 ret = btrfs_commit_transaction(trans, root); 4395 if (received_uuid_changed && !btrfs_is_empty_uuid(sa->uuid)) {
4351 if (ret < 0) 4396 ret = btrfs_uuid_tree_add(trans, root->fs_info->uuid_root,
4397 sa->uuid,
4398 BTRFS_UUID_KEY_RECEIVED_SUBVOL,
4399 root->root_key.objectid);
4400 if (ret < 0 && ret != -EEXIST) {
4401 btrfs_abort_transaction(trans, root, ret);
4352 goto out; 4402 goto out;
4403 }
4404 }
4405 ret = btrfs_commit_transaction(trans, root);
4406 if (ret < 0) {
4407 btrfs_abort_transaction(trans, root, ret);
4408 goto out;
4353 } 4409 }
4354 4410
4355 ret = copy_to_user(arg, sa, sizeof(*sa)); 4411 ret = copy_to_user(arg, sa, sizeof(*sa));