From nobody Wed Apr 29 09:34:32 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 78994C43334 for ; Sat, 11 Jun 2022 03:23:06 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1349907AbiFKDXF (ORCPT ); Fri, 10 Jun 2022 23:23:05 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40670 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1348434AbiFKDW5 (ORCPT ); Fri, 10 Jun 2022 23:22:57 -0400 Received: from p3plwbeout27-05.prod.phx3.secureserver.net (p3plsmtp27-05-2.prod.phx3.secureserver.net [216.69.139.54]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 22E1B6C0FD for ; Fri, 10 Jun 2022 20:22:54 -0700 (PDT) Received: from mailex.mailcore.me ([94.136.40.142]) by :WBEOUT: with ESMTP id zri9nQCFBAU9fzriAnzxNw; Fri, 10 Jun 2022 20:22:54 -0700 X-CMAE-Analysis: v=2.4 cv=WeTJ12tX c=1 sm=1 tr=0 ts=62a40a8e a=s1hRAmXuQnGNrIj+3lWWVA==:117 a=84ok6UeoqCVsigPHarzEiQ==:17 a=ggZhUymU-5wA:10 a=JPEYwPQDsx4A:10 a=FXvPX3liAAAA:8 a=v4aROKBdHILR9-7NOdAA:9 a=UObqyxdv-6Yh2QiB9mM_:22 X-SECURESERVER-ACCT: phillip@squashfs.org.uk X-SID: zri9nQCFBAU9f Received: from 82-69-79-175.dsl.in-addr.zen.co.uk ([82.69.79.175] helo=localhost.localdomain) by smtp02.mailcore.me with esmtpa (Exim 4.94.2) (envelope-from ) id 1nzri8-0001TR-C9; Sat, 11 Jun 2022 04:22:53 +0100 From: Phillip Lougher To: linux-kernel@vger.kernel.org, akpm@linux-foundation.org Cc: willy@infradead.org, hsinyi@chromium.org, Xiongwei.Song@windriver.com, linux-mm@kvack.org, squashfs-devel@lists.sourceforge.net, Phillip Lougher Subject: [PATCH 1/2] Squashfs: extend "page actor" to handle missing pages Date: Sat, 11 Jun 2022 04:21:32 +0100 Message-Id: <20220611032133.5743-2-phillip@squashfs.org.uk> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220611032133.5743-1-phillip@squashfs.org.uk> References: <20220611032133.5743-1-phillip@squashfs.org.uk> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Mailcore-Auth: 439999529 X-Mailcore-Domain: 1394945 X-123-reg-Authenticated: phillip@squashfs.org.uk X-Originating-IP: 82.69.79.175 X-CMAE-Envelope: MS4xfM3JTBUUmTwmaQTfuJo+NUjFPduhGg84mOIWq2AthQsH21cU98UPz1ucnb4+m/pk4n97V2GN83NSFPq/XtvBWjIS3xRch4bZq0b+4pInW4mplvAeMCNX LBJrbtTcFOHv2GUNuZ2UlwteKAPBtXkxqCIJHTdOzEmgDU8Dbe3n0qIgFDKNjinY78ZKGRobYTJscAqUmYjz61B/18riiI7o8Io= Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" This patch extends the "page actor" code to handle missing pages. Previously if the full set of pages needed to decompress a Squashfs datablock was unavailable, this would cause decompression to fail on the missing pages. In this case direct decompression into the page cache could not be achieved and the code would fall back to using the older intermediate buffer method. With this patch, direct decompression into the page cache can be achieved with missing pages. For "multi-shot" decompressors (zlib, xz, zstd), the page actor will allocate a temporary buffer which is passed to the decompressor, and then freed by the page actor. For "single shot" decompressors (lz4, lzo) which decompress into a contiguous "bounce buffer", and which is then copied into the page cache, it would be pointless to allocate a temporary buffer, memcpy into it, and then free it. For these decompressors -ENOMEM is returned, which signifies that the memcpy for that page should be skipped. This also happens if the data block is uncompressed. Signed-off-by: Phillip Lougher --- fs/squashfs/block.c | 10 ++++--- fs/squashfs/decompressor.h | 1 + fs/squashfs/file_direct.c | 21 ++++++++------- fs/squashfs/lz4_wrapper.c | 7 +++-- fs/squashfs/lzo_wrapper.c | 7 +++-- fs/squashfs/page_actor.c | 55 ++++++++++++++++++++++++++++++++------ fs/squashfs/page_actor.h | 21 ++++++++++++--- fs/squashfs/xz_wrapper.c | 11 +++++++- fs/squashfs/zlib_wrapper.c | 12 ++++++++- fs/squashfs/zstd_wrapper.c | 12 ++++++++- 10 files changed, 126 insertions(+), 31 deletions(-) diff --git a/fs/squashfs/block.c b/fs/squashfs/block.c index 622c844f6d11..acbb0dc80f89 100644 --- a/fs/squashfs/block.c +++ b/fs/squashfs/block.c @@ -34,12 +34,15 @@ static int copy_bio_to_actor(struct bio *bio, struct squashfs_page_actor *actor, int offset, int req_length) { - void *actor_addr =3D squashfs_first_page(actor); + void *actor_addr; struct bvec_iter_all iter_all =3D {}; struct bio_vec *bvec =3D bvec_init_iter_all(&iter_all); int copied_bytes =3D 0; int actor_offset =3D 0; =20 + squashfs_actor_nobuff(actor); + actor_addr =3D squashfs_first_page(actor); + if (WARN_ON_ONCE(!bio_next_segment(bio, &iter_all))) return 0; =20 @@ -49,8 +52,9 @@ static int copy_bio_to_actor(struct bio *bio, =20 bytes_to_copy =3D min_t(int, bytes_to_copy, req_length - copied_bytes); - memcpy(actor_addr + actor_offset, bvec_virt(bvec) + offset, - bytes_to_copy); + if (!IS_ERR(actor_addr)) + memcpy(actor_addr + actor_offset, bvec_virt(bvec) + + offset, bytes_to_copy); =20 actor_offset +=3D bytes_to_copy; copied_bytes +=3D bytes_to_copy; diff --git a/fs/squashfs/decompressor.h b/fs/squashfs/decompressor.h index 1b9ccfd0aa51..19ab60834389 100644 --- a/fs/squashfs/decompressor.h +++ b/fs/squashfs/decompressor.h @@ -20,6 +20,7 @@ struct squashfs_decompressor { struct bio *, int, int, struct squashfs_page_actor *); int id; char *name; + int alloc_buffer; int supported; }; =20 diff --git a/fs/squashfs/file_direct.c b/fs/squashfs/file_direct.c index a4894cc59447..5af5802f5626 100644 --- a/fs/squashfs/file_direct.c +++ b/fs/squashfs/file_direct.c @@ -47,14 +47,6 @@ int squashfs_readpage_block(struct page *target_page, u6= 4 block, int bsize, if (page =3D=3D NULL) return res; =20 - /* - * Create a "page actor" which will kmap and kunmap the - * page cache pages appropriately within the decompressor - */ - actor =3D squashfs_page_actor_init_special(page, pages, 0); - if (actor =3D=3D NULL) - goto out; - /* Try to grab all the pages covered by the Squashfs block */ for (missing_pages =3D 0, i =3D 0, n =3D start_index; i < pages; i++, n++= ) { page[i] =3D (n =3D=3D target_page->index) ? target_page : @@ -89,8 +81,19 @@ int squashfs_readpage_block(struct page *target_page, u6= 4 block, int bsize, goto out; } =20 + /* + * Create a "page actor" which will kmap and kunmap the + * page cache pages appropriately within the decompressor + */ + actor =3D squashfs_page_actor_init_special(msblk, page, pages, 0); + if (actor =3D=3D NULL) + goto out; + /* Decompress directly into the page cache buffers */ res =3D squashfs_read_data(inode->i_sb, block, bsize, NULL, actor); + + kfree(actor); + if (res < 0) goto mark_errored; =20 @@ -116,7 +119,6 @@ int squashfs_readpage_block(struct page *target_page, u= 64 block, int bsize, put_page(page[i]); } =20 - kfree(actor); kfree(page); =20 return 0; @@ -135,7 +137,6 @@ int squashfs_readpage_block(struct page *target_page, u= 64 block, int bsize, } =20 out: - kfree(actor); kfree(page); return res; } diff --git a/fs/squashfs/lz4_wrapper.c b/fs/squashfs/lz4_wrapper.c index b685b6238316..49797729f143 100644 --- a/fs/squashfs/lz4_wrapper.c +++ b/fs/squashfs/lz4_wrapper.c @@ -119,10 +119,12 @@ static int lz4_uncompress(struct squashfs_sb_info *ms= blk, void *strm, buff =3D stream->output; while (data) { if (bytes <=3D PAGE_SIZE) { - memcpy(data, buff, bytes); + if (!IS_ERR(data)) + memcpy(data, buff, bytes); break; } - memcpy(data, buff, PAGE_SIZE); + if (!IS_ERR(data)) + memcpy(data, buff, PAGE_SIZE); buff +=3D PAGE_SIZE; bytes -=3D PAGE_SIZE; data =3D squashfs_next_page(output); @@ -139,5 +141,6 @@ const struct squashfs_decompressor squashfs_lz4_comp_op= s =3D { .decompress =3D lz4_uncompress, .id =3D LZ4_COMPRESSION, .name =3D "lz4", + .alloc_buffer =3D 0, .supported =3D 1 }; diff --git a/fs/squashfs/lzo_wrapper.c b/fs/squashfs/lzo_wrapper.c index cb510a631968..d216aeefa865 100644 --- a/fs/squashfs/lzo_wrapper.c +++ b/fs/squashfs/lzo_wrapper.c @@ -93,10 +93,12 @@ static int lzo_uncompress(struct squashfs_sb_info *msbl= k, void *strm, buff =3D stream->output; while (data) { if (bytes <=3D PAGE_SIZE) { - memcpy(data, buff, bytes); + if (!IS_ERR(data)) + memcpy(data, buff, bytes); break; } else { - memcpy(data, buff, PAGE_SIZE); + if (!IS_ERR(data)) + memcpy(data, buff, PAGE_SIZE); buff +=3D PAGE_SIZE; bytes -=3D PAGE_SIZE; data =3D squashfs_next_page(output); @@ -116,5 +118,6 @@ const struct squashfs_decompressor squashfs_lzo_comp_op= s =3D { .decompress =3D lzo_uncompress, .id =3D LZO_COMPRESSION, .name =3D "lzo", + .alloc_buffer =3D 0, .supported =3D 1 }; diff --git a/fs/squashfs/page_actor.c b/fs/squashfs/page_actor.c index 520d323a99ce..b23b780d8f42 100644 --- a/fs/squashfs/page_actor.c +++ b/fs/squashfs/page_actor.c @@ -7,6 +7,8 @@ #include #include #include +#include "squashfs_fs_sb.h" +#include "decompressor.h" #include "page_actor.h" =20 /* @@ -57,29 +59,62 @@ struct squashfs_page_actor *squashfs_page_actor_init(vo= id **buffer, } =20 /* Implementation of page_actor for decompressing directly into page cache= . */ +static void *handle_next_page(struct squashfs_page_actor *actor) +{ + int max_pages =3D (actor->length + PAGE_SIZE - 1) >> PAGE_SHIFT; + + if (actor->returned_pages =3D=3D max_pages) + return NULL; + + if ((actor->next_page =3D=3D actor->pages) || + (actor->next_index !=3D actor->page[actor->next_page]->index)) { + if (actor->alloc_buffer) { + void *tmp_buffer =3D kmalloc(PAGE_SIZE, GFP_KERNEL); + + if (tmp_buffer) { + actor->tmp_buffer =3D tmp_buffer; + actor->next_index++; + actor->returned_pages++; + return tmp_buffer; + } + } + + actor->next_index++; + actor->returned_pages++; + return ERR_PTR(-ENOMEM); + } + + actor->next_index++; + actor->returned_pages++; + return actor->pageaddr =3D kmap_local_page(actor->page[actor->next_page++= ]); +} + static void *direct_first_page(struct squashfs_page_actor *actor) { - actor->next_page =3D 1; - return actor->pageaddr =3D kmap_atomic(actor->page[0]); + return handle_next_page(actor); } =20 static void *direct_next_page(struct squashfs_page_actor *actor) { if (actor->pageaddr) - kunmap_atomic(actor->pageaddr); + kunmap_local(actor->pageaddr); + + kfree(actor->tmp_buffer); + actor->pageaddr =3D actor->tmp_buffer =3D NULL; =20 - return actor->pageaddr =3D actor->next_page =3D=3D actor->pages ? NULL : - kmap_atomic(actor->page[actor->next_page++]); + return handle_next_page(actor); } =20 static void direct_finish_page(struct squashfs_page_actor *actor) { if (actor->pageaddr) - kunmap_atomic(actor->pageaddr); + kunmap_local(actor->pageaddr); + + kfree(actor->tmp_buffer); } =20 -struct squashfs_page_actor *squashfs_page_actor_init_special(struct page *= *page, - int pages, int length) +struct squashfs_page_actor *squashfs_page_actor_init_special(struct squash= fs_sb_info *msblk, + struct page **page, int pages, int length) { struct squashfs_page_actor *actor =3D kmalloc(sizeof(*actor), GFP_KERNEL); =20 @@ -90,7 +125,11 @@ struct squashfs_page_actor *squashfs_page_actor_init_sp= ecial(struct page **page, actor->page =3D page; actor->pages =3D pages; actor->next_page =3D 0; + actor->returned_pages =3D 0; + actor->next_index =3D page[0]->index & ~((1 << (msblk->block_log - PAGE_S= HIFT)) - 1); actor->pageaddr =3D NULL; + actor->tmp_buffer =3D NULL; + actor->alloc_buffer =3D msblk->decompressor->alloc_buffer; actor->squashfs_first_page =3D direct_first_page; actor->squashfs_next_page =3D direct_next_page; actor->squashfs_finish_page =3D direct_finish_page; diff --git a/fs/squashfs/page_actor.h b/fs/squashfs/page_actor.h index 2e3073ace009..37523c54256f 100644 --- a/fs/squashfs/page_actor.h +++ b/fs/squashfs/page_actor.h @@ -45,6 +45,11 @@ static inline void squashfs_finish_page(struct squashfs_= page_actor *actor) { /* empty */ } + +static inline void squashfs_actor_nobuff(struct squashfs_page_actor *actor) +{ + /* empty */ +} #else struct squashfs_page_actor { union { @@ -52,17 +57,23 @@ struct squashfs_page_actor { struct page **page; }; void *pageaddr; + void *tmp_buffer; void *(*squashfs_first_page)(struct squashfs_page_actor *); void *(*squashfs_next_page)(struct squashfs_page_actor *); void (*squashfs_finish_page)(struct squashfs_page_actor *); int pages; int length; int next_page; + int alloc_buffer; + int returned_pages; + pgoff_t next_index; }; =20 -extern struct squashfs_page_actor *squashfs_page_actor_init(void **, int, = int); -extern struct squashfs_page_actor *squashfs_page_actor_init_special(struct= page - **, int, int); +extern struct squashfs_page_actor *squashfs_page_actor_init(void **buffer, + int pages, int length); +extern struct squashfs_page_actor *squashfs_page_actor_init_special( + struct squashfs_sb_info *msblk, + struct page **page, int pages, int length); static inline void *squashfs_first_page(struct squashfs_page_actor *actor) { return actor->squashfs_first_page(actor); @@ -75,5 +86,9 @@ static inline void squashfs_finish_page(struct squashfs_p= age_actor *actor) { actor->squashfs_finish_page(actor); } +static inline void squashfs_actor_nobuff(struct squashfs_page_actor *actor) +{ + actor->alloc_buffer =3D 0; +} #endif #endif diff --git a/fs/squashfs/xz_wrapper.c b/fs/squashfs/xz_wrapper.c index 68f6d09bb3a2..6c49481a2f8c 100644 --- a/fs/squashfs/xz_wrapper.c +++ b/fs/squashfs/xz_wrapper.c @@ -131,6 +131,10 @@ static int squashfs_xz_uncompress(struct squashfs_sb_i= nfo *msblk, void *strm, stream->buf.out_pos =3D 0; stream->buf.out_size =3D PAGE_SIZE; stream->buf.out =3D squashfs_first_page(output); + if (IS_ERR(stream->buf.out)) { + error =3D PTR_ERR(stream->buf.out); + goto finish; + } =20 for (;;) { enum xz_ret xz_err; @@ -156,7 +160,10 @@ static int squashfs_xz_uncompress(struct squashfs_sb_i= nfo *msblk, void *strm, =20 if (stream->buf.out_pos =3D=3D stream->buf.out_size) { stream->buf.out =3D squashfs_next_page(output); - if (stream->buf.out !=3D NULL) { + if (IS_ERR(stream->buf.out)) { + error =3D PTR_ERR(stream->buf.out); + break; + } else if (stream->buf.out !=3D NULL) { stream->buf.out_pos =3D 0; total +=3D PAGE_SIZE; } @@ -171,6 +178,7 @@ static int squashfs_xz_uncompress(struct squashfs_sb_in= fo *msblk, void *strm, } } =20 +finish: squashfs_finish_page(output); =20 return error ? error : total + stream->buf.out_pos; @@ -183,5 +191,6 @@ const struct squashfs_decompressor squashfs_xz_comp_ops= =3D { .decompress =3D squashfs_xz_uncompress, .id =3D XZ_COMPRESSION, .name =3D "xz", + .alloc_buffer =3D 1, .supported =3D 1 }; diff --git a/fs/squashfs/zlib_wrapper.c b/fs/squashfs/zlib_wrapper.c index a20e9042146b..cbb7afe7bc46 100644 --- a/fs/squashfs/zlib_wrapper.c +++ b/fs/squashfs/zlib_wrapper.c @@ -62,6 +62,11 @@ static int zlib_uncompress(struct squashfs_sb_info *msbl= k, void *strm, stream->next_out =3D squashfs_first_page(output); stream->avail_in =3D 0; =20 + if (IS_ERR(stream->next_out)) { + error =3D PTR_ERR(stream->next_out); + goto finish; + } + for (;;) { int zlib_err; =20 @@ -85,7 +90,10 @@ static int zlib_uncompress(struct squashfs_sb_info *msbl= k, void *strm, =20 if (stream->avail_out =3D=3D 0) { stream->next_out =3D squashfs_next_page(output); - if (stream->next_out !=3D NULL) + if (IS_ERR(stream->next_out)) { + error =3D PTR_ERR(stream->next_out); + break; + } else if (stream->next_out !=3D NULL) stream->avail_out =3D PAGE_SIZE; } =20 @@ -107,6 +115,7 @@ static int zlib_uncompress(struct squashfs_sb_info *msb= lk, void *strm, } } =20 +finish: squashfs_finish_page(output); =20 if (!error) @@ -122,6 +131,7 @@ const struct squashfs_decompressor squashfs_zlib_comp_o= ps =3D { .decompress =3D zlib_uncompress, .id =3D ZLIB_COMPRESSION, .name =3D "zlib", + .alloc_buffer =3D 1, .supported =3D 1 }; =20 diff --git a/fs/squashfs/zstd_wrapper.c b/fs/squashfs/zstd_wrapper.c index c40445dbf38c..0e407c4d8b3b 100644 --- a/fs/squashfs/zstd_wrapper.c +++ b/fs/squashfs/zstd_wrapper.c @@ -80,6 +80,10 @@ static int zstd_uncompress(struct squashfs_sb_info *msbl= k, void *strm, =20 out_buf.size =3D PAGE_SIZE; out_buf.dst =3D squashfs_first_page(output); + if (IS_ERR(out_buf.dst)) { + error =3D PTR_ERR(out_buf.dst); + goto finish; + } =20 for (;;) { size_t zstd_err; @@ -104,7 +108,10 @@ static int zstd_uncompress(struct squashfs_sb_info *ms= blk, void *strm, =20 if (out_buf.pos =3D=3D out_buf.size) { out_buf.dst =3D squashfs_next_page(output); - if (out_buf.dst =3D=3D NULL) { + if (IS_ERR(out_buf.dst)) { + error =3D PTR_ERR(out_buf.dst); + break; + } else if (out_buf.dst =3D=3D NULL) { /* Shouldn't run out of pages * before stream is done. */ @@ -129,6 +136,8 @@ static int zstd_uncompress(struct squashfs_sb_info *msb= lk, void *strm, } } =20 +finish: + squashfs_finish_page(output); =20 return error ? error : total_out; @@ -140,5 +149,6 @@ const struct squashfs_decompressor squashfs_zstd_comp_o= ps =3D { .decompress =3D zstd_uncompress, .id =3D ZSTD_COMPRESSION, .name =3D "zstd", + .alloc_buffer =3D 1, .supported =3D 1 }; --=20 2.34.1 From nobody Wed Apr 29 09:34:32 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id BD118C43334 for ; Sat, 11 Jun 2022 03:23:02 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1349860AbiFKDXA (ORCPT ); Fri, 10 Jun 2022 23:23:00 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40678 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236391AbiFKDW4 (ORCPT ); Fri, 10 Jun 2022 23:22:56 -0400 Received: from p3plwbeout16-02.prod.phx3.secureserver.net (p3plsmtp16-02-2.prod.phx3.secureserver.net [173.201.193.56]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id F35016C55A for ; Fri, 10 Jun 2022 20:22:55 -0700 (PDT) Received: from mailex.mailcore.me ([94.136.40.142]) by :WBEOUT: with ESMTP id zriAndxSIJglUzriBnMf5G; Fri, 10 Jun 2022 20:22:55 -0700 X-CMAE-Analysis: v=2.4 cv=cNIlDnSN c=1 sm=1 tr=0 ts=62a40a8f a=s1hRAmXuQnGNrIj+3lWWVA==:117 a=84ok6UeoqCVsigPHarzEiQ==:17 a=ggZhUymU-5wA:10 a=JPEYwPQDsx4A:10 a=FXvPX3liAAAA:8 a=EtPFtR80rDWv2_rSRC0A:9 a=UObqyxdv-6Yh2QiB9mM_:22 X-SECURESERVER-ACCT: phillip@squashfs.org.uk X-SID: zriAndxSIJglU Received: from 82-69-79-175.dsl.in-addr.zen.co.uk ([82.69.79.175] helo=localhost.localdomain) by smtp02.mailcore.me with esmtpa (Exim 4.94.2) (envelope-from ) id 1nzri9-0001TR-MA; Sat, 11 Jun 2022 04:22:54 +0100 From: Phillip Lougher To: linux-kernel@vger.kernel.org, akpm@linux-foundation.org Cc: willy@infradead.org, hsinyi@chromium.org, Xiongwei.Song@windriver.com, linux-mm@kvack.org, squashfs-devel@lists.sourceforge.net, Phillip Lougher Subject: [PATCH 2/2] Squashfs: don't use intermediate buffer if pages missing Date: Sat, 11 Jun 2022 04:21:33 +0100 Message-Id: <20220611032133.5743-3-phillip@squashfs.org.uk> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220611032133.5743-1-phillip@squashfs.org.uk> References: <20220611032133.5743-1-phillip@squashfs.org.uk> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Mailcore-Auth: 439999529 X-Mailcore-Domain: 1394945 X-123-reg-Authenticated: phillip@squashfs.org.uk X-Originating-IP: 82.69.79.175 X-CMAE-Envelope: MS4xfJjfcaPyDqY2Ng4a+iygPSR1DwPaO1RK6VeUyxhCb8WpqYsoW6KorsH8HWVl5f/iu4PjpKIreT+vfVBrShm9/kVNNDKkQgldVHk9KnwBuvnl7OYkq7PA q086RClsnWxDYAjQarCXg1NOovOx1mmKxKEY5FCV/RDmJzduRg+Ff8QlkcsLcajhATC+lxexVO7PTojPJ4HOosZPfs9BEvZlkaM= Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" 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. Signed-off-by: Phillip Lougher --- fs/squashfs/file_direct.c | 75 +++++++-------------------------------- 1 file changed, 12 insertions(+), 63 deletions(-) diff --git a/fs/squashfs/file_direct.c b/fs/squashfs/file_direct.c index 5af5802f5626..be4b12d31e0c 100644 --- a/fs/squashfs/file_direct.c +++ b/fs/squashfs/file_direct.c @@ -18,9 +18,6 @@ #include "squashfs.h" #include "page_actor.h" =20 -static int squashfs_read_cache(struct page *target_page, u64 block, int bs= ize, - 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) @@ -33,7 +30,7 @@ int squashfs_readpage_block(struct page *target_page, u64= block, int bsize, int mask =3D (1 << (msblk->block_log - PAGE_SHIFT)) - 1; int start_index =3D target_page->index & ~mask; int end_index =3D start_index | mask; - int i, n, pages, missing_pages, bytes, res =3D -ENOMEM; + int i, n, pages, bytes, res =3D -ENOMEM; struct page **page; struct squashfs_page_actor *actor; void *pageaddr; @@ -48,44 +45,29 @@ int squashfs_readpage_block(struct page *target_page, u= 64 block, int bsize, return res; =20 /* Try to grab all the pages covered by the Squashfs block */ - for (missing_pages =3D 0, i =3D 0, n =3D start_index; i < pages; i++, n++= ) { + for (i =3D 0, n =3D start_index; n <=3D end_index; n++) { page[i] =3D (n =3D=3D target_page->index) ? target_page : grab_cache_page_nowait(target_page->mapping, n); =20 - if (page[i] =3D=3D NULL) { - missing_pages++; + if (page[i] =3D=3D NULL) continue; - } =20 if (PageUptodate(page[i])) { unlock_page(page[i]); put_page(page[i]); - page[i] =3D 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 =3D squashfs_read_cache(target_page, block, bsize, pages, - page, expected); - if (res < 0) - goto mark_errored; =20 - goto out; + i++; } =20 + pages =3D i; + /* * Create a "page actor" which will kmap and kunmap the * page cache pages appropriately within the decompressor */ - actor =3D squashfs_page_actor_init_special(msblk, page, pages, 0); + actor =3D squashfs_page_actor_init_special(msblk, page, pages, expected); if (actor =3D=3D NULL) goto out; =20 @@ -102,12 +84,12 @@ int squashfs_readpage_block(struct page *target_page, = u64 block, int bsize, goto mark_errored; } =20 - /* Last page may have trailing bytes not filled */ + /* Last page (if present) may have trailing bytes not filled */ bytes =3D res % PAGE_SIZE; - if (bytes) { - pageaddr =3D kmap_atomic(page[pages - 1]); + if (page[pages - 1]->index =3D=3D end_index && bytes) { + pageaddr =3D kmap_local_page(page[pages - 1]); memset(pageaddr + bytes, 0, PAGE_SIZE - bytes); - kunmap_atomic(pageaddr); + kunmap_local(pageaddr); } =20 /* Mark pages as uptodate, unlock and release */ @@ -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 bs= ize, - int pages, struct page **page, int bytes) -{ - struct inode *i =3D target_page->mapping->host; - struct squashfs_cache_entry *buffer =3D squashfs_get_datablock(i->i_sb, - block, bsize); - int res =3D buffer->error, n, offset =3D 0; - - if (res) { - ERROR("Unable to read page, block %llx, size %x\n", block, - bsize); - goto out; - } - - for (n =3D 0; n < pages && bytes > 0; n++, - bytes -=3D PAGE_SIZE, offset +=3D PAGE_SIZE) { - int avail =3D min_t(int, bytes, PAGE_SIZE); - - if (page[n] =3D=3D NULL) - continue; - - squashfs_fill_page(page[n], buffer, offset, avail); - unlock_page(page[n]); - if (page[n] !=3D target_page) - put_page(page[n]); - } - -out: - squashfs_cache_put(buffer); - return res; -} --=20 2.34.1