Skip to content

Commit

Permalink
iomap: Support arbitrarily many blocks per page
Browse files Browse the repository at this point in the history
Size the uptodate array dynamically to support larger pages in the
page cache.  With a 64kB page, we're only saving 8 bytes per page today,
but with a 2MB maximum page size, we'd have to allocate more than 4kB
per page.  Add a few debugging assertions.

Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
  • Loading branch information
Matthew Wilcox (Oracle) authored and Darrick J. Wong committed Sep 21, 2020
1 parent b21866f commit 0a195b9
Showing 1 changed file with 17 additions and 5 deletions.
22 changes: 17 additions & 5 deletions fs/iomap/buffered-io.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,25 @@
#include "../internal.h"

/*
* Structure allocated for each page when block size < PAGE_SIZE to track
* sub-page uptodate status and I/O completions.
* Structure allocated for each page or THP when block size < page size
* to track sub-page uptodate status and I/O completions.
*/
struct iomap_page {
atomic_t read_count;
atomic_t write_count;
spinlock_t uptodate_lock;
DECLARE_BITMAP(uptodate, PAGE_SIZE / 512);
unsigned long uptodate[];
};

static inline struct iomap_page *to_iomap_page(struct page *page)
{
/*
* per-block data is stored in the head page. Callers should
* not be dealing with tail pages (and if they are, they can
* call thp_head() first.
*/
VM_BUG_ON_PGFLAGS(PageTail(page), page);

if (page_has_private(page))
return (struct iomap_page *)page_private(page);
return NULL;
Expand All @@ -45,11 +52,13 @@ static struct iomap_page *
iomap_page_create(struct inode *inode, struct page *page)
{
struct iomap_page *iop = to_iomap_page(page);
unsigned int nr_blocks = i_blocks_per_page(inode, page);

if (iop || i_blocks_per_page(inode, page) <= 1)
if (iop || nr_blocks <= 1)
return iop;

iop = kzalloc(sizeof(*iop), GFP_NOFS | __GFP_NOFAIL);
iop = kzalloc(struct_size(iop, uptodate, BITS_TO_LONGS(nr_blocks)),
GFP_NOFS | __GFP_NOFAIL);
spin_lock_init(&iop->uptodate_lock);
attach_page_private(page, iop);
return iop;
Expand All @@ -59,11 +68,14 @@ static void
iomap_page_release(struct page *page)
{
struct iomap_page *iop = detach_page_private(page);
unsigned int nr_blocks = i_blocks_per_page(page->mapping->host, page);

if (!iop)
return;
WARN_ON_ONCE(atomic_read(&iop->read_count));
WARN_ON_ONCE(atomic_read(&iop->write_count));
WARN_ON_ONCE(bitmap_full(iop->uptodate, nr_blocks) !=
PageUptodate(page));
kfree(iop);
}

Expand Down

0 comments on commit 0a195b9

Please sign in to comment.