diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-03-04 14:04:27 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-03-04 14:04:27 -0500 |
| commit | af8c081627478e0610b2fc7d28f466462978383d (patch) | |
| tree | 5f090bf92bde83663dc7414c2373dc064c9bbd41 | |
| parent | 58bdf601c2de6071d0386a7a6fa707bd04761c47 (diff) | |
| parent | 1f250e929a9c9332fd6ea34da684afee73837cfe (diff) | |
Merge tag 'for-4.16-rc3-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux
Pull btrfs fixes from David Sterba:
- when NR_CPUS is large, a SRCU structure can significantly inflate
size of the main filesystem structure that would not be possible to
allocate by kmalloc, so the kvalloc fallback is used
- improved error handling
- fix endiannes when printing some filesystem attributes via sysfs,
this is could happen when a filesystem is moved between different
endianity hosts
- send fixes: the NO_HOLE mode should not send a write operation for a
file hole
- fix log replay for for special files followed by file hardlinks
- fix log replay failure after unlink and link combination
- fix max chunk size calculation for DUP allocation
* tag 'for-4.16-rc3-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux:
Btrfs: fix log replay failure after unlink and link combination
Btrfs: fix log replay failure after linking special file and fsync
Btrfs: send, fix issuing write op when processing hole in no data mode
btrfs: use proper endianness accessors for super_copy
btrfs: alloc_chunk: fix DUP stripe size handling
btrfs: Handle btrfs_set_extent_delalloc failure in relocate_file_extent_cluster
btrfs: handle failure of add_pending_csums
btrfs: use kvzalloc to allocate btrfs_fs_info
| -rw-r--r-- | fs/btrfs/ctree.h | 7 | ||||
| -rw-r--r-- | fs/btrfs/inode-item.c | 44 | ||||
| -rw-r--r-- | fs/btrfs/inode.c | 11 | ||||
| -rw-r--r-- | fs/btrfs/relocation.c | 18 | ||||
| -rw-r--r-- | fs/btrfs/send.c | 3 | ||||
| -rw-r--r-- | fs/btrfs/super.c | 2 | ||||
| -rw-r--r-- | fs/btrfs/sysfs.c | 8 | ||||
| -rw-r--r-- | fs/btrfs/transaction.c | 20 | ||||
| -rw-r--r-- | fs/btrfs/tree-log.c | 114 | ||||
| -rw-r--r-- | fs/btrfs/volumes.c | 11 |
10 files changed, 191 insertions, 47 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 1a462ab85c49..da308774b8a4 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
| @@ -2974,7 +2974,7 @@ static inline void free_fs_info(struct btrfs_fs_info *fs_info) | |||
| 2974 | kfree(fs_info->super_copy); | 2974 | kfree(fs_info->super_copy); |
| 2975 | kfree(fs_info->super_for_commit); | 2975 | kfree(fs_info->super_for_commit); |
| 2976 | security_free_mnt_opts(&fs_info->security_opts); | 2976 | security_free_mnt_opts(&fs_info->security_opts); |
| 2977 | kfree(fs_info); | 2977 | kvfree(fs_info); |
| 2978 | } | 2978 | } |
| 2979 | 2979 | ||
| 2980 | /* tree mod log functions from ctree.c */ | 2980 | /* tree mod log functions from ctree.c */ |
| @@ -3095,7 +3095,10 @@ btrfs_lookup_inode_extref(struct btrfs_trans_handle *trans, | |||
| 3095 | u64 inode_objectid, u64 ref_objectid, int ins_len, | 3095 | u64 inode_objectid, u64 ref_objectid, int ins_len, |
| 3096 | int cow); | 3096 | int cow); |
| 3097 | 3097 | ||
| 3098 | int btrfs_find_name_in_ext_backref(struct btrfs_path *path, | 3098 | int btrfs_find_name_in_backref(struct extent_buffer *leaf, int slot, |
| 3099 | const char *name, | ||
| 3100 | int name_len, struct btrfs_inode_ref **ref_ret); | ||
| 3101 | int btrfs_find_name_in_ext_backref(struct extent_buffer *leaf, int slot, | ||
| 3099 | u64 ref_objectid, const char *name, | 3102 | u64 ref_objectid, const char *name, |
| 3100 | int name_len, | 3103 | int name_len, |
| 3101 | struct btrfs_inode_extref **extref_ret); | 3104 | struct btrfs_inode_extref **extref_ret); |
diff --git a/fs/btrfs/inode-item.c b/fs/btrfs/inode-item.c index 39c968f80157..65e1a76bf755 100644 --- a/fs/btrfs/inode-item.c +++ b/fs/btrfs/inode-item.c | |||
| @@ -22,10 +22,10 @@ | |||
| 22 | #include "transaction.h" | 22 | #include "transaction.h" |
| 23 | #include "print-tree.h" | 23 | #include "print-tree.h" |
| 24 | 24 | ||
| 25 | static int find_name_in_backref(struct btrfs_path *path, const char *name, | 25 | int btrfs_find_name_in_backref(struct extent_buffer *leaf, int slot, |
| 26 | int name_len, struct btrfs_inode_ref **ref_ret) | 26 | const char *name, |
| 27 | int name_len, struct btrfs_inode_ref **ref_ret) | ||
| 27 | { | 28 | { |
| 28 | struct extent_buffer *leaf; | ||
| 29 | struct btrfs_inode_ref *ref; | 29 | struct btrfs_inode_ref *ref; |
| 30 | unsigned long ptr; | 30 | unsigned long ptr; |
| 31 | unsigned long name_ptr; | 31 | unsigned long name_ptr; |
| @@ -33,9 +33,8 @@ static int find_name_in_backref(struct btrfs_path *path, const char *name, | |||
| 33 | u32 cur_offset = 0; | 33 | u32 cur_offset = 0; |
| 34 | int len; | 34 | int len; |
| 35 | 35 | ||
| 36 | leaf = path->nodes[0]; | 36 | item_size = btrfs_item_size_nr(leaf, slot); |
| 37 | item_size = btrfs_item_size_nr(leaf, path->slots[0]); | 37 | ptr = btrfs_item_ptr_offset(leaf, slot); |
| 38 | ptr = btrfs_item_ptr_offset(leaf, path->slots[0]); | ||
| 39 | while (cur_offset < item_size) { | 38 | while (cur_offset < item_size) { |
| 40 | ref = (struct btrfs_inode_ref *)(ptr + cur_offset); | 39 | ref = (struct btrfs_inode_ref *)(ptr + cur_offset); |
| 41 | len = btrfs_inode_ref_name_len(leaf, ref); | 40 | len = btrfs_inode_ref_name_len(leaf, ref); |
| @@ -44,18 +43,19 @@ static int find_name_in_backref(struct btrfs_path *path, const char *name, | |||
| 44 | if (len != name_len) | 43 | if (len != name_len) |
| 45 | continue; | 44 | continue; |
| 46 | if (memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0) { | 45 | if (memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0) { |
| 47 | *ref_ret = ref; | 46 | if (ref_ret) |
| 47 | *ref_ret = ref; | ||
| 48 | return 1; | 48 | return 1; |
| 49 | } | 49 | } |
| 50 | } | 50 | } |
| 51 | return 0; | 51 | return 0; |
| 52 | } | 52 | } |
| 53 | 53 | ||
| 54 | int btrfs_find_name_in_ext_backref(struct btrfs_path *path, u64 ref_objectid, | 54 | int btrfs_find_name_in_ext_backref(struct extent_buffer *leaf, int slot, |
| 55 | u64 ref_objectid, | ||
| 55 | const char *name, int name_len, | 56 | const char *name, int name_len, |
| 56 | struct btrfs_inode_extref **extref_ret) | 57 | struct btrfs_inode_extref **extref_ret) |
| 57 | { | 58 | { |
| 58 | struct extent_buffer *leaf; | ||
| 59 | struct btrfs_inode_extref *extref; | 59 | struct btrfs_inode_extref *extref; |
| 60 | unsigned long ptr; | 60 | unsigned long ptr; |
| 61 | unsigned long name_ptr; | 61 | unsigned long name_ptr; |
| @@ -63,9 +63,8 @@ int btrfs_find_name_in_ext_backref(struct btrfs_path *path, u64 ref_objectid, | |||
| 63 | u32 cur_offset = 0; | 63 | u32 cur_offset = 0; |
| 64 | int ref_name_len; | 64 | int ref_name_len; |
| 65 | 65 | ||
| 66 | leaf = path->nodes[0]; | 66 | item_size = btrfs_item_size_nr(leaf, slot); |
| 67 | item_size = btrfs_item_size_nr(leaf, path->slots[0]); | 67 | ptr = btrfs_item_ptr_offset(leaf, slot); |
| 68 | ptr = btrfs_item_ptr_offset(leaf, path->slots[0]); | ||
| 69 | 68 | ||
| 70 | /* | 69 | /* |
| 71 | * Search all extended backrefs in this item. We're only | 70 | * Search all extended backrefs in this item. We're only |
| @@ -113,7 +112,9 @@ btrfs_lookup_inode_extref(struct btrfs_trans_handle *trans, | |||
| 113 | return ERR_PTR(ret); | 112 | return ERR_PTR(ret); |
| 114 | if (ret > 0) | 113 | if (ret > 0) |
| 115 | return NULL; | 114 | return NULL; |
| 116 | if (!btrfs_find_name_in_ext_backref(path, ref_objectid, name, name_len, &extref)) | 115 | if (!btrfs_find_name_in_ext_backref(path->nodes[0], path->slots[0], |
| 116 | ref_objectid, name, name_len, | ||
| 117 | &extref)) | ||
| 117 | return NULL; | 118 | return NULL; |
| 118 | return extref; | 119 | return extref; |
| 119 | } | 120 | } |
| @@ -155,7 +156,8 @@ static int btrfs_del_inode_extref(struct btrfs_trans_handle *trans, | |||
| 155 | * This should always succeed so error here will make the FS | 156 | * This should always succeed so error here will make the FS |
| 156 | * readonly. | 157 | * readonly. |
| 157 | */ | 158 | */ |
| 158 | if (!btrfs_find_name_in_ext_backref(path, ref_objectid, | 159 | if (!btrfs_find_name_in_ext_backref(path->nodes[0], path->slots[0], |
| 160 | ref_objectid, | ||
| 159 | name, name_len, &extref)) { | 161 | name, name_len, &extref)) { |
| 160 | btrfs_handle_fs_error(root->fs_info, -ENOENT, NULL); | 162 | btrfs_handle_fs_error(root->fs_info, -ENOENT, NULL); |
| 161 | ret = -EROFS; | 163 | ret = -EROFS; |
| @@ -225,7 +227,8 @@ int btrfs_del_inode_ref(struct btrfs_trans_handle *trans, | |||
| 225 | } else if (ret < 0) { | 227 | } else if (ret < 0) { |
| 226 | goto out; | 228 | goto out; |
| 227 | } | 229 | } |
| 228 | if (!find_name_in_backref(path, name, name_len, &ref)) { | 230 | if (!btrfs_find_name_in_backref(path->nodes[0], path->slots[0], |
| 231 | name, name_len, &ref)) { | ||
| 229 | ret = -ENOENT; | 232 | ret = -ENOENT; |
| 230 | search_ext_refs = 1; | 233 | search_ext_refs = 1; |
| 231 | goto out; | 234 | goto out; |
| @@ -293,7 +296,9 @@ static int btrfs_insert_inode_extref(struct btrfs_trans_handle *trans, | |||
| 293 | ret = btrfs_insert_empty_item(trans, root, path, &key, | 296 | ret = btrfs_insert_empty_item(trans, root, path, &key, |
| 294 | ins_len); | 297 | ins_len); |
| 295 | if (ret == -EEXIST) { | 298 | if (ret == -EEXIST) { |
| 296 | if (btrfs_find_name_in_ext_backref(path, ref_objectid, | 299 | if (btrfs_find_name_in_ext_backref(path->nodes[0], |
| 300 | path->slots[0], | ||
| 301 | ref_objectid, | ||
| 297 | name, name_len, NULL)) | 302 | name, name_len, NULL)) |
| 298 | goto out; | 303 | goto out; |
| 299 | 304 | ||
| @@ -351,7 +356,8 @@ int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans, | |||
| 351 | if (ret == -EEXIST) { | 356 | if (ret == -EEXIST) { |
| 352 | u32 old_size; | 357 | u32 old_size; |
| 353 | 358 | ||
| 354 | if (find_name_in_backref(path, name, name_len, &ref)) | 359 | if (btrfs_find_name_in_backref(path->nodes[0], path->slots[0], |
| 360 | name, name_len, &ref)) | ||
| 355 | goto out; | 361 | goto out; |
| 356 | 362 | ||
| 357 | old_size = btrfs_item_size_nr(path->nodes[0], path->slots[0]); | 363 | old_size = btrfs_item_size_nr(path->nodes[0], path->slots[0]); |
| @@ -365,7 +371,9 @@ int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans, | |||
| 365 | ret = 0; | 371 | ret = 0; |
| 366 | } else if (ret < 0) { | 372 | } else if (ret < 0) { |
| 367 | if (ret == -EOVERFLOW) { | 373 | if (ret == -EOVERFLOW) { |
| 368 | if (find_name_in_backref(path, name, name_len, &ref)) | 374 | if (btrfs_find_name_in_backref(path->nodes[0], |
| 375 | path->slots[0], | ||
| 376 | name, name_len, &ref)) | ||
| 369 | ret = -EEXIST; | 377 | ret = -EEXIST; |
| 370 | else | 378 | else |
| 371 | ret = -EMLINK; | 379 | ret = -EMLINK; |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index a79299a89b7d..f53470112670 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
| @@ -2043,12 +2043,15 @@ static noinline int add_pending_csums(struct btrfs_trans_handle *trans, | |||
| 2043 | struct inode *inode, struct list_head *list) | 2043 | struct inode *inode, struct list_head *list) |
| 2044 | { | 2044 | { |
| 2045 | struct btrfs_ordered_sum *sum; | 2045 | struct btrfs_ordered_sum *sum; |
| 2046 | int ret; | ||
| 2046 | 2047 | ||
| 2047 | list_for_each_entry(sum, list, list) { | 2048 | list_for_each_entry(sum, list, list) { |
| 2048 | trans->adding_csums = true; | 2049 | trans->adding_csums = true; |
| 2049 | btrfs_csum_file_blocks(trans, | 2050 | ret = btrfs_csum_file_blocks(trans, |
| 2050 | BTRFS_I(inode)->root->fs_info->csum_root, sum); | 2051 | BTRFS_I(inode)->root->fs_info->csum_root, sum); |
| 2051 | trans->adding_csums = false; | 2052 | trans->adding_csums = false; |
| 2053 | if (ret) | ||
| 2054 | return ret; | ||
| 2052 | } | 2055 | } |
| 2053 | return 0; | 2056 | return 0; |
| 2054 | } | 2057 | } |
| @@ -3062,7 +3065,11 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent) | |||
| 3062 | goto out; | 3065 | goto out; |
| 3063 | } | 3066 | } |
| 3064 | 3067 | ||
| 3065 | add_pending_csums(trans, inode, &ordered_extent->list); | 3068 | ret = add_pending_csums(trans, inode, &ordered_extent->list); |
| 3069 | if (ret) { | ||
| 3070 | btrfs_abort_transaction(trans, ret); | ||
| 3071 | goto out; | ||
| 3072 | } | ||
| 3066 | 3073 | ||
| 3067 | btrfs_ordered_update_i_size(inode, 0, ordered_extent); | 3074 | btrfs_ordered_update_i_size(inode, 0, ordered_extent); |
| 3068 | ret = btrfs_update_inode_fallback(trans, root, inode); | 3075 | ret = btrfs_update_inode_fallback(trans, root, inode); |
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index f0c3f00e97cb..cd2298d185dd 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c | |||
| @@ -3268,8 +3268,22 @@ static int relocate_file_extent_cluster(struct inode *inode, | |||
| 3268 | nr++; | 3268 | nr++; |
| 3269 | } | 3269 | } |
| 3270 | 3270 | ||
| 3271 | btrfs_set_extent_delalloc(inode, page_start, page_end, 0, NULL, | 3271 | ret = btrfs_set_extent_delalloc(inode, page_start, page_end, 0, |
| 3272 | 0); | 3272 | NULL, 0); |
| 3273 | if (ret) { | ||
| 3274 | unlock_page(page); | ||
| 3275 | put_page(page); | ||
| 3276 | btrfs_delalloc_release_metadata(BTRFS_I(inode), | ||
| 3277 | PAGE_SIZE); | ||
| 3278 | btrfs_delalloc_release_extents(BTRFS_I(inode), | ||
| 3279 | PAGE_SIZE); | ||
| 3280 | |||
| 3281 | clear_extent_bits(&BTRFS_I(inode)->io_tree, | ||
| 3282 | page_start, page_end, | ||
| 3283 | EXTENT_LOCKED | EXTENT_BOUNDARY); | ||
| 3284 | goto out; | ||
| 3285 | |||
| 3286 | } | ||
| 3273 | set_page_dirty(page); | 3287 | set_page_dirty(page); |
| 3274 | 3288 | ||
| 3275 | unlock_extent(&BTRFS_I(inode)->io_tree, | 3289 | unlock_extent(&BTRFS_I(inode)->io_tree, |
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index f306c608dc28..484e2af793de 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c | |||
| @@ -5005,6 +5005,9 @@ static int send_hole(struct send_ctx *sctx, u64 end) | |||
| 5005 | u64 len; | 5005 | u64 len; |
| 5006 | int ret = 0; | 5006 | int ret = 0; |
| 5007 | 5007 | ||
| 5008 | if (sctx->flags & BTRFS_SEND_FLAG_NO_FILE_DATA) | ||
| 5009 | return send_update_extent(sctx, offset, end - offset); | ||
| 5010 | |||
| 5008 | p = fs_path_alloc(); | 5011 | p = fs_path_alloc(); |
| 5009 | if (!p) | 5012 | if (!p) |
| 5010 | return -ENOMEM; | 5013 | return -ENOMEM; |
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 6e71a2a78363..4b817947e00f 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c | |||
| @@ -1545,7 +1545,7 @@ static struct dentry *btrfs_mount_root(struct file_system_type *fs_type, | |||
| 1545 | * it for searching for existing supers, so this lets us do that and | 1545 | * it for searching for existing supers, so this lets us do that and |
| 1546 | * then open_ctree will properly initialize everything later. | 1546 | * then open_ctree will properly initialize everything later. |
| 1547 | */ | 1547 | */ |
| 1548 | fs_info = kzalloc(sizeof(struct btrfs_fs_info), GFP_KERNEL); | 1548 | fs_info = kvzalloc(sizeof(struct btrfs_fs_info), GFP_KERNEL); |
| 1549 | if (!fs_info) { | 1549 | if (!fs_info) { |
| 1550 | error = -ENOMEM; | 1550 | error = -ENOMEM; |
| 1551 | goto error_sec_opts; | 1551 | goto error_sec_opts; |
diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c index a8bafed931f4..d11c70bff5a9 100644 --- a/fs/btrfs/sysfs.c +++ b/fs/btrfs/sysfs.c | |||
| @@ -423,7 +423,7 @@ static ssize_t btrfs_nodesize_show(struct kobject *kobj, | |||
| 423 | { | 423 | { |
| 424 | struct btrfs_fs_info *fs_info = to_fs_info(kobj); | 424 | struct btrfs_fs_info *fs_info = to_fs_info(kobj); |
| 425 | 425 | ||
| 426 | return snprintf(buf, PAGE_SIZE, "%u\n", fs_info->super_copy->nodesize); | 426 | return snprintf(buf, PAGE_SIZE, "%u\n", fs_info->nodesize); |
| 427 | } | 427 | } |
| 428 | 428 | ||
| 429 | BTRFS_ATTR(, nodesize, btrfs_nodesize_show); | 429 | BTRFS_ATTR(, nodesize, btrfs_nodesize_show); |
| @@ -433,8 +433,7 @@ static ssize_t btrfs_sectorsize_show(struct kobject *kobj, | |||
| 433 | { | 433 | { |
| 434 | struct btrfs_fs_info *fs_info = to_fs_info(kobj); | 434 | struct btrfs_fs_info *fs_info = to_fs_info(kobj); |
| 435 | 435 | ||
| 436 | return snprintf(buf, PAGE_SIZE, "%u\n", | 436 | return snprintf(buf, PAGE_SIZE, "%u\n", fs_info->sectorsize); |
| 437 | fs_info->super_copy->sectorsize); | ||
| 438 | } | 437 | } |
| 439 | 438 | ||
| 440 | BTRFS_ATTR(, sectorsize, btrfs_sectorsize_show); | 439 | BTRFS_ATTR(, sectorsize, btrfs_sectorsize_show); |
| @@ -444,8 +443,7 @@ static ssize_t btrfs_clone_alignment_show(struct kobject *kobj, | |||
| 444 | { | 443 | { |
| 445 | struct btrfs_fs_info *fs_info = to_fs_info(kobj); | 444 | struct btrfs_fs_info *fs_info = to_fs_info(kobj); |
| 446 | 445 | ||
| 447 | return snprintf(buf, PAGE_SIZE, "%u\n", | 446 | return snprintf(buf, PAGE_SIZE, "%u\n", fs_info->sectorsize); |
| 448 | fs_info->super_copy->sectorsize); | ||
| 449 | } | 447 | } |
| 450 | 448 | ||
| 451 | BTRFS_ATTR(, clone_alignment, btrfs_clone_alignment_show); | 449 | BTRFS_ATTR(, clone_alignment, btrfs_clone_alignment_show); |
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 04f07144b45c..9220f004001c 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
| @@ -1722,19 +1722,23 @@ static void update_super_roots(struct btrfs_fs_info *fs_info) | |||
| 1722 | 1722 | ||
| 1723 | super = fs_info->super_copy; | 1723 | super = fs_info->super_copy; |
| 1724 | 1724 | ||
| 1725 | /* update latest btrfs_super_block::chunk_root refs */ | ||
| 1725 | root_item = &fs_info->chunk_root->root_item; | 1726 | root_item = &fs_info->chunk_root->root_item; |
| 1726 | super->chunk_root = root_item->bytenr; | 1727 | btrfs_set_super_chunk_root(super, root_item->bytenr); |
| 1727 | super->chunk_root_generation = root_item->generation; | 1728 | btrfs_set_super_chunk_root_generation(super, root_item->generation); |
| 1728 | super->chunk_root_level = root_item->level; | 1729 | btrfs_set_super_chunk_root_level(super, root_item->level); |
| 1729 | 1730 | ||
| 1731 | /* update latest btrfs_super_block::root refs */ | ||
| 1730 | root_item = &fs_info->tree_root->root_item; | 1732 | root_item = &fs_info->tree_root->root_item; |
| 1731 | super->root = root_item->bytenr; | 1733 | btrfs_set_super_root(super, root_item->bytenr); |
| 1732 | super->generation = root_item->generation; | 1734 | btrfs_set_super_generation(super, root_item->generation); |
| 1733 | super->root_level = root_item->level; | 1735 | btrfs_set_super_root_level(super, root_item->level); |
| 1736 | |||
| 1734 | if (btrfs_test_opt(fs_info, SPACE_CACHE)) | 1737 | if (btrfs_test_opt(fs_info, SPACE_CACHE)) |
| 1735 | super->cache_generation = root_item->generation; | 1738 | btrfs_set_super_cache_generation(super, root_item->generation); |
| 1736 | if (test_bit(BTRFS_FS_UPDATE_UUID_TREE_GEN, &fs_info->flags)) | 1739 | if (test_bit(BTRFS_FS_UPDATE_UUID_TREE_GEN, &fs_info->flags)) |
| 1737 | super->uuid_tree_generation = root_item->generation; | 1740 | btrfs_set_super_uuid_tree_generation(super, |
| 1741 | root_item->generation); | ||
| 1738 | } | 1742 | } |
| 1739 | 1743 | ||
| 1740 | int btrfs_transaction_in_commit(struct btrfs_fs_info *info) | 1744 | int btrfs_transaction_in_commit(struct btrfs_fs_info *info) |
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 4fd19b4d6675..434457794c27 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c | |||
| @@ -967,7 +967,9 @@ static noinline int backref_in_log(struct btrfs_root *log, | |||
| 967 | ptr = btrfs_item_ptr_offset(path->nodes[0], path->slots[0]); | 967 | ptr = btrfs_item_ptr_offset(path->nodes[0], path->slots[0]); |
| 968 | 968 | ||
| 969 | if (key->type == BTRFS_INODE_EXTREF_KEY) { | 969 | if (key->type == BTRFS_INODE_EXTREF_KEY) { |
| 970 | if (btrfs_find_name_in_ext_backref(path, ref_objectid, | 970 | if (btrfs_find_name_in_ext_backref(path->nodes[0], |
| 971 | path->slots[0], | ||
| 972 | ref_objectid, | ||
| 971 | name, namelen, NULL)) | 973 | name, namelen, NULL)) |
| 972 | match = 1; | 974 | match = 1; |
| 973 | 975 | ||
| @@ -1191,7 +1193,8 @@ static int extref_get_fields(struct extent_buffer *eb, unsigned long ref_ptr, | |||
| 1191 | read_extent_buffer(eb, *name, (unsigned long)&extref->name, | 1193 | read_extent_buffer(eb, *name, (unsigned long)&extref->name, |
| 1192 | *namelen); | 1194 | *namelen); |
| 1193 | 1195 | ||
| 1194 | *index = btrfs_inode_extref_index(eb, extref); | 1196 | if (index) |
| 1197 | *index = btrfs_inode_extref_index(eb, extref); | ||
| 1195 | if (parent_objectid) | 1198 | if (parent_objectid) |
| 1196 | *parent_objectid = btrfs_inode_extref_parent(eb, extref); | 1199 | *parent_objectid = btrfs_inode_extref_parent(eb, extref); |
| 1197 | 1200 | ||
| @@ -1212,12 +1215,102 @@ static int ref_get_fields(struct extent_buffer *eb, unsigned long ref_ptr, | |||
| 1212 | 1215 | ||
| 1213 | read_extent_buffer(eb, *name, (unsigned long)(ref + 1), *namelen); | 1216 | read_extent_buffer(eb, *name, (unsigned long)(ref + 1), *namelen); |
| 1214 | 1217 | ||
| 1215 | *index = btrfs_inode_ref_index(eb, ref); | 1218 | if (index) |
| 1219 | *index = btrfs_inode_ref_index(eb, ref); | ||
| 1216 | 1220 | ||
| 1217 | return 0; | 1221 | return 0; |
| 1218 | } | 1222 | } |
| 1219 | 1223 | ||
| 1220 | /* | 1224 | /* |
| 1225 | * Take an inode reference item from the log tree and iterate all names from the | ||
| 1226 | * inode reference item in the subvolume tree with the same key (if it exists). | ||
| 1227 | * For any name that is not in the inode reference item from the log tree, do a | ||
| 1228 | * proper unlink of that name (that is, remove its entry from the inode | ||
| 1229 | * reference item and both dir index keys). | ||
| 1230 | */ | ||
| 1231 | static int unlink_old_inode_refs(struct btrfs_trans_handle *trans, | ||
| 1232 | struct btrfs_root *root, | ||
| 1233 | struct btrfs_path *path, | ||
| 1234 | struct btrfs_inode *inode, | ||
| 1235 | struct extent_buffer *log_eb, | ||
| 1236 | int log_slot, | ||
| 1237 | struct btrfs_key *key) | ||
| 1238 | { | ||
| 1239 | int ret; | ||
| 1240 | unsigned long ref_ptr; | ||
| 1241 | unsigned long ref_end; | ||
| 1242 | struct extent_buffer *eb; | ||
| 1243 | |||
| 1244 | again: | ||
| 1245 | btrfs_release_path(path); | ||
| 1246 | ret = btrfs_search_slot(NULL, root, key, path, 0, 0); | ||
| 1247 | if (ret > 0) { | ||
| 1248 | ret = 0; | ||
| 1249 | goto out; | ||
| 1250 | } | ||
| 1251 | if (ret < 0) | ||
| 1252 | goto out; | ||
| 1253 | |||
| 1254 | eb = path->nodes[0]; | ||
| 1255 | ref_ptr = btrfs_item_ptr_offset(eb, path->slots[0]); | ||
| 1256 | ref_end = ref_ptr + btrfs_item_size_nr(eb, path->slots[0]); | ||
| 1257 | while (ref_ptr < ref_end) { | ||
| 1258 | char *name = NULL; | ||
| 1259 | int namelen; | ||
| 1260 | u64 parent_id; | ||
| 1261 | |||
| 1262 | if (key->type == BTRFS_INODE_EXTREF_KEY) { | ||
| 1263 | ret = extref_get_fields(eb, ref_ptr, &namelen, &name, | ||
| 1264 | NULL, &parent_id); | ||
| 1265 | } else { | ||
| 1266 | parent_id = key->offset; | ||
| 1267 | ret = ref_get_fields(eb, ref_ptr, &namelen, &name, | ||
| 1268 | NULL); | ||
| 1269 | } | ||
| 1270 | if (ret) | ||
| 1271 | goto out; | ||
| 1272 | |||
| 1273 | if (key->type == BTRFS_INODE_EXTREF_KEY) | ||
| 1274 | ret = btrfs_find_name_in_ext_backref(log_eb, log_slot, | ||
| 1275 | parent_id, name, | ||
| 1276 | namelen, NULL); | ||
| 1277 | else | ||
| 1278 | ret = btrfs_find_name_in_backref(log_eb, log_slot, name, | ||
| 1279 | namelen, NULL); | ||
| 1280 | |||
| 1281 | if (!ret) { | ||
| 1282 | struct inode *dir; | ||
| 1283 | |||
| 1284 | btrfs_release_path(path); | ||
| 1285 | dir = read_one_inode(root, parent_id); | ||
| 1286 | if (!dir) { | ||
| 1287 | ret = -ENOENT; | ||
| 1288 | kfree(name); | ||
| 1289 | goto out; | ||
| 1290 | } | ||
| 1291 | ret = btrfs_unlink_inode(trans, root, BTRFS_I(dir), | ||
| 1292 | inode, name, namelen); | ||
| 1293 | kfree(name); | ||
| 1294 | iput(dir); | ||
| 1295 | if (ret) | ||
| 1296 | goto out; | ||
| 1297 | goto again; | ||
| 1298 | } | ||
| 1299 | |||
| 1300 | kfree(name); | ||
| 1301 | ref_ptr += namelen; | ||
| 1302 | if (key->type == BTRFS_INODE_EXTREF_KEY) | ||
| 1303 | ref_ptr += sizeof(struct btrfs_inode_extref); | ||
| 1304 | else | ||
| 1305 | ref_ptr += sizeof(struct btrfs_inode_ref); | ||
| 1306 | } | ||
| 1307 | ret = 0; | ||
| 1308 | out: | ||
| 1309 | btrfs_release_path(path); | ||
| 1310 | return ret; | ||
| 1311 | } | ||
| 1312 | |||
| 1313 | /* | ||
| 1221 | * replay one inode back reference item found in the log tree. | 1314 | * replay one inode back reference item found in the log tree. |
| 1222 | * eb, slot and key refer to the buffer and key found in the log tree. | 1315 | * eb, slot and key refer to the buffer and key found in the log tree. |
| 1223 | * root is the destination we are replaying into, and path is for temp | 1316 | * root is the destination we are replaying into, and path is for temp |
| @@ -1345,6 +1438,19 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, | |||
| 1345 | } | 1438 | } |
| 1346 | } | 1439 | } |
| 1347 | 1440 | ||
| 1441 | /* | ||
| 1442 | * Before we overwrite the inode reference item in the subvolume tree | ||
| 1443 | * with the item from the log tree, we must unlink all names from the | ||
| 1444 | * parent directory that are in the subvolume's tree inode reference | ||
| 1445 | * item, otherwise we end up with an inconsistent subvolume tree where | ||
| 1446 | * dir index entries exist for a name but there is no inode reference | ||
| 1447 | * item with the same name. | ||
| 1448 | */ | ||
| 1449 | ret = unlink_old_inode_refs(trans, root, path, BTRFS_I(inode), eb, slot, | ||
| 1450 | key); | ||
| 1451 | if (ret) | ||
| 1452 | goto out; | ||
| 1453 | |||
| 1348 | /* finally write the back reference in the inode */ | 1454 | /* finally write the back reference in the inode */ |
| 1349 | ret = overwrite_item(trans, root, path, eb, slot, key); | 1455 | ret = overwrite_item(trans, root, path, eb, slot, key); |
| 1350 | out: | 1456 | out: |
| @@ -5853,7 +5959,7 @@ int btrfs_log_new_name(struct btrfs_trans_handle *trans, | |||
| 5853 | * this will force the logging code to walk the dentry chain | 5959 | * this will force the logging code to walk the dentry chain |
| 5854 | * up for the file | 5960 | * up for the file |
| 5855 | */ | 5961 | */ |
| 5856 | if (S_ISREG(inode->vfs_inode.i_mode)) | 5962 | if (!S_ISDIR(inode->vfs_inode.i_mode)) |
| 5857 | inode->last_unlink_trans = trans->transid; | 5963 | inode->last_unlink_trans = trans->transid; |
| 5858 | 5964 | ||
| 5859 | /* | 5965 | /* |
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 2ceb924ca0d6..b2d05c6b1c56 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c | |||
| @@ -4829,10 +4829,13 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans, | |||
| 4829 | ndevs = min(ndevs, devs_max); | 4829 | ndevs = min(ndevs, devs_max); |
| 4830 | 4830 | ||
| 4831 | /* | 4831 | /* |
| 4832 | * the primary goal is to maximize the number of stripes, so use as many | 4832 | * The primary goal is to maximize the number of stripes, so use as |
| 4833 | * devices as possible, even if the stripes are not maximum sized. | 4833 | * many devices as possible, even if the stripes are not maximum sized. |
| 4834 | * | ||
| 4835 | * The DUP profile stores more than one stripe per device, the | ||
| 4836 | * max_avail is the total size so we have to adjust. | ||
| 4834 | */ | 4837 | */ |
| 4835 | stripe_size = devices_info[ndevs-1].max_avail; | 4838 | stripe_size = div_u64(devices_info[ndevs - 1].max_avail, dev_stripes); |
| 4836 | num_stripes = ndevs * dev_stripes; | 4839 | num_stripes = ndevs * dev_stripes; |
| 4837 | 4840 | ||
| 4838 | /* | 4841 | /* |
| @@ -4867,8 +4870,6 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans, | |||
| 4867 | stripe_size = devices_info[ndevs-1].max_avail; | 4870 | stripe_size = devices_info[ndevs-1].max_avail; |
| 4868 | } | 4871 | } |
| 4869 | 4872 | ||
| 4870 | stripe_size = div_u64(stripe_size, dev_stripes); | ||
| 4871 | |||
| 4872 | /* align to BTRFS_STRIPE_LEN */ | 4873 | /* align to BTRFS_STRIPE_LEN */ |
| 4873 | stripe_size = round_down(stripe_size, BTRFS_STRIPE_LEN); | 4874 | stripe_size = round_down(stripe_size, BTRFS_STRIPE_LEN); |
| 4874 | 4875 | ||
