1 // SPDX-License-Identifier: GPL-2.0-only
4 * Phillip Lougher <phillip@squashfs.org.uk>
7 #include <linux/kernel.h>
8 #include <linux/slab.h>
9 #include <linux/pagemap.h>
10 #include "squashfs_fs_sb.h"
11 #include "decompressor.h"
12 #include "page_actor.h"
15 * This file contains implementations of page_actor for decompressing into
16 * an intermediate buffer, and for decompressing directly into the
19 * Calling code should avoid sleeping between calls to squashfs_first_page()
20 * and squashfs_finish_page().
23 /* Implementation of page_actor for decompressing into intermediate buffer */
24 static void *cache_first_page(struct squashfs_page_actor
*actor
)
27 return actor
->buffer
[0];
30 static void *cache_next_page(struct squashfs_page_actor
*actor
)
32 if (actor
->next_page
== actor
->pages
)
35 return actor
->buffer
[actor
->next_page
++];
38 static void cache_finish_page(struct squashfs_page_actor
*actor
)
43 struct squashfs_page_actor
*squashfs_page_actor_init(void **buffer
,
44 int pages
, int length
)
46 struct squashfs_page_actor
*actor
= kmalloc(sizeof(*actor
), GFP_KERNEL
);
51 actor
->length
= length
? : pages
* PAGE_SIZE
;
52 actor
->buffer
= buffer
;
55 actor
->tmp_buffer
= NULL
;
56 actor
->squashfs_first_page
= cache_first_page
;
57 actor
->squashfs_next_page
= cache_next_page
;
58 actor
->squashfs_finish_page
= cache_finish_page
;
62 /* Implementation of page_actor for decompressing directly into page cache. */
63 static loff_t
page_next_index(struct squashfs_page_actor
*actor
)
65 return page_folio(actor
->page
[actor
->next_page
])->index
;
68 static void *handle_next_page(struct squashfs_page_actor
*actor
)
70 int max_pages
= (actor
->length
+ PAGE_SIZE
- 1) >> PAGE_SHIFT
;
72 if (actor
->returned_pages
== max_pages
)
75 if ((actor
->next_page
== actor
->pages
) ||
76 (actor
->next_index
!= page_next_index(actor
))) {
78 actor
->returned_pages
++;
79 actor
->last_page
= NULL
;
80 return actor
->alloc_buffer
? actor
->tmp_buffer
: ERR_PTR(-ENOMEM
);
84 actor
->returned_pages
++;
85 actor
->last_page
= actor
->page
[actor
->next_page
];
86 return actor
->pageaddr
= kmap_local_page(actor
->page
[actor
->next_page
++]);
89 static void *direct_first_page(struct squashfs_page_actor
*actor
)
91 return handle_next_page(actor
);
94 static void *direct_next_page(struct squashfs_page_actor
*actor
)
96 if (actor
->pageaddr
) {
97 kunmap_local(actor
->pageaddr
);
98 actor
->pageaddr
= NULL
;
101 return handle_next_page(actor
);
104 static void direct_finish_page(struct squashfs_page_actor
*actor
)
107 kunmap_local(actor
->pageaddr
);
110 struct squashfs_page_actor
*squashfs_page_actor_init_special(struct squashfs_sb_info
*msblk
,
111 struct page
**page
, int pages
, int length
, loff_t start_index
)
113 struct squashfs_page_actor
*actor
= kmalloc(sizeof(*actor
), GFP_KERNEL
);
118 if (msblk
->decompressor
->alloc_buffer
) {
119 actor
->tmp_buffer
= kmalloc(PAGE_SIZE
, GFP_KERNEL
);
121 if (actor
->tmp_buffer
== NULL
) {
126 actor
->tmp_buffer
= NULL
;
128 actor
->length
= length
? : pages
* PAGE_SIZE
;
130 actor
->pages
= pages
;
131 actor
->next_page
= 0;
132 actor
->returned_pages
= 0;
133 actor
->next_index
= start_index
>> PAGE_SHIFT
;
134 actor
->pageaddr
= NULL
;
135 actor
->last_page
= NULL
;
136 actor
->alloc_buffer
= msblk
->decompressor
->alloc_buffer
;
137 actor
->squashfs_first_page
= direct_first_page
;
138 actor
->squashfs_next_page
= direct_next_page
;
139 actor
->squashfs_finish_page
= direct_finish_page
;