diff options
author | Chris Mason <clm@fb.com> | 2016-10-12 16:16:00 -0400 |
---|---|---|
committer | Chris Mason <clm@fb.com> | 2016-10-12 16:16:00 -0400 |
commit | d9ed71e5457c8c5bf1dc706e06468eab9e2aa87e (patch) | |
tree | ddc02c4207fc2c828ea4612d45f4af32d5dc292f | |
parent | 19c4d2f994788a954af1aa7e53b0fdb46fd7925a (diff) | |
parent | 0e6757859efea6ed919fc37e4ee468634220b2d2 (diff) |
Merge branch 'fst-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux into for-linus-4.9
Signed-off-by: Chris Mason <clm@fb.com>
-rw-r--r-- | fs/btrfs/ctree.h | 3 | ||||
-rw-r--r-- | fs/btrfs/disk-io.c | 33 | ||||
-rw-r--r-- | fs/btrfs/extent_io.c | 64 | ||||
-rw-r--r-- | fs/btrfs/extent_io.h | 22 | ||||
-rw-r--r-- | fs/btrfs/free-space-tree.c | 19 | ||||
-rw-r--r-- | fs/btrfs/tests/extent-io-tests.c | 87 | ||||
-rw-r--r-- | fs/btrfs/tests/free-space-tree-tests.c | 189 | ||||
-rw-r--r-- | include/uapi/linux/btrfs.h | 12 |
8 files changed, 272 insertions, 157 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index bf7cb6da78e6..9d8edcb0813c 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -252,7 +252,8 @@ struct btrfs_super_block { | |||
252 | #define BTRFS_FEATURE_COMPAT_SAFE_CLEAR 0ULL | 252 | #define BTRFS_FEATURE_COMPAT_SAFE_CLEAR 0ULL |
253 | 253 | ||
254 | #define BTRFS_FEATURE_COMPAT_RO_SUPP \ | 254 | #define BTRFS_FEATURE_COMPAT_RO_SUPP \ |
255 | (BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE) | 255 | (BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE | \ |
256 | BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE_VALID) | ||
256 | 257 | ||
257 | #define BTRFS_FEATURE_COMPAT_RO_SAFE_SET 0ULL | 258 | #define BTRFS_FEATURE_COMPAT_RO_SAFE_SET 0ULL |
258 | #define BTRFS_FEATURE_COMPAT_RO_SAFE_CLEAR 0ULL | 259 | #define BTRFS_FEATURE_COMPAT_RO_SAFE_CLEAR 0ULL |
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index e720d3e6ec20..3a57f99d96aa 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -2586,6 +2586,7 @@ int open_ctree(struct super_block *sb, | |||
2586 | int num_backups_tried = 0; | 2586 | int num_backups_tried = 0; |
2587 | int backup_index = 0; | 2587 | int backup_index = 0; |
2588 | int max_active; | 2588 | int max_active; |
2589 | int clear_free_space_tree = 0; | ||
2589 | 2590 | ||
2590 | tree_root = fs_info->tree_root = btrfs_alloc_root(fs_info, GFP_KERNEL); | 2591 | tree_root = fs_info->tree_root = btrfs_alloc_root(fs_info, GFP_KERNEL); |
2591 | chunk_root = fs_info->chunk_root = btrfs_alloc_root(fs_info, GFP_KERNEL); | 2592 | chunk_root = fs_info->chunk_root = btrfs_alloc_root(fs_info, GFP_KERNEL); |
@@ -3148,6 +3149,26 @@ retry_root_backup: | |||
3148 | if (sb->s_flags & MS_RDONLY) | 3149 | if (sb->s_flags & MS_RDONLY) |
3149 | return 0; | 3150 | return 0; |
3150 | 3151 | ||
3152 | if (btrfs_test_opt(fs_info, CLEAR_CACHE) && | ||
3153 | btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE)) { | ||
3154 | clear_free_space_tree = 1; | ||
3155 | } else if (btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE) && | ||
3156 | !btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE_VALID)) { | ||
3157 | btrfs_warn(fs_info, "free space tree is invalid"); | ||
3158 | clear_free_space_tree = 1; | ||
3159 | } | ||
3160 | |||
3161 | if (clear_free_space_tree) { | ||
3162 | btrfs_info(fs_info, "clearing free space tree"); | ||
3163 | ret = btrfs_clear_free_space_tree(fs_info); | ||
3164 | if (ret) { | ||
3165 | btrfs_warn(fs_info, | ||
3166 | "failed to clear free space tree: %d", ret); | ||
3167 | close_ctree(tree_root); | ||
3168 | return ret; | ||
3169 | } | ||
3170 | } | ||
3171 | |||
3151 | if (btrfs_test_opt(tree_root->fs_info, FREE_SPACE_TREE) && | 3172 | if (btrfs_test_opt(tree_root->fs_info, FREE_SPACE_TREE) && |
3152 | !btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE)) { | 3173 | !btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE)) { |
3153 | btrfs_info(fs_info, "creating free space tree"); | 3174 | btrfs_info(fs_info, "creating free space tree"); |
@@ -3185,18 +3206,6 @@ retry_root_backup: | |||
3185 | 3206 | ||
3186 | btrfs_qgroup_rescan_resume(fs_info); | 3207 | btrfs_qgroup_rescan_resume(fs_info); |
3187 | 3208 | ||
3188 | if (btrfs_test_opt(tree_root->fs_info, CLEAR_CACHE) && | ||
3189 | btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE)) { | ||
3190 | btrfs_info(fs_info, "clearing free space tree"); | ||
3191 | ret = btrfs_clear_free_space_tree(fs_info); | ||
3192 | if (ret) { | ||
3193 | btrfs_warn(fs_info, | ||
3194 | "failed to clear free space tree: %d", ret); | ||
3195 | close_ctree(tree_root); | ||
3196 | return ret; | ||
3197 | } | ||
3198 | } | ||
3199 | |||
3200 | if (!fs_info->uuid_root) { | 3209 | if (!fs_info->uuid_root) { |
3201 | btrfs_info(fs_info, "creating UUID tree"); | 3210 | btrfs_info(fs_info, "creating UUID tree"); |
3202 | ret = btrfs_create_uuid_tree(fs_info); | 3211 | ret = btrfs_create_uuid_tree(fs_info); |
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index ee40384c394d..66a755150056 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c | |||
@@ -5558,17 +5558,45 @@ void copy_extent_buffer(struct extent_buffer *dst, struct extent_buffer *src, | |||
5558 | } | 5558 | } |
5559 | } | 5559 | } |
5560 | 5560 | ||
5561 | /* | 5561 | void le_bitmap_set(u8 *map, unsigned int start, int len) |
5562 | * The extent buffer bitmap operations are done with byte granularity because | 5562 | { |
5563 | * bitmap items are not guaranteed to be aligned to a word and therefore a | 5563 | u8 *p = map + BIT_BYTE(start); |
5564 | * single word in a bitmap may straddle two pages in the extent buffer. | 5564 | const unsigned int size = start + len; |
5565 | */ | 5565 | int bits_to_set = BITS_PER_BYTE - (start % BITS_PER_BYTE); |
5566 | #define BIT_BYTE(nr) ((nr) / BITS_PER_BYTE) | 5566 | u8 mask_to_set = BITMAP_FIRST_BYTE_MASK(start); |
5567 | #define BYTE_MASK ((1 << BITS_PER_BYTE) - 1) | 5567 | |
5568 | #define BITMAP_FIRST_BYTE_MASK(start) \ | 5568 | while (len - bits_to_set >= 0) { |
5569 | ((BYTE_MASK << ((start) & (BITS_PER_BYTE - 1))) & BYTE_MASK) | 5569 | *p |= mask_to_set; |
5570 | #define BITMAP_LAST_BYTE_MASK(nbits) \ | 5570 | len -= bits_to_set; |
5571 | (BYTE_MASK >> (-(nbits) & (BITS_PER_BYTE - 1))) | 5571 | bits_to_set = BITS_PER_BYTE; |
5572 | mask_to_set = ~(u8)0; | ||
5573 | p++; | ||
5574 | } | ||
5575 | if (len) { | ||
5576 | mask_to_set &= BITMAP_LAST_BYTE_MASK(size); | ||
5577 | *p |= mask_to_set; | ||
5578 | } | ||
5579 | } | ||
5580 | |||
5581 | void le_bitmap_clear(u8 *map, unsigned int start, int len) | ||
5582 | { | ||
5583 | u8 *p = map + BIT_BYTE(start); | ||
5584 | const unsigned int size = start + len; | ||
5585 | int bits_to_clear = BITS_PER_BYTE - (start % BITS_PER_BYTE); | ||
5586 | u8 mask_to_clear = BITMAP_FIRST_BYTE_MASK(start); | ||
5587 | |||
5588 | while (len - bits_to_clear >= 0) { | ||
5589 | *p &= ~mask_to_clear; | ||
5590 | len -= bits_to_clear; | ||
5591 | bits_to_clear = BITS_PER_BYTE; | ||
5592 | mask_to_clear = ~(u8)0; | ||
5593 | p++; | ||
5594 | } | ||
5595 | if (len) { | ||
5596 | mask_to_clear &= BITMAP_LAST_BYTE_MASK(size); | ||
5597 | *p &= ~mask_to_clear; | ||
5598 | } | ||
5599 | } | ||
5572 | 5600 | ||
5573 | /* | 5601 | /* |
5574 | * eb_bitmap_offset() - calculate the page and offset of the byte containing the | 5602 | * eb_bitmap_offset() - calculate the page and offset of the byte containing the |
@@ -5612,7 +5640,7 @@ static inline void eb_bitmap_offset(struct extent_buffer *eb, | |||
5612 | int extent_buffer_test_bit(struct extent_buffer *eb, unsigned long start, | 5640 | int extent_buffer_test_bit(struct extent_buffer *eb, unsigned long start, |
5613 | unsigned long nr) | 5641 | unsigned long nr) |
5614 | { | 5642 | { |
5615 | char *kaddr; | 5643 | u8 *kaddr; |
5616 | struct page *page; | 5644 | struct page *page; |
5617 | unsigned long i; | 5645 | unsigned long i; |
5618 | size_t offset; | 5646 | size_t offset; |
@@ -5634,13 +5662,13 @@ int extent_buffer_test_bit(struct extent_buffer *eb, unsigned long start, | |||
5634 | void extent_buffer_bitmap_set(struct extent_buffer *eb, unsigned long start, | 5662 | void extent_buffer_bitmap_set(struct extent_buffer *eb, unsigned long start, |
5635 | unsigned long pos, unsigned long len) | 5663 | unsigned long pos, unsigned long len) |
5636 | { | 5664 | { |
5637 | char *kaddr; | 5665 | u8 *kaddr; |
5638 | struct page *page; | 5666 | struct page *page; |
5639 | unsigned long i; | 5667 | unsigned long i; |
5640 | size_t offset; | 5668 | size_t offset; |
5641 | const unsigned int size = pos + len; | 5669 | const unsigned int size = pos + len; |
5642 | int bits_to_set = BITS_PER_BYTE - (pos % BITS_PER_BYTE); | 5670 | int bits_to_set = BITS_PER_BYTE - (pos % BITS_PER_BYTE); |
5643 | unsigned int mask_to_set = BITMAP_FIRST_BYTE_MASK(pos); | 5671 | u8 mask_to_set = BITMAP_FIRST_BYTE_MASK(pos); |
5644 | 5672 | ||
5645 | eb_bitmap_offset(eb, start, pos, &i, &offset); | 5673 | eb_bitmap_offset(eb, start, pos, &i, &offset); |
5646 | page = eb->pages[i]; | 5674 | page = eb->pages[i]; |
@@ -5651,7 +5679,7 @@ void extent_buffer_bitmap_set(struct extent_buffer *eb, unsigned long start, | |||
5651 | kaddr[offset] |= mask_to_set; | 5679 | kaddr[offset] |= mask_to_set; |
5652 | len -= bits_to_set; | 5680 | len -= bits_to_set; |
5653 | bits_to_set = BITS_PER_BYTE; | 5681 | bits_to_set = BITS_PER_BYTE; |
5654 | mask_to_set = ~0U; | 5682 | mask_to_set = ~(u8)0; |
5655 | if (++offset >= PAGE_SIZE && len > 0) { | 5683 | if (++offset >= PAGE_SIZE && len > 0) { |
5656 | offset = 0; | 5684 | offset = 0; |
5657 | page = eb->pages[++i]; | 5685 | page = eb->pages[++i]; |
@@ -5676,13 +5704,13 @@ void extent_buffer_bitmap_set(struct extent_buffer *eb, unsigned long start, | |||
5676 | void extent_buffer_bitmap_clear(struct extent_buffer *eb, unsigned long start, | 5704 | void extent_buffer_bitmap_clear(struct extent_buffer *eb, unsigned long start, |
5677 | unsigned long pos, unsigned long len) | 5705 | unsigned long pos, unsigned long len) |
5678 | { | 5706 | { |
5679 | char *kaddr; | 5707 | u8 *kaddr; |
5680 | struct page *page; | 5708 | struct page *page; |
5681 | unsigned long i; | 5709 | unsigned long i; |
5682 | size_t offset; | 5710 | size_t offset; |
5683 | const unsigned int size = pos + len; | 5711 | const unsigned int size = pos + len; |
5684 | int bits_to_clear = BITS_PER_BYTE - (pos % BITS_PER_BYTE); | 5712 | int bits_to_clear = BITS_PER_BYTE - (pos % BITS_PER_BYTE); |
5685 | unsigned int mask_to_clear = BITMAP_FIRST_BYTE_MASK(pos); | 5713 | u8 mask_to_clear = BITMAP_FIRST_BYTE_MASK(pos); |
5686 | 5714 | ||
5687 | eb_bitmap_offset(eb, start, pos, &i, &offset); | 5715 | eb_bitmap_offset(eb, start, pos, &i, &offset); |
5688 | page = eb->pages[i]; | 5716 | page = eb->pages[i]; |
@@ -5693,7 +5721,7 @@ void extent_buffer_bitmap_clear(struct extent_buffer *eb, unsigned long start, | |||
5693 | kaddr[offset] &= ~mask_to_clear; | 5721 | kaddr[offset] &= ~mask_to_clear; |
5694 | len -= bits_to_clear; | 5722 | len -= bits_to_clear; |
5695 | bits_to_clear = BITS_PER_BYTE; | 5723 | bits_to_clear = BITS_PER_BYTE; |
5696 | mask_to_clear = ~0U; | 5724 | mask_to_clear = ~(u8)0; |
5697 | if (++offset >= PAGE_SIZE && len > 0) { | 5725 | if (++offset >= PAGE_SIZE && len > 0) { |
5698 | offset = 0; | 5726 | offset = 0; |
5699 | page = eb->pages[++i]; | 5727 | page = eb->pages[++i]; |
diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h index 4a094f1dc7ef..ab31d145227e 100644 --- a/fs/btrfs/extent_io.h +++ b/fs/btrfs/extent_io.h | |||
@@ -59,6 +59,28 @@ | |||
59 | */ | 59 | */ |
60 | #define EXTENT_PAGE_PRIVATE 1 | 60 | #define EXTENT_PAGE_PRIVATE 1 |
61 | 61 | ||
62 | /* | ||
63 | * The extent buffer bitmap operations are done with byte granularity instead of | ||
64 | * word granularity for two reasons: | ||
65 | * 1. The bitmaps must be little-endian on disk. | ||
66 | * 2. Bitmap items are not guaranteed to be aligned to a word and therefore a | ||
67 | * single word in a bitmap may straddle two pages in the extent buffer. | ||
68 | */ | ||
69 | #define BIT_BYTE(nr) ((nr) / BITS_PER_BYTE) | ||
70 | #define BYTE_MASK ((1 << BITS_PER_BYTE) - 1) | ||
71 | #define BITMAP_FIRST_BYTE_MASK(start) \ | ||
72 | ((BYTE_MASK << ((start) & (BITS_PER_BYTE - 1))) & BYTE_MASK) | ||
73 | #define BITMAP_LAST_BYTE_MASK(nbits) \ | ||
74 | (BYTE_MASK >> (-(nbits) & (BITS_PER_BYTE - 1))) | ||
75 | |||
76 | static inline int le_test_bit(int nr, const u8 *addr) | ||
77 | { | ||
78 | return 1U & (addr[BIT_BYTE(nr)] >> (nr & (BITS_PER_BYTE-1))); | ||
79 | } | ||
80 | |||
81 | extern void le_bitmap_set(u8 *map, unsigned int start, int len); | ||
82 | extern void le_bitmap_clear(u8 *map, unsigned int start, int len); | ||
83 | |||
62 | struct extent_state; | 84 | struct extent_state; |
63 | struct btrfs_root; | 85 | struct btrfs_root; |
64 | struct btrfs_io_bio; | 86 | struct btrfs_io_bio; |
diff --git a/fs/btrfs/free-space-tree.c b/fs/btrfs/free-space-tree.c index e4a42a8e4f84..57401b474ec6 100644 --- a/fs/btrfs/free-space-tree.c +++ b/fs/btrfs/free-space-tree.c | |||
@@ -151,7 +151,7 @@ static inline u32 free_space_bitmap_size(u64 size, u32 sectorsize) | |||
151 | return DIV_ROUND_UP((u32)div_u64(size, sectorsize), BITS_PER_BYTE); | 151 | return DIV_ROUND_UP((u32)div_u64(size, sectorsize), BITS_PER_BYTE); |
152 | } | 152 | } |
153 | 153 | ||
154 | static unsigned long *alloc_bitmap(u32 bitmap_size) | 154 | static u8 *alloc_bitmap(u32 bitmap_size) |
155 | { | 155 | { |
156 | void *mem; | 156 | void *mem; |
157 | 157 | ||
@@ -180,8 +180,7 @@ int convert_free_space_to_bitmaps(struct btrfs_trans_handle *trans, | |||
180 | struct btrfs_free_space_info *info; | 180 | struct btrfs_free_space_info *info; |
181 | struct btrfs_key key, found_key; | 181 | struct btrfs_key key, found_key; |
182 | struct extent_buffer *leaf; | 182 | struct extent_buffer *leaf; |
183 | unsigned long *bitmap; | 183 | u8 *bitmap, *bitmap_cursor; |
184 | char *bitmap_cursor; | ||
185 | u64 start, end; | 184 | u64 start, end; |
186 | u64 bitmap_range, i; | 185 | u64 bitmap_range, i; |
187 | u32 bitmap_size, flags, expected_extent_count; | 186 | u32 bitmap_size, flags, expected_extent_count; |
@@ -231,7 +230,7 @@ int convert_free_space_to_bitmaps(struct btrfs_trans_handle *trans, | |||
231 | block_group->sectorsize); | 230 | block_group->sectorsize); |
232 | last = div_u64(found_key.objectid + found_key.offset - start, | 231 | last = div_u64(found_key.objectid + found_key.offset - start, |
233 | block_group->sectorsize); | 232 | block_group->sectorsize); |
234 | bitmap_set(bitmap, first, last - first); | 233 | le_bitmap_set(bitmap, first, last - first); |
235 | 234 | ||
236 | extent_count++; | 235 | extent_count++; |
237 | nr++; | 236 | nr++; |
@@ -270,7 +269,7 @@ int convert_free_space_to_bitmaps(struct btrfs_trans_handle *trans, | |||
270 | goto out; | 269 | goto out; |
271 | } | 270 | } |
272 | 271 | ||
273 | bitmap_cursor = (char *)bitmap; | 272 | bitmap_cursor = bitmap; |
274 | bitmap_range = block_group->sectorsize * BTRFS_FREE_SPACE_BITMAP_BITS; | 273 | bitmap_range = block_group->sectorsize * BTRFS_FREE_SPACE_BITMAP_BITS; |
275 | i = start; | 274 | i = start; |
276 | while (i < end) { | 275 | while (i < end) { |
@@ -319,7 +318,7 @@ int convert_free_space_to_extents(struct btrfs_trans_handle *trans, | |||
319 | struct btrfs_free_space_info *info; | 318 | struct btrfs_free_space_info *info; |
320 | struct btrfs_key key, found_key; | 319 | struct btrfs_key key, found_key; |
321 | struct extent_buffer *leaf; | 320 | struct extent_buffer *leaf; |
322 | unsigned long *bitmap; | 321 | u8 *bitmap; |
323 | u64 start, end; | 322 | u64 start, end; |
324 | /* Initialize to silence GCC. */ | 323 | /* Initialize to silence GCC. */ |
325 | u64 extent_start = 0; | 324 | u64 extent_start = 0; |
@@ -363,7 +362,7 @@ int convert_free_space_to_extents(struct btrfs_trans_handle *trans, | |||
363 | break; | 362 | break; |
364 | } else if (found_key.type == BTRFS_FREE_SPACE_BITMAP_KEY) { | 363 | } else if (found_key.type == BTRFS_FREE_SPACE_BITMAP_KEY) { |
365 | unsigned long ptr; | 364 | unsigned long ptr; |
366 | char *bitmap_cursor; | 365 | u8 *bitmap_cursor; |
367 | u32 bitmap_pos, data_size; | 366 | u32 bitmap_pos, data_size; |
368 | 367 | ||
369 | ASSERT(found_key.objectid >= start); | 368 | ASSERT(found_key.objectid >= start); |
@@ -373,7 +372,7 @@ int convert_free_space_to_extents(struct btrfs_trans_handle *trans, | |||
373 | bitmap_pos = div_u64(found_key.objectid - start, | 372 | bitmap_pos = div_u64(found_key.objectid - start, |
374 | block_group->sectorsize * | 373 | block_group->sectorsize * |
375 | BITS_PER_BYTE); | 374 | BITS_PER_BYTE); |
376 | bitmap_cursor = ((char *)bitmap) + bitmap_pos; | 375 | bitmap_cursor = bitmap + bitmap_pos; |
377 | data_size = free_space_bitmap_size(found_key.offset, | 376 | data_size = free_space_bitmap_size(found_key.offset, |
378 | block_group->sectorsize); | 377 | block_group->sectorsize); |
379 | 378 | ||
@@ -410,7 +409,7 @@ int convert_free_space_to_extents(struct btrfs_trans_handle *trans, | |||
410 | offset = start; | 409 | offset = start; |
411 | bitnr = 0; | 410 | bitnr = 0; |
412 | while (offset < end) { | 411 | while (offset < end) { |
413 | bit = !!test_bit(bitnr, bitmap); | 412 | bit = !!le_test_bit(bitnr, bitmap); |
414 | if (prev_bit == 0 && bit == 1) { | 413 | if (prev_bit == 0 && bit == 1) { |
415 | extent_start = offset; | 414 | extent_start = offset; |
416 | } else if (prev_bit == 1 && bit == 0) { | 415 | } else if (prev_bit == 1 && bit == 0) { |
@@ -1185,6 +1184,7 @@ int btrfs_create_free_space_tree(struct btrfs_fs_info *fs_info) | |||
1185 | } | 1184 | } |
1186 | 1185 | ||
1187 | btrfs_set_fs_compat_ro(fs_info, FREE_SPACE_TREE); | 1186 | btrfs_set_fs_compat_ro(fs_info, FREE_SPACE_TREE); |
1187 | btrfs_set_fs_compat_ro(fs_info, FREE_SPACE_TREE_VALID); | ||
1188 | clear_bit(BTRFS_FS_CREATING_FREE_SPACE_TREE, &fs_info->flags); | 1188 | clear_bit(BTRFS_FS_CREATING_FREE_SPACE_TREE, &fs_info->flags); |
1189 | 1189 | ||
1190 | ret = btrfs_commit_transaction(trans, tree_root); | 1190 | ret = btrfs_commit_transaction(trans, tree_root); |
@@ -1253,6 +1253,7 @@ int btrfs_clear_free_space_tree(struct btrfs_fs_info *fs_info) | |||
1253 | return PTR_ERR(trans); | 1253 | return PTR_ERR(trans); |
1254 | 1254 | ||
1255 | btrfs_clear_fs_compat_ro(fs_info, FREE_SPACE_TREE); | 1255 | btrfs_clear_fs_compat_ro(fs_info, FREE_SPACE_TREE); |
1256 | btrfs_clear_fs_compat_ro(fs_info, FREE_SPACE_TREE_VALID); | ||
1256 | fs_info->free_space_root = NULL; | 1257 | fs_info->free_space_root = NULL; |
1257 | 1258 | ||
1258 | ret = clear_free_space_tree(trans, free_space_root); | 1259 | ret = clear_free_space_tree(trans, free_space_root); |
diff --git a/fs/btrfs/tests/extent-io-tests.c b/fs/btrfs/tests/extent-io-tests.c index d19ab0317283..caad80bb9bd0 100644 --- a/fs/btrfs/tests/extent-io-tests.c +++ b/fs/btrfs/tests/extent-io-tests.c | |||
@@ -273,20 +273,37 @@ out: | |||
273 | return ret; | 273 | return ret; |
274 | } | 274 | } |
275 | 275 | ||
276 | /** | 276 | static int check_eb_bitmap(unsigned long *bitmap, struct extent_buffer *eb, |
277 | * test_bit_in_byte - Determine whether a bit is set in a byte | 277 | unsigned long len) |
278 | * @nr: bit number to test | ||
279 | * @addr: Address to start counting from | ||
280 | */ | ||
281 | static inline int test_bit_in_byte(int nr, const u8 *addr) | ||
282 | { | 278 | { |
283 | return 1UL & (addr[nr / BITS_PER_BYTE] >> (nr & (BITS_PER_BYTE - 1))); | 279 | unsigned long i; |
280 | |||
281 | for (i = 0; i < len * BITS_PER_BYTE; i++) { | ||
282 | int bit, bit1; | ||
283 | |||
284 | bit = !!test_bit(i, bitmap); | ||
285 | bit1 = !!extent_buffer_test_bit(eb, 0, i); | ||
286 | if (bit1 != bit) { | ||
287 | test_msg("Bits do not match\n"); | ||
288 | return -EINVAL; | ||
289 | } | ||
290 | |||
291 | bit1 = !!extent_buffer_test_bit(eb, i / BITS_PER_BYTE, | ||
292 | i % BITS_PER_BYTE); | ||
293 | if (bit1 != bit) { | ||
294 | test_msg("Offset bits do not match\n"); | ||
295 | return -EINVAL; | ||
296 | } | ||
297 | } | ||
298 | return 0; | ||
284 | } | 299 | } |
285 | 300 | ||
286 | static int __test_eb_bitmaps(unsigned long *bitmap, struct extent_buffer *eb, | 301 | static int __test_eb_bitmaps(unsigned long *bitmap, struct extent_buffer *eb, |
287 | unsigned long len) | 302 | unsigned long len) |
288 | { | 303 | { |
289 | unsigned long i, x; | 304 | unsigned long i, j; |
305 | u32 x; | ||
306 | int ret; | ||
290 | 307 | ||
291 | memset(bitmap, 0, len); | 308 | memset(bitmap, 0, len); |
292 | memset_extent_buffer(eb, 0, 0, len); | 309 | memset_extent_buffer(eb, 0, 0, len); |
@@ -297,16 +314,18 @@ static int __test_eb_bitmaps(unsigned long *bitmap, struct extent_buffer *eb, | |||
297 | 314 | ||
298 | bitmap_set(bitmap, 0, len * BITS_PER_BYTE); | 315 | bitmap_set(bitmap, 0, len * BITS_PER_BYTE); |
299 | extent_buffer_bitmap_set(eb, 0, 0, len * BITS_PER_BYTE); | 316 | extent_buffer_bitmap_set(eb, 0, 0, len * BITS_PER_BYTE); |
300 | if (memcmp_extent_buffer(eb, bitmap, 0, len) != 0) { | 317 | ret = check_eb_bitmap(bitmap, eb, len); |
318 | if (ret) { | ||
301 | test_msg("Setting all bits failed\n"); | 319 | test_msg("Setting all bits failed\n"); |
302 | return -EINVAL; | 320 | return ret; |
303 | } | 321 | } |
304 | 322 | ||
305 | bitmap_clear(bitmap, 0, len * BITS_PER_BYTE); | 323 | bitmap_clear(bitmap, 0, len * BITS_PER_BYTE); |
306 | extent_buffer_bitmap_clear(eb, 0, 0, len * BITS_PER_BYTE); | 324 | extent_buffer_bitmap_clear(eb, 0, 0, len * BITS_PER_BYTE); |
307 | if (memcmp_extent_buffer(eb, bitmap, 0, len) != 0) { | 325 | ret = check_eb_bitmap(bitmap, eb, len); |
326 | if (ret) { | ||
308 | test_msg("Clearing all bits failed\n"); | 327 | test_msg("Clearing all bits failed\n"); |
309 | return -EINVAL; | 328 | return ret; |
310 | } | 329 | } |
311 | 330 | ||
312 | /* Straddling pages test */ | 331 | /* Straddling pages test */ |
@@ -316,9 +335,10 @@ static int __test_eb_bitmaps(unsigned long *bitmap, struct extent_buffer *eb, | |||
316 | sizeof(long) * BITS_PER_BYTE); | 335 | sizeof(long) * BITS_PER_BYTE); |
317 | extent_buffer_bitmap_set(eb, PAGE_SIZE - sizeof(long) / 2, 0, | 336 | extent_buffer_bitmap_set(eb, PAGE_SIZE - sizeof(long) / 2, 0, |
318 | sizeof(long) * BITS_PER_BYTE); | 337 | sizeof(long) * BITS_PER_BYTE); |
319 | if (memcmp_extent_buffer(eb, bitmap, 0, len) != 0) { | 338 | ret = check_eb_bitmap(bitmap, eb, len); |
339 | if (ret) { | ||
320 | test_msg("Setting straddling pages failed\n"); | 340 | test_msg("Setting straddling pages failed\n"); |
321 | return -EINVAL; | 341 | return ret; |
322 | } | 342 | } |
323 | 343 | ||
324 | bitmap_set(bitmap, 0, len * BITS_PER_BYTE); | 344 | bitmap_set(bitmap, 0, len * BITS_PER_BYTE); |
@@ -328,9 +348,10 @@ static int __test_eb_bitmaps(unsigned long *bitmap, struct extent_buffer *eb, | |||
328 | extent_buffer_bitmap_set(eb, 0, 0, len * BITS_PER_BYTE); | 348 | extent_buffer_bitmap_set(eb, 0, 0, len * BITS_PER_BYTE); |
329 | extent_buffer_bitmap_clear(eb, PAGE_SIZE - sizeof(long) / 2, 0, | 349 | extent_buffer_bitmap_clear(eb, PAGE_SIZE - sizeof(long) / 2, 0, |
330 | sizeof(long) * BITS_PER_BYTE); | 350 | sizeof(long) * BITS_PER_BYTE); |
331 | if (memcmp_extent_buffer(eb, bitmap, 0, len) != 0) { | 351 | ret = check_eb_bitmap(bitmap, eb, len); |
352 | if (ret) { | ||
332 | test_msg("Clearing straddling pages failed\n"); | 353 | test_msg("Clearing straddling pages failed\n"); |
333 | return -EINVAL; | 354 | return ret; |
334 | } | 355 | } |
335 | } | 356 | } |
336 | 357 | ||
@@ -339,28 +360,22 @@ static int __test_eb_bitmaps(unsigned long *bitmap, struct extent_buffer *eb, | |||
339 | * something repetitive that could miss some hypothetical off-by-n bug. | 360 | * something repetitive that could miss some hypothetical off-by-n bug. |
340 | */ | 361 | */ |
341 | x = 0; | 362 | x = 0; |
342 | for (i = 0; i < len / sizeof(long); i++) { | 363 | bitmap_clear(bitmap, 0, len * BITS_PER_BYTE); |
343 | x = (0x19660dULL * (u64)x + 0x3c6ef35fULL) & 0xffffffffUL; | 364 | extent_buffer_bitmap_clear(eb, 0, 0, len * BITS_PER_BYTE); |
344 | bitmap[i] = x; | 365 | for (i = 0; i < len * BITS_PER_BYTE / 32; i++) { |
345 | } | 366 | x = (0x19660dULL * (u64)x + 0x3c6ef35fULL) & 0xffffffffU; |
346 | write_extent_buffer(eb, bitmap, 0, len); | 367 | for (j = 0; j < 32; j++) { |
347 | 368 | if (x & (1U << j)) { | |
348 | for (i = 0; i < len * BITS_PER_BYTE; i++) { | 369 | bitmap_set(bitmap, i * 32 + j, 1); |
349 | int bit, bit1; | 370 | extent_buffer_bitmap_set(eb, 0, i * 32 + j, 1); |
350 | 371 | } | |
351 | bit = !!test_bit_in_byte(i, (u8 *)bitmap); | ||
352 | bit1 = !!extent_buffer_test_bit(eb, 0, i); | ||
353 | if (bit1 != bit) { | ||
354 | test_msg("Testing bit pattern failed\n"); | ||
355 | return -EINVAL; | ||
356 | } | 372 | } |
373 | } | ||
357 | 374 | ||
358 | bit1 = !!extent_buffer_test_bit(eb, i / BITS_PER_BYTE, | 375 | ret = check_eb_bitmap(bitmap, eb, len); |
359 | i % BITS_PER_BYTE); | 376 | if (ret) { |
360 | if (bit1 != bit) { | 377 | test_msg("Random bit pattern failed\n"); |
361 | test_msg("Testing bit pattern with offset failed\n"); | 378 | return ret; |
362 | return -EINVAL; | ||
363 | } | ||
364 | } | 379 | } |
365 | 380 | ||
366 | return 0; | 381 | return 0; |
diff --git a/fs/btrfs/tests/free-space-tree-tests.c b/fs/btrfs/tests/free-space-tree-tests.c index 7508d3b42780..6e144048a72e 100644 --- a/fs/btrfs/tests/free-space-tree-tests.c +++ b/fs/btrfs/tests/free-space-tree-tests.c | |||
@@ -24,20 +24,15 @@ | |||
24 | #include "../transaction.h" | 24 | #include "../transaction.h" |
25 | 25 | ||
26 | struct free_space_extent { | 26 | struct free_space_extent { |
27 | u64 start, length; | 27 | u64 start; |
28 | u64 length; | ||
28 | }; | 29 | }; |
29 | 30 | ||
30 | /* | ||
31 | * The test cases align their operations to this in order to hit some of the | ||
32 | * edge cases in the bitmap code. | ||
33 | */ | ||
34 | #define BITMAP_RANGE (BTRFS_FREE_SPACE_BITMAP_BITS * PAGE_SIZE) | ||
35 | |||
36 | static int __check_free_space_extents(struct btrfs_trans_handle *trans, | 31 | static int __check_free_space_extents(struct btrfs_trans_handle *trans, |
37 | struct btrfs_fs_info *fs_info, | 32 | struct btrfs_fs_info *fs_info, |
38 | struct btrfs_block_group_cache *cache, | 33 | struct btrfs_block_group_cache *cache, |
39 | struct btrfs_path *path, | 34 | struct btrfs_path *path, |
40 | struct free_space_extent *extents, | 35 | const struct free_space_extent * const extents, |
41 | unsigned int num_extents) | 36 | unsigned int num_extents) |
42 | { | 37 | { |
43 | struct btrfs_free_space_info *info; | 38 | struct btrfs_free_space_info *info; |
@@ -126,7 +121,7 @@ static int check_free_space_extents(struct btrfs_trans_handle *trans, | |||
126 | struct btrfs_fs_info *fs_info, | 121 | struct btrfs_fs_info *fs_info, |
127 | struct btrfs_block_group_cache *cache, | 122 | struct btrfs_block_group_cache *cache, |
128 | struct btrfs_path *path, | 123 | struct btrfs_path *path, |
129 | struct free_space_extent *extents, | 124 | const struct free_space_extent * const extents, |
130 | unsigned int num_extents) | 125 | unsigned int num_extents) |
131 | { | 126 | { |
132 | struct btrfs_free_space_info *info; | 127 | struct btrfs_free_space_info *info; |
@@ -168,9 +163,10 @@ static int check_free_space_extents(struct btrfs_trans_handle *trans, | |||
168 | static int test_empty_block_group(struct btrfs_trans_handle *trans, | 163 | static int test_empty_block_group(struct btrfs_trans_handle *trans, |
169 | struct btrfs_fs_info *fs_info, | 164 | struct btrfs_fs_info *fs_info, |
170 | struct btrfs_block_group_cache *cache, | 165 | struct btrfs_block_group_cache *cache, |
171 | struct btrfs_path *path) | 166 | struct btrfs_path *path, |
167 | u32 alignment) | ||
172 | { | 168 | { |
173 | struct free_space_extent extents[] = { | 169 | const struct free_space_extent extents[] = { |
174 | {cache->key.objectid, cache->key.offset}, | 170 | {cache->key.objectid, cache->key.offset}, |
175 | }; | 171 | }; |
176 | 172 | ||
@@ -181,9 +177,10 @@ static int test_empty_block_group(struct btrfs_trans_handle *trans, | |||
181 | static int test_remove_all(struct btrfs_trans_handle *trans, | 177 | static int test_remove_all(struct btrfs_trans_handle *trans, |
182 | struct btrfs_fs_info *fs_info, | 178 | struct btrfs_fs_info *fs_info, |
183 | struct btrfs_block_group_cache *cache, | 179 | struct btrfs_block_group_cache *cache, |
184 | struct btrfs_path *path) | 180 | struct btrfs_path *path, |
181 | u32 alignment) | ||
185 | { | 182 | { |
186 | struct free_space_extent extents[] = {}; | 183 | const struct free_space_extent extents[] = {}; |
187 | int ret; | 184 | int ret; |
188 | 185 | ||
189 | ret = __remove_from_free_space_tree(trans, fs_info, cache, path, | 186 | ret = __remove_from_free_space_tree(trans, fs_info, cache, path, |
@@ -201,16 +198,17 @@ static int test_remove_all(struct btrfs_trans_handle *trans, | |||
201 | static int test_remove_beginning(struct btrfs_trans_handle *trans, | 198 | static int test_remove_beginning(struct btrfs_trans_handle *trans, |
202 | struct btrfs_fs_info *fs_info, | 199 | struct btrfs_fs_info *fs_info, |
203 | struct btrfs_block_group_cache *cache, | 200 | struct btrfs_block_group_cache *cache, |
204 | struct btrfs_path *path) | 201 | struct btrfs_path *path, |
202 | u32 alignment) | ||
205 | { | 203 | { |
206 | struct free_space_extent extents[] = { | 204 | const struct free_space_extent extents[] = { |
207 | {cache->key.objectid + BITMAP_RANGE, | 205 | {cache->key.objectid + alignment, |
208 | cache->key.offset - BITMAP_RANGE}, | 206 | cache->key.offset - alignment}, |
209 | }; | 207 | }; |
210 | int ret; | 208 | int ret; |
211 | 209 | ||
212 | ret = __remove_from_free_space_tree(trans, fs_info, cache, path, | 210 | ret = __remove_from_free_space_tree(trans, fs_info, cache, path, |
213 | cache->key.objectid, BITMAP_RANGE); | 211 | cache->key.objectid, alignment); |
214 | if (ret) { | 212 | if (ret) { |
215 | test_msg("Could not remove free space\n"); | 213 | test_msg("Could not remove free space\n"); |
216 | return ret; | 214 | return ret; |
@@ -224,17 +222,18 @@ static int test_remove_beginning(struct btrfs_trans_handle *trans, | |||
224 | static int test_remove_end(struct btrfs_trans_handle *trans, | 222 | static int test_remove_end(struct btrfs_trans_handle *trans, |
225 | struct btrfs_fs_info *fs_info, | 223 | struct btrfs_fs_info *fs_info, |
226 | struct btrfs_block_group_cache *cache, | 224 | struct btrfs_block_group_cache *cache, |
227 | struct btrfs_path *path) | 225 | struct btrfs_path *path, |
226 | u32 alignment) | ||
228 | { | 227 | { |
229 | struct free_space_extent extents[] = { | 228 | const struct free_space_extent extents[] = { |
230 | {cache->key.objectid, cache->key.offset - BITMAP_RANGE}, | 229 | {cache->key.objectid, cache->key.offset - alignment}, |
231 | }; | 230 | }; |
232 | int ret; | 231 | int ret; |
233 | 232 | ||
234 | ret = __remove_from_free_space_tree(trans, fs_info, cache, path, | 233 | ret = __remove_from_free_space_tree(trans, fs_info, cache, path, |
235 | cache->key.objectid + | 234 | cache->key.objectid + |
236 | cache->key.offset - BITMAP_RANGE, | 235 | cache->key.offset - alignment, |
237 | BITMAP_RANGE); | 236 | alignment); |
238 | if (ret) { | 237 | if (ret) { |
239 | test_msg("Could not remove free space\n"); | 238 | test_msg("Could not remove free space\n"); |
240 | return ret; | 239 | return ret; |
@@ -247,18 +246,19 @@ static int test_remove_end(struct btrfs_trans_handle *trans, | |||
247 | static int test_remove_middle(struct btrfs_trans_handle *trans, | 246 | static int test_remove_middle(struct btrfs_trans_handle *trans, |
248 | struct btrfs_fs_info *fs_info, | 247 | struct btrfs_fs_info *fs_info, |
249 | struct btrfs_block_group_cache *cache, | 248 | struct btrfs_block_group_cache *cache, |
250 | struct btrfs_path *path) | 249 | struct btrfs_path *path, |
250 | u32 alignment) | ||
251 | { | 251 | { |
252 | struct free_space_extent extents[] = { | 252 | const struct free_space_extent extents[] = { |
253 | {cache->key.objectid, BITMAP_RANGE}, | 253 | {cache->key.objectid, alignment}, |
254 | {cache->key.objectid + 2 * BITMAP_RANGE, | 254 | {cache->key.objectid + 2 * alignment, |
255 | cache->key.offset - 2 * BITMAP_RANGE}, | 255 | cache->key.offset - 2 * alignment}, |
256 | }; | 256 | }; |
257 | int ret; | 257 | int ret; |
258 | 258 | ||
259 | ret = __remove_from_free_space_tree(trans, fs_info, cache, path, | 259 | ret = __remove_from_free_space_tree(trans, fs_info, cache, path, |
260 | cache->key.objectid + BITMAP_RANGE, | 260 | cache->key.objectid + alignment, |
261 | BITMAP_RANGE); | 261 | alignment); |
262 | if (ret) { | 262 | if (ret) { |
263 | test_msg("Could not remove free space\n"); | 263 | test_msg("Could not remove free space\n"); |
264 | return ret; | 264 | return ret; |
@@ -271,10 +271,11 @@ static int test_remove_middle(struct btrfs_trans_handle *trans, | |||
271 | static int test_merge_left(struct btrfs_trans_handle *trans, | 271 | static int test_merge_left(struct btrfs_trans_handle *trans, |
272 | struct btrfs_fs_info *fs_info, | 272 | struct btrfs_fs_info *fs_info, |
273 | struct btrfs_block_group_cache *cache, | 273 | struct btrfs_block_group_cache *cache, |
274 | struct btrfs_path *path) | 274 | struct btrfs_path *path, |
275 | u32 alignment) | ||
275 | { | 276 | { |
276 | struct free_space_extent extents[] = { | 277 | const struct free_space_extent extents[] = { |
277 | {cache->key.objectid, 2 * BITMAP_RANGE}, | 278 | {cache->key.objectid, 2 * alignment}, |
278 | }; | 279 | }; |
279 | int ret; | 280 | int ret; |
280 | 281 | ||
@@ -287,15 +288,15 @@ static int test_merge_left(struct btrfs_trans_handle *trans, | |||
287 | } | 288 | } |
288 | 289 | ||
289 | ret = __add_to_free_space_tree(trans, fs_info, cache, path, | 290 | ret = __add_to_free_space_tree(trans, fs_info, cache, path, |
290 | cache->key.objectid, BITMAP_RANGE); | 291 | cache->key.objectid, alignment); |
291 | if (ret) { | 292 | if (ret) { |
292 | test_msg("Could not add free space\n"); | 293 | test_msg("Could not add free space\n"); |
293 | return ret; | 294 | return ret; |
294 | } | 295 | } |
295 | 296 | ||
296 | ret = __add_to_free_space_tree(trans, fs_info, cache, path, | 297 | ret = __add_to_free_space_tree(trans, fs_info, cache, path, |
297 | cache->key.objectid + BITMAP_RANGE, | 298 | cache->key.objectid + alignment, |
298 | BITMAP_RANGE); | 299 | alignment); |
299 | if (ret) { | 300 | if (ret) { |
300 | test_msg("Could not add free space\n"); | 301 | test_msg("Could not add free space\n"); |
301 | return ret; | 302 | return ret; |
@@ -308,10 +309,11 @@ static int test_merge_left(struct btrfs_trans_handle *trans, | |||
308 | static int test_merge_right(struct btrfs_trans_handle *trans, | 309 | static int test_merge_right(struct btrfs_trans_handle *trans, |
309 | struct btrfs_fs_info *fs_info, | 310 | struct btrfs_fs_info *fs_info, |
310 | struct btrfs_block_group_cache *cache, | 311 | struct btrfs_block_group_cache *cache, |
311 | struct btrfs_path *path) | 312 | struct btrfs_path *path, |
313 | u32 alignment) | ||
312 | { | 314 | { |
313 | struct free_space_extent extents[] = { | 315 | const struct free_space_extent extents[] = { |
314 | {cache->key.objectid + BITMAP_RANGE, 2 * BITMAP_RANGE}, | 316 | {cache->key.objectid + alignment, 2 * alignment}, |
315 | }; | 317 | }; |
316 | int ret; | 318 | int ret; |
317 | 319 | ||
@@ -324,16 +326,16 @@ static int test_merge_right(struct btrfs_trans_handle *trans, | |||
324 | } | 326 | } |
325 | 327 | ||
326 | ret = __add_to_free_space_tree(trans, fs_info, cache, path, | 328 | ret = __add_to_free_space_tree(trans, fs_info, cache, path, |
327 | cache->key.objectid + 2 * BITMAP_RANGE, | 329 | cache->key.objectid + 2 * alignment, |
328 | BITMAP_RANGE); | 330 | alignment); |
329 | if (ret) { | 331 | if (ret) { |
330 | test_msg("Could not add free space\n"); | 332 | test_msg("Could not add free space\n"); |
331 | return ret; | 333 | return ret; |
332 | } | 334 | } |
333 | 335 | ||
334 | ret = __add_to_free_space_tree(trans, fs_info, cache, path, | 336 | ret = __add_to_free_space_tree(trans, fs_info, cache, path, |
335 | cache->key.objectid + BITMAP_RANGE, | 337 | cache->key.objectid + alignment, |
336 | BITMAP_RANGE); | 338 | alignment); |
337 | if (ret) { | 339 | if (ret) { |
338 | test_msg("Could not add free space\n"); | 340 | test_msg("Could not add free space\n"); |
339 | return ret; | 341 | return ret; |
@@ -346,10 +348,11 @@ static int test_merge_right(struct btrfs_trans_handle *trans, | |||
346 | static int test_merge_both(struct btrfs_trans_handle *trans, | 348 | static int test_merge_both(struct btrfs_trans_handle *trans, |
347 | struct btrfs_fs_info *fs_info, | 349 | struct btrfs_fs_info *fs_info, |
348 | struct btrfs_block_group_cache *cache, | 350 | struct btrfs_block_group_cache *cache, |
349 | struct btrfs_path *path) | 351 | struct btrfs_path *path, |
352 | u32 alignment) | ||
350 | { | 353 | { |
351 | struct free_space_extent extents[] = { | 354 | const struct free_space_extent extents[] = { |
352 | {cache->key.objectid, 3 * BITMAP_RANGE}, | 355 | {cache->key.objectid, 3 * alignment}, |
353 | }; | 356 | }; |
354 | int ret; | 357 | int ret; |
355 | 358 | ||
@@ -362,23 +365,23 @@ static int test_merge_both(struct btrfs_trans_handle *trans, | |||
362 | } | 365 | } |
363 | 366 | ||
364 | ret = __add_to_free_space_tree(trans, fs_info, cache, path, | 367 | ret = __add_to_free_space_tree(trans, fs_info, cache, path, |
365 | cache->key.objectid, BITMAP_RANGE); | 368 | cache->key.objectid, alignment); |
366 | if (ret) { | 369 | if (ret) { |
367 | test_msg("Could not add free space\n"); | 370 | test_msg("Could not add free space\n"); |
368 | return ret; | 371 | return ret; |
369 | } | 372 | } |
370 | 373 | ||
371 | ret = __add_to_free_space_tree(trans, fs_info, cache, path, | 374 | ret = __add_to_free_space_tree(trans, fs_info, cache, path, |
372 | cache->key.objectid + 2 * BITMAP_RANGE, | 375 | cache->key.objectid + 2 * alignment, |
373 | BITMAP_RANGE); | 376 | alignment); |
374 | if (ret) { | 377 | if (ret) { |
375 | test_msg("Could not add free space\n"); | 378 | test_msg("Could not add free space\n"); |
376 | return ret; | 379 | return ret; |
377 | } | 380 | } |
378 | 381 | ||
379 | ret = __add_to_free_space_tree(trans, fs_info, cache, path, | 382 | ret = __add_to_free_space_tree(trans, fs_info, cache, path, |
380 | cache->key.objectid + BITMAP_RANGE, | 383 | cache->key.objectid + alignment, |
381 | BITMAP_RANGE); | 384 | alignment); |
382 | if (ret) { | 385 | if (ret) { |
383 | test_msg("Could not add free space\n"); | 386 | test_msg("Could not add free space\n"); |
384 | return ret; | 387 | return ret; |
@@ -391,12 +394,13 @@ static int test_merge_both(struct btrfs_trans_handle *trans, | |||
391 | static int test_merge_none(struct btrfs_trans_handle *trans, | 394 | static int test_merge_none(struct btrfs_trans_handle *trans, |
392 | struct btrfs_fs_info *fs_info, | 395 | struct btrfs_fs_info *fs_info, |
393 | struct btrfs_block_group_cache *cache, | 396 | struct btrfs_block_group_cache *cache, |
394 | struct btrfs_path *path) | 397 | struct btrfs_path *path, |
398 | u32 alignment) | ||
395 | { | 399 | { |
396 | struct free_space_extent extents[] = { | 400 | const struct free_space_extent extents[] = { |
397 | {cache->key.objectid, BITMAP_RANGE}, | 401 | {cache->key.objectid, alignment}, |
398 | {cache->key.objectid + 2 * BITMAP_RANGE, BITMAP_RANGE}, | 402 | {cache->key.objectid + 2 * alignment, alignment}, |
399 | {cache->key.objectid + 4 * BITMAP_RANGE, BITMAP_RANGE}, | 403 | {cache->key.objectid + 4 * alignment, alignment}, |
400 | }; | 404 | }; |
401 | int ret; | 405 | int ret; |
402 | 406 | ||
@@ -409,23 +413,23 @@ static int test_merge_none(struct btrfs_trans_handle *trans, | |||
409 | } | 413 | } |
410 | 414 | ||
411 | ret = __add_to_free_space_tree(trans, fs_info, cache, path, | 415 | ret = __add_to_free_space_tree(trans, fs_info, cache, path, |
412 | cache->key.objectid, BITMAP_RANGE); | 416 | cache->key.objectid, alignment); |
413 | if (ret) { | 417 | if (ret) { |
414 | test_msg("Could not add free space\n"); | 418 | test_msg("Could not add free space\n"); |
415 | return ret; | 419 | return ret; |
416 | } | 420 | } |
417 | 421 | ||
418 | ret = __add_to_free_space_tree(trans, fs_info, cache, path, | 422 | ret = __add_to_free_space_tree(trans, fs_info, cache, path, |
419 | cache->key.objectid + 4 * BITMAP_RANGE, | 423 | cache->key.objectid + 4 * alignment, |
420 | BITMAP_RANGE); | 424 | alignment); |
421 | if (ret) { | 425 | if (ret) { |
422 | test_msg("Could not add free space\n"); | 426 | test_msg("Could not add free space\n"); |
423 | return ret; | 427 | return ret; |
424 | } | 428 | } |
425 | 429 | ||
426 | ret = __add_to_free_space_tree(trans, fs_info, cache, path, | 430 | ret = __add_to_free_space_tree(trans, fs_info, cache, path, |
427 | cache->key.objectid + 2 * BITMAP_RANGE, | 431 | cache->key.objectid + 2 * alignment, |
428 | BITMAP_RANGE); | 432 | alignment); |
429 | if (ret) { | 433 | if (ret) { |
430 | test_msg("Could not add free space\n"); | 434 | test_msg("Could not add free space\n"); |
431 | return ret; | 435 | return ret; |
@@ -438,10 +442,11 @@ static int test_merge_none(struct btrfs_trans_handle *trans, | |||
438 | typedef int (*test_func_t)(struct btrfs_trans_handle *, | 442 | typedef int (*test_func_t)(struct btrfs_trans_handle *, |
439 | struct btrfs_fs_info *, | 443 | struct btrfs_fs_info *, |
440 | struct btrfs_block_group_cache *, | 444 | struct btrfs_block_group_cache *, |
441 | struct btrfs_path *); | 445 | struct btrfs_path *, |
446 | u32 alignment); | ||
442 | 447 | ||
443 | static int run_test(test_func_t test_func, int bitmaps, | 448 | static int run_test(test_func_t test_func, int bitmaps, u32 sectorsize, |
444 | u32 sectorsize, u32 nodesize) | 449 | u32 nodesize, u32 alignment) |
445 | { | 450 | { |
446 | struct btrfs_fs_info *fs_info; | 451 | struct btrfs_fs_info *fs_info; |
447 | struct btrfs_root *root = NULL; | 452 | struct btrfs_root *root = NULL; |
@@ -480,7 +485,7 @@ static int run_test(test_func_t test_func, int bitmaps, | |||
480 | btrfs_set_header_nritems(root->node, 0); | 485 | btrfs_set_header_nritems(root->node, 0); |
481 | root->alloc_bytenr += 2 * nodesize; | 486 | root->alloc_bytenr += 2 * nodesize; |
482 | 487 | ||
483 | cache = btrfs_alloc_dummy_block_group(8 * BITMAP_RANGE, sectorsize); | 488 | cache = btrfs_alloc_dummy_block_group(8 * alignment, sectorsize); |
484 | if (!cache) { | 489 | if (!cache) { |
485 | test_msg("Couldn't allocate dummy block group cache\n"); | 490 | test_msg("Couldn't allocate dummy block group cache\n"); |
486 | ret = -ENOMEM; | 491 | ret = -ENOMEM; |
@@ -514,7 +519,7 @@ static int run_test(test_func_t test_func, int bitmaps, | |||
514 | } | 519 | } |
515 | } | 520 | } |
516 | 521 | ||
517 | ret = test_func(&trans, root->fs_info, cache, path); | 522 | ret = test_func(&trans, root->fs_info, cache, path, alignment); |
518 | if (ret) | 523 | if (ret) |
519 | goto out; | 524 | goto out; |
520 | 525 | ||
@@ -539,15 +544,27 @@ out: | |||
539 | return ret; | 544 | return ret; |
540 | } | 545 | } |
541 | 546 | ||
542 | static int run_test_both_formats(test_func_t test_func, | 547 | static int run_test_both_formats(test_func_t test_func, u32 sectorsize, |
543 | u32 sectorsize, u32 nodesize) | 548 | u32 nodesize, u32 alignment) |
544 | { | 549 | { |
550 | int test_ret = 0; | ||
545 | int ret; | 551 | int ret; |
546 | 552 | ||
547 | ret = run_test(test_func, 0, sectorsize, nodesize); | 553 | ret = run_test(test_func, 0, sectorsize, nodesize, alignment); |
548 | if (ret) | 554 | if (ret) { |
549 | return ret; | 555 | test_msg("%pf failed with extents, sectorsize=%u, nodesize=%u, alignment=%u\n", |
550 | return run_test(test_func, 1, sectorsize, nodesize); | 556 | test_func, sectorsize, nodesize, alignment); |
557 | test_ret = ret; | ||
558 | } | ||
559 | |||
560 | ret = run_test(test_func, 1, sectorsize, nodesize, alignment); | ||
561 | if (ret) { | ||
562 | test_msg("%pf failed with bitmaps, sectorsize=%u, nodesize=%u, alignment=%u\n", | ||
563 | test_func, sectorsize, nodesize, alignment); | ||
564 | test_ret = ret; | ||
565 | } | ||
566 | |||
567 | return test_ret; | ||
551 | } | 568 | } |
552 | 569 | ||
553 | int btrfs_test_free_space_tree(u32 sectorsize, u32 nodesize) | 570 | int btrfs_test_free_space_tree(u32 sectorsize, u32 nodesize) |
@@ -563,18 +580,30 @@ int btrfs_test_free_space_tree(u32 sectorsize, u32 nodesize) | |||
563 | test_merge_both, | 580 | test_merge_both, |
564 | test_merge_none, | 581 | test_merge_none, |
565 | }; | 582 | }; |
583 | u32 bitmap_alignment; | ||
584 | int test_ret = 0; | ||
566 | int i; | 585 | int i; |
567 | 586 | ||
587 | /* | ||
588 | * Align some operations to a page to flush out bugs in the extent | ||
589 | * buffer bitmap handling of highmem. | ||
590 | */ | ||
591 | bitmap_alignment = BTRFS_FREE_SPACE_BITMAP_BITS * PAGE_SIZE; | ||
592 | |||
568 | test_msg("Running free space tree tests\n"); | 593 | test_msg("Running free space tree tests\n"); |
569 | for (i = 0; i < ARRAY_SIZE(tests); i++) { | 594 | for (i = 0; i < ARRAY_SIZE(tests); i++) { |
570 | int ret = run_test_both_formats(tests[i], sectorsize, | 595 | int ret; |
571 | nodesize); | 596 | |
572 | if (ret) { | 597 | ret = run_test_both_formats(tests[i], sectorsize, nodesize, |
573 | test_msg("%pf : sectorsize %u failed\n", | 598 | sectorsize); |
574 | tests[i], sectorsize); | 599 | if (ret) |
575 | return ret; | 600 | test_ret = ret; |
576 | } | 601 | |
602 | ret = run_test_both_formats(tests[i], sectorsize, nodesize, | ||
603 | bitmap_alignment); | ||
604 | if (ret) | ||
605 | test_ret = ret; | ||
577 | } | 606 | } |
578 | 607 | ||
579 | return 0; | 608 | return test_ret; |
580 | } | 609 | } |
diff --git a/include/uapi/linux/btrfs.h b/include/uapi/linux/btrfs.h index ac5eacd3055b..db4c253f8011 100644 --- a/include/uapi/linux/btrfs.h +++ b/include/uapi/linux/btrfs.h | |||
@@ -239,7 +239,17 @@ struct btrfs_ioctl_fs_info_args { | |||
239 | * Used by: | 239 | * Used by: |
240 | * struct btrfs_ioctl_feature_flags | 240 | * struct btrfs_ioctl_feature_flags |
241 | */ | 241 | */ |
242 | #define BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE (1ULL << 0) | 242 | #define BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE (1ULL << 0) |
243 | /* | ||
244 | * Older kernels (< 4.9) on big-endian systems produced broken free space tree | ||
245 | * bitmaps, and btrfs-progs also used to corrupt the free space tree (versions | ||
246 | * < 4.7.3). If this bit is clear, then the free space tree cannot be trusted. | ||
247 | * btrfs-progs can also intentionally clear this bit to ask the kernel to | ||
248 | * rebuild the free space tree, however this might not work on older kernels | ||
249 | * that do not know about this bit. If not sure, clear the cache manually on | ||
250 | * first mount when booting older kernel versions. | ||
251 | */ | ||
252 | #define BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE_VALID (1ULL << 1) | ||
243 | 253 | ||
244 | #define BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF (1ULL << 0) | 254 | #define BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF (1ULL << 0) |
245 | #define BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL (1ULL << 1) | 255 | #define BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL (1ULL << 1) |