Skip to content

Commit 8ea05e3

Browse files
author
Alexander Block
committed
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 <[email protected]> Reviewed-by: David Sterba <[email protected]> Reviewed-by: Arne Jansen <[email protected]> Reviewed-by: Jan Schmidt <[email protected]> Reviewed-by: Alex Lyakas <[email protected]>
1 parent 91cb916 commit 8ea05e3

File tree

8 files changed

+292
-15
lines changed

8 files changed

+292
-15
lines changed

fs/btrfs/check-integrity.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1032,6 +1032,7 @@ static int btrfsic_process_metablock(
10321032
struct btrfs_disk_key *disk_key;
10331033
u8 type;
10341034
u32 item_offset;
1035+
u32 item_size;
10351036

10361037
if (disk_item_offset + sizeof(struct btrfs_item) >
10371038
sf->block_ctx->len) {
@@ -1047,6 +1048,7 @@ static int btrfsic_process_metablock(
10471048
disk_item_offset,
10481049
sizeof(struct btrfs_item));
10491050
item_offset = le32_to_cpu(disk_item.offset);
1051+
item_size = le32_to_cpu(disk_item.size);
10501052
disk_key = &disk_item.key;
10511053
type = disk_key->type;
10521054

@@ -1057,14 +1059,13 @@ static int btrfsic_process_metablock(
10571059

10581060
root_item_offset = item_offset +
10591061
offsetof(struct btrfs_leaf, items);
1060-
if (root_item_offset +
1061-
sizeof(struct btrfs_root_item) >
1062+
if (root_item_offset + item_size >
10621063
sf->block_ctx->len)
10631064
goto leaf_item_out_of_bounce_error;
10641065
btrfsic_read_from_block_data(
10651066
sf->block_ctx, &root_item,
10661067
root_item_offset,
1067-
sizeof(struct btrfs_root_item));
1068+
item_size);
10681069
next_bytenr = le64_to_cpu(root_item.bytenr);
10691070

10701071
sf->error =

fs/btrfs/ctree.h

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -709,6 +709,36 @@ struct btrfs_root_item {
709709
struct btrfs_disk_key drop_progress;
710710
u8 drop_level;
711711
u8 level;
712+
713+
/*
714+
* The following fields appear after subvol_uuids+subvol_times
715+
* were introduced.
716+
*/
717+
718+
/*
719+
* This generation number is used to test if the new fields are valid
720+
* and up to date while reading the root item. Everytime the root item
721+
* is written out, the "generation" field is copied into this field. If
722+
* anyone ever mounted the fs with an older kernel, we will have
723+
* mismatching generation values here and thus must invalidate the
724+
* new fields. See btrfs_update_root and btrfs_find_last_root for
725+
* details.
726+
* the offset of generation_v2 is also used as the start for the memset
727+
* when invalidating the fields.
728+
*/
729+
__le64 generation_v2;
730+
u8 uuid[BTRFS_UUID_SIZE];
731+
u8 parent_uuid[BTRFS_UUID_SIZE];
732+
u8 received_uuid[BTRFS_UUID_SIZE];
733+
__le64 ctransid; /* updated when an inode changes */
734+
__le64 otransid; /* trans when created */
735+
__le64 stransid; /* trans when sent. non-zero for received subvol */
736+
__le64 rtransid; /* trans when received. non-zero for received subvol */
737+
struct btrfs_timespec ctime;
738+
struct btrfs_timespec otime;
739+
struct btrfs_timespec stime;
740+
struct btrfs_timespec rtime;
741+
__le64 reserved[8]; /* for future */
712742
} __attribute__ ((__packed__));
713743

714744
/*
@@ -1416,6 +1446,8 @@ struct btrfs_root {
14161446
dev_t anon_dev;
14171447

14181448
int force_cow;
1449+
1450+
spinlock_t root_times_lock;
14191451
};
14201452

14211453
struct btrfs_ioctl_defrag_range_args {
@@ -2189,6 +2221,16 @@ BTRFS_SETGET_STACK_FUNCS(root_used, struct btrfs_root_item, bytes_used, 64);
21892221
BTRFS_SETGET_STACK_FUNCS(root_limit, struct btrfs_root_item, byte_limit, 64);
21902222
BTRFS_SETGET_STACK_FUNCS(root_last_snapshot, struct btrfs_root_item,
21912223
last_snapshot, 64);
2224+
BTRFS_SETGET_STACK_FUNCS(root_generation_v2, struct btrfs_root_item,
2225+
generation_v2, 64);
2226+
BTRFS_SETGET_STACK_FUNCS(root_ctransid, struct btrfs_root_item,
2227+
ctransid, 64);
2228+
BTRFS_SETGET_STACK_FUNCS(root_otransid, struct btrfs_root_item,
2229+
otransid, 64);
2230+
BTRFS_SETGET_STACK_FUNCS(root_stransid, struct btrfs_root_item,
2231+
stransid, 64);
2232+
BTRFS_SETGET_STACK_FUNCS(root_rtransid, struct btrfs_root_item,
2233+
rtransid, 64);
21922234

21932235
static inline bool btrfs_root_readonly(struct btrfs_root *root)
21942236
{
@@ -2822,13 +2864,18 @@ int __must_check btrfs_update_root(struct btrfs_trans_handle *trans,
28222864
struct btrfs_root *root,
28232865
struct btrfs_key *key,
28242866
struct btrfs_root_item *item);
2867+
void btrfs_read_root_item(struct btrfs_root *root,
2868+
struct extent_buffer *eb, int slot,
2869+
struct btrfs_root_item *item);
28252870
int btrfs_find_last_root(struct btrfs_root *root, u64 objectid, struct
28262871
btrfs_root_item *item, struct btrfs_key *key);
28272872
int btrfs_find_dead_roots(struct btrfs_root *root, u64 objectid);
28282873
int btrfs_find_orphan_roots(struct btrfs_root *tree_root);
28292874
void btrfs_set_root_node(struct btrfs_root_item *item,
28302875
struct extent_buffer *node);
28312876
void btrfs_check_and_init_root_item(struct btrfs_root_item *item);
2877+
void btrfs_update_root_times(struct btrfs_trans_handle *trans,
2878+
struct btrfs_root *root);
28322879

28332880
/* dir-item.c */
28342881
int btrfs_insert_dir_item(struct btrfs_trans_handle *trans,

fs/btrfs/disk-io.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1182,6 +1182,8 @@ static void __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
11821182
root->defrag_running = 0;
11831183
root->root_key.objectid = objectid;
11841184
root->anon_dev = 0;
1185+
1186+
spin_lock_init(&root->root_times_lock);
11851187
}
11861188

11871189
static int __must_check find_and_setup_root(struct btrfs_root *tree_root,
@@ -1326,6 +1328,7 @@ struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_root *tree_root,
13261328
u64 generation;
13271329
u32 blocksize;
13281330
int ret = 0;
1331+
int slot;
13291332

13301333
root = btrfs_alloc_root(fs_info);
13311334
if (!root)
@@ -1352,9 +1355,8 @@ struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_root *tree_root,
13521355
ret = btrfs_search_slot(NULL, tree_root, location, path, 0, 0);
13531356
if (ret == 0) {
13541357
l = path->nodes[0];
1355-
read_extent_buffer(l, &root->root_item,
1356-
btrfs_item_ptr_offset(l, path->slots[0]),
1357-
sizeof(root->root_item));
1358+
slot = path->slots[0];
1359+
btrfs_read_root_item(tree_root, l, slot, &root->root_item);
13581360
memcpy(&root->root_key, location, sizeof(*location));
13591361
}
13601362
btrfs_free_path(path);

fs/btrfs/inode.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2734,6 +2734,8 @@ noinline int btrfs_update_inode(struct btrfs_trans_handle *trans,
27342734
*/
27352735
if (!btrfs_is_free_space_inode(root, inode)
27362736
&& root->root_key.objectid != BTRFS_DATA_RELOC_TREE_OBJECTID) {
2737+
btrfs_update_root_times(trans, root);
2738+
27372739
ret = btrfs_delayed_update_inode(trans, root, inode);
27382740
if (!ret)
27392741
btrfs_set_inode_last_trans(trans, inode);
@@ -4723,6 +4725,8 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
47234725
trace_btrfs_inode_new(inode);
47244726
btrfs_set_inode_last_trans(trans, inode);
47254727

4728+
btrfs_update_root_times(trans, root);
4729+
47264730
return inode;
47274731
fail:
47284732
if (dir)

fs/btrfs/ioctl.c

Lines changed: 97 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
#include <linux/vmalloc.h>
4242
#include <linux/slab.h>
4343
#include <linux/blkdev.h>
44+
#include <linux/uuid.h>
4445
#include "compat.h"
4546
#include "ctree.h"
4647
#include "disk-io.h"
@@ -346,11 +347,13 @@ static noinline int create_subvol(struct btrfs_root *root,
346347
struct btrfs_root *new_root;
347348
struct dentry *parent = dentry->d_parent;
348349
struct inode *dir;
350+
struct timespec cur_time = CURRENT_TIME;
349351
int ret;
350352
int err;
351353
u64 objectid;
352354
u64 new_dirid = BTRFS_FIRST_FREE_OBJECTID;
353355
u64 index = 0;
356+
uuid_le new_uuid;
354357

355358
ret = btrfs_find_free_objectid(root->fs_info->tree_root, &objectid);
356359
if (ret)
@@ -389,8 +392,9 @@ static noinline int create_subvol(struct btrfs_root *root,
389392
BTRFS_UUID_SIZE);
390393
btrfs_mark_buffer_dirty(leaf);
391394

395+
memset(&root_item, 0, sizeof(root_item));
396+
392397
inode_item = &root_item.inode;
393-
memset(inode_item, 0, sizeof(*inode_item));
394398
inode_item->generation = cpu_to_le64(1);
395399
inode_item->size = cpu_to_le64(3);
396400
inode_item->nlink = cpu_to_le32(1);
@@ -408,8 +412,15 @@ static noinline int create_subvol(struct btrfs_root *root,
408412
btrfs_set_root_used(&root_item, leaf->len);
409413
btrfs_set_root_last_snapshot(&root_item, 0);
410414

411-
memset(&root_item.drop_progress, 0, sizeof(root_item.drop_progress));
412-
root_item.drop_level = 0;
415+
btrfs_set_root_generation_v2(&root_item,
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);
413424

414425
btrfs_tree_unlock(leaf);
415426
free_extent_buffer(leaf);
@@ -3395,6 +3406,87 @@ static long btrfs_ioctl_balance_progress(struct btrfs_root *root,
33953406
return ret;
33963407
}
33973408

3409+
static 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+
3483+
out:
3484+
kfree(sa);
3485+
up_write(&root->fs_info->subvol_sem);
3486+
mnt_drop_write_file(file);
3487+
return ret;
3488+
}
3489+
33983490
long btrfs_ioctl(struct file *file, unsigned int
33993491
cmd, unsigned long arg)
34003492
{
@@ -3477,6 +3569,8 @@ long btrfs_ioctl(struct file *file, unsigned int
34773569
return btrfs_ioctl_balance_ctl(root, arg);
34783570
case BTRFS_IOC_BALANCE_PROGRESS:
34793571
return btrfs_ioctl_balance_progress(root, argp);
3572+
case BTRFS_IOC_SET_RECEIVED_SUBVOL:
3573+
return btrfs_ioctl_set_received_subvol(file, argp);
34803574
case BTRFS_IOC_GET_DEV_STATS:
34813575
return btrfs_ioctl_get_dev_stats(root, argp, 0);
34823576
case BTRFS_IOC_GET_AND_RESET_DEV_STATS:

fs/btrfs/ioctl.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,21 @@ struct btrfs_ioctl_get_dev_stats {
295295
__u64 unused[128 - 2 - BTRFS_DEV_STAT_VALUES_MAX]; /* pad to 1k */
296296
};
297297

298+
struct btrfs_ioctl_timespec {
299+
__u64 sec;
300+
__u32 nsec;
301+
};
302+
303+
struct btrfs_ioctl_received_subvol_args {
304+
char uuid[BTRFS_UUID_SIZE]; /* in */
305+
__u64 stransid; /* in */
306+
__u64 rtransid; /* out */
307+
struct btrfs_ioctl_timespec stime; /* in */
308+
struct btrfs_ioctl_timespec rtime; /* out */
309+
__u64 flags; /* in */
310+
__u64 reserved[16]; /* in */
311+
};
312+
298313
#define BTRFS_IOC_SNAP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 1, \
299314
struct btrfs_ioctl_vol_args)
300315
#define BTRFS_IOC_DEFRAG _IOW(BTRFS_IOCTL_MAGIC, 2, \
@@ -359,6 +374,8 @@ struct btrfs_ioctl_get_dev_stats {
359374
struct btrfs_ioctl_ino_path_args)
360375
#define BTRFS_IOC_LOGICAL_INO _IOWR(BTRFS_IOCTL_MAGIC, 36, \
361376
struct btrfs_ioctl_ino_path_args)
377+
#define BTRFS_IOC_SET_RECEIVED_SUBVOL _IOWR(BTRFS_IOCTL_MAGIC, 37, \
378+
struct btrfs_ioctl_received_subvol_args)
362379
#define BTRFS_IOC_GET_DEV_STATS _IOWR(BTRFS_IOCTL_MAGIC, 52, \
363380
struct btrfs_ioctl_get_dev_stats)
364381
#define BTRFS_IOC_GET_AND_RESET_DEV_STATS _IOWR(BTRFS_IOCTL_MAGIC, 53, \

0 commit comments

Comments
 (0)