diff options
| -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 da6e9364a5e3..9197e2e33407 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 8cfde9326dd6..d5f6d7458676 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 2936ca49b3b4..c39eb71fae31 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 a7d1921ac76b..4ffc87389545 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 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 | ||
| 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 e440aa653c30..0c505d7ff8ed 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 24fb8ce4e071..6bb465cca20f 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 b72b068183ec..a21f3085a334 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) { |
