diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/check-integrity.c | 7 | ||||
-rw-r--r-- | fs/btrfs/ctree.h | 47 | ||||
-rw-r--r-- | fs/btrfs/disk-io.c | 8 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 4 | ||||
-rw-r--r-- | fs/btrfs/ioctl.c | 100 | ||||
-rw-r--r-- | fs/btrfs/ioctl.h | 17 | ||||
-rw-r--r-- | fs/btrfs/root-tree.c | 107 | ||||
-rw-r--r-- | fs/btrfs/transaction.c | 17 |
8 files changed, 292 insertions, 15 deletions
diff --git a/fs/btrfs/check-integrity.c b/fs/btrfs/check-integrity.c index da6e9364a5e..9197e2e3340 100644 --- a/fs/btrfs/check-integrity.c +++ b/fs/btrfs/check-integrity.c | |||
@@ -1032,6 +1032,7 @@ continue_with_current_leaf_stack_frame: | |||
1032 | struct btrfs_disk_key *disk_key; | 1032 | struct btrfs_disk_key *disk_key; |
1033 | u8 type; | 1033 | u8 type; |
1034 | u32 item_offset; | 1034 | u32 item_offset; |
1035 | u32 item_size; | ||
1035 | 1036 | ||
1036 | if (disk_item_offset + sizeof(struct btrfs_item) > | 1037 | if (disk_item_offset + sizeof(struct btrfs_item) > |
1037 | sf->block_ctx->len) { | 1038 | sf->block_ctx->len) { |
@@ -1047,6 +1048,7 @@ leaf_item_out_of_bounce_error: | |||
1047 | disk_item_offset, | 1048 | disk_item_offset, |
1048 | sizeof(struct btrfs_item)); | 1049 | sizeof(struct btrfs_item)); |
1049 | item_offset = le32_to_cpu(disk_item.offset); | 1050 | item_offset = le32_to_cpu(disk_item.offset); |
1051 | item_size = le32_to_cpu(disk_item.size); | ||
1050 | disk_key = &disk_item.key; | 1052 | disk_key = &disk_item.key; |
1051 | type = disk_key->type; | 1053 | type = disk_key->type; |
1052 | 1054 | ||
@@ -1057,14 +1059,13 @@ leaf_item_out_of_bounce_error: | |||
1057 | 1059 | ||
1058 | root_item_offset = item_offset + | 1060 | root_item_offset = item_offset + |
1059 | offsetof(struct btrfs_leaf, items); | 1061 | offsetof(struct btrfs_leaf, items); |
1060 | if (root_item_offset + | 1062 | if (root_item_offset + item_size > |
1061 | sizeof(struct btrfs_root_item) > | ||
1062 | sf->block_ctx->len) | 1063 | sf->block_ctx->len) |
1063 | goto leaf_item_out_of_bounce_error; | 1064 | goto leaf_item_out_of_bounce_error; |
1064 | btrfsic_read_from_block_data( | 1065 | btrfsic_read_from_block_data( |
1065 | sf->block_ctx, &root_item, | 1066 | sf->block_ctx, &root_item, |
1066 | root_item_offset, | 1067 | root_item_offset, |
1067 | sizeof(struct btrfs_root_item)); | 1068 | item_size); |
1068 | next_bytenr = le64_to_cpu(root_item.bytenr); | 1069 | next_bytenr = le64_to_cpu(root_item.bytenr); |
1069 | 1070 | ||
1070 | sf->error = | 1071 | sf->error = |
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 8cfde9326dd..d5f6d745867 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -709,6 +709,36 @@ struct btrfs_root_item { | |||
709 | struct btrfs_disk_key drop_progress; | 709 | struct btrfs_disk_key drop_progress; |
710 | u8 drop_level; | 710 | u8 drop_level; |
711 | u8 level; | 711 | 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 */ | ||
712 | } __attribute__ ((__packed__)); | 742 | } __attribute__ ((__packed__)); |
713 | 743 | ||
714 | /* | 744 | /* |
@@ -1416,6 +1446,8 @@ struct btrfs_root { | |||
1416 | dev_t anon_dev; | 1446 | dev_t anon_dev; |
1417 | 1447 | ||
1418 | int force_cow; | 1448 | int force_cow; |
1449 | |||
1450 | spinlock_t root_times_lock; | ||
1419 | }; | 1451 | }; |
1420 | 1452 | ||
1421 | struct btrfs_ioctl_defrag_range_args { | 1453 | struct btrfs_ioctl_defrag_range_args { |
@@ -2189,6 +2221,16 @@ BTRFS_SETGET_STACK_FUNCS(root_used, struct btrfs_root_item, bytes_used, 64); | |||
2189 | BTRFS_SETGET_STACK_FUNCS(root_limit, struct btrfs_root_item, byte_limit, 64); | 2221 | BTRFS_SETGET_STACK_FUNCS(root_limit, struct btrfs_root_item, byte_limit, 64); |
2190 | BTRFS_SETGET_STACK_FUNCS(root_last_snapshot, struct btrfs_root_item, | 2222 | BTRFS_SETGET_STACK_FUNCS(root_last_snapshot, struct btrfs_root_item, |
2191 | last_snapshot, 64); | 2223 | 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); | ||
2192 | 2234 | ||
2193 | static inline bool btrfs_root_readonly(struct btrfs_root *root) | 2235 | static inline bool btrfs_root_readonly(struct btrfs_root *root) |
2194 | { | 2236 | { |
@@ -2822,6 +2864,9 @@ int __must_check btrfs_update_root(struct btrfs_trans_handle *trans, | |||
2822 | struct btrfs_root *root, | 2864 | struct btrfs_root *root, |
2823 | struct btrfs_key *key, | 2865 | struct btrfs_key *key, |
2824 | struct btrfs_root_item *item); | 2866 | 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); | ||
2825 | int btrfs_find_last_root(struct btrfs_root *root, u64 objectid, struct | 2870 | int btrfs_find_last_root(struct btrfs_root *root, u64 objectid, struct |
2826 | btrfs_root_item *item, struct btrfs_key *key); | 2871 | btrfs_root_item *item, struct btrfs_key *key); |
2827 | int btrfs_find_dead_roots(struct btrfs_root *root, u64 objectid); | 2872 | int btrfs_find_dead_roots(struct btrfs_root *root, u64 objectid); |
@@ -2829,6 +2874,8 @@ int btrfs_find_orphan_roots(struct btrfs_root *tree_root); | |||
2829 | void btrfs_set_root_node(struct btrfs_root_item *item, | 2874 | void btrfs_set_root_node(struct btrfs_root_item *item, |
2830 | struct extent_buffer *node); | 2875 | struct extent_buffer *node); |
2831 | void btrfs_check_and_init_root_item(struct btrfs_root_item *item); | 2876 | 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); | ||
2832 | 2879 | ||
2833 | /* dir-item.c */ | 2880 | /* dir-item.c */ |
2834 | int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, | 2881 | int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, |
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 2936ca49b3b..c39eb71fae3 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -1182,6 +1182,8 @@ static void __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize, | |||
1182 | root->defrag_running = 0; | 1182 | root->defrag_running = 0; |
1183 | root->root_key.objectid = objectid; | 1183 | root->root_key.objectid = objectid; |
1184 | root->anon_dev = 0; | 1184 | root->anon_dev = 0; |
1185 | |||
1186 | spin_lock_init(&root->root_times_lock); | ||
1185 | } | 1187 | } |
1186 | 1188 | ||
1187 | static int __must_check find_and_setup_root(struct btrfs_root *tree_root, | 1189 | 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, | |||
1326 | u64 generation; | 1328 | u64 generation; |
1327 | u32 blocksize; | 1329 | u32 blocksize; |
1328 | int ret = 0; | 1330 | int ret = 0; |
1331 | int slot; | ||
1329 | 1332 | ||
1330 | root = btrfs_alloc_root(fs_info); | 1333 | root = btrfs_alloc_root(fs_info); |
1331 | if (!root) | 1334 | if (!root) |
@@ -1352,9 +1355,8 @@ struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_root *tree_root, | |||
1352 | ret = btrfs_search_slot(NULL, tree_root, location, path, 0, 0); | 1355 | ret = btrfs_search_slot(NULL, tree_root, location, path, 0, 0); |
1353 | if (ret == 0) { | 1356 | if (ret == 0) { |
1354 | l = path->nodes[0]; | 1357 | l = path->nodes[0]; |
1355 | read_extent_buffer(l, &root->root_item, | 1358 | slot = path->slots[0]; |
1356 | btrfs_item_ptr_offset(l, path->slots[0]), | 1359 | btrfs_read_root_item(tree_root, l, slot, &root->root_item); |
1357 | sizeof(root->root_item)); | ||
1358 | memcpy(&root->root_key, location, sizeof(*location)); | 1360 | memcpy(&root->root_key, location, sizeof(*location)); |
1359 | } | 1361 | } |
1360 | btrfs_free_path(path); | 1362 | btrfs_free_path(path); |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index a7d1921ac76..4ffc8738954 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -2734,6 +2734,8 @@ noinline int btrfs_update_inode(struct btrfs_trans_handle *trans, | |||
2734 | */ | 2734 | */ |
2735 | if (!btrfs_is_free_space_inode(root, inode) | 2735 | if (!btrfs_is_free_space_inode(root, inode) |
2736 | && root->root_key.objectid != BTRFS_DATA_RELOC_TREE_OBJECTID) { | 2736 | && root->root_key.objectid != BTRFS_DATA_RELOC_TREE_OBJECTID) { |
2737 | btrfs_update_root_times(trans, root); | ||
2738 | |||
2737 | ret = btrfs_delayed_update_inode(trans, root, inode); | 2739 | ret = btrfs_delayed_update_inode(trans, root, inode); |
2738 | if (!ret) | 2740 | if (!ret) |
2739 | btrfs_set_inode_last_trans(trans, inode); | 2741 | btrfs_set_inode_last_trans(trans, inode); |
@@ -4723,6 +4725,8 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, | |||
4723 | trace_btrfs_inode_new(inode); | 4725 | trace_btrfs_inode_new(inode); |
4724 | btrfs_set_inode_last_trans(trans, inode); | 4726 | btrfs_set_inode_last_trans(trans, inode); |
4725 | 4727 | ||
4728 | btrfs_update_root_times(trans, root); | ||
4729 | |||
4726 | return inode; | 4730 | return inode; |
4727 | fail: | 4731 | fail: |
4728 | if (dir) | 4732 | if (dir) |
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 7011871c45b..99fe2ce7f72 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 | ||
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 | |||
3398 | long btrfs_ioctl(struct file *file, unsigned int | 3490 | long 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: |
diff --git a/fs/btrfs/ioctl.h b/fs/btrfs/ioctl.h index e440aa653c3..0c505d7ff8e 100644 --- a/fs/btrfs/ioctl.h +++ b/fs/btrfs/ioctl.h | |||
@@ -295,6 +295,21 @@ struct btrfs_ioctl_get_dev_stats { | |||
295 | __u64 unused[128 - 2 - BTRFS_DEV_STAT_VALUES_MAX]; /* pad to 1k */ | 295 | __u64 unused[128 - 2 - BTRFS_DEV_STAT_VALUES_MAX]; /* pad to 1k */ |
296 | }; | 296 | }; |
297 | 297 | ||
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 | |||
298 | #define BTRFS_IOC_SNAP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 1, \ | 313 | #define BTRFS_IOC_SNAP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 1, \ |
299 | struct btrfs_ioctl_vol_args) | 314 | struct btrfs_ioctl_vol_args) |
300 | #define BTRFS_IOC_DEFRAG _IOW(BTRFS_IOCTL_MAGIC, 2, \ | 315 | #define BTRFS_IOC_DEFRAG _IOW(BTRFS_IOCTL_MAGIC, 2, \ |
@@ -359,6 +374,8 @@ struct btrfs_ioctl_get_dev_stats { | |||
359 | struct btrfs_ioctl_ino_path_args) | 374 | struct btrfs_ioctl_ino_path_args) |
360 | #define BTRFS_IOC_LOGICAL_INO _IOWR(BTRFS_IOCTL_MAGIC, 36, \ | 375 | #define BTRFS_IOC_LOGICAL_INO _IOWR(BTRFS_IOCTL_MAGIC, 36, \ |
361 | struct btrfs_ioctl_ino_path_args) | 376 | 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) | ||
362 | #define BTRFS_IOC_GET_DEV_STATS _IOWR(BTRFS_IOCTL_MAGIC, 52, \ | 379 | #define BTRFS_IOC_GET_DEV_STATS _IOWR(BTRFS_IOCTL_MAGIC, 52, \ |
363 | struct btrfs_ioctl_get_dev_stats) | 380 | struct btrfs_ioctl_get_dev_stats) |
364 | #define BTRFS_IOC_GET_AND_RESET_DEV_STATS _IOWR(BTRFS_IOCTL_MAGIC, 53, \ | 381 | #define BTRFS_IOC_GET_AND_RESET_DEV_STATS _IOWR(BTRFS_IOCTL_MAGIC, 53, \ |
diff --git a/fs/btrfs/root-tree.c b/fs/btrfs/root-tree.c index 24fb8ce4e07..6bb465cca20 100644 --- a/fs/btrfs/root-tree.c +++ b/fs/btrfs/root-tree.c | |||
@@ -16,12 +16,55 @@ | |||
16 | * Boston, MA 021110-1307, USA. | 16 | * Boston, MA 021110-1307, USA. |
17 | */ | 17 | */ |
18 | 18 | ||
19 | #include <linux/uuid.h> | ||
19 | #include "ctree.h" | 20 | #include "ctree.h" |
20 | #include "transaction.h" | 21 | #include "transaction.h" |
21 | #include "disk-io.h" | 22 | #include "disk-io.h" |
22 | #include "print-tree.h" | 23 | #include "print-tree.h" |
23 | 24 | ||
24 | /* | 25 | /* |
26 | * Read a root item from the tree. In case we detect a root item smaller then | ||
27 | * sizeof(root_item), we know it's an old version of the root structure and | ||
28 | * initialize all new fields to zero. The same happens if we detect mismatching | ||
29 | * generation numbers as then we know the root was once mounted with an older | ||
30 | * kernel that was not aware of the root item structure change. | ||
31 | */ | ||
32 | void btrfs_read_root_item(struct btrfs_root *root, | ||
33 | struct extent_buffer *eb, int slot, | ||
34 | struct btrfs_root_item *item) | ||
35 | { | ||
36 | uuid_le uuid; | ||
37 | int len; | ||
38 | int need_reset = 0; | ||
39 | |||
40 | len = btrfs_item_size_nr(eb, slot); | ||
41 | read_extent_buffer(eb, item, btrfs_item_ptr_offset(eb, slot), | ||
42 | min_t(int, len, (int)sizeof(*item))); | ||
43 | if (len < sizeof(*item)) | ||
44 | need_reset = 1; | ||
45 | if (!need_reset && btrfs_root_generation(item) | ||
46 | != btrfs_root_generation_v2(item)) { | ||
47 | if (btrfs_root_generation_v2(item) != 0) { | ||
48 | printk(KERN_WARNING "btrfs: mismatching " | ||
49 | "generation and generation_v2 " | ||
50 | "found in root item. This root " | ||
51 | "was probably mounted with an " | ||
52 | "older kernel. Resetting all " | ||
53 | "new fields.\n"); | ||
54 | } | ||
55 | need_reset = 1; | ||
56 | } | ||
57 | if (need_reset) { | ||
58 | memset(&item->generation_v2, 0, | ||
59 | sizeof(*item) - offsetof(struct btrfs_root_item, | ||
60 | generation_v2)); | ||
61 | |||
62 | uuid_le_gen(&uuid); | ||
63 | memcpy(item->uuid, uuid.b, BTRFS_UUID_SIZE); | ||
64 | } | ||
65 | } | ||
66 | |||
67 | /* | ||
25 | * lookup the root with the highest offset for a given objectid. The key we do | 68 | * lookup the root with the highest offset for a given objectid. The key we do |
26 | * find is copied into 'key'. If we find something return 0, otherwise 1, < 0 | 69 | * find is copied into 'key'. If we find something return 0, otherwise 1, < 0 |
27 | * on error. | 70 | * on error. |
@@ -61,10 +104,10 @@ int btrfs_find_last_root(struct btrfs_root *root, u64 objectid, | |||
61 | goto out; | 104 | goto out; |
62 | } | 105 | } |
63 | if (item) | 106 | if (item) |
64 | read_extent_buffer(l, item, btrfs_item_ptr_offset(l, slot), | 107 | btrfs_read_root_item(root, l, slot, item); |
65 | sizeof(*item)); | ||
66 | if (key) | 108 | if (key) |
67 | memcpy(key, &found_key, sizeof(found_key)); | 109 | memcpy(key, &found_key, sizeof(found_key)); |
110 | |||
68 | ret = 0; | 111 | ret = 0; |
69 | out: | 112 | out: |
70 | btrfs_free_path(path); | 113 | btrfs_free_path(path); |
@@ -91,16 +134,15 @@ int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root | |||
91 | int ret; | 134 | int ret; |
92 | int slot; | 135 | int slot; |
93 | unsigned long ptr; | 136 | unsigned long ptr; |
137 | int old_len; | ||
94 | 138 | ||
95 | path = btrfs_alloc_path(); | 139 | path = btrfs_alloc_path(); |
96 | if (!path) | 140 | if (!path) |
97 | return -ENOMEM; | 141 | return -ENOMEM; |
98 | 142 | ||
99 | ret = btrfs_search_slot(trans, root, key, path, 0, 1); | 143 | ret = btrfs_search_slot(trans, root, key, path, 0, 1); |
100 | if (ret < 0) { | 144 | if (ret < 0) |
101 | btrfs_abort_transaction(trans, root, ret); | 145 | goto out_abort; |
102 | goto out; | ||
103 | } | ||
104 | 146 | ||
105 | if (ret != 0) { | 147 | if (ret != 0) { |
106 | btrfs_print_leaf(root, path->nodes[0]); | 148 | btrfs_print_leaf(root, path->nodes[0]); |
@@ -113,16 +155,56 @@ int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root | |||
113 | l = path->nodes[0]; | 155 | l = path->nodes[0]; |
114 | slot = path->slots[0]; | 156 | slot = path->slots[0]; |
115 | ptr = btrfs_item_ptr_offset(l, slot); | 157 | ptr = btrfs_item_ptr_offset(l, slot); |
158 | old_len = btrfs_item_size_nr(l, slot); | ||
159 | |||
160 | /* | ||
161 | * If this is the first time we update the root item which originated | ||
162 | * from an older kernel, we need to enlarge the item size to make room | ||
163 | * for the added fields. | ||
164 | */ | ||
165 | if (old_len < sizeof(*item)) { | ||
166 | btrfs_release_path(path); | ||
167 | ret = btrfs_search_slot(trans, root, key, path, | ||
168 | -1, 1); | ||
169 | if (ret < 0) | ||
170 | goto out_abort; | ||
171 | ret = btrfs_del_item(trans, root, path); | ||
172 | if (ret < 0) | ||
173 | goto out_abort; | ||
174 | btrfs_release_path(path); | ||
175 | ret = btrfs_insert_empty_item(trans, root, path, | ||
176 | key, sizeof(*item)); | ||
177 | if (ret < 0) | ||
178 | goto out_abort; | ||
179 | l = path->nodes[0]; | ||
180 | slot = path->slots[0]; | ||
181 | ptr = btrfs_item_ptr_offset(l, slot); | ||
182 | } | ||
183 | |||
184 | /* | ||
185 | * Update generation_v2 so at the next mount we know the new root | ||
186 | * fields are valid. | ||
187 | */ | ||
188 | btrfs_set_root_generation_v2(item, btrfs_root_generation(item)); | ||
189 | |||
116 | write_extent_buffer(l, item, ptr, sizeof(*item)); | 190 | write_extent_buffer(l, item, ptr, sizeof(*item)); |
117 | btrfs_mark_buffer_dirty(path->nodes[0]); | 191 | btrfs_mark_buffer_dirty(path->nodes[0]); |
118 | out: | 192 | out: |
119 | btrfs_free_path(path); | 193 | btrfs_free_path(path); |
120 | return ret; | 194 | return ret; |
195 | |||
196 | out_abort: | ||
197 | btrfs_abort_transaction(trans, root, ret); | ||
198 | goto out; | ||
121 | } | 199 | } |
122 | 200 | ||
123 | int btrfs_insert_root(struct btrfs_trans_handle *trans, struct btrfs_root *root, | 201 | int btrfs_insert_root(struct btrfs_trans_handle *trans, struct btrfs_root *root, |
124 | struct btrfs_key *key, struct btrfs_root_item *item) | 202 | struct btrfs_key *key, struct btrfs_root_item *item) |
125 | { | 203 | { |
204 | /* | ||
205 | * Make sure generation v1 and v2 match. See update_root for details. | ||
206 | */ | ||
207 | btrfs_set_root_generation_v2(item, btrfs_root_generation(item)); | ||
126 | return btrfs_insert_item(trans, root, key, item, sizeof(*item)); | 208 | return btrfs_insert_item(trans, root, key, item, sizeof(*item)); |
127 | } | 209 | } |
128 | 210 | ||
@@ -454,3 +536,16 @@ void btrfs_check_and_init_root_item(struct btrfs_root_item *root_item) | |||
454 | root_item->byte_limit = 0; | 536 | root_item->byte_limit = 0; |
455 | } | 537 | } |
456 | } | 538 | } |
539 | |||
540 | void btrfs_update_root_times(struct btrfs_trans_handle *trans, | ||
541 | struct btrfs_root *root) | ||
542 | { | ||
543 | struct btrfs_root_item *item = &root->root_item; | ||
544 | struct timespec ct = CURRENT_TIME; | ||
545 | |||
546 | spin_lock(&root->root_times_lock); | ||
547 | item->ctransid = trans->transid; | ||
548 | item->ctime.sec = cpu_to_le64(ct.tv_sec); | ||
549 | item->ctime.nsec = cpu_to_le64(ct.tv_nsec); | ||
550 | spin_unlock(&root->root_times_lock); | ||
551 | } | ||
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index b72b068183e..a21f3085a33 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/writeback.h> | 22 | #include <linux/writeback.h> |
23 | #include <linux/pagemap.h> | 23 | #include <linux/pagemap.h> |
24 | #include <linux/blkdev.h> | 24 | #include <linux/blkdev.h> |
25 | #include <linux/uuid.h> | ||
25 | #include "ctree.h" | 26 | #include "ctree.h" |
26 | #include "disk-io.h" | 27 | #include "disk-io.h" |
27 | #include "transaction.h" | 28 | #include "transaction.h" |
@@ -926,11 +927,13 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
926 | struct dentry *dentry; | 927 | struct dentry *dentry; |
927 | struct extent_buffer *tmp; | 928 | struct extent_buffer *tmp; |
928 | struct extent_buffer *old; | 929 | struct extent_buffer *old; |
930 | struct timespec cur_time = CURRENT_TIME; | ||
929 | int ret; | 931 | int ret; |
930 | u64 to_reserve = 0; | 932 | u64 to_reserve = 0; |
931 | u64 index = 0; | 933 | u64 index = 0; |
932 | u64 objectid; | 934 | u64 objectid; |
933 | u64 root_flags; | 935 | u64 root_flags; |
936 | uuid_le new_uuid; | ||
934 | 937 | ||
935 | rsv = trans->block_rsv; | 938 | rsv = trans->block_rsv; |
936 | 939 | ||
@@ -1016,6 +1019,20 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
1016 | root_flags &= ~BTRFS_ROOT_SUBVOL_RDONLY; | 1019 | root_flags &= ~BTRFS_ROOT_SUBVOL_RDONLY; |
1017 | btrfs_set_root_flags(new_root_item, root_flags); | 1020 | btrfs_set_root_flags(new_root_item, root_flags); |
1018 | 1021 | ||
1022 | btrfs_set_root_generation_v2(new_root_item, | ||
1023 | trans->transid); | ||
1024 | uuid_le_gen(&new_uuid); | ||
1025 | memcpy(new_root_item->uuid, new_uuid.b, BTRFS_UUID_SIZE); | ||
1026 | memcpy(new_root_item->parent_uuid, root->root_item.uuid, | ||
1027 | BTRFS_UUID_SIZE); | ||
1028 | new_root_item->otime.sec = cpu_to_le64(cur_time.tv_sec); | ||
1029 | new_root_item->otime.nsec = cpu_to_le64(cur_time.tv_nsec); | ||
1030 | btrfs_set_root_otransid(new_root_item, trans->transid); | ||
1031 | memset(&new_root_item->stime, 0, sizeof(new_root_item->stime)); | ||
1032 | memset(&new_root_item->rtime, 0, sizeof(new_root_item->rtime)); | ||
1033 | btrfs_set_root_stransid(new_root_item, 0); | ||
1034 | btrfs_set_root_rtransid(new_root_item, 0); | ||
1035 | |||
1019 | old = btrfs_lock_root_node(root); | 1036 | old = btrfs_lock_root_node(root); |
1020 | ret = btrfs_cow_block(trans, root, old, NULL, 0, &old); | 1037 | ret = btrfs_cow_block(trans, root, old, NULL, 0, &old); |
1021 | if (ret) { | 1038 | if (ret) { |