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 /fs | |
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
Diffstat (limited to 'fs')
-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 | ||