Commit 17d552ab authored by Qu Wenruo's avatar Qu Wenruo Committed by David Sterba
Browse files

btrfs: raid56: remove sector_ptr::has_paddr member



We can use paddr -1 as an indicator for unset/uninitialized paddr.

We can not use 0 paddr, unlike virtual address 0 which is never mapped
thus will always trigger a page fault, physical address 0 may be a valid
page.

So here we follow swiotlb to use (paddr)-1 as a special indicator for
invalid/unset physical address.

Even if the PFN may still be valid, our usage of the physical address
should always be aligned to fs block size (or page size for bs > ps
cases), thus such -1 paddr should never be a valid one.

With this special -1 paddr, we can get rid of has_paddr member and save
1 byte for sector_ptr structure.

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 9b3743a6
Loading
Loading
Loading
Loading
+26 −20
Original line number Diff line number Diff line
@@ -133,6 +133,12 @@ struct btrfs_stripe_hash_table {
	struct btrfs_stripe_hash table[];
};

/*
 * The PFN may still be valid, but our paddrs should always be block size
 * aligned, thus such -1 paddr is definitely not a valid one.
 */
#define INVALID_PADDR	(~(phys_addr_t)0)

/*
 * A structure to present a sector inside a page, the length is fixed to
 * sectorsize;
@@ -141,9 +147,10 @@ struct sector_ptr {
	/*
	 * Blocks from the bio list can still be highmem.
	 * So here we use physical address to present a page and the offset inside it.
	 *
	 * If it's INVALID_PADDR then it's not set.
	 */
	phys_addr_t paddr;
	bool has_paddr;
	bool uptodate;
};

