If we're punching a hole in a THP, we need to remove the per-page
iomap data as the THP is about to be split and each page will need
its own.  This means that writepage can now come across a page with
no iop allocated, so remove the assertions that there is already one,
and just create one (with the Uptodate bits set) if there isn't one.

Signed-off-by: Matthew Wilcox (Oracle) <[email protected]>
---
 fs/iomap/buffered-io.c | 17 ++++++++++++-----
 1 file changed, 12 insertions(+), 5 deletions(-)

diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c
index 5cc0343b6a8e..9ea162617398 100644
--- a/fs/iomap/buffered-io.c
+++ b/fs/iomap/buffered-io.c
@@ -54,6 +54,8 @@ iomap_page_create(struct inode *inode, struct page *page)
        iop = kzalloc(struct_size(iop, uptodate, BITS_TO_LONGS(nr_blocks)),
                        GFP_NOFS | __GFP_NOFAIL);
        spin_lock_init(&iop->uptodate_lock);
+       if (PageUptodate(page))
+               bitmap_fill(iop->uptodate, nr_blocks);
        attach_page_private(page, iop);
        return iop;
 }
@@ -483,10 +485,17 @@ iomap_invalidatepage(struct page *page, unsigned int 
offset, unsigned int len)
         * If we are invalidating the entire page, clear the dirty state from it
         * and release it to avoid unnecessary buildup of the LRU.
         */
-       if (offset == 0 && len == PAGE_SIZE) {
+       if (offset == 0 && len == thp_size(page)) {
                WARN_ON_ONCE(PageWriteback(page));
                cancel_dirty_page(page);
                iomap_page_release(page);
+               return;
+       }
+
+       /* Punching a hole in a THP requires releasing the iop */
+       if (PageTransHuge(page)) {
+               VM_BUG_ON_PAGE(!PageUptodate(page), page);
+               iomap_page_release(page);
        }
 }
 EXPORT_SYMBOL_GPL(iomap_invalidatepage);
@@ -1043,14 +1052,13 @@ static void
 iomap_finish_page_writeback(struct inode *inode, struct page *page,
                int error, unsigned int len)
 {
-       struct iomap_page *iop = to_iomap_page(page);
+       struct iomap_page *iop = iomap_page_create(inode, page);
 
        if (error) {
                SetPageError(page);
                mapping_set_error(inode->i_mapping, -EIO);
        }
 
-       WARN_ON_ONCE(i_blocks_per_page(inode, page) > 1 && !iop);
        WARN_ON_ONCE(iop && atomic_read(&iop->write_count) <= 0);
 
        if (!iop || atomic_sub_and_test(len, &iop->write_count))
@@ -1340,14 +1348,13 @@ iomap_writepage_map(struct iomap_writepage_ctx *wpc,
                struct writeback_control *wbc, struct inode *inode,
                struct page *page, u64 end_offset)
 {
-       struct iomap_page *iop = to_iomap_page(page);
+       struct iomap_page *iop = iomap_page_create(inode, page);
        struct iomap_ioend *ioend, *next;
        unsigned len = i_blocksize(inode);
        u64 file_offset; /* file offset of page */
        int error = 0, count = 0, i;
        LIST_HEAD(submit_list);
 
-       WARN_ON_ONCE(i_blocks_per_page(inode, page) > 1 && !iop);
        WARN_ON_ONCE(iop && atomic_read(&iop->write_count) != 0);
 
        /*
-- 
2.28.0

Reply via email to