Patch "Btrfs: fix free space tree bitmaps on big-endian systems" has been added to the 4.8-stable tree
Subsystems (2)
This is a note to let you know that I've just added the patch titled
Btrfs: fix free space tree bitmaps on big-endian systems
to the 4.8-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
btrfs-fix-free-space-tree-bitmaps-on-big-endian-systems.patch
and it can be found in the queue-4.8 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.
Quoted 1 line
From
2fe1d55134fce05c17ea118a2e37a4af771887bcMon Sep 17 00:00:00 2001
From: Omar Sandoval <[email protected]>
Date: Thu, 22 Sep 2016 17:24:20 -0700
Subject: Btrfs: fix free space tree bitmaps on big-endian systems
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
From: Omar Sandoval <[email protected]>
commit 2fe1d55134fce05c17ea118a2e37a4af771887bc upstream.
In convert_free_space_to_{bitmaps,extents}(), we buffer the free space bitmaps in memory and copy them directly to/from the extent buffers with {read,write}_extent_buffer(). The extent buffer bitmap helpers use byte granularity, which is equivalent to a little-endian bitmap. This means that on big-endian systems, the in-memory bitmaps will be written to disk byte-swapped. To fix this, use byte-granularity for the bitmaps in memory.
--- fs/btrfs/extent_io.c | 64 ++++++++++++++++++++++++++++++++------------- fs/btrfs/extent_io.h | 22 +++++++++++++++ fs/btrfs/free-space-tree.c | 17 +++++------ 3 files changed, 76 insertions(+), 27 deletions(-)
fs/btrfs/extent_io.c +46 -18
@@ -5524,17 +5524,45 @@ void copy_extent_buffer(struct extent_bu } } -/* -* The extent buffer bitmap operations are done with byte granularity because -* bitmap items are not guaranteed to be aligned to a word and therefore a -* single word in a bitmap may straddle two pages in the extent buffer. -*/ -#define BIT_BYTE (nr) ((nr) / BITS_PER_BYTE) -#define BYTE_MASK ((1 << BITS_PER_BYTE) - 1) -#define BITMAP_FIRST_BYTE_MASK (start) \ - ((BYTE_MASK << ((start) & (BITS_PER_BYTE - 1))) & BYTE_MASK) -#define BITMAP_LAST_BYTE_MASK (nbits) \ - (BYTE_MASK >> (-(nbits) & (BITS_PER_BYTE - 1))) +void le_bitmap_set (u8 *map,unsigned int start,int len) +{ +u8 *p = map +BIT_BYTE (start); +const unsigned int size = start + len; +int bits_to_set =BITS_PER_BYTE - (start %BITS_PER_BYTE ); +u8 mask_to_set =BITMAP_FIRST_BYTE_MASK (start); + +while (len - bits_to_set >=0 ) { + *p |= mask_to_set; + len -= bits_to_set; + bits_to_set =BITS_PER_BYTE ; + mask_to_set = ~(u8 )0 ; + p++; + } +if (len) { + mask_to_set &=BITMAP_LAST_BYTE_MASK (size); + *p |= mask_to_set; + } +} + +void le_bitmap_clear (u8 *map,unsigned int start,int len) +{ +u8 *p = map +BIT_BYTE (start); +const unsigned int size = start + len; +int bits_to_clear =BITS_PER_BYTE - (start %BITS_PER_BYTE ); +u8 mask_to_clear =BITMAP_FIRST_BYTE_MASK (start); + +while (len - bits_to_clear >=0 ) { + *p &= ~mask_to_clear; + len -= bits_to_clear; + bits_to_clear =BITS_PER_BYTE ; + mask_to_clear = ~(u8 )0 ; + p++; + } +if (len) { + mask_to_clear &=BITMAP_LAST_BYTE_MASK (size); + *p &= ~mask_to_clear; + } +}/* * eb_bitmap_offset() - calculate the page and offset of the byte containing the
@@ -5578,7 +5606,7 @@ static inline void eb_bitmap_offset(struint extent_buffer_test_bit (struct extent_buffer *eb,unsigned long start,unsigned long nr) { -char *kaddr; +u8 *kaddr;struct page *page;unsigned long i;size_t offset;
@@ -5600,13 +5628,13 @@ int extent_buffer_test_bit(struct extentvoid extent_buffer_bitmap_set (struct extent_buffer *eb,unsigned long start,unsigned long pos,unsigned long len) { -char *kaddr; +u8 *kaddr;struct page *page;unsigned long i;size_t offset;const unsigned int size = pos + len;int bits_to_set =BITS_PER_BYTE - (pos %BITS_PER_BYTE ); -unsigned int mask_to_set =BITMAP_FIRST_BYTE_MASK (pos); +u8 mask_to_set =BITMAP_FIRST_BYTE_MASK (pos);eb_bitmap_offset (eb, start, pos, &i, &offset); page = eb->pages[i];
@@ -5617,7 +5645,7 @@ void extent_buffer_bitmap_set(struct ext kaddr[offset] |= mask_to_set; len -= bits_to_set; bits_to_set =BITS_PER_BYTE ; - mask_to_set = ~0U ; + mask_to_set = ~(u8 )0 ;if (++offset >=PAGE_SIZE && len >0 ) { offset =0 ; page = eb->pages[++i];
@@ -5642,13 +5670,13 @@ void extent_buffer_bitmap_set(struct extvoid extent_buffer_bitmap_clear (struct extent_buffer *eb,unsigned long start,unsigned long pos,unsigned long len) { -char *kaddr; +u8 *kaddr;struct page *page;unsigned long i;size_t offset;const unsigned int size = pos + len;int bits_to_clear =BITS_PER_BYTE - (pos %BITS_PER_BYTE ); -unsigned int mask_to_clear =BITMAP_FIRST_BYTE_MASK (pos); +u8 mask_to_clear =BITMAP_FIRST_BYTE_MASK (pos);eb_bitmap_offset (eb, start, pos, &i, &offset); page = eb->pages[i];
@@ -5659,7 +5687,7 @@ void extent_buffer_bitmap_clear(struct e kaddr[offset] &= ~mask_to_clear; len -= bits_to_clear; bits_to_clear =BITS_PER_BYTE ; - mask_to_clear = ~0U ; + mask_to_clear = ~(u8 )0 ;if (++offset >=PAGE_SIZE && len >0 ) { offset =0 ; page = eb->pages[++i];
fs/btrfs/extent_io.h +22 -0
@@ -59,6 +59,28 @@*/ #define EXTENT_PAGE_PRIVATE 1 +/* +* The extent buffer bitmap operations are done with byte granularity instead of +* word granularity for two reasons: +* 1. The bitmaps must be little-endian on disk. +* 2. Bitmap items are not guaranteed to be aligned to a word and therefore a +* single word in a bitmap may straddle two pages in the extent buffer. +*/ +#define BIT_BYTE (nr) ((nr) / BITS_PER_BYTE) +#define BYTE_MASK ((1 << BITS_PER_BYTE) - 1) +#define BITMAP_FIRST_BYTE_MASK (start) \ + ((BYTE_MASK << ((start) & (BITS_PER_BYTE - 1))) & BYTE_MASK) +#define BITMAP_LAST_BYTE_MASK (nbits) \ + (BYTE_MASK >> (-(nbits) & (BITS_PER_BYTE - 1))) + +static inline int le_test_bit (int nr,const u8 *addr) +{ +return 1U & (addr[BIT_BYTE (nr)] >> (nr & (BITS_PER_BYTE -1 ))); +} + +extern void le_bitmap_set (u8 *map,unsigned int start,int len); +extern void le_bitmap_clear (u8 *map,unsigned int start,int len); +struct extent_state ;struct btrfs_root ;struct btrfs_io_bio ;
fs/btrfs/free-space-tree.c +8 -9
@@ -151,7 +151,7 @@ static inline u32 free_space_bitmap_sizereturn DIV_ROUND_UP ((u32 )div_u64 (size, sectorsize),BITS_PER_BYTE ); } -static unsigned long *alloc_bitmap (u32 bitmap_size) +static u8 *alloc_bitmap (u32 bitmap_size) {void *mem;
@@ -180,8 +180,7 @@ int convert_free_space_to_bitmaps(structstruct btrfs_free_space_info *info;struct btrfs_key key, found_key;struct extent_buffer *leaf; -unsigned long *bitmap; -char *bitmap_cursor; +u8 *bitmap, *bitmap_cursor;u64 start, end;u64 bitmap_range, i;u32 bitmap_size, flags, expected_extent_count;
@@ -231,7 +230,7 @@ int convert_free_space_to_bitmaps(struct block_group->sectorsize); last =div_u64 (found_key.objectid + found_key.offset - start, block_group->sectorsize); -bitmap_set (bitmap, first, last - first); +le_bitmap_set (bitmap, first, last - first); extent_count++; nr++;
@@ -269,7 +268,7 @@ int convert_free_space_to_bitmaps(struct goto out; } - bitmap_cursor = (char *)bitmap; + bitmap_cursor = bitmap; bitmap_range = block_group->sectorsize *BTRFS_FREE_SPACE_BITMAP_BITS ; i = start;while (i < end) {
@@ -318,7 +317,7 @@ int convert_free_space_to_extents(structstruct btrfs_free_space_info *info;struct btrfs_key key, found_key;struct extent_buffer *leaf; -unsigned long *bitmap; +u8 *bitmap;u64 start, end;/* Initialize to silence GCC. */ u64 extent_start =0 ;
@@ -362,7 +361,7 @@ int convert_free_space_to_extents(structbreak ; }else if (found_key.type ==BTRFS_FREE_SPACE_BITMAP_KEY ) {unsigned long ptr; -char *bitmap_cursor; +u8 *bitmap_cursor;u32 bitmap_pos, data_size;ASSERT (found_key.objectid >= start);
@@ -372,7 +371,7 @@ int convert_free_space_to_extents(struct bitmap_pos =div_u64 (found_key.objectid - start, block_group->sectorsize *BITS_PER_BYTE ); - bitmap_cursor = ((char *)bitmap) + bitmap_pos; + bitmap_cursor = bitmap + bitmap_pos; data_size =free_space_bitmap_size (found_key.offset, block_group->sectorsize);
@@ -409,7 +408,7 @@ int convert_free_space_to_extents(struct offset = start; bitnr =0 ;while (offset < end) { - bit = !!test_bit (bitnr, bitmap); + bit = !!le_test_bit (bitnr, bitmap);if (prev_bit ==0 && bit ==1 ) { extent_start = offset; }else if (prev_bit ==1 && bit ==0 ) {
Patches currently in stable-queue which might be from [email protected] are
queue-4.8/btrfs-fix-free-space-tree-bitmaps-on-big-endian-systems.patch queue-4.8/btrfs-catch-invalid-free-space-trees.patch queue-4.8/btrfs-fix-mount-o-clear_cache-space_cache-v2.patch