@@ -263,7 +270,7 @@ static void cache_rbio_pages(struct btrfs_raid_bio *rbio)

	for (i = 0; i < rbio->nr_sectors; i++) {
		/* Some range not covered by bio (partial write), skip it */
		if (!rbio->bio_sectors[i].has_paddr) {
		if (rbio->bio_sectors[i].paddr == INVALID_PADDR) {
			/*
			 * Even if the sector is not covered by bio, if it is
			 * a data sector it should still be uptodate as it is
@@ -335,7 +342,6 @@ static void index_stripe_sectors(struct btrfs_raid_bio *rbio)
		if (!rbio->stripe_pages[page_index])
			continue;

		rbio->stripe_sectors[i].has_paddr = true;
		rbio->stripe_sectors[i].paddr =
			page_to_phys(rbio->stripe_pages[page_index]) +
			offset_in_page(offset);
@@ -972,9 +978,9 @@ static struct sector_ptr *sector_in_rbio(struct btrfs_raid_bio *rbio,

	spin_lock(&rbio->bio_list_lock);
	sector = &rbio->bio_sectors[index];
	if (sector->has_paddr || bio_list_only) {
	if (sector->paddr != INVALID_PADDR || bio_list_only) {
		/* Don't return sector without a valid page pointer */
		if (!sector->has_paddr)
		if (sector->paddr == INVALID_PADDR)
			sector = NULL;
		spin_unlock(&rbio->bio_list_lock);
		return sector;
@@ -1032,6 +1038,10 @@ static struct btrfs_raid_bio *alloc_rbio(struct btrfs_fs_info *fs_info,
		kfree(rbio);
		return ERR_PTR(-ENOMEM);
	}
	for (int i = 0; i < num_sectors; i++) {
		rbio->stripe_sectors[i].paddr = INVALID_PADDR;
		rbio->bio_sectors[i].paddr = INVALID_PADDR;
	}

	bio_list_init(&rbio->bio_list);
	init_waitqueue_head(&rbio->io_wait);
@@ -1152,7 +1162,7 @@ static int rbio_add_io_sector(struct btrfs_raid_bio *rbio,
			   rbio, stripe_nr);
	ASSERT_RBIO_SECTOR(sector_nr >= 0 && sector_nr < rbio->stripe_nsectors,
			   rbio, sector_nr);
	ASSERT(sector->has_paddr);
	ASSERT(sector->paddr != INVALID_PADDR);

	stripe = &rbio->bioc->stripes[stripe_nr];
	disk_start = stripe->physical + sector_nr * sectorsize;
@@ -1216,7 +1226,6 @@ static void index_one_bio(struct btrfs_raid_bio *rbio, struct bio *bio)
		unsigned int index = (offset >> sectorsize_bits);
		struct sector_ptr *sector = &rbio->bio_sectors[index];

		sector->has_paddr = true;
		sector->paddr = paddr;
		offset += sectorsize;
	}
@@ -1299,7 +1308,7 @@ static void assert_rbio(struct btrfs_raid_bio *rbio)
static inline void *kmap_local_sector(const struct sector_ptr *sector)
{
	/* The sector pointer must have a page mapped to it. */
	ASSERT(sector->has_paddr);
	ASSERT(sector->paddr != INVALID_PADDR);

	return kmap_local_page(phys_to_page(sector->paddr)) +
	       offset_in_page(sector->paddr);
@@ -1498,7 +1507,7 @@ static struct sector_ptr *find_stripe_sector(struct btrfs_raid_bio *rbio,
	for (i = 0; i < rbio->nr_sectors; i++) {
		struct sector_ptr *sector = &rbio->stripe_sectors[i];

		if (sector->has_paddr && sector->paddr == paddr)
		if (sector->paddr == paddr)
			return sector;
	}
	return NULL;
@@ -1532,8 +1541,7 @@ static int get_bio_sector_nr(struct btrfs_raid_bio *rbio, struct bio *bio)
	for (i = 0; i < rbio->nr_sectors; i++) {
		if (rbio->stripe_sectors[i].paddr == bvec_paddr)
			break;
		if (rbio->bio_sectors[i].has_paddr &&
		    rbio->bio_sectors[i].paddr == bvec_paddr)
		if (rbio->bio_sectors[i].paddr == bvec_paddr)
			break;
	}
	ASSERT(i < rbio->nr_sectors);
@@ -2317,7 +2325,7 @@ static bool need_read_stripe_sectors(struct btrfs_raid_bio *rbio)
		 * thus this rbio can not be cached one, as cached one must
		 * have all its data sectors present and uptodate.
		 */
		if (!sector->has_paddr || !sector->uptodate)
		if (sector->paddr == INVALID_PADDR || !sector->uptodate)
			return true;
	}
	return false;
@@ -2508,8 +2516,8 @@ static int finish_parity_scrub(struct btrfs_raid_bio *rbio)
	int sectornr;
	bool has_qstripe;
	struct page *page;
	struct sector_ptr p_sector = { 0 };
	struct sector_ptr q_sector = { 0 };
	struct sector_ptr p_sector = { .paddr = INVALID_PADDR };
	struct sector_ptr q_sector = { .paddr = INVALID_PADDR };
	struct bio_list bio_list;
	int is_replace = 0;
	int ret;
@@ -2542,7 +2550,6 @@ static int finish_parity_scrub(struct btrfs_raid_bio *rbio)
	page = alloc_page(GFP_NOFS);
	if (!page)
		return -ENOMEM;
	p_sector.has_paddr = true;
	p_sector.paddr = page_to_phys(page);
	p_sector.uptodate = 1;
	page = NULL;
@@ -2552,10 +2559,9 @@ static int finish_parity_scrub(struct btrfs_raid_bio *rbio)
		page = alloc_page(GFP_NOFS);
		if (!page) {
			__free_page(phys_to_page(p_sector.paddr));
			p_sector.has_paddr = false;
			p_sector.paddr = INVALID_PADDR;
			return -ENOMEM;
		}
		q_sector.has_paddr = true;
		q_sector.paddr = page_to_phys(page);
		q_sector.uptodate = 1;
		page = NULL;
@@ -2604,10 +2610,10 @@ static int finish_parity_scrub(struct btrfs_raid_bio *rbio)

	kunmap_local(pointers[nr_data]);
	__free_page(phys_to_page(p_sector.paddr));
	p_sector.has_paddr = false;
	if (q_sector.has_paddr) {
	p_sector.paddr = INVALID_PADDR;
	if (q_sector.paddr != INVALID_PADDR) {
		__free_page(phys_to_page(q_sector.paddr));
		q_sector.has_paddr = false;
		q_sector.paddr = INVALID_PADDR;
	}

	/*