> The problem with this fallback intermediate buffer is it is slow, both
> due to the additional memcopies, but, more importantly because it
> introduces contention on a single shared buffer.
>
> I have long had the intention to fix this performance issue in
> squashfs_readpage_block(), but, due it being a rare issue there, the
> additional work has seemed to be nice but not essential.
>
> The problem is we don't want the readahead code to be using this
> slow method, because the scenario will probably happen much more
> often, and for a performance improvement patch, falling back to
> an old slow method isn't very useful.
>
> So I have finally done the work to make the "page actor" code handle
> missing pages.
>
> This I have sent out in the following patch-set updating the
> squashfs_readpage_block() function to use it.
>
>
https://lore.kernel.org/lkml/20220611032133.5743-1-phillip@squashfs.org.uk/
>
> You can use this updated "page actor" code to eliminate the
> "nr_pages < max_pages" special case in your patch. With the benefit
> that decompression is done directly into the page cache.
>
> I have updated your patch to use the new functionality. The diff
> including a bug fix I have appended to this email.
>
> Phillip
>
> diff --git a/fs/squashfs/file.c b/fs/squashfs/file.c
> index b86b2f9d9ae6..721d35ecfca9 100644
> --- a/fs/squashfs/file.c
> +++ b/fs/squashfs/file.c
> @@ -519,10 +519,6 @@ static void squashfs_readahead(struct
> readahead_control *ractl)
> if (!pages)
> return;
>
> - actor = squashfs_page_actor_init_special(pages, max_pages, 0);
> - if (!actor)
> - goto out;
> -
> for (;;) {
> pgoff_t index;
> int res, bsize;
> @@ -548,41 +544,21 @@ static void squashfs_readahead(struct
> readahead_control *ractl)
> if (bsize == 0)
> goto skip_pages;
>
> - if (nr_pages < max_pages) {
> - struct squashfs_cache_entry *buffer;
> - unsigned int block_mask = max_pages - 1;
> - int offset = pages[0]->index - (pages[0]->index & ~block_mask);
> -
> - buffer = squashfs_get_datablock(inode->i_sb, block,
> - bsize);
> - if (buffer->error) {
> - squashfs_cache_put(buffer);
> - goto skip_pages;
> - }
> -
> - expected -= offset * PAGE_SIZE;
> - for (i = 0; i < nr_pages && expected > 0; i++,
> - expected -= PAGE_SIZE, offset++) {
> - int avail = min_t(int, expected, PAGE_SIZE);
> -
> - squashfs_fill_page(pages[i], buffer,
> - offset * PAGE_SIZE, avail);
> - unlock_page(pages[i]);
> - }
> -
> - squashfs_cache_put(buffer);
> - continue;
> - }
> + actor = squashfs_page_actor_init_special(msblk, pages, nr_pages,
> expected);
> + if (!actor)
> + goto out;
>
> res = squashfs_read_data(inode->i_sb, block, bsize, NULL,
> actor);
>
> + kfree(actor);
> +
> if (res == expected) {
> int bytes;
>
> - /* Last page may have trailing bytes not filled */
> + /* Last page (if present) may have trailing bytes not filled */
> bytes = res % PAGE_SIZE;
> - if (bytes) {
> + if (pages[nr_pages - 1]->index == file_end && bytes) {
> void *pageaddr;
>
> pageaddr = kmap_atomic(pages[nr_pages - 1]);
> @@ -602,7 +578,6 @@ static void squashfs_readahead(struct
> readahead_control *ractl)
> }
> }
>
> - kfree(actor);
> kfree(pages);
> return;
>
> @@ -612,7 +587,6 @@ static void squashfs_readahead(struct
> readahead_control *ractl)
> put_page(pages[i]);
> }
>
> - kfree(actor);
> out:
> kfree(pages);
> }
> --
> 2.34.1