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) |
