1 // SPDX-License-Identifier: GPL-2.0-only
4 * Phillip Lougher <phillip@squashfs.org.uk>
9 #include <linux/kernel.h>
10 #include <linux/slab.h>
11 #include <linux/string.h>
12 #include <linux/pagemap.h>
13 #include <linux/mutex.h>
15 #include "squashfs_fs.h"
16 #include "squashfs_fs_sb.h"
17 #include "squashfs_fs_i.h"
19 #include "page_actor.h"
21 /* Read separately compressed datablock directly into page cache */
22 int squashfs_readpage_block(struct page
*target_page
, u64 block
, int bsize
,
26 struct folio
*folio
= page_folio(target_page
);
27 struct inode
*inode
= target_page
->mapping
->host
;
28 struct squashfs_sb_info
*msblk
= inode
->i_sb
->s_fs_info
;
29 loff_t file_end
= (i_size_read(inode
) - 1) >> PAGE_SHIFT
;
30 int mask
= (1 << (msblk
->block_log
- PAGE_SHIFT
)) - 1;
31 loff_t start_index
= folio
->index
& ~mask
;
32 loff_t end_index
= start_index
| mask
;
34 int i
, pages
, bytes
, res
= -ENOMEM
;
35 struct page
**page
, *last_page
;
36 struct squashfs_page_actor
*actor
;
39 if (end_index
> file_end
)
42 pages
= end_index
- start_index
+ 1;
44 page
= kmalloc_array(pages
, sizeof(void *), GFP_KERNEL
);
48 /* Try to grab all the pages covered by the Squashfs block */
49 for (i
= 0, index
= start_index
; index
<= end_index
; index
++) {
50 page
[i
] = (index
== folio
->index
) ? target_page
:
51 grab_cache_page_nowait(target_page
->mapping
, index
);
56 if (PageUptodate(page
[i
])) {
68 * Create a "page actor" which will kmap and kunmap the
69 * page cache pages appropriately within the decompressor
71 actor
= squashfs_page_actor_init_special(msblk
, page
, pages
, expected
,
72 start_index
<< PAGE_SHIFT
);
76 /* Decompress directly into the page cache buffers */
77 res
= squashfs_read_data(inode
->i_sb
, block
, bsize
, NULL
, actor
);
79 last_page
= squashfs_page_actor_free(actor
);
84 if (res
!= expected
|| IS_ERR(last_page
)) {
89 /* Last page (if present) may have trailing bytes not filled */
90 bytes
= res
% PAGE_SIZE
;
91 if (end_index
== file_end
&& last_page
&& bytes
) {
92 pageaddr
= kmap_local_page(last_page
);
93 memset(pageaddr
+ bytes
, 0, PAGE_SIZE
- bytes
);
94 kunmap_local(pageaddr
);
97 /* Mark pages as uptodate, unlock and release */
98 for (i
= 0; i
< pages
; i
++) {
99 flush_dcache_page(page
[i
]);
100 SetPageUptodate(page
[i
]);
101 unlock_page(page
[i
]);
102 if (page
[i
] != target_page
)
111 /* Decompression failed. Target_page is
112 * dealt with by the caller
114 for (i
= 0; i
< pages
; i
++) {
115 if (page
[i
] == NULL
|| page
[i
] == target_page
)
117 flush_dcache_page(page
[i
]);
118 unlock_page(page
[i
]);