Commit cb22964f authored by Qu Wenruo's avatar Qu Wenruo Committed by David Sterba

btrfs: refactor extent buffer bitmaps operations

[BACKGROUND]
Currently we handle extent bitmaps manually in
extent_buffer_bitmap_set() and extent_buffer_bitmap_clear().

Although with various helpers like eb_bitmap_offset() it's still a little
messy to read.  The code seems to be a copy of bitmap_set(), but with
all the cross-page handling embedded into the code.

[ENHANCEMENT]
This patch would enhance the readability by introducing two helpers:

- memset_extent_buffer()
  To handle the byte aligned range, thus all the cross-page handling is
  done there.

- extent_buffer_get_byte()
  This for the first and the last byte operations, which only need to
  grab one byte, thus no need for any cross-page handling.

So we can split both extent_buffer_bitmap_set() and
extent_buffer_bitmap_clear() into 3 parts:

- Handle the first byte
  If the range fits inside the first byte, we can exit early.

- Handle the byte aligned part
  This is the part which can have cross-page operations, and it would
  be handled by memset_extent_buffer().

- Handle the last byte

This refactoring does not only make the code a little easier to read,
but also makes later folio/page switch much easier, as the switch only
needs to be done inside memset_extent_buffer() and extent_buffer_get_byte().
Reviewed-by: default avatarSweet Tea Dorminy <sweettea-kernel@dorminy.me>
Signed-off-by: default avatarQu Wenruo <wqu@suse.com>
Reviewed-by: default avatarDavid Sterba <dsterba@suse.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent 5864f1da
...@@ -4183,34 +4183,32 @@ void write_extent_buffer(const struct extent_buffer *eb, const void *srcv, ...@@ -4183,34 +4183,32 @@ void write_extent_buffer(const struct extent_buffer *eb, const void *srcv,
} }
} }
void memzero_extent_buffer(const struct extent_buffer *eb, unsigned long start, static void memset_extent_buffer(const struct extent_buffer *eb, int c,
unsigned long len) unsigned long start, unsigned long len)
{ {
size_t cur; unsigned long cur = start;
size_t offset;
struct page *page;
char *kaddr;
unsigned long i = get_eb_page_index(start);
if (check_eb_range(eb, start, len)) while (cur < start + len) {
return; unsigned long index = get_eb_page_index(cur);
unsigned int offset = get_eb_offset_in_page(eb, cur);
offset = get_eb_offset_in_page(eb, start); unsigned int cur_len = min(start + len - cur, PAGE_SIZE - offset);
struct page *page = eb->pages[index];
while (len > 0) {
page = eb->pages[i];
assert_eb_page_uptodate(eb, page); assert_eb_page_uptodate(eb, page);
memset(page_address(page) + offset, c, cur_len);
cur = min(len, PAGE_SIZE - offset); cur += cur_len;
kaddr = page_address(page);
memset(kaddr + offset, 0, cur);
len -= cur;
offset = 0;
i++;
} }
} }
void memzero_extent_buffer(const struct extent_buffer *eb, unsigned long start,
unsigned long len)
{
if (check_eb_range(eb, start, len))
return;
return memset_extent_buffer(eb, 0, start, len);
}
void copy_extent_buffer_full(const struct extent_buffer *dst, void copy_extent_buffer_full(const struct extent_buffer *dst,
const struct extent_buffer *src) const struct extent_buffer *src)
{ {
...@@ -4325,6 +4323,15 @@ int extent_buffer_test_bit(const struct extent_buffer *eb, unsigned long start, ...@@ -4325,6 +4323,15 @@ int extent_buffer_test_bit(const struct extent_buffer *eb, unsigned long start,
return 1U & (kaddr[offset] >> (nr & (BITS_PER_BYTE - 1))); return 1U & (kaddr[offset] >> (nr & (BITS_PER_BYTE - 1)));
} }
static u8 *extent_buffer_get_byte(const struct extent_buffer *eb, unsigned long bytenr)
{
unsigned long index = get_eb_page_index(bytenr);
if (check_eb_range(eb, bytenr, 1))
return NULL;
return page_address(eb->pages[index]) + get_eb_offset_in_page(eb, bytenr);
}
/* /*
* Set an area of a bitmap to 1. * Set an area of a bitmap to 1.
* *
...@@ -4336,35 +4343,28 @@ int extent_buffer_test_bit(const struct extent_buffer *eb, unsigned long start, ...@@ -4336,35 +4343,28 @@ int extent_buffer_test_bit(const struct extent_buffer *eb, unsigned long start,
void extent_buffer_bitmap_set(const struct extent_buffer *eb, unsigned long start, void extent_buffer_bitmap_set(const struct extent_buffer *eb, unsigned long start,
unsigned long pos, unsigned long len) unsigned long pos, unsigned long len)
{ {
unsigned int first_byte = start + BIT_BYTE(pos);
unsigned int last_byte = start + BIT_BYTE(pos + len - 1);
const bool same_byte = (first_byte == last_byte);
u8 mask = BITMAP_FIRST_BYTE_MASK(pos);
u8 *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);
u8 mask_to_set = BITMAP_FIRST_BYTE_MASK(pos);
eb_bitmap_offset(eb, start, pos, &i, &offset); if (same_byte)
page = eb->pages[i]; mask &= BITMAP_LAST_BYTE_MASK(pos + len);
assert_eb_page_uptodate(eb, page);
kaddr = page_address(page);
while (len >= bits_to_set) { /* Handle the first byte. */
kaddr[offset] |= mask_to_set; kaddr = extent_buffer_get_byte(eb, first_byte);
len -= bits_to_set; *kaddr |= mask;
bits_to_set = BITS_PER_BYTE; if (same_byte)
mask_to_set = ~0; return;
if (++offset >= PAGE_SIZE && len > 0) {
offset = 0; /* Handle the byte aligned part. */
page = eb->pages[++i]; ASSERT(first_byte + 1 <= last_byte);
assert_eb_page_uptodate(eb, page); memset_extent_buffer(eb, 0xff, first_byte + 1, last_byte - first_byte - 1);
kaddr = page_address(page);
} /* Handle the last byte. */
} kaddr = extent_buffer_get_byte(eb, last_byte);
if (len) { *kaddr |= BITMAP_LAST_BYTE_MASK(pos + len);
mask_to_set &= BITMAP_LAST_BYTE_MASK(size);
kaddr[offset] |= mask_to_set;
}
} }
...@@ -4380,35 +4380,28 @@ void extent_buffer_bitmap_clear(const struct extent_buffer *eb, ...@@ -4380,35 +4380,28 @@ void extent_buffer_bitmap_clear(const struct extent_buffer *eb,
unsigned long start, unsigned long pos, unsigned long start, unsigned long pos,
unsigned long len) unsigned long len)
{ {
unsigned int first_byte = start + BIT_BYTE(pos);
unsigned int last_byte = start + BIT_BYTE(pos + len - 1);
const bool same_byte = (first_byte == last_byte);
u8 mask = BITMAP_FIRST_BYTE_MASK(pos);
u8 *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);
u8 mask_to_clear = BITMAP_FIRST_BYTE_MASK(pos);
eb_bitmap_offset(eb, start, pos, &i, &offset); if (same_byte)
page = eb->pages[i]; mask &= BITMAP_LAST_BYTE_MASK(pos + len);
assert_eb_page_uptodate(eb, page);
kaddr = page_address(page);
while (len >= bits_to_clear) { /* Handle the first byte. */
kaddr[offset] &= ~mask_to_clear; kaddr = extent_buffer_get_byte(eb, first_byte);
len -= bits_to_clear; *kaddr &= ~mask;
bits_to_clear = BITS_PER_BYTE; if (same_byte)
mask_to_clear = ~0; return;
if (++offset >= PAGE_SIZE && len > 0) {
offset = 0; /* Handle the byte aligned part. */
page = eb->pages[++i]; ASSERT(first_byte + 1 <= last_byte);
assert_eb_page_uptodate(eb, page); memset_extent_buffer(eb, 0, first_byte + 1, last_byte - first_byte - 1);
kaddr = page_address(page);
} /* Handle the last byte. */
} kaddr = extent_buffer_get_byte(eb, last_byte);
if (len) { *kaddr &= ~BITMAP_LAST_BYTE_MASK(pos + len);
mask_to_clear &= BITMAP_LAST_BYTE_MASK(size);
kaddr[offset] &= ~mask_to_clear;
}
} }
static inline bool areas_overlap(unsigned long src, unsigned long dst, unsigned long len) static inline bool areas_overlap(unsigned long src, unsigned long dst, unsigned long len)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment