[PATCH v2] isofs: convert the zisofs read path to use folios

Tal Zussman posted 1 patch 2 weeks, 4 days ago
fs/isofs/compress.c | 77 ++++++++++++++++++++++++++++++-----------------------
1 file changed, 43 insertions(+), 34 deletions(-)
[PATCH v2] isofs: convert the zisofs read path to use folios
Posted by Tal Zussman 2 weeks, 4 days ago
Store folios in the array that zisofs_read_folio() passes to
zisofs_fill_pages() and zisofs_uncompress_block(), use the folio APIs on
them, and grab the folios with __filemap_get_folio() instead of
grab_cache_page_nowait(). This removes six compound_head() calls, from
page_offset(), the three SetPageUptodate() calls, unlock_page() and
put_page(), and the last struct page usage in isofs.

isofs only uses order-0 folios, so folio_size() is PAGE_SIZE and the
logic is unchanged.

grab_cache_page_nowait() passed FGP_NOFS as well, but FGP_NOWAIT already
prevents reclaim entirely, so leave it out, as FGP_NOFS is on its way
out [1].

Change poffset to be unsigned int rather than just unsigned while at
it.

[1] https://lore.kernel.org/linux-mm/20260830041901.2668-9-willy@infradead.org/

Signed-off-by: Tal Zussman <tz2294@columbia.edu>
---
Changes in v2:
- Pass the offset to kmap_local_folio() and use folio_size(), per Jan
- Add a sentence in the commit message about how all folios here are
  order-0 for now
- Link to v1: https://patch.msgid.link/20260906-isofs-zisofs-folio-v1-1-cbea614a773f@columbia.edu
---
 fs/isofs/compress.c | 77 ++++++++++++++++++++++++++++++-----------------------
 1 file changed, 43 insertions(+), 34 deletions(-)

diff --git a/fs/isofs/compress.c b/fs/isofs/compress.c
index f9869d62b850..2d23abaeb874 100644
--- a/fs/isofs/compress.c
+++ b/fs/isofs/compress.c
@@ -39,7 +39,7 @@ static DEFINE_MUTEX(zisofs_zlib_lock);
  */
 static loff_t zisofs_uncompress_block(struct inode *inode, loff_t block_start,
 				      loff_t block_end, int pcount,
-				      struct page **pages, unsigned poffset,
+				      struct folio **folios, unsigned int poffset,
 				      int *errp)
 {
 	unsigned int zisofs_block_shift = ISOFS_I(inode)->i_format_parm[1];
@@ -66,11 +66,12 @@ static loff_t zisofs_uncompress_block(struct inode *inode, loff_t block_start,
 	if (block_size == 0) {
 		for ( i = 0 ; i < pcount ; i++ ) {
 			unsigned int off = i ? 0 : poffset;
+			struct folio *folio = folios[i];
 
-			if (!pages[i])
+			if (!folio)
 				continue;
-			memzero_page(pages[i], off, PAGE_SIZE - off);
-			SetPageUptodate(pages[i]);
+			folio_zero_range(folio, off, folio_size(folio) - off);
+			folio_mark_uptodate(folio);
 		}
 		return (((loff_t)pcount) << PAGE_SHIFT) - poffset;
 	}
@@ -119,11 +120,12 @@ static loff_t zisofs_uncompress_block(struct inode *inode, loff_t block_start,
 
 	while (curpage < pcount && curbh < haveblocks &&
 	       zerr != Z_STREAM_END) {
+		struct folio *folio = folios[curpage];
+
 		if (!stream.avail_out) {
-			if (pages[curpage]) {
-				stream.next_out = kmap_local_page(pages[curpage])
-						+ poffset;
-				stream.avail_out = PAGE_SIZE - poffset;
+			if (folio) {
+				stream.next_out = kmap_local_folio(folio, poffset);
+				stream.avail_out = folio_size(folio) - poffset;
 				poffset = 0;
 			} else {
 				stream.next_out = (void *)&zisofs_sink_page;
@@ -173,9 +175,9 @@ static loff_t zisofs_uncompress_block(struct inode *inode, loff_t block_start,
 
 		if (!stream.avail_out) {
 			/* This page completed */
-			if (pages[curpage]) {
-				flush_dcache_page(pages[curpage]);
-				SetPageUptodate(pages[curpage]);
+			if (folio) {
+				flush_dcache_folio(folio);
+				folio_mark_uptodate(folio);
 			}
 			if (stream.next_out != (unsigned char *)zisofs_sink_page) {
 				kunmap_local(stream.next_out);
@@ -206,7 +208,7 @@ static loff_t zisofs_uncompress_block(struct inode *inode, loff_t block_start,
  * fills in other pages if we have data for them.
  */
 static int zisofs_fill_pages(struct inode *inode, int full_page, int pcount,
-			     struct page **pages)
+			     struct folio **folios)
 {
 	loff_t start_off, end_off;
 	loff_t block_start, block_end;
@@ -221,14 +223,14 @@ static int zisofs_fill_pages(struct inode *inode, int full_page, int pcount,
 	int err;
 	loff_t ret;
 
-	BUG_ON(!pages[full_page]);
+	BUG_ON(!folios[full_page]);
 
 	/*
 	 * We want to read at least 'full_page' page. Because we have to
 	 * uncompress the whole compression block anyway, fill the surrounding
 	 * pages with the data we have anyway...
 	 */
-	start_off = page_offset(pages[full_page]);
+	start_off = folio_pos(folios[full_page]);
 	end_off = min_t(loff_t, start_off + PAGE_SIZE, inode->i_size);
 
 	cstart_block = start_off >> zisofs_block_shift;
@@ -267,9 +269,9 @@ static int zisofs_fill_pages(struct inode *inode, int full_page, int pcount,
 		}
 		err = 0;
 		ret = zisofs_uncompress_block(inode, block_start, block_end,
-					      pcount, pages, poffset, &err);
+					      pcount, folios, poffset, &err);
 		poffset += ret;
-		pages += poffset >> PAGE_SHIFT;
+		folios += poffset >> PAGE_SHIFT;
 		pcount -= poffset >> PAGE_SHIFT;
 		full_page -= poffset >> PAGE_SHIFT;
 		poffset &= ~PAGE_MASK;
@@ -289,9 +291,11 @@ static int zisofs_fill_pages(struct inode *inode, int full_page, int pcount,
 		cstart_block++;
 	}
 
-	if (poffset && *pages) {
-		memzero_page(*pages, poffset, PAGE_SIZE - poffset);
-		SetPageUptodate(*pages);
+	if (poffset && *folios) {
+		struct folio *folio = *folios;
+
+		folio_zero_range(folio, poffset, folio_size(folio) - poffset);
+		folio_mark_uptodate(folio);
 	}
 	brelse(bh);
 	return 0;
@@ -312,7 +316,7 @@ static int zisofs_read_folio(struct file *file, struct folio *folio)
 	unsigned int zisofs_pages_per_cblock =
 		PAGE_SHIFT <= zisofs_block_shift ?
 		(1 << (zisofs_block_shift - PAGE_SHIFT)) : 0;
-	struct page **pages;
+	struct folio **folios;
 	pgoff_t index = folio->index, end_index;
 
 	end_index = (inode->i_size + PAGE_SIZE - 1) >> PAGE_SHIFT;
@@ -336,33 +340,38 @@ static int zisofs_read_folio(struct file *file, struct folio *folio)
 		full_page = 0;
 		pcount = 1;
 	}
-	pages = kzalloc_objs(*pages,
-			     max_t(unsigned int, zisofs_pages_per_cblock, 1));
-	if (!pages) {
+	folios = kzalloc_objs(*folios,
+			      max_t(unsigned int, zisofs_pages_per_cblock, 1));
+	if (!folios) {
 		folio_unlock(folio);
 		return -ENOMEM;
 	}
-	pages[full_page] = &folio->page;
+	folios[full_page] = folio;
 
 	for (i = 0; i < pcount; i++, index++) {
-		if (i != full_page)
-			pages[i] = grab_cache_page_nowait(mapping, index);
+		if (i == full_page)
+			continue;
+		folios[i] = __filemap_get_folio(mapping, index,
+				FGP_LOCK | FGP_CREAT | FGP_NOWAIT,
+				mapping_gfp_mask(mapping));
+		if (IS_ERR(folios[i]))
+			folios[i] = NULL;
 	}
 
-	err = zisofs_fill_pages(inode, full_page, pcount, pages);
+	err = zisofs_fill_pages(inode, full_page, pcount, folios);
 
-	/* Release any residual pages, do not SetPageUptodate */
+	/* Release any residual folios, do not mark them uptodate */
 	for (i = 0; i < pcount; i++) {
-		if (pages[i]) {
-			flush_dcache_page(pages[i]);
-			unlock_page(pages[i]);
+		if (folios[i]) {
+			flush_dcache_folio(folios[i]);
+			folio_unlock(folios[i]);
 			if (i != full_page)
-				put_page(pages[i]);
+				folio_put(folios[i]);
 		}
-	}			
+	}
 
 	/* At this point, err contains 0 or -EIO depending on the "critical" page */
-	kfree(pages);
+	kfree(folios);
 	return err;
 }
 

---
base-commit: df2908090cda368b01ff43709f51890076c56157
change-id: 20260906-isofs-zisofs-folio-5b1621d694e4

Best regards,
--  
Tal Zussman <tz2294@columbia.edu>
Re: [PATCH v2] isofs: convert the zisofs read path to use folios
Posted by Jan Kara 2 weeks, 3 days ago
On Mon 07-09-26 11:18:38, Tal Zussman wrote:
> Store folios in the array that zisofs_read_folio() passes to
> zisofs_fill_pages() and zisofs_uncompress_block(), use the folio APIs on
> them, and grab the folios with __filemap_get_folio() instead of
> grab_cache_page_nowait(). This removes six compound_head() calls, from
> page_offset(), the three SetPageUptodate() calls, unlock_page() and
> put_page(), and the last struct page usage in isofs.
> 
> isofs only uses order-0 folios, so folio_size() is PAGE_SIZE and the
> logic is unchanged.
> 
> grab_cache_page_nowait() passed FGP_NOFS as well, but FGP_NOWAIT already
> prevents reclaim entirely, so leave it out, as FGP_NOFS is on its way
> out [1].
> 
> Change poffset to be unsigned int rather than just unsigned while at
> it.
> 
> [1] https://lore.kernel.org/linux-mm/20260830041901.2668-9-willy@infradead.org/
> 
> Signed-off-by: Tal Zussman <tz2294@columbia.edu>

Thanks! I've added the patch to my tree.

								Honza


> ---
> Changes in v2:
> - Pass the offset to kmap_local_folio() and use folio_size(), per Jan
> - Add a sentence in the commit message about how all folios here are
>   order-0 for now
> - Link to v1: https://patch.msgid.link/20260906-isofs-zisofs-folio-v1-1-cbea614a773f@columbia.edu
> ---
>  fs/isofs/compress.c | 77 ++++++++++++++++++++++++++++++-----------------------
>  1 file changed, 43 insertions(+), 34 deletions(-)
> 
> diff --git a/fs/isofs/compress.c b/fs/isofs/compress.c
> index f9869d62b850..2d23abaeb874 100644
> --- a/fs/isofs/compress.c
> +++ b/fs/isofs/compress.c
> @@ -39,7 +39,7 @@ static DEFINE_MUTEX(zisofs_zlib_lock);
>   */
>  static loff_t zisofs_uncompress_block(struct inode *inode, loff_t block_start,
>  				      loff_t block_end, int pcount,
> -				      struct page **pages, unsigned poffset,
> +				      struct folio **folios, unsigned int poffset,
>  				      int *errp)
>  {
>  	unsigned int zisofs_block_shift = ISOFS_I(inode)->i_format_parm[1];
> @@ -66,11 +66,12 @@ static loff_t zisofs_uncompress_block(struct inode *inode, loff_t block_start,
>  	if (block_size == 0) {
>  		for ( i = 0 ; i < pcount ; i++ ) {
>  			unsigned int off = i ? 0 : poffset;
> +			struct folio *folio = folios[i];
>  
> -			if (!pages[i])
> +			if (!folio)
>  				continue;
> -			memzero_page(pages[i], off, PAGE_SIZE - off);
> -			SetPageUptodate(pages[i]);
> +			folio_zero_range(folio, off, folio_size(folio) - off);
> +			folio_mark_uptodate(folio);
>  		}
>  		return (((loff_t)pcount) << PAGE_SHIFT) - poffset;
>  	}
> @@ -119,11 +120,12 @@ static loff_t zisofs_uncompress_block(struct inode *inode, loff_t block_start,
>  
>  	while (curpage < pcount && curbh < haveblocks &&
>  	       zerr != Z_STREAM_END) {
> +		struct folio *folio = folios[curpage];
> +
>  		if (!stream.avail_out) {
> -			if (pages[curpage]) {
> -				stream.next_out = kmap_local_page(pages[curpage])
> -						+ poffset;
> -				stream.avail_out = PAGE_SIZE - poffset;
> +			if (folio) {
> +				stream.next_out = kmap_local_folio(folio, poffset);
> +				stream.avail_out = folio_size(folio) - poffset;
>  				poffset = 0;
>  			} else {
>  				stream.next_out = (void *)&zisofs_sink_page;
> @@ -173,9 +175,9 @@ static loff_t zisofs_uncompress_block(struct inode *inode, loff_t block_start,
>  
>  		if (!stream.avail_out) {
>  			/* This page completed */
> -			if (pages[curpage]) {
> -				flush_dcache_page(pages[curpage]);
> -				SetPageUptodate(pages[curpage]);
> +			if (folio) {
> +				flush_dcache_folio(folio);
> +				folio_mark_uptodate(folio);
>  			}
>  			if (stream.next_out != (unsigned char *)zisofs_sink_page) {
>  				kunmap_local(stream.next_out);
> @@ -206,7 +208,7 @@ static loff_t zisofs_uncompress_block(struct inode *inode, loff_t block_start,
>   * fills in other pages if we have data for them.
>   */
>  static int zisofs_fill_pages(struct inode *inode, int full_page, int pcount,
> -			     struct page **pages)
> +			     struct folio **folios)
>  {
>  	loff_t start_off, end_off;
>  	loff_t block_start, block_end;
> @@ -221,14 +223,14 @@ static int zisofs_fill_pages(struct inode *inode, int full_page, int pcount,
>  	int err;
>  	loff_t ret;
>  
> -	BUG_ON(!pages[full_page]);
> +	BUG_ON(!folios[full_page]);
>  
>  	/*
>  	 * We want to read at least 'full_page' page. Because we have to
>  	 * uncompress the whole compression block anyway, fill the surrounding
>  	 * pages with the data we have anyway...
>  	 */
> -	start_off = page_offset(pages[full_page]);
> +	start_off = folio_pos(folios[full_page]);
>  	end_off = min_t(loff_t, start_off + PAGE_SIZE, inode->i_size);
>  
>  	cstart_block = start_off >> zisofs_block_shift;
> @@ -267,9 +269,9 @@ static int zisofs_fill_pages(struct inode *inode, int full_page, int pcount,
>  		}
>  		err = 0;
>  		ret = zisofs_uncompress_block(inode, block_start, block_end,
> -					      pcount, pages, poffset, &err);
> +					      pcount, folios, poffset, &err);
>  		poffset += ret;
> -		pages += poffset >> PAGE_SHIFT;
> +		folios += poffset >> PAGE_SHIFT;
>  		pcount -= poffset >> PAGE_SHIFT;
>  		full_page -= poffset >> PAGE_SHIFT;
>  		poffset &= ~PAGE_MASK;
> @@ -289,9 +291,11 @@ static int zisofs_fill_pages(struct inode *inode, int full_page, int pcount,
>  		cstart_block++;
>  	}
>  
> -	if (poffset && *pages) {
> -		memzero_page(*pages, poffset, PAGE_SIZE - poffset);
> -		SetPageUptodate(*pages);
> +	if (poffset && *folios) {
> +		struct folio *folio = *folios;
> +
> +		folio_zero_range(folio, poffset, folio_size(folio) - poffset);
> +		folio_mark_uptodate(folio);
>  	}
>  	brelse(bh);
>  	return 0;
> @@ -312,7 +316,7 @@ static int zisofs_read_folio(struct file *file, struct folio *folio)
>  	unsigned int zisofs_pages_per_cblock =
>  		PAGE_SHIFT <= zisofs_block_shift ?
>  		(1 << (zisofs_block_shift - PAGE_SHIFT)) : 0;
> -	struct page **pages;
> +	struct folio **folios;
>  	pgoff_t index = folio->index, end_index;
>  
>  	end_index = (inode->i_size + PAGE_SIZE - 1) >> PAGE_SHIFT;
> @@ -336,33 +340,38 @@ static int zisofs_read_folio(struct file *file, struct folio *folio)
>  		full_page = 0;
>  		pcount = 1;
>  	}
> -	pages = kzalloc_objs(*pages,
> -			     max_t(unsigned int, zisofs_pages_per_cblock, 1));
> -	if (!pages) {
> +	folios = kzalloc_objs(*folios,
> +			      max_t(unsigned int, zisofs_pages_per_cblock, 1));
> +	if (!folios) {
>  		folio_unlock(folio);
>  		return -ENOMEM;
>  	}
> -	pages[full_page] = &folio->page;
> +	folios[full_page] = folio;
>  
>  	for (i = 0; i < pcount; i++, index++) {
> -		if (i != full_page)
> -			pages[i] = grab_cache_page_nowait(mapping, index);
> +		if (i == full_page)
> +			continue;
> +		folios[i] = __filemap_get_folio(mapping, index,
> +				FGP_LOCK | FGP_CREAT | FGP_NOWAIT,
> +				mapping_gfp_mask(mapping));
> +		if (IS_ERR(folios[i]))
> +			folios[i] = NULL;
>  	}
>  
> -	err = zisofs_fill_pages(inode, full_page, pcount, pages);
> +	err = zisofs_fill_pages(inode, full_page, pcount, folios);
>  
> -	/* Release any residual pages, do not SetPageUptodate */
> +	/* Release any residual folios, do not mark them uptodate */
>  	for (i = 0; i < pcount; i++) {
> -		if (pages[i]) {
> -			flush_dcache_page(pages[i]);
> -			unlock_page(pages[i]);
> +		if (folios[i]) {
> +			flush_dcache_folio(folios[i]);
> +			folio_unlock(folios[i]);
>  			if (i != full_page)
> -				put_page(pages[i]);
> +				folio_put(folios[i]);
>  		}
> -	}			
> +	}
>  
>  	/* At this point, err contains 0 or -EIO depending on the "critical" page */
> -	kfree(pages);
> +	kfree(folios);
>  	return err;
>  }
>  
> 
> ---
> base-commit: df2908090cda368b01ff43709f51890076c56157
> change-id: 20260906-isofs-zisofs-folio-5b1621d694e4
> 
> Best regards,
> --  
> Tal Zussman <tz2294@columbia.edu>
> 
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR