Skip to content

Commit 72a69cd

Browse files
adam900710kdave
authored andcommitted
btrfs: subpage: pack all subpage bitmaps into a larger bitmap
Currently we use u16 bitmap to make 4k sectorsize work for 64K page size. But this u16 bitmap is not large enough to contain larger page size like 128K, nor is space efficient for 16K page size. To handle both cases, here we pack all subpage bitmaps into a larger bitmap, now btrfs_subpage::bitmaps[] will be the ultimate bitmap for subpage usage. Each sub-bitmap will has its start bit number recorded in btrfs_subpage_info::*_start, and its bitmap length will be recorded in btrfs_subpage_info::bitmap_nr_bits. All subpage bitmap operations will be converted from using direct u16 operations to bitmap operations, with above *_start calculated. For 64K page size with 4K sectorsize, this should not cause much difference. While for 16K page size, we will only need 1 unsigned long (u32) to store all the bitmaps, which saves quite some space. Furthermore, this allows us to support larger page size like 128K and 258K. Signed-off-by: Qu Wenruo <[email protected]> Reviewed-by: David Sterba <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent 8481dd8 commit 72a69cd

File tree

3 files changed

+121
-85
lines changed

3 files changed

+121
-85
lines changed

fs/btrfs/extent_io.c

Lines changed: 37 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3854,12 +3854,11 @@ static void find_next_dirty_byte(struct btrfs_fs_info *fs_info,
38543854
struct page *page, u64 *start, u64 *end)
38553855
{
38563856
struct btrfs_subpage *subpage = (struct btrfs_subpage *)page->private;
3857+
struct btrfs_subpage_info *spi = fs_info->subpage_info;
38573858
u64 orig_start = *start;
38583859
/* Declare as unsigned long so we can use bitmap ops */
3859-
unsigned long dirty_bitmap;
38603860
unsigned long flags;
3861-
int nbits = (orig_start - page_offset(page)) >> fs_info->sectorsize_bits;
3862-
int range_start_bit = nbits;
3861+
int range_start_bit;
38633862
int range_end_bit;
38643863

38653864
/*
@@ -3872,13 +3871,18 @@ static void find_next_dirty_byte(struct btrfs_fs_info *fs_info,
38723871
return;
38733872
}
38743873

3874+
range_start_bit = spi->dirty_offset +
3875+
(offset_in_page(orig_start) >> fs_info->sectorsize_bits);
3876+
38753877
/* We should have the page locked, but just in case */
38763878
spin_lock_irqsave(&subpage->lock, flags);
3877-
dirty_bitmap = subpage->dirty_bitmap;
3879+
bitmap_next_set_region(subpage->bitmaps, &range_start_bit, &range_end_bit,
3880+
spi->dirty_offset + spi->bitmap_nr_bits);
38783881
spin_unlock_irqrestore(&subpage->lock, flags);
38793882

3880-
bitmap_next_set_region(&dirty_bitmap, &range_start_bit, &range_end_bit,
3881-
BTRFS_SUBPAGE_BITMAP_SIZE);
3883+
range_start_bit -= spi->dirty_offset;
3884+
range_end_bit -= spi->dirty_offset;
3885+
38823886
*start = page_offset(page) + range_start_bit * fs_info->sectorsize;
38833887
*end = page_offset(page) + range_end_bit * fs_info->sectorsize;
38843888
}
@@ -4602,12 +4606,11 @@ static int submit_eb_subpage(struct page *page,
46024606
int submitted = 0;
46034607
u64 page_start = page_offset(page);
46044608
int bit_start = 0;
4605-
const int nbits = BTRFS_SUBPAGE_BITMAP_SIZE;
46064609
int sectors_per_node = fs_info->nodesize >> fs_info->sectorsize_bits;
46074610
int ret;
46084611

46094612
/* Lock and write each dirty extent buffers in the range */
4610-
while (bit_start < nbits) {
4613+
while (bit_start < fs_info->subpage_info->bitmap_nr_bits) {
46114614
struct btrfs_subpage *subpage = (struct btrfs_subpage *)page->private;
46124615
struct extent_buffer *eb;
46134616
unsigned long flags;
@@ -4623,7 +4626,8 @@ static int submit_eb_subpage(struct page *page,
46234626
break;
46244627
}
46254628
spin_lock_irqsave(&subpage->lock, flags);
4626-
if (!((1 << bit_start) & subpage->dirty_bitmap)) {
4629+
if (!test_bit(bit_start + fs_info->subpage_info->dirty_offset,
4630+
subpage->bitmaps)) {
46274631
spin_unlock_irqrestore(&subpage->lock, flags);
46284632
spin_unlock(&page->mapping->private_lock);
46294633
bit_start++;
@@ -7169,32 +7173,41 @@ void memmove_extent_buffer(const struct extent_buffer *dst,
71697173
}
71707174
}
71717175

7176+
#define GANG_LOOKUP_SIZE 16
71727177
static struct extent_buffer *get_next_extent_buffer(
71737178
struct btrfs_fs_info *fs_info, struct page *page, u64 bytenr)
71747179
{
7175-
struct extent_buffer *gang[BTRFS_SUBPAGE_BITMAP_SIZE];
7180+
struct extent_buffer *gang[GANG_LOOKUP_SIZE];
71767181
struct extent_buffer *found = NULL;
71777182
u64 page_start = page_offset(page);
7178-
int ret;
7179-
int i;
7183+
u64 cur = page_start;
71807184

71817185
ASSERT(in_range(bytenr, page_start, PAGE_SIZE));
7182-
ASSERT(PAGE_SIZE / fs_info->nodesize <= BTRFS_SUBPAGE_BITMAP_SIZE);
71837186
lockdep_assert_held(&fs_info->buffer_lock);
71847187

7185-
ret = radix_tree_gang_lookup(&fs_info->buffer_radix, (void **)gang,
7186-
bytenr >> fs_info->sectorsize_bits,
7187-
PAGE_SIZE / fs_info->nodesize);
7188-
for (i = 0; i < ret; i++) {
7189-
/* Already beyond page end */
7190-
if (gang[i]->start >= page_start + PAGE_SIZE)
7191-
break;
7192-
/* Found one */
7193-
if (gang[i]->start >= bytenr) {
7194-
found = gang[i];
7195-
break;
7188+
while (cur < page_start + PAGE_SIZE) {
7189+
int ret;
7190+
int i;
7191+
7192+
ret = radix_tree_gang_lookup(&fs_info->buffer_radix,
7193+
(void **)gang, cur >> fs_info->sectorsize_bits,
7194+
min_t(unsigned int, GANG_LOOKUP_SIZE,
7195+
PAGE_SIZE / fs_info->nodesize));
7196+
if (ret == 0)
7197+
goto out;
7198+
for (i = 0; i < ret; i++) {
7199+
/* Already beyond page end */
7200+
if (gang[i]->start >= page_start + PAGE_SIZE)
7201+
goto out;
7202+
/* Found one */
7203+
if (gang[i]->start >= bytenr) {
7204+
found = gang[i];
7205+
goto out;
7206+
}
71967207
}
7208+
cur = gang[ret - 1]->start + gang[ret - 1]->len;
71977209
}
7210+
out:
71987211
return found;
71997212
}
72007213

fs/btrfs/subpage.c

Lines changed: 81 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -133,10 +133,13 @@ struct btrfs_subpage *btrfs_alloc_subpage(const struct btrfs_fs_info *fs_info,
133133
enum btrfs_subpage_type type)
134134
{
135135
struct btrfs_subpage *ret;
136+
unsigned int real_size;
136137

137138
ASSERT(fs_info->sectorsize < PAGE_SIZE);
138139

139-
ret = kzalloc(sizeof(struct btrfs_subpage), GFP_NOFS);
140+
real_size = struct_size(ret, bitmaps,
141+
BITS_TO_LONGS(fs_info->subpage_info->total_nr_bits));
142+
ret = kzalloc(real_size, GFP_NOFS);
140143
if (!ret)
141144
return ERR_PTR(-ENOMEM);
142145

@@ -319,37 +322,59 @@ void btrfs_page_end_writer_lock(const struct btrfs_fs_info *fs_info,
319322
unlock_page(page);
320323
}
321324

322-
/*
323-
* Convert the [start, start + len) range into a u16 bitmap
324-
*
325-
* For example: if start == page_offset() + 16K, len = 16K, we get 0x00f0.
326-
*/
327-
static u16 btrfs_subpage_calc_bitmap(const struct btrfs_fs_info *fs_info,
328-
struct page *page, u64 start, u32 len)
325+
static bool bitmap_test_range_all_set(unsigned long *addr, unsigned int start,
326+
unsigned int nbits)
329327
{
330-
const int bit_start = offset_in_page(start) >> fs_info->sectorsize_bits;
331-
const int nbits = len >> fs_info->sectorsize_bits;
328+
unsigned int found_zero;
332329

333-
btrfs_subpage_assert(fs_info, page, start, len);
330+
found_zero = find_next_zero_bit(addr, start + nbits, start);
331+
if (found_zero == start + nbits)
332+
return true;
333+
return false;
334+
}
334335

335-
/*
336-
* Here nbits can be 16, thus can go beyond u16 range. We make the
337-
* first left shift to be calculate in unsigned long (at least u32),
338-
* then truncate the result to u16.
339-
*/
340-
return (u16)(((1UL << nbits) - 1) << bit_start);
336+
static bool bitmap_test_range_all_zero(unsigned long *addr, unsigned int start,
337+
unsigned int nbits)
338+
{
339+
unsigned int found_set;
340+
341+
found_set = find_next_bit(addr, start + nbits, start);
342+
if (found_set == start + nbits)
343+
return true;
344+
return false;
341345
}
342346

347+
#define subpage_calc_start_bit(fs_info, page, name, start, len) \
348+
({ \
349+
unsigned int start_bit; \
350+
\
351+
btrfs_subpage_assert(fs_info, page, start, len); \
352+
start_bit = offset_in_page(start) >> fs_info->sectorsize_bits; \
353+
start_bit += fs_info->subpage_info->name##_offset; \
354+
start_bit; \
355+
})
356+
357+
#define subpage_test_bitmap_all_set(fs_info, subpage, name) \
358+
bitmap_test_range_all_set(subpage->bitmaps, \
359+
fs_info->subpage_info->name##_offset, \
360+
fs_info->subpage_info->bitmap_nr_bits)
361+
362+
#define subpage_test_bitmap_all_zero(fs_info, subpage, name) \
363+
bitmap_test_range_all_zero(subpage->bitmaps, \
364+
fs_info->subpage_info->name##_offset, \
365+
fs_info->subpage_info->bitmap_nr_bits)
366+
343367
void btrfs_subpage_set_uptodate(const struct btrfs_fs_info *fs_info,
344368
struct page *page, u64 start, u32 len)
345369
{
346370
struct btrfs_subpage *subpage = (struct btrfs_subpage *)page->private;
347-
const u16 tmp = btrfs_subpage_calc_bitmap(fs_info, page, start, len);
371+
unsigned int start_bit = subpage_calc_start_bit(fs_info, page,
372+
uptodate, start, len);
348373
unsigned long flags;
349374

350375
spin_lock_irqsave(&subpage->lock, flags);
351-
subpage->uptodate_bitmap |= tmp;
352-
if (subpage->uptodate_bitmap == U16_MAX)
376+
bitmap_set(subpage->bitmaps, start_bit, len >> fs_info->sectorsize_bits);
377+
if (subpage_test_bitmap_all_set(fs_info, subpage, uptodate))
353378
SetPageUptodate(page);
354379
spin_unlock_irqrestore(&subpage->lock, flags);
355380
}
@@ -358,11 +383,12 @@ void btrfs_subpage_clear_uptodate(const struct btrfs_fs_info *fs_info,
358383
struct page *page, u64 start, u32 len)
359384
{
360385
struct btrfs_subpage *subpage = (struct btrfs_subpage *)page->private;
361-
const u16 tmp = btrfs_subpage_calc_bitmap(fs_info, page, start, len);
386+
unsigned int start_bit = subpage_calc_start_bit(fs_info, page,
387+
uptodate, start, len);
362388
unsigned long flags;
363389

364390
spin_lock_irqsave(&subpage->lock, flags);
365-
subpage->uptodate_bitmap &= ~tmp;
391+
bitmap_clear(subpage->bitmaps, start_bit, len >> fs_info->sectorsize_bits);
366392
ClearPageUptodate(page);
367393
spin_unlock_irqrestore(&subpage->lock, flags);
368394
}
@@ -371,11 +397,12 @@ void btrfs_subpage_set_error(const struct btrfs_fs_info *fs_info,
371397
struct page *page, u64 start, u32 len)
372398
{
373399
struct btrfs_subpage *subpage = (struct btrfs_subpage *)page->private;
374-
const u16 tmp = btrfs_subpage_calc_bitmap(fs_info, page, start, len);
400+
unsigned int start_bit = subpage_calc_start_bit(fs_info, page,
401+
error, start, len);
375402
unsigned long flags;
376403

377404
spin_lock_irqsave(&subpage->lock, flags);
378-
subpage->error_bitmap |= tmp;
405+
bitmap_set(subpage->bitmaps, start_bit, len >> fs_info->sectorsize_bits);
379406
SetPageError(page);
380407
spin_unlock_irqrestore(&subpage->lock, flags);
381408
}
@@ -384,12 +411,13 @@ void btrfs_subpage_clear_error(const struct btrfs_fs_info *fs_info,
384411
struct page *page, u64 start, u32 len)
385412
{
386413
struct btrfs_subpage *subpage = (struct btrfs_subpage *)page->private;
387-
const u16 tmp = btrfs_subpage_calc_bitmap(fs_info, page, start, len);
414+
unsigned int start_bit = subpage_calc_start_bit(fs_info, page,
415+
error, start, len);
388416
unsigned long flags;
389417

390418
spin_lock_irqsave(&subpage->lock, flags);
391-
subpage->error_bitmap &= ~tmp;
392-
if (subpage->error_bitmap == 0)
419+
bitmap_clear(subpage->bitmaps, start_bit, len >> fs_info->sectorsize_bits);
420+
if (subpage_test_bitmap_all_zero(fs_info, subpage, error))
393421
ClearPageError(page);
394422
spin_unlock_irqrestore(&subpage->lock, flags);
395423
}
@@ -398,11 +426,12 @@ void btrfs_subpage_set_dirty(const struct btrfs_fs_info *fs_info,
398426
struct page *page, u64 start, u32 len)
399427
{
400428
struct btrfs_subpage *subpage = (struct btrfs_subpage *)page->private;
401-
u16 tmp = btrfs_subpage_calc_bitmap(fs_info, page, start, len);
429+
unsigned int start_bit = subpage_calc_start_bit(fs_info, page,
430+
dirty, start, len);
402431
unsigned long flags;
403432

404433
spin_lock_irqsave(&subpage->lock, flags);
405-
subpage->dirty_bitmap |= tmp;
434+
bitmap_set(subpage->bitmaps, start_bit, len >> fs_info->sectorsize_bits);
406435
spin_unlock_irqrestore(&subpage->lock, flags);
407436
set_page_dirty(page);
408437
}
@@ -421,13 +450,14 @@ bool btrfs_subpage_clear_and_test_dirty(const struct btrfs_fs_info *fs_info,
421450
struct page *page, u64 start, u32 len)
422451
{
423452
struct btrfs_subpage *subpage = (struct btrfs_subpage *)page->private;
424-
u16 tmp = btrfs_subpage_calc_bitmap(fs_info, page, start, len);
453+
unsigned int start_bit = subpage_calc_start_bit(fs_info, page,
454+
dirty, start, len);
425455
unsigned long flags;
426456
bool last = false;
427457

428458
spin_lock_irqsave(&subpage->lock, flags);
429-
subpage->dirty_bitmap &= ~tmp;
430-
if (subpage->dirty_bitmap == 0)
459+
bitmap_clear(subpage->bitmaps, start_bit, len >> fs_info->sectorsize_bits);
460+
if (subpage_test_bitmap_all_zero(fs_info, subpage, dirty))
431461
last = true;
432462
spin_unlock_irqrestore(&subpage->lock, flags);
433463
return last;
@@ -447,11 +477,12 @@ void btrfs_subpage_set_writeback(const struct btrfs_fs_info *fs_info,
447477
struct page *page, u64 start, u32 len)
448478
{
449479
struct btrfs_subpage *subpage = (struct btrfs_subpage *)page->private;
450-
u16 tmp = btrfs_subpage_calc_bitmap(fs_info, page, start, len);
480+
unsigned int start_bit = subpage_calc_start_bit(fs_info, page,
481+
writeback, start, len);
451482
unsigned long flags;
452483

453484
spin_lock_irqsave(&subpage->lock, flags);
454-
subpage->writeback_bitmap |= tmp;
485+
bitmap_set(subpage->bitmaps, start_bit, len >> fs_info->sectorsize_bits);
455486
set_page_writeback(page);
456487
spin_unlock_irqrestore(&subpage->lock, flags);
457488
}
@@ -460,12 +491,13 @@ void btrfs_subpage_clear_writeback(const struct btrfs_fs_info *fs_info,
460491
struct page *page, u64 start, u32 len)
461492
{
462493
struct btrfs_subpage *subpage = (struct btrfs_subpage *)page->private;
463-
u16 tmp = btrfs_subpage_calc_bitmap(fs_info, page, start, len);
494+
unsigned int start_bit = subpage_calc_start_bit(fs_info, page,
495+
writeback, start, len);
464496
unsigned long flags;
465497

466498
spin_lock_irqsave(&subpage->lock, flags);
467-
subpage->writeback_bitmap &= ~tmp;
468-
if (subpage->writeback_bitmap == 0) {
499+
bitmap_clear(subpage->bitmaps, start_bit, len >> fs_info->sectorsize_bits);
500+
if (subpage_test_bitmap_all_zero(fs_info, subpage, writeback)) {
469501
ASSERT(PageWriteback(page));
470502
end_page_writeback(page);
471503
}
@@ -476,11 +508,12 @@ void btrfs_subpage_set_ordered(const struct btrfs_fs_info *fs_info,
476508
struct page *page, u64 start, u32 len)
477509
{
478510
struct btrfs_subpage *subpage = (struct btrfs_subpage *)page->private;
479-
const u16 tmp = btrfs_subpage_calc_bitmap(fs_info, page, start, len);
511+
unsigned int start_bit = subpage_calc_start_bit(fs_info, page,
512+
ordered, start, len);
480513
unsigned long flags;
481514

482515
spin_lock_irqsave(&subpage->lock, flags);
483-
subpage->ordered_bitmap |= tmp;
516+
bitmap_set(subpage->bitmaps, start_bit, len >> fs_info->sectorsize_bits);
484517
SetPageOrdered(page);
485518
spin_unlock_irqrestore(&subpage->lock, flags);
486519
}
@@ -489,12 +522,13 @@ void btrfs_subpage_clear_ordered(const struct btrfs_fs_info *fs_info,
489522
struct page *page, u64 start, u32 len)
490523
{
491524
struct btrfs_subpage *subpage = (struct btrfs_subpage *)page->private;
492-
const u16 tmp = btrfs_subpage_calc_bitmap(fs_info, page, start, len);
525+
unsigned int start_bit = subpage_calc_start_bit(fs_info, page,
526+
ordered, start, len);
493527
unsigned long flags;
494528

495529
spin_lock_irqsave(&subpage->lock, flags);
496-
subpage->ordered_bitmap &= ~tmp;
497-
if (subpage->ordered_bitmap == 0)
530+
bitmap_clear(subpage->bitmaps, start_bit, len >> fs_info->sectorsize_bits);
531+
if (subpage_test_bitmap_all_zero(fs_info, subpage, ordered))
498532
ClearPageOrdered(page);
499533
spin_unlock_irqrestore(&subpage->lock, flags);
500534
}
@@ -507,12 +541,14 @@ bool btrfs_subpage_test_##name(const struct btrfs_fs_info *fs_info, \
507541
struct page *page, u64 start, u32 len) \
508542
{ \
509543
struct btrfs_subpage *subpage = (struct btrfs_subpage *)page->private; \
510-
const u16 tmp = btrfs_subpage_calc_bitmap(fs_info, page, start, len); \
544+
unsigned int start_bit = subpage_calc_start_bit(fs_info, page, \
545+
name, start, len); \
511546
unsigned long flags; \
512547
bool ret; \
513548
\
514549
spin_lock_irqsave(&subpage->lock, flags); \
515-
ret = ((subpage->name##_bitmap & tmp) == tmp); \
550+
ret = bitmap_test_range_all_set(subpage->bitmaps, start_bit, \
551+
len >> fs_info->sectorsize_bits); \
516552
spin_unlock_irqrestore(&subpage->lock, flags); \
517553
return ret; \
518554
}
@@ -609,5 +645,5 @@ void btrfs_page_assert_not_dirty(const struct btrfs_fs_info *fs_info,
609645
return;
610646

611647
ASSERT(PagePrivate(page) && page->private);
612-
ASSERT(subpage->dirty_bitmap == 0);
648+
ASSERT(subpage_test_bitmap_all_zero(fs_info, subpage, dirty));
613649
}

0 commit comments

Comments
 (0)