Message ID | 3a178d6547fc13b561535194f9dff41f9b4fa4d4.1648807440.git.wqu@suse.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | btrfs: add subpage support for RAID56 | expand |
On Fri, Apr 01, 2022 at 07:23:19PM +0800, Qu Wenruo wrote: > The new member is an array of sector_ptr pointers, they will represent > all sectors inside a full stripe (including P/Q). > > They co-operate with btrfs_raid_bio::stripe_pages: > > stripe_pages: | Page 0, range [0, 64K) | Page 1 ... > stripe_sectors: | | | ... | | > | | \- sector 15, page 0, pgoff=60K > | \- sector 1, page 0, pgoff=4K > \---- sector 0, page 0, pfoff=0 > > With such structure, we can represent subpage sectors without using > extra pages. > > Here we introduce a new helper, index_stripe_sectors(), to update > stripe_sectors[] to point to correct page and pgoff. > > So every time rbio::stripe_pages[] pointer gets updated, the new helper > should be called. > > The following functions have to call the new helper: > > - steal_rbio() > - alloc_rbio_pages() > - alloc_rbio_parity_pages() > - alloc_rbio_essential_pages() > > Signed-off-by: Qu Wenruo <wqu@suse.com> > --- > fs/btrfs/raid56.c | 62 +++++++++++++++++++++++++++++++++++++++++------ > 1 file changed, 54 insertions(+), 8 deletions(-) > > diff --git a/fs/btrfs/raid56.c b/fs/btrfs/raid56.c > index 1bad7d3a0331..8cfe00db79c9 100644 > --- a/fs/btrfs/raid56.c > +++ b/fs/btrfs/raid56.c > @@ -52,6 +52,16 @@ struct btrfs_stripe_hash_table { > struct btrfs_stripe_hash table[]; > }; > > +/* > + * A bvec like structure to present a sector inside a page. > + * > + * Unlike bvec we don't need bvlen, as it's fixed to sectorsize. > + */ > +struct sector_ptr { > + struct page *page; > + unsigned int pgoff; > +} __attribute__ ((__packed__)); Packed does not make much sense here, it's an in-memory structure and there are no savings, besides that packed structures may force unaligned access. > + > enum btrfs_rbio_ops { > BTRFS_RBIO_WRITE, > BTRFS_RBIO_READ_REBUILD, > @@ -154,25 +164,27 @@ struct btrfs_raid_bio { > > atomic_t error; > /* > - * these are two arrays of pointers. We allocate the > + * These are two arrays of pointers. We allocate the Please don't fix comments that you don't move or change, this is unrelated change. > * rbio big enough to hold them both and setup their > * locations when the rbio is allocated > */ > > - /* pointers to pages that we allocated for > + /* > + * Pointers to pages that we allocated for Same > * reading/writing stripes directly from the disk (including P/Q) > */ > struct page **stripe_pages; > > - /* > - * pointers to the pages in the bio_list. Stored > - * here for faster lookup > - */ > + /* Pointers to the pages in the bio_list, for faster lookup */ > struct page **bio_pages; > > /* > - * bitmap to record which horizontal stripe has data > + * For subpage support, we need to map each sector to above > + * stripe_pages. > */ > + struct sector_ptr *stripe_sectors; > + > + /* Bitmap to record which horizontal stripe has data */ So this one got moved and it's fine to update. > unsigned long *dbitmap; > > /* allocated with real_stripes-many pointers for finish_*() calls */
On 2022/4/9 00:40, David Sterba wrote: > On Fri, Apr 01, 2022 at 07:23:19PM +0800, Qu Wenruo wrote: >> The new member is an array of sector_ptr pointers, they will represent >> all sectors inside a full stripe (including P/Q). >> >> They co-operate with btrfs_raid_bio::stripe_pages: >> >> stripe_pages: | Page 0, range [0, 64K) | Page 1 ... >> stripe_sectors: | | | ... | | >> | | \- sector 15, page 0, pgoff=60K >> | \- sector 1, page 0, pgoff=4K >> \---- sector 0, page 0, pfoff=0 >> >> With such structure, we can represent subpage sectors without using >> extra pages. >> >> Here we introduce a new helper, index_stripe_sectors(), to update >> stripe_sectors[] to point to correct page and pgoff. >> >> So every time rbio::stripe_pages[] pointer gets updated, the new helper >> should be called. >> >> The following functions have to call the new helper: >> >> - steal_rbio() >> - alloc_rbio_pages() >> - alloc_rbio_parity_pages() >> - alloc_rbio_essential_pages() >> >> Signed-off-by: Qu Wenruo <wqu@suse.com> >> --- >> fs/btrfs/raid56.c | 62 +++++++++++++++++++++++++++++++++++++++++------ >> 1 file changed, 54 insertions(+), 8 deletions(-) >> >> diff --git a/fs/btrfs/raid56.c b/fs/btrfs/raid56.c >> index 1bad7d3a0331..8cfe00db79c9 100644 >> --- a/fs/btrfs/raid56.c >> +++ b/fs/btrfs/raid56.c >> @@ -52,6 +52,16 @@ struct btrfs_stripe_hash_table { >> struct btrfs_stripe_hash table[]; >> }; >> >> +/* >> + * A bvec like structure to present a sector inside a page. >> + * >> + * Unlike bvec we don't need bvlen, as it's fixed to sectorsize. >> + */ >> +struct sector_ptr { >> + struct page *page; >> + unsigned int pgoff; >> +} __attribute__ ((__packed__)); > > Packed does not make much sense here, it's an in-memory structure and > there are no savings, besides that packed structures may force unaligned > access. Not exactly. The packed is for the later 1 bit flag, without packed it will take another hundred of bytes for the very basic 3 disks RAID5. Thanks, Qu > >> + >> enum btrfs_rbio_ops { >> BTRFS_RBIO_WRITE, >> BTRFS_RBIO_READ_REBUILD, >> @@ -154,25 +164,27 @@ struct btrfs_raid_bio { >> >> atomic_t error; >> /* >> - * these are two arrays of pointers. We allocate the >> + * These are two arrays of pointers. We allocate the > > Please don't fix comments that you don't move or change, this is > unrelated change. > >> * rbio big enough to hold them both and setup their >> * locations when the rbio is allocated >> */ >> >> - /* pointers to pages that we allocated for >> + /* >> + * Pointers to pages that we allocated for > > Same > >> * reading/writing stripes directly from the disk (including P/Q) >> */ >> struct page **stripe_pages; >> >> - /* >> - * pointers to the pages in the bio_list. Stored >> - * here for faster lookup >> - */ >> + /* Pointers to the pages in the bio_list, for faster lookup */ >> struct page **bio_pages; >> >> /* >> - * bitmap to record which horizontal stripe has data >> + * For subpage support, we need to map each sector to above >> + * stripe_pages. >> */ >> + struct sector_ptr *stripe_sectors; >> + >> + /* Bitmap to record which horizontal stripe has data */ > > So this one got moved and it's fine to update. > >> unsigned long *dbitmap; >> >> /* allocated with real_stripes-many pointers for finish_*() calls */
diff --git a/fs/btrfs/raid56.c b/fs/btrfs/raid56.c index 1bad7d3a0331..8cfe00db79c9 100644 --- a/fs/btrfs/raid56.c +++ b/fs/btrfs/raid56.c @@ -52,6 +52,16 @@ struct btrfs_stripe_hash_table { struct btrfs_stripe_hash table[]; }; +/* + * A bvec like structure to present a sector inside a page. + * + * Unlike bvec we don't need bvlen, as it's fixed to sectorsize. + */ +struct sector_ptr { + struct page *page; + unsigned int pgoff; +} __attribute__ ((__packed__)); + enum btrfs_rbio_ops { BTRFS_RBIO_WRITE, BTRFS_RBIO_READ_REBUILD, @@ -154,25 +164,27 @@ struct btrfs_raid_bio { atomic_t error; /* - * these are two arrays of pointers. We allocate the + * These are two arrays of pointers. We allocate the * rbio big enough to hold them both and setup their * locations when the rbio is allocated */ - /* pointers to pages that we allocated for + /* + * Pointers to pages that we allocated for * reading/writing stripes directly from the disk (including P/Q) */ struct page **stripe_pages; - /* - * pointers to the pages in the bio_list. Stored - * here for faster lookup - */ + /* Pointers to the pages in the bio_list, for faster lookup */ struct page **bio_pages; /* - * bitmap to record which horizontal stripe has data + * For subpage support, we need to map each sector to above + * stripe_pages. */ + struct sector_ptr *stripe_sectors; + + /* Bitmap to record which horizontal stripe has data */ unsigned long *dbitmap; /* allocated with real_stripes-many pointers for finish_*() calls */ @@ -291,6 +303,26 @@ static int rbio_bucket(struct btrfs_raid_bio *rbio) return hash_64(num >> 16, BTRFS_STRIPE_HASH_TABLE_BITS); } +/* + * Update the stripe_sectors[] array to use correct page and pgoff + * + * Should be called every time any page pointer in stripes_pages[] got modified. + */ +static void index_stripe_sectors(struct btrfs_raid_bio *rbio) +{ + const u32 sectorsize = rbio->bioc->fs_info->sectorsize; + u32 offset; + int i; + + for (i = 0, offset = 0; i < rbio->nr_sectors; i++, offset += sectorsize) { + int page_index = offset >> PAGE_SHIFT; + + ASSERT(page_index < rbio->nr_pages); + rbio->stripe_sectors[i].page = rbio->stripe_pages[page_index]; + rbio->stripe_sectors[i].pgoff = offset_in_page(offset); + } +} + /* * stealing an rbio means taking all the uptodate pages from the stripe * array in the source rbio and putting them into the destination rbio @@ -317,6 +349,8 @@ static void steal_rbio(struct btrfs_raid_bio *src, struct btrfs_raid_bio *dest) dest->stripe_pages[i] = s; src->stripe_pages[i] = NULL; } + index_stripe_sectors(dest); + index_stripe_sectors(src); } /* @@ -979,6 +1013,7 @@ static struct btrfs_raid_bio *alloc_rbio(struct btrfs_fs_info *fs_info, rbio = kzalloc(sizeof(*rbio) + sizeof(*rbio->stripe_pages) * num_pages + sizeof(*rbio->bio_pages) * num_pages + + sizeof(*rbio->stripe_sectors) * num_sectors + sizeof(*rbio->finish_pointers) * real_stripes + sizeof(*rbio->dbitmap) * BITS_TO_LONGS(stripe_nsectors) + sizeof(*rbio->finish_pbitmap) * @@ -1016,6 +1051,7 @@ static struct btrfs_raid_bio *alloc_rbio(struct btrfs_fs_info *fs_info, } while (0) CONSUME_ALLOC(rbio->stripe_pages, num_pages); CONSUME_ALLOC(rbio->bio_pages, num_pages); + CONSUME_ALLOC(rbio->stripe_sectors, num_sectors); CONSUME_ALLOC(rbio->finish_pointers, real_stripes); CONSUME_ALLOC(rbio->dbitmap, BITS_TO_LONGS(stripe_nsectors)); CONSUME_ALLOC(rbio->finish_pbitmap, BITS_TO_LONGS(stripe_nsectors)); @@ -1032,12 +1068,16 @@ static struct btrfs_raid_bio *alloc_rbio(struct btrfs_fs_info *fs_info, return rbio; } -/* allocate pages for all the stripes in the bio, including parity */ +/* + * Allocate pages for all the stripes in the bio including parity, and map all + * sectors to their corresponding pages + */ static int alloc_rbio_pages(struct btrfs_raid_bio *rbio) { int i; struct page *page; + /* Allocate all pages */ for (i = 0; i < rbio->nr_pages; i++) { if (rbio->stripe_pages[i]) continue; @@ -1046,6 +1086,9 @@ static int alloc_rbio_pages(struct btrfs_raid_bio *rbio) return -ENOMEM; rbio->stripe_pages[i] = page; } + + /* Mapping all sectors */ + index_stripe_sectors(rbio); return 0; } @@ -1065,6 +1108,8 @@ static int alloc_rbio_parity_pages(struct btrfs_raid_bio *rbio) return -ENOMEM; rbio->stripe_pages[i] = page; } + + index_stripe_sectors(rbio); return 0; } @@ -2313,6 +2358,7 @@ static int alloc_rbio_essential_pages(struct btrfs_raid_bio *rbio) rbio->stripe_pages[index] = page; } } + index_stripe_sectors(rbio); return 0; }
The new member is an array of sector_ptr pointers, they will represent all sectors inside a full stripe (including P/Q). They co-operate with btrfs_raid_bio::stripe_pages: stripe_pages: | Page 0, range [0, 64K) | Page 1 ... stripe_sectors: | | | ... | | | | \- sector 15, page 0, pgoff=60K | \- sector 1, page 0, pgoff=4K \---- sector 0, page 0, pfoff=0 With such structure, we can represent subpage sectors without using extra pages. Here we introduce a new helper, index_stripe_sectors(), to update stripe_sectors[] to point to correct page and pgoff. So every time rbio::stripe_pages[] pointer gets updated, the new helper should be called. The following functions have to call the new helper: - steal_rbio() - alloc_rbio_pages() - alloc_rbio_parity_pages() - alloc_rbio_essential_pages() Signed-off-by: Qu Wenruo <wqu@suse.com> --- fs/btrfs/raid56.c | 62 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 54 insertions(+), 8 deletions(-)