aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/ioctl.c
diff options
context:
space:
mode:
authorAlexander Block <ablock84@googlemail.com>2012-07-25 11:35:53 -0400
committerAlexander Block <ablock84@googlemail.com>2012-07-25 17:28:38 -0400
commit8ea05e3a4262b9e6871c349fa3486bcfc72ffd1a (patch)
tree893a8ff635b31caf920aaa97948e612640cbac6a /fs/btrfs/ioctl.c
parent91cb916ca26feb99c78c131a1643af3d10fefd96 (diff)
Btrfs: introduce subvol uuids and times
This patch introduces uuids for subvolumes. Each subvolume has it's own uuid. In case it was snapshotted, it also contains parent_uuid. In case it was received, it also contains received_uuid. It also introduces subvolume ctime/otime/stime/rtime. The first two are comparable to the times found in inodes. otime is the origin/creation time and ctime is the change time. stime/rtime are only valid on received subvolumes. stime is the time of the subvolume when it was sent. rtime is the time of the subvolume when it was received. Additionally to the times, we have a transid for each time. They are updated at the same place as the times. btrfs receive uses stransid and rtransid to find out if a received subvolume changed in the meantime. If an older kernel mounts a filesystem with the extented fields, all fields become invalid. The next mount with a new kernel will detect this and reset the fields. Signed-off-by: Alexander Block <ablock84@googlemail.com> Reviewed-by: David Sterba <dave@jikos.cz> Reviewed-by: Arne Jansen <sensille@gmx.net> Reviewed-by: Jan Schmidt <list.btrfs@jan-o-sch.net> Reviewed-by: Alex Lyakas <alex.bolshoy.btrfs@gmail.com>
Diffstat (limited to 'fs/btrfs/ioctl.c')
-rw-r--r--fs/btrfs/ioctl.c100
1 files changed, 97 insertions, 3 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 7011871c45b8..99fe2ce7f721 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -41,6 +41,7 @@
41#include <linux/vmalloc.h> 41#include <linux/vmalloc.h>
42#include <linux/slab.h> 42#include <linux/slab.h>
43#include <linux/blkdev.h> 43#include <linux/blkdev.h>
44#include <linux/uuid.h>
44#include "compat.h" 45#include "compat.h"
45#include "ctree.h" 46#include "ctree.h"
46#include "disk-io.h" 47#include "disk-io.h"
@@ -346,11 +347,13 @@ static noinline int create_subvol(struct btrfs_root *root,
346 struct btrfs_root *new_root; 347 struct btrfs_root *new_root;
347 struct dentry *parent = dentry->d_parent; 348 struct dentry *parent = dentry->d_parent;
348 struct inode *dir; 349 struct inode *dir;
350 struct timespec cur_time = CURRENT_TIME;
349 int ret; 351 int ret;
350 int err; 352 int err;
351 u64 objectid; 353 u64 objectid;
352 u64 new_dirid = BTRFS_FIRST_FREE_OBJECTID; 354 u64 new_dirid = BTRFS_FIRST_FREE_OBJECTID;
353 u64 index = 0; 355 u64 index = 0;
356 uuid_le new_uuid;
354 357
355 ret = btrfs_find_free_objectid(root->fs_info->tree_root, &objectid); 358 ret = btrfs_find_free_objectid(root->fs_info->tree_root, &objectid);
356 if (ret) 359 if (ret)
@@ -389,8 +392,9 @@ static noinline int create_subvol(struct btrfs_root *root,
389 BTRFS_UUID_SIZE); 392 BTRFS_UUID_SIZE);
390 btrfs_mark_buffer_dirty(leaf); 393 btrfs_mark_buffer_dirty(leaf);
391 394
395 memset(&root_item, 0, sizeof(root_item));
396
392 inode_item = &root_item.inode; 397 inode_item = &root_item.inode;
393 memset(inode_item, 0, sizeof(*inode_item));
394 inode_item->generation = cpu_to_le64(1); 398 inode_item->generation = cpu_to_le64(1);
395 inode_item->size = cpu_to_le64(3); 399 inode_item->size = cpu_to_le64(3);
396 inode_item->nlink = cpu_to_le32(1); 400 inode_item->nlink = cpu_to_le32(1);
@@ -408,8 +412,15 @@ static noinline int create_subvol(struct btrfs_root *root,
408 btrfs_set_root_used(&root_item, leaf->len); 412 btrfs_set_root_used(&root_item, leaf->len);
409 btrfs_set_root_last_snapshot(&root_item, 0); 413 btrfs_set_root_last_snapshot(&root_item, 0);
410 414
411 memset(&root_item.drop_progress, 0, sizeof(root_item.drop_progress)); 415 btrfs_set_root_generation_v2(&root_item,
412 root_item.drop_level = 0; 416 btrfs_root_generation(&root_item));
417 uuid_le_gen(&new_uuid);
418 memcpy(root_item.uuid, new_uuid.b, BTRFS_UUID_SIZE);
419 root_item.otime.sec = cpu_to_le64(cur_time.tv_sec);
420 root_item.otime.nsec = cpu_to_le64(cur_time.tv_nsec);
421 root_item.ctime = root_item.otime;
422 btrfs_set_root_ctransid(&root_item, trans->transid);
423 btrfs_set_root_otransid(&root_item, trans->transid);
413 424
414 btrfs_tree_unlock(leaf); 425 btrfs_tree_unlock(leaf);
415 free_extent_buffer(leaf); 426 free_extent_buffer(leaf);
@@ -3395,6 +3406,87 @@ out:
3395 return ret; 3406 return ret;
3396} 3407}
3397 3408
3409static long btrfs_ioctl_set_received_subvol(struct file *file,
3410 void __user *arg)
3411{
3412 struct btrfs_ioctl_received_subvol_args *sa = NULL;
3413 struct inode *inode = fdentry(file)->d_inode;
3414 struct btrfs_root *root = BTRFS_I(inode)->root;
3415 struct btrfs_root_item *root_item = &root->root_item;
3416 struct btrfs_trans_handle *trans;
3417 struct timespec ct = CURRENT_TIME;
3418 int ret = 0;
3419
3420 ret = mnt_want_write_file(file);
3421 if (ret < 0)
3422 return ret;
3423
3424 down_write(&root->fs_info->subvol_sem);
3425
3426 if (btrfs_ino(inode) != BTRFS_FIRST_FREE_OBJECTID) {
3427 ret = -EINVAL;
3428 goto out;
3429 }
3430
3431 if (btrfs_root_readonly(root)) {
3432 ret = -EROFS;
3433 goto out;
3434 }
3435
3436 if (!inode_owner_or_capable(inode)) {
3437 ret = -EACCES;
3438 goto out;
3439 }
3440
3441 sa = memdup_user(arg, sizeof(*sa));
3442 if (IS_ERR(sa)) {
3443 ret = PTR_ERR(sa);
3444 sa = NULL;
3445 goto out;
3446 }
3447
3448 trans = btrfs_start_transaction(root, 1);
3449 if (IS_ERR(trans)) {
3450 ret = PTR_ERR(trans);
3451 trans = NULL;
3452 goto out;
3453 }
3454
3455 sa->rtransid = trans->transid;
3456 sa->rtime.sec = ct.tv_sec;
3457 sa->rtime.nsec = ct.tv_nsec;
3458
3459 memcpy(root_item->received_uuid, sa->uuid, BTRFS_UUID_SIZE);
3460 btrfs_set_root_stransid(root_item, sa->stransid);
3461 btrfs_set_root_rtransid(root_item, sa->rtransid);
3462 root_item->stime.sec = cpu_to_le64(sa->stime.sec);
3463 root_item->stime.nsec = cpu_to_le32(sa->stime.nsec);
3464 root_item->rtime.sec = cpu_to_le64(sa->rtime.sec);
3465 root_item->rtime.nsec = cpu_to_le32(sa->rtime.nsec);
3466
3467 ret = btrfs_update_root(trans, root->fs_info->tree_root,
3468 &root->root_key, &root->root_item);
3469 if (ret < 0) {
3470 btrfs_end_transaction(trans, root);
3471 trans = NULL;
3472 goto out;
3473 } else {
3474 ret = btrfs_commit_transaction(trans, root);
3475 if (ret < 0)
3476 goto out;
3477 }
3478
3479 ret = copy_to_user(arg, sa, sizeof(*sa));
3480 if (ret)
3481 ret = -EFAULT;
3482
3483out:
3484 kfree(sa);
3485 up_write(&root->fs_info->subvol_sem);
3486 mnt_drop_write_file(file);
3487 return ret;
3488}
3489
3398long btrfs_ioctl(struct file *file, unsigned int 3490long btrfs_ioctl(struct file *file, unsigned int
3399 cmd, unsigned long arg) 3491 cmd, unsigned long arg)
3400{ 3492{
@@ -3477,6 +3569,8 @@ long btrfs_ioctl(struct file *file, unsigned int
3477 return btrfs_ioctl_balance_ctl(root, arg); 3569 return btrfs_ioctl_balance_ctl(root, arg);
3478 case BTRFS_IOC_BALANCE_PROGRESS: 3570 case BTRFS_IOC_BALANCE_PROGRESS:
3479 return btrfs_ioctl_balance_progress(root, argp); 3571 return btrfs_ioctl_balance_progress(root, argp);
3572 case BTRFS_IOC_SET_RECEIVED_SUBVOL:
3573 return btrfs_ioctl_set_received_subvol(file, argp);
3480 case BTRFS_IOC_GET_DEV_STATS: 3574 case BTRFS_IOC_GET_DEV_STATS:
3481 return btrfs_ioctl_get_dev_stats(root, argp, 0); 3575 return btrfs_ioctl_get_dev_stats(root, argp, 0);
3482 case BTRFS_IOC_GET_AND_RESET_DEV_STATS: 3576 case BTRFS_IOC_GET_AND_RESET_DEV_STATS: