Skip to content

Commit

Permalink
squashfs: don't use intermediate buffer if pages missing
Browse files Browse the repository at this point in the history
Now that the "page actor" can handle missing pages, we don't have to fall
back to using an intermediate buffer in Squashfs_readpage_block() if all
the pages necessary can't be obtained.

Link: https://lkml.kernel.org/r/20220611032133.5743-3-phillip@squashfs.org.uk
Signed-off-by: Phillip Lougher <phillip@squashfs.org.uk>
Cc: Hsin-Yi Wang <hsinyi@chromium.org>
Cc: Matthew Wilcox (Oracle) <willy@infradead.org>
Cc: Xiongwei Song <Xiongwei.Song@windriver.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
  • Loading branch information
Phillip Lougher authored and akpm committed Jun 17, 2022
1 parent f268eed commit 1bb1a07
Showing 1 changed file with 12 additions and 63 deletions.
75 changes: 12 additions & 63 deletions fs/squashfs/file_direct.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@
#include "squashfs.h"
#include "page_actor.h"

static int squashfs_read_cache(struct page *target_page, u64 block, int bsize,
int pages, struct page **page, int bytes);

/* Read separately compressed datablock directly into page cache */
int squashfs_readpage_block(struct page *target_page, u64 block, int bsize,
int expected)
Expand All @@ -33,7 +30,7 @@ int squashfs_readpage_block(struct page *target_page, u64 block, int bsize,
int mask = (1 << (msblk->block_log - PAGE_SHIFT)) - 1;
int start_index = target_page->index & ~mask;
int end_index = start_index | mask;
int i, n, pages, missing_pages, bytes, res = -ENOMEM;
int i, n, pages, bytes, res = -ENOMEM;
struct page **page;
struct squashfs_page_actor *actor;
void *pageaddr;
Expand All @@ -48,44 +45,29 @@ int squashfs_readpage_block(struct page *target_page, u64 block, int bsize,
return res;

/* Try to grab all the pages covered by the Squashfs block */
for (missing_pages = 0, i = 0, n = start_index; i < pages; i++, n++) {
for (i = 0, n = start_index; n <= end_index; n++) {
page[i] = (n == target_page->index) ? target_page :
grab_cache_page_nowait(target_page->mapping, n);

if (page[i] == NULL) {
missing_pages++;
if (page[i] == NULL)
continue;
}

if (PageUptodate(page[i])) {
unlock_page(page[i]);
put_page(page[i]);
page[i] = NULL;
missing_pages++;
continue;
}
}

if (missing_pages) {
/*
* Couldn't get one or more pages, this page has either
* been VM reclaimed, but others are still in the page cache
* and uptodate, or we're racing with another thread in
* squashfs_readpage also trying to grab them. Fall back to
* using an intermediate buffer.
*/
res = squashfs_read_cache(target_page, block, bsize, pages,
page, expected);
if (res < 0)
goto mark_errored;

goto out;
i++;
}

pages = i;

/*
* Create a "page actor" which will kmap and kunmap the
* page cache pages appropriately within the decompressor
*/
actor = squashfs_page_actor_init_special(msblk, page, pages, 0);
actor = squashfs_page_actor_init_special(msblk, page, pages, expected);
if (actor == NULL)
goto out;

Expand All @@ -102,12 +84,12 @@ int squashfs_readpage_block(struct page *target_page, u64 block, int bsize,
goto mark_errored;
}

/* Last page may have trailing bytes not filled */
/* Last page (if present) may have trailing bytes not filled */
bytes = res % PAGE_SIZE;
if (bytes) {
pageaddr = kmap_atomic(page[pages - 1]);
if (page[pages - 1]->index == end_index && bytes) {
pageaddr = kmap_local_page(page[pages - 1]);
memset(pageaddr + bytes, 0, PAGE_SIZE - bytes);
kunmap_atomic(pageaddr);
kunmap_local(pageaddr);
}

/* Mark pages as uptodate, unlock and release */
Expand Down Expand Up @@ -140,36 +122,3 @@ int squashfs_readpage_block(struct page *target_page, u64 block, int bsize,
kfree(page);
return res;
}


static int squashfs_read_cache(struct page *target_page, u64 block, int bsize,
int pages, struct page **page, int bytes)
{
struct inode *i = target_page->mapping->host;
struct squashfs_cache_entry *buffer = squashfs_get_datablock(i->i_sb,
block, bsize);
int res = buffer->error, n, offset = 0;

if (res) {
ERROR("Unable to read page, block %llx, size %x\n", block,
bsize);
goto out;
}

for (n = 0; n < pages && bytes > 0; n++,
bytes -= PAGE_SIZE, offset += PAGE_SIZE) {
int avail = min_t(int, bytes, PAGE_SIZE);

if (page[n] == NULL)
continue;

squashfs_fill_page(page[n], buffer, offset, avail);
unlock_page(page[n]);
if (page[n] != target_page)
put_page(page[n]);
}

out:
squashfs_cache_put(buffer);
return res;
}

0 comments on commit 1bb1a07

Please sign in to comment.