1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (C) 2018 HUAWEI, Inc.
4*4882a593Smuzhiyun * https://www.huawei.com/
5*4882a593Smuzhiyun * Created by Gao Xiang <gaoxiang25@huawei.com>
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun #include "zdata.h"
8*4882a593Smuzhiyun #include "compress.h"
9*4882a593Smuzhiyun #include <linux/prefetch.h>
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun #include <trace/events/erofs.h>
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun /*
14*4882a593Smuzhiyun * since pclustersize is variable for big pcluster feature, introduce slab
15*4882a593Smuzhiyun * pools implementation for different pcluster sizes.
16*4882a593Smuzhiyun */
17*4882a593Smuzhiyun struct z_erofs_pcluster_slab {
18*4882a593Smuzhiyun struct kmem_cache *slab;
19*4882a593Smuzhiyun unsigned int maxpages;
20*4882a593Smuzhiyun char name[48];
21*4882a593Smuzhiyun };
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun #define _PCLP(n) { .maxpages = n }
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun static struct z_erofs_pcluster_slab pcluster_pool[] __read_mostly = {
26*4882a593Smuzhiyun _PCLP(1), _PCLP(4), _PCLP(16), _PCLP(64), _PCLP(128),
27*4882a593Smuzhiyun _PCLP(Z_EROFS_PCLUSTER_MAX_PAGES)
28*4882a593Smuzhiyun };
29*4882a593Smuzhiyun
z_erofs_destroy_pcluster_pool(void)30*4882a593Smuzhiyun static void z_erofs_destroy_pcluster_pool(void)
31*4882a593Smuzhiyun {
32*4882a593Smuzhiyun int i;
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(pcluster_pool); ++i) {
35*4882a593Smuzhiyun if (!pcluster_pool[i].slab)
36*4882a593Smuzhiyun continue;
37*4882a593Smuzhiyun kmem_cache_destroy(pcluster_pool[i].slab);
38*4882a593Smuzhiyun pcluster_pool[i].slab = NULL;
39*4882a593Smuzhiyun }
40*4882a593Smuzhiyun }
41*4882a593Smuzhiyun
z_erofs_create_pcluster_pool(void)42*4882a593Smuzhiyun static int z_erofs_create_pcluster_pool(void)
43*4882a593Smuzhiyun {
44*4882a593Smuzhiyun struct z_erofs_pcluster_slab *pcs;
45*4882a593Smuzhiyun struct z_erofs_pcluster *a;
46*4882a593Smuzhiyun unsigned int size;
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun for (pcs = pcluster_pool;
49*4882a593Smuzhiyun pcs < pcluster_pool + ARRAY_SIZE(pcluster_pool); ++pcs) {
50*4882a593Smuzhiyun size = struct_size(a, compressed_pages, pcs->maxpages);
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun sprintf(pcs->name, "erofs_pcluster-%u", pcs->maxpages);
53*4882a593Smuzhiyun pcs->slab = kmem_cache_create(pcs->name, size, 0,
54*4882a593Smuzhiyun SLAB_RECLAIM_ACCOUNT, NULL);
55*4882a593Smuzhiyun if (pcs->slab)
56*4882a593Smuzhiyun continue;
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun z_erofs_destroy_pcluster_pool();
59*4882a593Smuzhiyun return -ENOMEM;
60*4882a593Smuzhiyun }
61*4882a593Smuzhiyun return 0;
62*4882a593Smuzhiyun }
63*4882a593Smuzhiyun
z_erofs_alloc_pcluster(unsigned int nrpages)64*4882a593Smuzhiyun static struct z_erofs_pcluster *z_erofs_alloc_pcluster(unsigned int nrpages)
65*4882a593Smuzhiyun {
66*4882a593Smuzhiyun int i;
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(pcluster_pool); ++i) {
69*4882a593Smuzhiyun struct z_erofs_pcluster_slab *pcs = pcluster_pool + i;
70*4882a593Smuzhiyun struct z_erofs_pcluster *pcl;
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun if (nrpages > pcs->maxpages)
73*4882a593Smuzhiyun continue;
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun pcl = kmem_cache_zalloc(pcs->slab, GFP_NOFS);
76*4882a593Smuzhiyun if (!pcl)
77*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
78*4882a593Smuzhiyun pcl->pclusterpages = nrpages;
79*4882a593Smuzhiyun return pcl;
80*4882a593Smuzhiyun }
81*4882a593Smuzhiyun return ERR_PTR(-EINVAL);
82*4882a593Smuzhiyun }
83*4882a593Smuzhiyun
z_erofs_free_pcluster(struct z_erofs_pcluster * pcl)84*4882a593Smuzhiyun static void z_erofs_free_pcluster(struct z_erofs_pcluster *pcl)
85*4882a593Smuzhiyun {
86*4882a593Smuzhiyun int i;
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(pcluster_pool); ++i) {
89*4882a593Smuzhiyun struct z_erofs_pcluster_slab *pcs = pcluster_pool + i;
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun if (pcl->pclusterpages > pcs->maxpages)
92*4882a593Smuzhiyun continue;
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun kmem_cache_free(pcs->slab, pcl);
95*4882a593Smuzhiyun return;
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun DBG_BUGON(1);
98*4882a593Smuzhiyun }
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun /*
101*4882a593Smuzhiyun * a compressed_pages[] placeholder in order to avoid
102*4882a593Smuzhiyun * being filled with file pages for in-place decompression.
103*4882a593Smuzhiyun */
104*4882a593Smuzhiyun #define PAGE_UNALLOCATED ((void *)0x5F0E4B1D)
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun /* how to allocate cached pages for a pcluster */
107*4882a593Smuzhiyun enum z_erofs_cache_alloctype {
108*4882a593Smuzhiyun DONTALLOC, /* don't allocate any cached pages */
109*4882a593Smuzhiyun DELAYEDALLOC, /* delayed allocation (at the time of submitting io) */
110*4882a593Smuzhiyun /*
111*4882a593Smuzhiyun * try to use cached I/O if page allocation succeeds or fallback
112*4882a593Smuzhiyun * to in-place I/O instead to avoid any direct reclaim.
113*4882a593Smuzhiyun */
114*4882a593Smuzhiyun TRYALLOC,
115*4882a593Smuzhiyun };
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun /*
118*4882a593Smuzhiyun * tagged pointer with 1-bit tag for all compressed pages
119*4882a593Smuzhiyun * tag 0 - the page is just found with an extra page reference
120*4882a593Smuzhiyun */
121*4882a593Smuzhiyun typedef tagptr1_t compressed_page_t;
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun #define tag_compressed_page_justfound(page) \
124*4882a593Smuzhiyun tagptr_fold(compressed_page_t, page, 1)
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun static struct workqueue_struct *z_erofs_workqueue __read_mostly;
127*4882a593Smuzhiyun
z_erofs_exit_zip_subsystem(void)128*4882a593Smuzhiyun void z_erofs_exit_zip_subsystem(void)
129*4882a593Smuzhiyun {
130*4882a593Smuzhiyun destroy_workqueue(z_erofs_workqueue);
131*4882a593Smuzhiyun z_erofs_destroy_pcluster_pool();
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun
z_erofs_init_workqueue(void)134*4882a593Smuzhiyun static inline int z_erofs_init_workqueue(void)
135*4882a593Smuzhiyun {
136*4882a593Smuzhiyun const unsigned int onlinecpus = num_possible_cpus();
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun /*
139*4882a593Smuzhiyun * no need to spawn too many threads, limiting threads could minimum
140*4882a593Smuzhiyun * scheduling overhead, perhaps per-CPU threads should be better?
141*4882a593Smuzhiyun */
142*4882a593Smuzhiyun z_erofs_workqueue = alloc_workqueue("erofs_unzipd",
143*4882a593Smuzhiyun WQ_UNBOUND | WQ_HIGHPRI,
144*4882a593Smuzhiyun onlinecpus + onlinecpus / 4);
145*4882a593Smuzhiyun return z_erofs_workqueue ? 0 : -ENOMEM;
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun
z_erofs_init_zip_subsystem(void)148*4882a593Smuzhiyun int __init z_erofs_init_zip_subsystem(void)
149*4882a593Smuzhiyun {
150*4882a593Smuzhiyun int err = z_erofs_create_pcluster_pool();
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun if (err)
153*4882a593Smuzhiyun return err;
154*4882a593Smuzhiyun err = z_erofs_init_workqueue();
155*4882a593Smuzhiyun if (err)
156*4882a593Smuzhiyun z_erofs_destroy_pcluster_pool();
157*4882a593Smuzhiyun return err;
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun enum z_erofs_collectmode {
161*4882a593Smuzhiyun COLLECT_SECONDARY,
162*4882a593Smuzhiyun COLLECT_PRIMARY,
163*4882a593Smuzhiyun /*
164*4882a593Smuzhiyun * The current collection was the tail of an exist chain, in addition
165*4882a593Smuzhiyun * that the previous processed chained collections are all decided to
166*4882a593Smuzhiyun * be hooked up to it.
167*4882a593Smuzhiyun * A new chain will be created for the remaining collections which are
168*4882a593Smuzhiyun * not processed yet, therefore different from COLLECT_PRIMARY_FOLLOWED,
169*4882a593Smuzhiyun * the next collection cannot reuse the whole page safely in
170*4882a593Smuzhiyun * the following scenario:
171*4882a593Smuzhiyun * ________________________________________________________________
172*4882a593Smuzhiyun * | tail (partial) page | head (partial) page |
173*4882a593Smuzhiyun * | (belongs to the next cl) | (belongs to the current cl) |
174*4882a593Smuzhiyun * |_______PRIMARY_FOLLOWED_______|________PRIMARY_HOOKED___________|
175*4882a593Smuzhiyun */
176*4882a593Smuzhiyun COLLECT_PRIMARY_HOOKED,
177*4882a593Smuzhiyun /*
178*4882a593Smuzhiyun * a weak form of COLLECT_PRIMARY_FOLLOWED, the difference is that it
179*4882a593Smuzhiyun * could be dispatched into bypass queue later due to uptodated managed
180*4882a593Smuzhiyun * pages. All related online pages cannot be reused for inplace I/O (or
181*4882a593Smuzhiyun * pagevec) since it can be directly decoded without I/O submission.
182*4882a593Smuzhiyun */
183*4882a593Smuzhiyun COLLECT_PRIMARY_FOLLOWED_NOINPLACE,
184*4882a593Smuzhiyun /*
185*4882a593Smuzhiyun * The current collection has been linked with the owned chain, and
186*4882a593Smuzhiyun * could also be linked with the remaining collections, which means
187*4882a593Smuzhiyun * if the processing page is the tail page of the collection, thus
188*4882a593Smuzhiyun * the current collection can safely use the whole page (since
189*4882a593Smuzhiyun * the previous collection is under control) for in-place I/O, as
190*4882a593Smuzhiyun * illustrated below:
191*4882a593Smuzhiyun * ________________________________________________________________
192*4882a593Smuzhiyun * | tail (partial) page | head (partial) page |
193*4882a593Smuzhiyun * | (of the current cl) | (of the previous collection) |
194*4882a593Smuzhiyun * | PRIMARY_FOLLOWED or | |
195*4882a593Smuzhiyun * |_____PRIMARY_HOOKED___|____________PRIMARY_FOLLOWED____________|
196*4882a593Smuzhiyun *
197*4882a593Smuzhiyun * [ (*) the above page can be used as inplace I/O. ]
198*4882a593Smuzhiyun */
199*4882a593Smuzhiyun COLLECT_PRIMARY_FOLLOWED,
200*4882a593Smuzhiyun };
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun struct z_erofs_collector {
203*4882a593Smuzhiyun struct z_erofs_pagevec_ctor vector;
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun struct z_erofs_pcluster *pcl, *tailpcl;
206*4882a593Smuzhiyun struct z_erofs_collection *cl;
207*4882a593Smuzhiyun /* a pointer used to pick up inplace I/O pages */
208*4882a593Smuzhiyun struct page **icpage_ptr;
209*4882a593Smuzhiyun z_erofs_next_pcluster_t owned_head;
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun enum z_erofs_collectmode mode;
212*4882a593Smuzhiyun };
213*4882a593Smuzhiyun
214*4882a593Smuzhiyun struct z_erofs_decompress_frontend {
215*4882a593Smuzhiyun struct inode *const inode;
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun struct z_erofs_collector clt;
218*4882a593Smuzhiyun struct erofs_map_blocks map;
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun bool readahead;
221*4882a593Smuzhiyun /* used for applying cache strategy on the fly */
222*4882a593Smuzhiyun bool backmost;
223*4882a593Smuzhiyun erofs_off_t headoffset;
224*4882a593Smuzhiyun };
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun #define COLLECTOR_INIT() { \
227*4882a593Smuzhiyun .owned_head = Z_EROFS_PCLUSTER_TAIL, \
228*4882a593Smuzhiyun .mode = COLLECT_PRIMARY_FOLLOWED }
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun #define DECOMPRESS_FRONTEND_INIT(__i) { \
231*4882a593Smuzhiyun .inode = __i, .clt = COLLECTOR_INIT(), \
232*4882a593Smuzhiyun .backmost = true, }
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun static struct page *z_pagemap_global[Z_EROFS_VMAP_GLOBAL_PAGES];
235*4882a593Smuzhiyun static DEFINE_MUTEX(z_pagemap_global_lock);
236*4882a593Smuzhiyun
preload_compressed_pages(struct z_erofs_collector * clt,struct address_space * mc,enum z_erofs_cache_alloctype type,struct list_head * pagepool)237*4882a593Smuzhiyun static void preload_compressed_pages(struct z_erofs_collector *clt,
238*4882a593Smuzhiyun struct address_space *mc,
239*4882a593Smuzhiyun enum z_erofs_cache_alloctype type,
240*4882a593Smuzhiyun struct list_head *pagepool)
241*4882a593Smuzhiyun {
242*4882a593Smuzhiyun struct z_erofs_pcluster *pcl = clt->pcl;
243*4882a593Smuzhiyun bool standalone = true;
244*4882a593Smuzhiyun gfp_t gfp = (mapping_gfp_mask(mc) & ~__GFP_DIRECT_RECLAIM) |
245*4882a593Smuzhiyun __GFP_NOMEMALLOC | __GFP_NORETRY | __GFP_NOWARN;
246*4882a593Smuzhiyun struct page **pages;
247*4882a593Smuzhiyun pgoff_t index;
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun if (clt->mode < COLLECT_PRIMARY_FOLLOWED)
250*4882a593Smuzhiyun return;
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun pages = pcl->compressed_pages;
253*4882a593Smuzhiyun index = pcl->obj.index;
254*4882a593Smuzhiyun for (; index < pcl->obj.index + pcl->pclusterpages; ++index, ++pages) {
255*4882a593Smuzhiyun struct page *page;
256*4882a593Smuzhiyun compressed_page_t t;
257*4882a593Smuzhiyun struct page *newpage = NULL;
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun /* the compressed page was loaded before */
260*4882a593Smuzhiyun if (READ_ONCE(*pages))
261*4882a593Smuzhiyun continue;
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun page = find_get_page(mc, index);
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun if (page) {
266*4882a593Smuzhiyun t = tag_compressed_page_justfound(page);
267*4882a593Smuzhiyun } else {
268*4882a593Smuzhiyun /* I/O is needed, no possible to decompress directly */
269*4882a593Smuzhiyun standalone = false;
270*4882a593Smuzhiyun switch (type) {
271*4882a593Smuzhiyun case DELAYEDALLOC:
272*4882a593Smuzhiyun t = tagptr_init(compressed_page_t,
273*4882a593Smuzhiyun PAGE_UNALLOCATED);
274*4882a593Smuzhiyun break;
275*4882a593Smuzhiyun case TRYALLOC:
276*4882a593Smuzhiyun newpage = erofs_allocpage(pagepool, gfp);
277*4882a593Smuzhiyun if (!newpage)
278*4882a593Smuzhiyun continue;
279*4882a593Smuzhiyun set_page_private(newpage,
280*4882a593Smuzhiyun Z_EROFS_PREALLOCATED_PAGE);
281*4882a593Smuzhiyun t = tag_compressed_page_justfound(newpage);
282*4882a593Smuzhiyun break;
283*4882a593Smuzhiyun default: /* DONTALLOC */
284*4882a593Smuzhiyun continue;
285*4882a593Smuzhiyun }
286*4882a593Smuzhiyun }
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun if (!cmpxchg_relaxed(pages, NULL, tagptr_cast_ptr(t)))
289*4882a593Smuzhiyun continue;
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun if (page) {
292*4882a593Smuzhiyun put_page(page);
293*4882a593Smuzhiyun } else if (newpage) {
294*4882a593Smuzhiyun set_page_private(newpage, 0);
295*4882a593Smuzhiyun list_add(&newpage->lru, pagepool);
296*4882a593Smuzhiyun }
297*4882a593Smuzhiyun }
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun /*
300*4882a593Smuzhiyun * don't do inplace I/O if all compressed pages are available in
301*4882a593Smuzhiyun * managed cache since it can be moved to the bypass queue instead.
302*4882a593Smuzhiyun */
303*4882a593Smuzhiyun if (standalone)
304*4882a593Smuzhiyun clt->mode = COLLECT_PRIMARY_FOLLOWED_NOINPLACE;
305*4882a593Smuzhiyun }
306*4882a593Smuzhiyun
307*4882a593Smuzhiyun /* called by erofs_shrinker to get rid of all compressed_pages */
erofs_try_to_free_all_cached_pages(struct erofs_sb_info * sbi,struct erofs_workgroup * grp)308*4882a593Smuzhiyun int erofs_try_to_free_all_cached_pages(struct erofs_sb_info *sbi,
309*4882a593Smuzhiyun struct erofs_workgroup *grp)
310*4882a593Smuzhiyun {
311*4882a593Smuzhiyun struct z_erofs_pcluster *const pcl =
312*4882a593Smuzhiyun container_of(grp, struct z_erofs_pcluster, obj);
313*4882a593Smuzhiyun struct address_space *const mapping = MNGD_MAPPING(sbi);
314*4882a593Smuzhiyun int i;
315*4882a593Smuzhiyun
316*4882a593Smuzhiyun /*
317*4882a593Smuzhiyun * refcount of workgroup is now freezed as 1,
318*4882a593Smuzhiyun * therefore no need to worry about available decompression users.
319*4882a593Smuzhiyun */
320*4882a593Smuzhiyun for (i = 0; i < pcl->pclusterpages; ++i) {
321*4882a593Smuzhiyun struct page *page = pcl->compressed_pages[i];
322*4882a593Smuzhiyun
323*4882a593Smuzhiyun if (!page)
324*4882a593Smuzhiyun continue;
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun /* block other users from reclaiming or migrating the page */
327*4882a593Smuzhiyun if (!trylock_page(page))
328*4882a593Smuzhiyun return -EBUSY;
329*4882a593Smuzhiyun
330*4882a593Smuzhiyun if (page->mapping != mapping)
331*4882a593Smuzhiyun continue;
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun /* barrier is implied in the following 'unlock_page' */
334*4882a593Smuzhiyun WRITE_ONCE(pcl->compressed_pages[i], NULL);
335*4882a593Smuzhiyun detach_page_private(page);
336*4882a593Smuzhiyun unlock_page(page);
337*4882a593Smuzhiyun }
338*4882a593Smuzhiyun return 0;
339*4882a593Smuzhiyun }
340*4882a593Smuzhiyun
erofs_try_to_free_cached_page(struct address_space * mapping,struct page * page)341*4882a593Smuzhiyun int erofs_try_to_free_cached_page(struct address_space *mapping,
342*4882a593Smuzhiyun struct page *page)
343*4882a593Smuzhiyun {
344*4882a593Smuzhiyun struct z_erofs_pcluster *const pcl = (void *)page_private(page);
345*4882a593Smuzhiyun int ret = 0; /* 0 - busy */
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun if (erofs_workgroup_try_to_freeze(&pcl->obj, 1)) {
348*4882a593Smuzhiyun unsigned int i;
349*4882a593Smuzhiyun
350*4882a593Smuzhiyun for (i = 0; i < pcl->pclusterpages; ++i) {
351*4882a593Smuzhiyun if (pcl->compressed_pages[i] == page) {
352*4882a593Smuzhiyun WRITE_ONCE(pcl->compressed_pages[i], NULL);
353*4882a593Smuzhiyun ret = 1;
354*4882a593Smuzhiyun break;
355*4882a593Smuzhiyun }
356*4882a593Smuzhiyun }
357*4882a593Smuzhiyun erofs_workgroup_unfreeze(&pcl->obj, 1);
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun if (ret)
360*4882a593Smuzhiyun detach_page_private(page);
361*4882a593Smuzhiyun }
362*4882a593Smuzhiyun return ret;
363*4882a593Smuzhiyun }
364*4882a593Smuzhiyun
365*4882a593Smuzhiyun /* page_type must be Z_EROFS_PAGE_TYPE_EXCLUSIVE */
z_erofs_try_inplace_io(struct z_erofs_collector * clt,struct page * page)366*4882a593Smuzhiyun static bool z_erofs_try_inplace_io(struct z_erofs_collector *clt,
367*4882a593Smuzhiyun struct page *page)
368*4882a593Smuzhiyun {
369*4882a593Smuzhiyun struct z_erofs_pcluster *const pcl = clt->pcl;
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun while (clt->icpage_ptr > pcl->compressed_pages)
372*4882a593Smuzhiyun if (!cmpxchg(--clt->icpage_ptr, NULL, page))
373*4882a593Smuzhiyun return true;
374*4882a593Smuzhiyun return false;
375*4882a593Smuzhiyun }
376*4882a593Smuzhiyun
377*4882a593Smuzhiyun /* callers must be with collection lock held */
z_erofs_attach_page(struct z_erofs_collector * clt,struct page * page,enum z_erofs_page_type type,bool pvec_safereuse)378*4882a593Smuzhiyun static int z_erofs_attach_page(struct z_erofs_collector *clt,
379*4882a593Smuzhiyun struct page *page, enum z_erofs_page_type type,
380*4882a593Smuzhiyun bool pvec_safereuse)
381*4882a593Smuzhiyun {
382*4882a593Smuzhiyun int ret;
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun /* give priority for inplaceio */
385*4882a593Smuzhiyun if (clt->mode >= COLLECT_PRIMARY &&
386*4882a593Smuzhiyun type == Z_EROFS_PAGE_TYPE_EXCLUSIVE &&
387*4882a593Smuzhiyun z_erofs_try_inplace_io(clt, page))
388*4882a593Smuzhiyun return 0;
389*4882a593Smuzhiyun
390*4882a593Smuzhiyun ret = z_erofs_pagevec_enqueue(&clt->vector, page, type,
391*4882a593Smuzhiyun pvec_safereuse);
392*4882a593Smuzhiyun clt->cl->vcnt += (unsigned int)ret;
393*4882a593Smuzhiyun return ret ? 0 : -EAGAIN;
394*4882a593Smuzhiyun }
395*4882a593Smuzhiyun
396*4882a593Smuzhiyun static enum z_erofs_collectmode
try_to_claim_pcluster(struct z_erofs_pcluster * pcl,z_erofs_next_pcluster_t * owned_head)397*4882a593Smuzhiyun try_to_claim_pcluster(struct z_erofs_pcluster *pcl,
398*4882a593Smuzhiyun z_erofs_next_pcluster_t *owned_head)
399*4882a593Smuzhiyun {
400*4882a593Smuzhiyun /* let's claim these following types of pclusters */
401*4882a593Smuzhiyun retry:
402*4882a593Smuzhiyun if (pcl->next == Z_EROFS_PCLUSTER_NIL) {
403*4882a593Smuzhiyun /* type 1, nil pcluster */
404*4882a593Smuzhiyun if (cmpxchg(&pcl->next, Z_EROFS_PCLUSTER_NIL,
405*4882a593Smuzhiyun *owned_head) != Z_EROFS_PCLUSTER_NIL)
406*4882a593Smuzhiyun goto retry;
407*4882a593Smuzhiyun
408*4882a593Smuzhiyun *owned_head = &pcl->next;
409*4882a593Smuzhiyun /* lucky, I am the followee :) */
410*4882a593Smuzhiyun return COLLECT_PRIMARY_FOLLOWED;
411*4882a593Smuzhiyun } else if (pcl->next == Z_EROFS_PCLUSTER_TAIL) {
412*4882a593Smuzhiyun /*
413*4882a593Smuzhiyun * type 2, link to the end of a existing open chain,
414*4882a593Smuzhiyun * be careful that its submission itself is governed
415*4882a593Smuzhiyun * by the original owned chain.
416*4882a593Smuzhiyun */
417*4882a593Smuzhiyun if (cmpxchg(&pcl->next, Z_EROFS_PCLUSTER_TAIL,
418*4882a593Smuzhiyun *owned_head) != Z_EROFS_PCLUSTER_TAIL)
419*4882a593Smuzhiyun goto retry;
420*4882a593Smuzhiyun *owned_head = Z_EROFS_PCLUSTER_TAIL;
421*4882a593Smuzhiyun return COLLECT_PRIMARY_HOOKED;
422*4882a593Smuzhiyun }
423*4882a593Smuzhiyun return COLLECT_PRIMARY; /* :( better luck next time */
424*4882a593Smuzhiyun }
425*4882a593Smuzhiyun
z_erofs_lookup_collection(struct z_erofs_collector * clt,struct inode * inode,struct erofs_map_blocks * map)426*4882a593Smuzhiyun static int z_erofs_lookup_collection(struct z_erofs_collector *clt,
427*4882a593Smuzhiyun struct inode *inode,
428*4882a593Smuzhiyun struct erofs_map_blocks *map)
429*4882a593Smuzhiyun {
430*4882a593Smuzhiyun struct z_erofs_pcluster *pcl = clt->pcl;
431*4882a593Smuzhiyun struct z_erofs_collection *cl;
432*4882a593Smuzhiyun unsigned int length;
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun /* to avoid unexpected loop formed by corrupted images */
435*4882a593Smuzhiyun if (clt->owned_head == &pcl->next || pcl == clt->tailpcl) {
436*4882a593Smuzhiyun DBG_BUGON(1);
437*4882a593Smuzhiyun return -EFSCORRUPTED;
438*4882a593Smuzhiyun }
439*4882a593Smuzhiyun
440*4882a593Smuzhiyun cl = z_erofs_primarycollection(pcl);
441*4882a593Smuzhiyun if (cl->pageofs != (map->m_la & ~PAGE_MASK)) {
442*4882a593Smuzhiyun DBG_BUGON(1);
443*4882a593Smuzhiyun return -EFSCORRUPTED;
444*4882a593Smuzhiyun }
445*4882a593Smuzhiyun
446*4882a593Smuzhiyun length = READ_ONCE(pcl->length);
447*4882a593Smuzhiyun if (length & Z_EROFS_PCLUSTER_FULL_LENGTH) {
448*4882a593Smuzhiyun if ((map->m_llen << Z_EROFS_PCLUSTER_LENGTH_BIT) > length) {
449*4882a593Smuzhiyun DBG_BUGON(1);
450*4882a593Smuzhiyun return -EFSCORRUPTED;
451*4882a593Smuzhiyun }
452*4882a593Smuzhiyun } else {
453*4882a593Smuzhiyun unsigned int llen = map->m_llen << Z_EROFS_PCLUSTER_LENGTH_BIT;
454*4882a593Smuzhiyun
455*4882a593Smuzhiyun if (map->m_flags & EROFS_MAP_FULL_MAPPED)
456*4882a593Smuzhiyun llen |= Z_EROFS_PCLUSTER_FULL_LENGTH;
457*4882a593Smuzhiyun
458*4882a593Smuzhiyun while (llen > length &&
459*4882a593Smuzhiyun length != cmpxchg_relaxed(&pcl->length, length, llen)) {
460*4882a593Smuzhiyun cpu_relax();
461*4882a593Smuzhiyun length = READ_ONCE(pcl->length);
462*4882a593Smuzhiyun }
463*4882a593Smuzhiyun }
464*4882a593Smuzhiyun mutex_lock(&cl->lock);
465*4882a593Smuzhiyun /* used to check tail merging loop due to corrupted images */
466*4882a593Smuzhiyun if (clt->owned_head == Z_EROFS_PCLUSTER_TAIL)
467*4882a593Smuzhiyun clt->tailpcl = pcl;
468*4882a593Smuzhiyun clt->mode = try_to_claim_pcluster(pcl, &clt->owned_head);
469*4882a593Smuzhiyun /* clean tailpcl if the current owned_head is Z_EROFS_PCLUSTER_TAIL */
470*4882a593Smuzhiyun if (clt->owned_head == Z_EROFS_PCLUSTER_TAIL)
471*4882a593Smuzhiyun clt->tailpcl = NULL;
472*4882a593Smuzhiyun clt->cl = cl;
473*4882a593Smuzhiyun return 0;
474*4882a593Smuzhiyun }
475*4882a593Smuzhiyun
z_erofs_register_collection(struct z_erofs_collector * clt,struct inode * inode,struct erofs_map_blocks * map)476*4882a593Smuzhiyun static int z_erofs_register_collection(struct z_erofs_collector *clt,
477*4882a593Smuzhiyun struct inode *inode,
478*4882a593Smuzhiyun struct erofs_map_blocks *map)
479*4882a593Smuzhiyun {
480*4882a593Smuzhiyun struct z_erofs_pcluster *pcl;
481*4882a593Smuzhiyun struct z_erofs_collection *cl;
482*4882a593Smuzhiyun struct erofs_workgroup *grp;
483*4882a593Smuzhiyun int err;
484*4882a593Smuzhiyun
485*4882a593Smuzhiyun /* no available pcluster, let's allocate one */
486*4882a593Smuzhiyun pcl = z_erofs_alloc_pcluster(map->m_plen >> PAGE_SHIFT);
487*4882a593Smuzhiyun if (IS_ERR(pcl))
488*4882a593Smuzhiyun return PTR_ERR(pcl);
489*4882a593Smuzhiyun
490*4882a593Smuzhiyun atomic_set(&pcl->obj.refcount, 1);
491*4882a593Smuzhiyun pcl->obj.index = map->m_pa >> PAGE_SHIFT;
492*4882a593Smuzhiyun
493*4882a593Smuzhiyun pcl->length = (map->m_llen << Z_EROFS_PCLUSTER_LENGTH_BIT) |
494*4882a593Smuzhiyun (map->m_flags & EROFS_MAP_FULL_MAPPED ?
495*4882a593Smuzhiyun Z_EROFS_PCLUSTER_FULL_LENGTH : 0);
496*4882a593Smuzhiyun
497*4882a593Smuzhiyun if (map->m_flags & EROFS_MAP_ZIPPED)
498*4882a593Smuzhiyun pcl->algorithmformat = Z_EROFS_COMPRESSION_LZ4;
499*4882a593Smuzhiyun else
500*4882a593Smuzhiyun pcl->algorithmformat = Z_EROFS_COMPRESSION_SHIFTED;
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun /* new pclusters should be claimed as type 1, primary and followed */
503*4882a593Smuzhiyun pcl->next = clt->owned_head;
504*4882a593Smuzhiyun clt->mode = COLLECT_PRIMARY_FOLLOWED;
505*4882a593Smuzhiyun
506*4882a593Smuzhiyun cl = z_erofs_primarycollection(pcl);
507*4882a593Smuzhiyun cl->pageofs = map->m_la & ~PAGE_MASK;
508*4882a593Smuzhiyun
509*4882a593Smuzhiyun /*
510*4882a593Smuzhiyun * lock all primary followed works before visible to others
511*4882a593Smuzhiyun * and mutex_trylock *never* fails for a new pcluster.
512*4882a593Smuzhiyun */
513*4882a593Smuzhiyun mutex_init(&cl->lock);
514*4882a593Smuzhiyun DBG_BUGON(!mutex_trylock(&cl->lock));
515*4882a593Smuzhiyun
516*4882a593Smuzhiyun grp = erofs_insert_workgroup(inode->i_sb, &pcl->obj);
517*4882a593Smuzhiyun if (IS_ERR(grp)) {
518*4882a593Smuzhiyun err = PTR_ERR(grp);
519*4882a593Smuzhiyun goto err_out;
520*4882a593Smuzhiyun }
521*4882a593Smuzhiyun
522*4882a593Smuzhiyun if (grp != &pcl->obj) {
523*4882a593Smuzhiyun clt->pcl = container_of(grp, struct z_erofs_pcluster, obj);
524*4882a593Smuzhiyun err = -EEXIST;
525*4882a593Smuzhiyun goto err_out;
526*4882a593Smuzhiyun }
527*4882a593Smuzhiyun /* used to check tail merging loop due to corrupted images */
528*4882a593Smuzhiyun if (clt->owned_head == Z_EROFS_PCLUSTER_TAIL)
529*4882a593Smuzhiyun clt->tailpcl = pcl;
530*4882a593Smuzhiyun clt->owned_head = &pcl->next;
531*4882a593Smuzhiyun clt->pcl = pcl;
532*4882a593Smuzhiyun clt->cl = cl;
533*4882a593Smuzhiyun return 0;
534*4882a593Smuzhiyun
535*4882a593Smuzhiyun err_out:
536*4882a593Smuzhiyun mutex_unlock(&cl->lock);
537*4882a593Smuzhiyun z_erofs_free_pcluster(pcl);
538*4882a593Smuzhiyun return err;
539*4882a593Smuzhiyun }
540*4882a593Smuzhiyun
z_erofs_collector_begin(struct z_erofs_collector * clt,struct inode * inode,struct erofs_map_blocks * map)541*4882a593Smuzhiyun static int z_erofs_collector_begin(struct z_erofs_collector *clt,
542*4882a593Smuzhiyun struct inode *inode,
543*4882a593Smuzhiyun struct erofs_map_blocks *map)
544*4882a593Smuzhiyun {
545*4882a593Smuzhiyun struct erofs_workgroup *grp;
546*4882a593Smuzhiyun int ret;
547*4882a593Smuzhiyun
548*4882a593Smuzhiyun DBG_BUGON(clt->cl);
549*4882a593Smuzhiyun
550*4882a593Smuzhiyun /* must be Z_EROFS_PCLUSTER_TAIL or pointed to previous collection */
551*4882a593Smuzhiyun DBG_BUGON(clt->owned_head == Z_EROFS_PCLUSTER_NIL);
552*4882a593Smuzhiyun DBG_BUGON(clt->owned_head == Z_EROFS_PCLUSTER_TAIL_CLOSED);
553*4882a593Smuzhiyun
554*4882a593Smuzhiyun if (!PAGE_ALIGNED(map->m_pa)) {
555*4882a593Smuzhiyun DBG_BUGON(1);
556*4882a593Smuzhiyun return -EINVAL;
557*4882a593Smuzhiyun }
558*4882a593Smuzhiyun
559*4882a593Smuzhiyun grp = erofs_find_workgroup(inode->i_sb, map->m_pa >> PAGE_SHIFT);
560*4882a593Smuzhiyun if (grp) {
561*4882a593Smuzhiyun clt->pcl = container_of(grp, struct z_erofs_pcluster, obj);
562*4882a593Smuzhiyun } else {
563*4882a593Smuzhiyun ret = z_erofs_register_collection(clt, inode, map);
564*4882a593Smuzhiyun
565*4882a593Smuzhiyun if (!ret)
566*4882a593Smuzhiyun goto out;
567*4882a593Smuzhiyun if (ret != -EEXIST)
568*4882a593Smuzhiyun return ret;
569*4882a593Smuzhiyun }
570*4882a593Smuzhiyun
571*4882a593Smuzhiyun ret = z_erofs_lookup_collection(clt, inode, map);
572*4882a593Smuzhiyun if (ret) {
573*4882a593Smuzhiyun erofs_workgroup_put(&clt->pcl->obj);
574*4882a593Smuzhiyun return ret;
575*4882a593Smuzhiyun }
576*4882a593Smuzhiyun
577*4882a593Smuzhiyun out:
578*4882a593Smuzhiyun z_erofs_pagevec_ctor_init(&clt->vector, Z_EROFS_NR_INLINE_PAGEVECS,
579*4882a593Smuzhiyun clt->cl->pagevec, clt->cl->vcnt);
580*4882a593Smuzhiyun
581*4882a593Smuzhiyun /* since file-backed online pages are traversed in reverse order */
582*4882a593Smuzhiyun clt->icpage_ptr = clt->pcl->compressed_pages + clt->pcl->pclusterpages;
583*4882a593Smuzhiyun return 0;
584*4882a593Smuzhiyun }
585*4882a593Smuzhiyun
586*4882a593Smuzhiyun /*
587*4882a593Smuzhiyun * keep in mind that no referenced pclusters will be freed
588*4882a593Smuzhiyun * only after a RCU grace period.
589*4882a593Smuzhiyun */
z_erofs_rcu_callback(struct rcu_head * head)590*4882a593Smuzhiyun static void z_erofs_rcu_callback(struct rcu_head *head)
591*4882a593Smuzhiyun {
592*4882a593Smuzhiyun struct z_erofs_collection *const cl =
593*4882a593Smuzhiyun container_of(head, struct z_erofs_collection, rcu);
594*4882a593Smuzhiyun
595*4882a593Smuzhiyun z_erofs_free_pcluster(container_of(cl, struct z_erofs_pcluster,
596*4882a593Smuzhiyun primary_collection));
597*4882a593Smuzhiyun }
598*4882a593Smuzhiyun
erofs_workgroup_free_rcu(struct erofs_workgroup * grp)599*4882a593Smuzhiyun void erofs_workgroup_free_rcu(struct erofs_workgroup *grp)
600*4882a593Smuzhiyun {
601*4882a593Smuzhiyun struct z_erofs_pcluster *const pcl =
602*4882a593Smuzhiyun container_of(grp, struct z_erofs_pcluster, obj);
603*4882a593Smuzhiyun struct z_erofs_collection *const cl = z_erofs_primarycollection(pcl);
604*4882a593Smuzhiyun
605*4882a593Smuzhiyun call_rcu(&cl->rcu, z_erofs_rcu_callback);
606*4882a593Smuzhiyun }
607*4882a593Smuzhiyun
z_erofs_collection_put(struct z_erofs_collection * cl)608*4882a593Smuzhiyun static void z_erofs_collection_put(struct z_erofs_collection *cl)
609*4882a593Smuzhiyun {
610*4882a593Smuzhiyun struct z_erofs_pcluster *const pcl =
611*4882a593Smuzhiyun container_of(cl, struct z_erofs_pcluster, primary_collection);
612*4882a593Smuzhiyun
613*4882a593Smuzhiyun erofs_workgroup_put(&pcl->obj);
614*4882a593Smuzhiyun }
615*4882a593Smuzhiyun
z_erofs_collector_end(struct z_erofs_collector * clt)616*4882a593Smuzhiyun static bool z_erofs_collector_end(struct z_erofs_collector *clt)
617*4882a593Smuzhiyun {
618*4882a593Smuzhiyun struct z_erofs_collection *cl = clt->cl;
619*4882a593Smuzhiyun
620*4882a593Smuzhiyun if (!cl)
621*4882a593Smuzhiyun return false;
622*4882a593Smuzhiyun
623*4882a593Smuzhiyun z_erofs_pagevec_ctor_exit(&clt->vector, false);
624*4882a593Smuzhiyun mutex_unlock(&cl->lock);
625*4882a593Smuzhiyun
626*4882a593Smuzhiyun /*
627*4882a593Smuzhiyun * if all pending pages are added, don't hold its reference
628*4882a593Smuzhiyun * any longer if the pcluster isn't hosted by ourselves.
629*4882a593Smuzhiyun */
630*4882a593Smuzhiyun if (clt->mode < COLLECT_PRIMARY_FOLLOWED_NOINPLACE)
631*4882a593Smuzhiyun z_erofs_collection_put(cl);
632*4882a593Smuzhiyun
633*4882a593Smuzhiyun clt->cl = NULL;
634*4882a593Smuzhiyun return true;
635*4882a593Smuzhiyun }
636*4882a593Smuzhiyun
should_alloc_managed_pages(struct z_erofs_decompress_frontend * fe,unsigned int cachestrategy,erofs_off_t la)637*4882a593Smuzhiyun static bool should_alloc_managed_pages(struct z_erofs_decompress_frontend *fe,
638*4882a593Smuzhiyun unsigned int cachestrategy,
639*4882a593Smuzhiyun erofs_off_t la)
640*4882a593Smuzhiyun {
641*4882a593Smuzhiyun if (cachestrategy <= EROFS_ZIP_CACHE_DISABLED)
642*4882a593Smuzhiyun return false;
643*4882a593Smuzhiyun
644*4882a593Smuzhiyun if (fe->backmost)
645*4882a593Smuzhiyun return true;
646*4882a593Smuzhiyun
647*4882a593Smuzhiyun return cachestrategy >= EROFS_ZIP_CACHE_READAROUND &&
648*4882a593Smuzhiyun la < fe->headoffset;
649*4882a593Smuzhiyun }
650*4882a593Smuzhiyun
z_erofs_do_read_page(struct z_erofs_decompress_frontend * fe,struct page * page,struct list_head * pagepool)651*4882a593Smuzhiyun static int z_erofs_do_read_page(struct z_erofs_decompress_frontend *fe,
652*4882a593Smuzhiyun struct page *page, struct list_head *pagepool)
653*4882a593Smuzhiyun {
654*4882a593Smuzhiyun struct inode *const inode = fe->inode;
655*4882a593Smuzhiyun struct erofs_sb_info *const sbi = EROFS_I_SB(inode);
656*4882a593Smuzhiyun struct erofs_map_blocks *const map = &fe->map;
657*4882a593Smuzhiyun struct z_erofs_collector *const clt = &fe->clt;
658*4882a593Smuzhiyun const loff_t offset = page_offset(page);
659*4882a593Smuzhiyun bool tight = true;
660*4882a593Smuzhiyun
661*4882a593Smuzhiyun enum z_erofs_cache_alloctype cache_strategy;
662*4882a593Smuzhiyun enum z_erofs_page_type page_type;
663*4882a593Smuzhiyun unsigned int cur, end, spiltted, index;
664*4882a593Smuzhiyun int err = 0;
665*4882a593Smuzhiyun
666*4882a593Smuzhiyun /* register locked file pages as online pages in pack */
667*4882a593Smuzhiyun z_erofs_onlinepage_init(page);
668*4882a593Smuzhiyun
669*4882a593Smuzhiyun spiltted = 0;
670*4882a593Smuzhiyun end = PAGE_SIZE;
671*4882a593Smuzhiyun repeat:
672*4882a593Smuzhiyun cur = end - 1;
673*4882a593Smuzhiyun
674*4882a593Smuzhiyun /* lucky, within the range of the current map_blocks */
675*4882a593Smuzhiyun if (offset + cur >= map->m_la &&
676*4882a593Smuzhiyun offset + cur < map->m_la + map->m_llen) {
677*4882a593Smuzhiyun /* didn't get a valid collection previously (very rare) */
678*4882a593Smuzhiyun if (!clt->cl)
679*4882a593Smuzhiyun goto restart_now;
680*4882a593Smuzhiyun goto hitted;
681*4882a593Smuzhiyun }
682*4882a593Smuzhiyun
683*4882a593Smuzhiyun /* go ahead the next map_blocks */
684*4882a593Smuzhiyun erofs_dbg("%s: [out-of-range] pos %llu", __func__, offset + cur);
685*4882a593Smuzhiyun
686*4882a593Smuzhiyun if (z_erofs_collector_end(clt))
687*4882a593Smuzhiyun fe->backmost = false;
688*4882a593Smuzhiyun
689*4882a593Smuzhiyun map->m_la = offset + cur;
690*4882a593Smuzhiyun map->m_llen = 0;
691*4882a593Smuzhiyun err = z_erofs_map_blocks_iter(inode, map, 0);
692*4882a593Smuzhiyun if (err)
693*4882a593Smuzhiyun goto err_out;
694*4882a593Smuzhiyun
695*4882a593Smuzhiyun restart_now:
696*4882a593Smuzhiyun if (!(map->m_flags & EROFS_MAP_MAPPED))
697*4882a593Smuzhiyun goto hitted;
698*4882a593Smuzhiyun
699*4882a593Smuzhiyun err = z_erofs_collector_begin(clt, inode, map);
700*4882a593Smuzhiyun if (err)
701*4882a593Smuzhiyun goto err_out;
702*4882a593Smuzhiyun
703*4882a593Smuzhiyun /* preload all compressed pages (maybe downgrade role if necessary) */
704*4882a593Smuzhiyun if (should_alloc_managed_pages(fe, sbi->ctx.cache_strategy, map->m_la))
705*4882a593Smuzhiyun cache_strategy = TRYALLOC;
706*4882a593Smuzhiyun else
707*4882a593Smuzhiyun cache_strategy = DONTALLOC;
708*4882a593Smuzhiyun
709*4882a593Smuzhiyun preload_compressed_pages(clt, MNGD_MAPPING(sbi),
710*4882a593Smuzhiyun cache_strategy, pagepool);
711*4882a593Smuzhiyun
712*4882a593Smuzhiyun hitted:
713*4882a593Smuzhiyun /*
714*4882a593Smuzhiyun * Ensure the current partial page belongs to this submit chain rather
715*4882a593Smuzhiyun * than other concurrent submit chains or the noio(bypass) chain since
716*4882a593Smuzhiyun * those chains are handled asynchronously thus the page cannot be used
717*4882a593Smuzhiyun * for inplace I/O or pagevec (should be processed in strict order.)
718*4882a593Smuzhiyun */
719*4882a593Smuzhiyun tight &= (clt->mode >= COLLECT_PRIMARY_HOOKED &&
720*4882a593Smuzhiyun clt->mode != COLLECT_PRIMARY_FOLLOWED_NOINPLACE);
721*4882a593Smuzhiyun
722*4882a593Smuzhiyun cur = end - min_t(unsigned int, offset + end - map->m_la, end);
723*4882a593Smuzhiyun if (!(map->m_flags & EROFS_MAP_MAPPED)) {
724*4882a593Smuzhiyun zero_user_segment(page, cur, end);
725*4882a593Smuzhiyun goto next_part;
726*4882a593Smuzhiyun }
727*4882a593Smuzhiyun
728*4882a593Smuzhiyun /* let's derive page type */
729*4882a593Smuzhiyun page_type = cur ? Z_EROFS_VLE_PAGE_TYPE_HEAD :
730*4882a593Smuzhiyun (!spiltted ? Z_EROFS_PAGE_TYPE_EXCLUSIVE :
731*4882a593Smuzhiyun (tight ? Z_EROFS_PAGE_TYPE_EXCLUSIVE :
732*4882a593Smuzhiyun Z_EROFS_VLE_PAGE_TYPE_TAIL_SHARED));
733*4882a593Smuzhiyun
734*4882a593Smuzhiyun if (cur)
735*4882a593Smuzhiyun tight &= (clt->mode >= COLLECT_PRIMARY_FOLLOWED);
736*4882a593Smuzhiyun
737*4882a593Smuzhiyun retry:
738*4882a593Smuzhiyun err = z_erofs_attach_page(clt, page, page_type,
739*4882a593Smuzhiyun clt->mode >= COLLECT_PRIMARY_FOLLOWED);
740*4882a593Smuzhiyun /* should allocate an additional staging page for pagevec */
741*4882a593Smuzhiyun if (err == -EAGAIN) {
742*4882a593Smuzhiyun struct page *const newpage =
743*4882a593Smuzhiyun alloc_page(GFP_NOFS | __GFP_NOFAIL);
744*4882a593Smuzhiyun
745*4882a593Smuzhiyun set_page_private(newpage, Z_EROFS_SHORTLIVED_PAGE);
746*4882a593Smuzhiyun err = z_erofs_attach_page(clt, newpage,
747*4882a593Smuzhiyun Z_EROFS_PAGE_TYPE_EXCLUSIVE, true);
748*4882a593Smuzhiyun if (!err)
749*4882a593Smuzhiyun goto retry;
750*4882a593Smuzhiyun }
751*4882a593Smuzhiyun
752*4882a593Smuzhiyun if (err)
753*4882a593Smuzhiyun goto err_out;
754*4882a593Smuzhiyun
755*4882a593Smuzhiyun index = page->index - (map->m_la >> PAGE_SHIFT);
756*4882a593Smuzhiyun
757*4882a593Smuzhiyun z_erofs_onlinepage_fixup(page, index, true);
758*4882a593Smuzhiyun
759*4882a593Smuzhiyun /* bump up the number of spiltted parts of a page */
760*4882a593Smuzhiyun ++spiltted;
761*4882a593Smuzhiyun /* also update nr_pages */
762*4882a593Smuzhiyun clt->cl->nr_pages = max_t(pgoff_t, clt->cl->nr_pages, index + 1);
763*4882a593Smuzhiyun next_part:
764*4882a593Smuzhiyun /* can be used for verification */
765*4882a593Smuzhiyun map->m_llen = offset + cur - map->m_la;
766*4882a593Smuzhiyun
767*4882a593Smuzhiyun end = cur;
768*4882a593Smuzhiyun if (end > 0)
769*4882a593Smuzhiyun goto repeat;
770*4882a593Smuzhiyun
771*4882a593Smuzhiyun out:
772*4882a593Smuzhiyun z_erofs_onlinepage_endio(page);
773*4882a593Smuzhiyun
774*4882a593Smuzhiyun erofs_dbg("%s, finish page: %pK spiltted: %u map->m_llen %llu",
775*4882a593Smuzhiyun __func__, page, spiltted, map->m_llen);
776*4882a593Smuzhiyun return err;
777*4882a593Smuzhiyun
778*4882a593Smuzhiyun /* if some error occurred while processing this page */
779*4882a593Smuzhiyun err_out:
780*4882a593Smuzhiyun SetPageError(page);
781*4882a593Smuzhiyun goto out;
782*4882a593Smuzhiyun }
783*4882a593Smuzhiyun
784*4882a593Smuzhiyun static void z_erofs_decompressqueue_work(struct work_struct *work);
z_erofs_decompress_kickoff(struct z_erofs_decompressqueue * io,bool sync,int bios)785*4882a593Smuzhiyun static void z_erofs_decompress_kickoff(struct z_erofs_decompressqueue *io,
786*4882a593Smuzhiyun bool sync, int bios)
787*4882a593Smuzhiyun {
788*4882a593Smuzhiyun struct erofs_sb_info *const sbi = EROFS_SB(io->sb);
789*4882a593Smuzhiyun
790*4882a593Smuzhiyun /* wake up the caller thread for sync decompression */
791*4882a593Smuzhiyun if (sync) {
792*4882a593Smuzhiyun if (!atomic_add_return(bios, &io->pending_bios))
793*4882a593Smuzhiyun complete(&io->u.done);
794*4882a593Smuzhiyun
795*4882a593Smuzhiyun return;
796*4882a593Smuzhiyun }
797*4882a593Smuzhiyun
798*4882a593Smuzhiyun if (atomic_add_return(bios, &io->pending_bios))
799*4882a593Smuzhiyun return;
800*4882a593Smuzhiyun /* Use workqueue and sync decompression for atomic contexts only */
801*4882a593Smuzhiyun if (in_atomic() || irqs_disabled()) {
802*4882a593Smuzhiyun queue_work(z_erofs_workqueue, &io->u.work);
803*4882a593Smuzhiyun sbi->ctx.readahead_sync_decompress = true;
804*4882a593Smuzhiyun return;
805*4882a593Smuzhiyun }
806*4882a593Smuzhiyun z_erofs_decompressqueue_work(&io->u.work);
807*4882a593Smuzhiyun }
808*4882a593Smuzhiyun
z_erofs_page_is_invalidated(struct page * page)809*4882a593Smuzhiyun static bool z_erofs_page_is_invalidated(struct page *page)
810*4882a593Smuzhiyun {
811*4882a593Smuzhiyun return !page->mapping && !z_erofs_is_shortlived_page(page);
812*4882a593Smuzhiyun }
813*4882a593Smuzhiyun
z_erofs_decompressqueue_endio(struct bio * bio)814*4882a593Smuzhiyun static void z_erofs_decompressqueue_endio(struct bio *bio)
815*4882a593Smuzhiyun {
816*4882a593Smuzhiyun tagptr1_t t = tagptr_init(tagptr1_t, bio->bi_private);
817*4882a593Smuzhiyun struct z_erofs_decompressqueue *q = tagptr_unfold_ptr(t);
818*4882a593Smuzhiyun blk_status_t err = bio->bi_status;
819*4882a593Smuzhiyun struct bio_vec *bvec;
820*4882a593Smuzhiyun struct bvec_iter_all iter_all;
821*4882a593Smuzhiyun
822*4882a593Smuzhiyun bio_for_each_segment_all(bvec, bio, iter_all) {
823*4882a593Smuzhiyun struct page *page = bvec->bv_page;
824*4882a593Smuzhiyun
825*4882a593Smuzhiyun DBG_BUGON(PageUptodate(page));
826*4882a593Smuzhiyun DBG_BUGON(z_erofs_page_is_invalidated(page));
827*4882a593Smuzhiyun
828*4882a593Smuzhiyun if (err)
829*4882a593Smuzhiyun SetPageError(page);
830*4882a593Smuzhiyun
831*4882a593Smuzhiyun if (erofs_page_is_managed(EROFS_SB(q->sb), page)) {
832*4882a593Smuzhiyun if (!err)
833*4882a593Smuzhiyun SetPageUptodate(page);
834*4882a593Smuzhiyun unlock_page(page);
835*4882a593Smuzhiyun }
836*4882a593Smuzhiyun }
837*4882a593Smuzhiyun z_erofs_decompress_kickoff(q, tagptr_unfold_tags(t), -1);
838*4882a593Smuzhiyun bio_put(bio);
839*4882a593Smuzhiyun }
840*4882a593Smuzhiyun
z_erofs_decompress_pcluster(struct super_block * sb,struct z_erofs_pcluster * pcl,struct list_head * pagepool)841*4882a593Smuzhiyun static int z_erofs_decompress_pcluster(struct super_block *sb,
842*4882a593Smuzhiyun struct z_erofs_pcluster *pcl,
843*4882a593Smuzhiyun struct list_head *pagepool)
844*4882a593Smuzhiyun {
845*4882a593Smuzhiyun struct erofs_sb_info *const sbi = EROFS_SB(sb);
846*4882a593Smuzhiyun struct z_erofs_pagevec_ctor ctor;
847*4882a593Smuzhiyun unsigned int i, inputsize, outputsize, llen, nr_pages;
848*4882a593Smuzhiyun struct page *pages_onstack[Z_EROFS_VMAP_ONSTACK_PAGES];
849*4882a593Smuzhiyun struct page **pages, **compressed_pages, *page;
850*4882a593Smuzhiyun
851*4882a593Smuzhiyun enum z_erofs_page_type page_type;
852*4882a593Smuzhiyun bool overlapped, partial;
853*4882a593Smuzhiyun struct z_erofs_collection *cl;
854*4882a593Smuzhiyun int err;
855*4882a593Smuzhiyun
856*4882a593Smuzhiyun might_sleep();
857*4882a593Smuzhiyun cl = z_erofs_primarycollection(pcl);
858*4882a593Smuzhiyun DBG_BUGON(!READ_ONCE(cl->nr_pages));
859*4882a593Smuzhiyun
860*4882a593Smuzhiyun mutex_lock(&cl->lock);
861*4882a593Smuzhiyun nr_pages = cl->nr_pages;
862*4882a593Smuzhiyun
863*4882a593Smuzhiyun if (nr_pages <= Z_EROFS_VMAP_ONSTACK_PAGES) {
864*4882a593Smuzhiyun pages = pages_onstack;
865*4882a593Smuzhiyun } else if (nr_pages <= Z_EROFS_VMAP_GLOBAL_PAGES &&
866*4882a593Smuzhiyun mutex_trylock(&z_pagemap_global_lock)) {
867*4882a593Smuzhiyun pages = z_pagemap_global;
868*4882a593Smuzhiyun } else {
869*4882a593Smuzhiyun gfp_t gfp_flags = GFP_KERNEL;
870*4882a593Smuzhiyun
871*4882a593Smuzhiyun if (nr_pages > Z_EROFS_VMAP_GLOBAL_PAGES)
872*4882a593Smuzhiyun gfp_flags |= __GFP_NOFAIL;
873*4882a593Smuzhiyun
874*4882a593Smuzhiyun pages = kvmalloc_array(nr_pages, sizeof(struct page *),
875*4882a593Smuzhiyun gfp_flags);
876*4882a593Smuzhiyun
877*4882a593Smuzhiyun /* fallback to global pagemap for the lowmem scenario */
878*4882a593Smuzhiyun if (!pages) {
879*4882a593Smuzhiyun mutex_lock(&z_pagemap_global_lock);
880*4882a593Smuzhiyun pages = z_pagemap_global;
881*4882a593Smuzhiyun }
882*4882a593Smuzhiyun }
883*4882a593Smuzhiyun
884*4882a593Smuzhiyun for (i = 0; i < nr_pages; ++i)
885*4882a593Smuzhiyun pages[i] = NULL;
886*4882a593Smuzhiyun
887*4882a593Smuzhiyun err = 0;
888*4882a593Smuzhiyun z_erofs_pagevec_ctor_init(&ctor, Z_EROFS_NR_INLINE_PAGEVECS,
889*4882a593Smuzhiyun cl->pagevec, 0);
890*4882a593Smuzhiyun
891*4882a593Smuzhiyun for (i = 0; i < cl->vcnt; ++i) {
892*4882a593Smuzhiyun unsigned int pagenr;
893*4882a593Smuzhiyun
894*4882a593Smuzhiyun page = z_erofs_pagevec_dequeue(&ctor, &page_type);
895*4882a593Smuzhiyun
896*4882a593Smuzhiyun /* all pages in pagevec ought to be valid */
897*4882a593Smuzhiyun DBG_BUGON(!page);
898*4882a593Smuzhiyun DBG_BUGON(z_erofs_page_is_invalidated(page));
899*4882a593Smuzhiyun
900*4882a593Smuzhiyun if (z_erofs_put_shortlivedpage(pagepool, page))
901*4882a593Smuzhiyun continue;
902*4882a593Smuzhiyun
903*4882a593Smuzhiyun if (page_type == Z_EROFS_VLE_PAGE_TYPE_HEAD)
904*4882a593Smuzhiyun pagenr = 0;
905*4882a593Smuzhiyun else
906*4882a593Smuzhiyun pagenr = z_erofs_onlinepage_index(page);
907*4882a593Smuzhiyun
908*4882a593Smuzhiyun DBG_BUGON(pagenr >= nr_pages);
909*4882a593Smuzhiyun
910*4882a593Smuzhiyun /*
911*4882a593Smuzhiyun * currently EROFS doesn't support multiref(dedup),
912*4882a593Smuzhiyun * so here erroring out one multiref page.
913*4882a593Smuzhiyun */
914*4882a593Smuzhiyun if (pages[pagenr]) {
915*4882a593Smuzhiyun DBG_BUGON(1);
916*4882a593Smuzhiyun SetPageError(pages[pagenr]);
917*4882a593Smuzhiyun z_erofs_onlinepage_endio(pages[pagenr]);
918*4882a593Smuzhiyun err = -EFSCORRUPTED;
919*4882a593Smuzhiyun }
920*4882a593Smuzhiyun pages[pagenr] = page;
921*4882a593Smuzhiyun }
922*4882a593Smuzhiyun z_erofs_pagevec_ctor_exit(&ctor, true);
923*4882a593Smuzhiyun
924*4882a593Smuzhiyun overlapped = false;
925*4882a593Smuzhiyun compressed_pages = pcl->compressed_pages;
926*4882a593Smuzhiyun
927*4882a593Smuzhiyun for (i = 0; i < pcl->pclusterpages; ++i) {
928*4882a593Smuzhiyun unsigned int pagenr;
929*4882a593Smuzhiyun
930*4882a593Smuzhiyun page = compressed_pages[i];
931*4882a593Smuzhiyun
932*4882a593Smuzhiyun /* all compressed pages ought to be valid */
933*4882a593Smuzhiyun DBG_BUGON(!page);
934*4882a593Smuzhiyun DBG_BUGON(z_erofs_page_is_invalidated(page));
935*4882a593Smuzhiyun
936*4882a593Smuzhiyun if (!z_erofs_is_shortlived_page(page)) {
937*4882a593Smuzhiyun if (erofs_page_is_managed(sbi, page)) {
938*4882a593Smuzhiyun if (!PageUptodate(page))
939*4882a593Smuzhiyun err = -EIO;
940*4882a593Smuzhiyun continue;
941*4882a593Smuzhiyun }
942*4882a593Smuzhiyun
943*4882a593Smuzhiyun /*
944*4882a593Smuzhiyun * only if non-head page can be selected
945*4882a593Smuzhiyun * for inplace decompression
946*4882a593Smuzhiyun */
947*4882a593Smuzhiyun pagenr = z_erofs_onlinepage_index(page);
948*4882a593Smuzhiyun
949*4882a593Smuzhiyun DBG_BUGON(pagenr >= nr_pages);
950*4882a593Smuzhiyun if (pages[pagenr]) {
951*4882a593Smuzhiyun DBG_BUGON(1);
952*4882a593Smuzhiyun SetPageError(pages[pagenr]);
953*4882a593Smuzhiyun z_erofs_onlinepage_endio(pages[pagenr]);
954*4882a593Smuzhiyun err = -EFSCORRUPTED;
955*4882a593Smuzhiyun }
956*4882a593Smuzhiyun pages[pagenr] = page;
957*4882a593Smuzhiyun
958*4882a593Smuzhiyun overlapped = true;
959*4882a593Smuzhiyun }
960*4882a593Smuzhiyun
961*4882a593Smuzhiyun /* PG_error needs checking for all non-managed pages */
962*4882a593Smuzhiyun if (PageError(page)) {
963*4882a593Smuzhiyun DBG_BUGON(PageUptodate(page));
964*4882a593Smuzhiyun err = -EIO;
965*4882a593Smuzhiyun }
966*4882a593Smuzhiyun }
967*4882a593Smuzhiyun
968*4882a593Smuzhiyun if (err)
969*4882a593Smuzhiyun goto out;
970*4882a593Smuzhiyun
971*4882a593Smuzhiyun llen = pcl->length >> Z_EROFS_PCLUSTER_LENGTH_BIT;
972*4882a593Smuzhiyun if (nr_pages << PAGE_SHIFT >= cl->pageofs + llen) {
973*4882a593Smuzhiyun outputsize = llen;
974*4882a593Smuzhiyun partial = !(pcl->length & Z_EROFS_PCLUSTER_FULL_LENGTH);
975*4882a593Smuzhiyun } else {
976*4882a593Smuzhiyun outputsize = (nr_pages << PAGE_SHIFT) - cl->pageofs;
977*4882a593Smuzhiyun partial = true;
978*4882a593Smuzhiyun }
979*4882a593Smuzhiyun
980*4882a593Smuzhiyun inputsize = pcl->pclusterpages * PAGE_SIZE;
981*4882a593Smuzhiyun err = z_erofs_decompress(&(struct z_erofs_decompress_req) {
982*4882a593Smuzhiyun .sb = sb,
983*4882a593Smuzhiyun .in = compressed_pages,
984*4882a593Smuzhiyun .out = pages,
985*4882a593Smuzhiyun .pageofs_out = cl->pageofs,
986*4882a593Smuzhiyun .inputsize = inputsize,
987*4882a593Smuzhiyun .outputsize = outputsize,
988*4882a593Smuzhiyun .alg = pcl->algorithmformat,
989*4882a593Smuzhiyun .inplace_io = overlapped,
990*4882a593Smuzhiyun .partial_decoding = partial
991*4882a593Smuzhiyun }, pagepool);
992*4882a593Smuzhiyun
993*4882a593Smuzhiyun out:
994*4882a593Smuzhiyun /* must handle all compressed pages before ending pages */
995*4882a593Smuzhiyun for (i = 0; i < pcl->pclusterpages; ++i) {
996*4882a593Smuzhiyun page = compressed_pages[i];
997*4882a593Smuzhiyun
998*4882a593Smuzhiyun if (erofs_page_is_managed(sbi, page))
999*4882a593Smuzhiyun continue;
1000*4882a593Smuzhiyun
1001*4882a593Smuzhiyun /* recycle all individual short-lived pages */
1002*4882a593Smuzhiyun (void)z_erofs_put_shortlivedpage(pagepool, page);
1003*4882a593Smuzhiyun
1004*4882a593Smuzhiyun WRITE_ONCE(compressed_pages[i], NULL);
1005*4882a593Smuzhiyun }
1006*4882a593Smuzhiyun
1007*4882a593Smuzhiyun for (i = 0; i < nr_pages; ++i) {
1008*4882a593Smuzhiyun page = pages[i];
1009*4882a593Smuzhiyun if (!page)
1010*4882a593Smuzhiyun continue;
1011*4882a593Smuzhiyun
1012*4882a593Smuzhiyun DBG_BUGON(z_erofs_page_is_invalidated(page));
1013*4882a593Smuzhiyun
1014*4882a593Smuzhiyun /* recycle all individual short-lived pages */
1015*4882a593Smuzhiyun if (z_erofs_put_shortlivedpage(pagepool, page))
1016*4882a593Smuzhiyun continue;
1017*4882a593Smuzhiyun
1018*4882a593Smuzhiyun if (err < 0)
1019*4882a593Smuzhiyun SetPageError(page);
1020*4882a593Smuzhiyun
1021*4882a593Smuzhiyun z_erofs_onlinepage_endio(page);
1022*4882a593Smuzhiyun }
1023*4882a593Smuzhiyun
1024*4882a593Smuzhiyun if (pages == z_pagemap_global)
1025*4882a593Smuzhiyun mutex_unlock(&z_pagemap_global_lock);
1026*4882a593Smuzhiyun else if (pages != pages_onstack)
1027*4882a593Smuzhiyun kvfree(pages);
1028*4882a593Smuzhiyun
1029*4882a593Smuzhiyun cl->nr_pages = 0;
1030*4882a593Smuzhiyun cl->vcnt = 0;
1031*4882a593Smuzhiyun
1032*4882a593Smuzhiyun /* all cl locks MUST be taken before the following line */
1033*4882a593Smuzhiyun WRITE_ONCE(pcl->next, Z_EROFS_PCLUSTER_NIL);
1034*4882a593Smuzhiyun
1035*4882a593Smuzhiyun /* all cl locks SHOULD be released right now */
1036*4882a593Smuzhiyun mutex_unlock(&cl->lock);
1037*4882a593Smuzhiyun
1038*4882a593Smuzhiyun z_erofs_collection_put(cl);
1039*4882a593Smuzhiyun return err;
1040*4882a593Smuzhiyun }
1041*4882a593Smuzhiyun
z_erofs_decompress_queue(const struct z_erofs_decompressqueue * io,struct list_head * pagepool)1042*4882a593Smuzhiyun static void z_erofs_decompress_queue(const struct z_erofs_decompressqueue *io,
1043*4882a593Smuzhiyun struct list_head *pagepool)
1044*4882a593Smuzhiyun {
1045*4882a593Smuzhiyun z_erofs_next_pcluster_t owned = io->head;
1046*4882a593Smuzhiyun
1047*4882a593Smuzhiyun while (owned != Z_EROFS_PCLUSTER_TAIL_CLOSED) {
1048*4882a593Smuzhiyun struct z_erofs_pcluster *pcl;
1049*4882a593Smuzhiyun
1050*4882a593Smuzhiyun /* no possible that 'owned' equals Z_EROFS_WORK_TPTR_TAIL */
1051*4882a593Smuzhiyun DBG_BUGON(owned == Z_EROFS_PCLUSTER_TAIL);
1052*4882a593Smuzhiyun
1053*4882a593Smuzhiyun /* no possible that 'owned' equals NULL */
1054*4882a593Smuzhiyun DBG_BUGON(owned == Z_EROFS_PCLUSTER_NIL);
1055*4882a593Smuzhiyun
1056*4882a593Smuzhiyun pcl = container_of(owned, struct z_erofs_pcluster, next);
1057*4882a593Smuzhiyun owned = READ_ONCE(pcl->next);
1058*4882a593Smuzhiyun
1059*4882a593Smuzhiyun z_erofs_decompress_pcluster(io->sb, pcl, pagepool);
1060*4882a593Smuzhiyun }
1061*4882a593Smuzhiyun }
1062*4882a593Smuzhiyun
z_erofs_decompressqueue_work(struct work_struct * work)1063*4882a593Smuzhiyun static void z_erofs_decompressqueue_work(struct work_struct *work)
1064*4882a593Smuzhiyun {
1065*4882a593Smuzhiyun struct z_erofs_decompressqueue *bgq =
1066*4882a593Smuzhiyun container_of(work, struct z_erofs_decompressqueue, u.work);
1067*4882a593Smuzhiyun LIST_HEAD(pagepool);
1068*4882a593Smuzhiyun
1069*4882a593Smuzhiyun DBG_BUGON(bgq->head == Z_EROFS_PCLUSTER_TAIL_CLOSED);
1070*4882a593Smuzhiyun z_erofs_decompress_queue(bgq, &pagepool);
1071*4882a593Smuzhiyun
1072*4882a593Smuzhiyun put_pages_list(&pagepool);
1073*4882a593Smuzhiyun kvfree(bgq);
1074*4882a593Smuzhiyun }
1075*4882a593Smuzhiyun
pickup_page_for_submission(struct z_erofs_pcluster * pcl,unsigned int nr,struct list_head * pagepool,struct address_space * mc,gfp_t gfp)1076*4882a593Smuzhiyun static struct page *pickup_page_for_submission(struct z_erofs_pcluster *pcl,
1077*4882a593Smuzhiyun unsigned int nr,
1078*4882a593Smuzhiyun struct list_head *pagepool,
1079*4882a593Smuzhiyun struct address_space *mc,
1080*4882a593Smuzhiyun gfp_t gfp)
1081*4882a593Smuzhiyun {
1082*4882a593Smuzhiyun const pgoff_t index = pcl->obj.index;
1083*4882a593Smuzhiyun bool tocache = false;
1084*4882a593Smuzhiyun
1085*4882a593Smuzhiyun struct address_space *mapping;
1086*4882a593Smuzhiyun struct page *oldpage, *page;
1087*4882a593Smuzhiyun
1088*4882a593Smuzhiyun compressed_page_t t;
1089*4882a593Smuzhiyun int justfound;
1090*4882a593Smuzhiyun
1091*4882a593Smuzhiyun repeat:
1092*4882a593Smuzhiyun page = READ_ONCE(pcl->compressed_pages[nr]);
1093*4882a593Smuzhiyun oldpage = page;
1094*4882a593Smuzhiyun
1095*4882a593Smuzhiyun if (!page)
1096*4882a593Smuzhiyun goto out_allocpage;
1097*4882a593Smuzhiyun
1098*4882a593Smuzhiyun /*
1099*4882a593Smuzhiyun * the cached page has not been allocated and
1100*4882a593Smuzhiyun * an placeholder is out there, prepare it now.
1101*4882a593Smuzhiyun */
1102*4882a593Smuzhiyun if (page == PAGE_UNALLOCATED) {
1103*4882a593Smuzhiyun tocache = true;
1104*4882a593Smuzhiyun goto out_allocpage;
1105*4882a593Smuzhiyun }
1106*4882a593Smuzhiyun
1107*4882a593Smuzhiyun /* process the target tagged pointer */
1108*4882a593Smuzhiyun t = tagptr_init(compressed_page_t, page);
1109*4882a593Smuzhiyun justfound = tagptr_unfold_tags(t);
1110*4882a593Smuzhiyun page = tagptr_unfold_ptr(t);
1111*4882a593Smuzhiyun
1112*4882a593Smuzhiyun /*
1113*4882a593Smuzhiyun * preallocated cached pages, which is used to avoid direct reclaim
1114*4882a593Smuzhiyun * otherwise, it will go inplace I/O path instead.
1115*4882a593Smuzhiyun */
1116*4882a593Smuzhiyun if (page->private == Z_EROFS_PREALLOCATED_PAGE) {
1117*4882a593Smuzhiyun WRITE_ONCE(pcl->compressed_pages[nr], page);
1118*4882a593Smuzhiyun set_page_private(page, 0);
1119*4882a593Smuzhiyun tocache = true;
1120*4882a593Smuzhiyun goto out_tocache;
1121*4882a593Smuzhiyun }
1122*4882a593Smuzhiyun mapping = READ_ONCE(page->mapping);
1123*4882a593Smuzhiyun
1124*4882a593Smuzhiyun /*
1125*4882a593Smuzhiyun * file-backed online pages in plcuster are all locked steady,
1126*4882a593Smuzhiyun * therefore it is impossible for `mapping' to be NULL.
1127*4882a593Smuzhiyun */
1128*4882a593Smuzhiyun if (mapping && mapping != mc)
1129*4882a593Smuzhiyun /* ought to be unmanaged pages */
1130*4882a593Smuzhiyun goto out;
1131*4882a593Smuzhiyun
1132*4882a593Smuzhiyun /* directly return for shortlived page as well */
1133*4882a593Smuzhiyun if (z_erofs_is_shortlived_page(page))
1134*4882a593Smuzhiyun goto out;
1135*4882a593Smuzhiyun
1136*4882a593Smuzhiyun lock_page(page);
1137*4882a593Smuzhiyun
1138*4882a593Smuzhiyun /* only true if page reclaim goes wrong, should never happen */
1139*4882a593Smuzhiyun DBG_BUGON(justfound && PagePrivate(page));
1140*4882a593Smuzhiyun
1141*4882a593Smuzhiyun /* the page is still in manage cache */
1142*4882a593Smuzhiyun if (page->mapping == mc) {
1143*4882a593Smuzhiyun WRITE_ONCE(pcl->compressed_pages[nr], page);
1144*4882a593Smuzhiyun
1145*4882a593Smuzhiyun ClearPageError(page);
1146*4882a593Smuzhiyun if (!PagePrivate(page)) {
1147*4882a593Smuzhiyun /*
1148*4882a593Smuzhiyun * impossible to be !PagePrivate(page) for
1149*4882a593Smuzhiyun * the current restriction as well if
1150*4882a593Smuzhiyun * the page is already in compressed_pages[].
1151*4882a593Smuzhiyun */
1152*4882a593Smuzhiyun DBG_BUGON(!justfound);
1153*4882a593Smuzhiyun
1154*4882a593Smuzhiyun justfound = 0;
1155*4882a593Smuzhiyun set_page_private(page, (unsigned long)pcl);
1156*4882a593Smuzhiyun SetPagePrivate(page);
1157*4882a593Smuzhiyun }
1158*4882a593Smuzhiyun
1159*4882a593Smuzhiyun /* no need to submit io if it is already up-to-date */
1160*4882a593Smuzhiyun if (PageUptodate(page)) {
1161*4882a593Smuzhiyun unlock_page(page);
1162*4882a593Smuzhiyun page = NULL;
1163*4882a593Smuzhiyun }
1164*4882a593Smuzhiyun goto out;
1165*4882a593Smuzhiyun }
1166*4882a593Smuzhiyun
1167*4882a593Smuzhiyun /*
1168*4882a593Smuzhiyun * the managed page has been truncated, it's unsafe to
1169*4882a593Smuzhiyun * reuse this one, let's allocate a new cache-managed page.
1170*4882a593Smuzhiyun */
1171*4882a593Smuzhiyun DBG_BUGON(page->mapping);
1172*4882a593Smuzhiyun DBG_BUGON(!justfound);
1173*4882a593Smuzhiyun
1174*4882a593Smuzhiyun tocache = true;
1175*4882a593Smuzhiyun unlock_page(page);
1176*4882a593Smuzhiyun put_page(page);
1177*4882a593Smuzhiyun out_allocpage:
1178*4882a593Smuzhiyun page = erofs_allocpage(pagepool, gfp | __GFP_NOFAIL);
1179*4882a593Smuzhiyun if (oldpage != cmpxchg(&pcl->compressed_pages[nr], oldpage, page)) {
1180*4882a593Smuzhiyun list_add(&page->lru, pagepool);
1181*4882a593Smuzhiyun cond_resched();
1182*4882a593Smuzhiyun goto repeat;
1183*4882a593Smuzhiyun }
1184*4882a593Smuzhiyun out_tocache:
1185*4882a593Smuzhiyun if (!tocache || add_to_page_cache_lru(page, mc, index + nr, gfp)) {
1186*4882a593Smuzhiyun /* turn into temporary page if fails (1 ref) */
1187*4882a593Smuzhiyun set_page_private(page, Z_EROFS_SHORTLIVED_PAGE);
1188*4882a593Smuzhiyun goto out;
1189*4882a593Smuzhiyun }
1190*4882a593Smuzhiyun attach_page_private(page, pcl);
1191*4882a593Smuzhiyun /* drop a refcount added by allocpage (then we have 2 refs here) */
1192*4882a593Smuzhiyun put_page(page);
1193*4882a593Smuzhiyun
1194*4882a593Smuzhiyun out: /* the only exit (for tracing and debugging) */
1195*4882a593Smuzhiyun return page;
1196*4882a593Smuzhiyun }
1197*4882a593Smuzhiyun
1198*4882a593Smuzhiyun static struct z_erofs_decompressqueue *
jobqueue_init(struct super_block * sb,struct z_erofs_decompressqueue * fgq,bool * fg)1199*4882a593Smuzhiyun jobqueue_init(struct super_block *sb,
1200*4882a593Smuzhiyun struct z_erofs_decompressqueue *fgq, bool *fg)
1201*4882a593Smuzhiyun {
1202*4882a593Smuzhiyun struct z_erofs_decompressqueue *q;
1203*4882a593Smuzhiyun
1204*4882a593Smuzhiyun if (fg && !*fg) {
1205*4882a593Smuzhiyun q = kvzalloc(sizeof(*q), GFP_KERNEL | __GFP_NOWARN);
1206*4882a593Smuzhiyun if (!q) {
1207*4882a593Smuzhiyun *fg = true;
1208*4882a593Smuzhiyun goto fg_out;
1209*4882a593Smuzhiyun }
1210*4882a593Smuzhiyun INIT_WORK(&q->u.work, z_erofs_decompressqueue_work);
1211*4882a593Smuzhiyun } else {
1212*4882a593Smuzhiyun fg_out:
1213*4882a593Smuzhiyun q = fgq;
1214*4882a593Smuzhiyun init_completion(&fgq->u.done);
1215*4882a593Smuzhiyun atomic_set(&fgq->pending_bios, 0);
1216*4882a593Smuzhiyun }
1217*4882a593Smuzhiyun q->sb = sb;
1218*4882a593Smuzhiyun q->head = Z_EROFS_PCLUSTER_TAIL_CLOSED;
1219*4882a593Smuzhiyun return q;
1220*4882a593Smuzhiyun }
1221*4882a593Smuzhiyun
1222*4882a593Smuzhiyun /* define decompression jobqueue types */
1223*4882a593Smuzhiyun enum {
1224*4882a593Smuzhiyun JQ_BYPASS,
1225*4882a593Smuzhiyun JQ_SUBMIT,
1226*4882a593Smuzhiyun NR_JOBQUEUES,
1227*4882a593Smuzhiyun };
1228*4882a593Smuzhiyun
jobqueueset_init(struct super_block * sb,struct z_erofs_decompressqueue * q[],struct z_erofs_decompressqueue * fgq,bool * fg)1229*4882a593Smuzhiyun static void *jobqueueset_init(struct super_block *sb,
1230*4882a593Smuzhiyun struct z_erofs_decompressqueue *q[],
1231*4882a593Smuzhiyun struct z_erofs_decompressqueue *fgq, bool *fg)
1232*4882a593Smuzhiyun {
1233*4882a593Smuzhiyun /*
1234*4882a593Smuzhiyun * if managed cache is enabled, bypass jobqueue is needed,
1235*4882a593Smuzhiyun * no need to read from device for all pclusters in this queue.
1236*4882a593Smuzhiyun */
1237*4882a593Smuzhiyun q[JQ_BYPASS] = jobqueue_init(sb, fgq + JQ_BYPASS, NULL);
1238*4882a593Smuzhiyun q[JQ_SUBMIT] = jobqueue_init(sb, fgq + JQ_SUBMIT, fg);
1239*4882a593Smuzhiyun
1240*4882a593Smuzhiyun return tagptr_cast_ptr(tagptr_fold(tagptr1_t, q[JQ_SUBMIT], *fg));
1241*4882a593Smuzhiyun }
1242*4882a593Smuzhiyun
move_to_bypass_jobqueue(struct z_erofs_pcluster * pcl,z_erofs_next_pcluster_t qtail[],z_erofs_next_pcluster_t owned_head)1243*4882a593Smuzhiyun static void move_to_bypass_jobqueue(struct z_erofs_pcluster *pcl,
1244*4882a593Smuzhiyun z_erofs_next_pcluster_t qtail[],
1245*4882a593Smuzhiyun z_erofs_next_pcluster_t owned_head)
1246*4882a593Smuzhiyun {
1247*4882a593Smuzhiyun z_erofs_next_pcluster_t *const submit_qtail = qtail[JQ_SUBMIT];
1248*4882a593Smuzhiyun z_erofs_next_pcluster_t *const bypass_qtail = qtail[JQ_BYPASS];
1249*4882a593Smuzhiyun
1250*4882a593Smuzhiyun DBG_BUGON(owned_head == Z_EROFS_PCLUSTER_TAIL_CLOSED);
1251*4882a593Smuzhiyun if (owned_head == Z_EROFS_PCLUSTER_TAIL)
1252*4882a593Smuzhiyun owned_head = Z_EROFS_PCLUSTER_TAIL_CLOSED;
1253*4882a593Smuzhiyun
1254*4882a593Smuzhiyun WRITE_ONCE(pcl->next, Z_EROFS_PCLUSTER_TAIL_CLOSED);
1255*4882a593Smuzhiyun
1256*4882a593Smuzhiyun WRITE_ONCE(*submit_qtail, owned_head);
1257*4882a593Smuzhiyun WRITE_ONCE(*bypass_qtail, &pcl->next);
1258*4882a593Smuzhiyun
1259*4882a593Smuzhiyun qtail[JQ_BYPASS] = &pcl->next;
1260*4882a593Smuzhiyun }
1261*4882a593Smuzhiyun
z_erofs_submit_queue(struct super_block * sb,struct z_erofs_decompress_frontend * f,struct list_head * pagepool,struct z_erofs_decompressqueue * fgq,bool * force_fg)1262*4882a593Smuzhiyun static void z_erofs_submit_queue(struct super_block *sb,
1263*4882a593Smuzhiyun struct z_erofs_decompress_frontend *f,
1264*4882a593Smuzhiyun struct list_head *pagepool,
1265*4882a593Smuzhiyun struct z_erofs_decompressqueue *fgq,
1266*4882a593Smuzhiyun bool *force_fg)
1267*4882a593Smuzhiyun {
1268*4882a593Smuzhiyun struct erofs_sb_info *const sbi = EROFS_SB(sb);
1269*4882a593Smuzhiyun z_erofs_next_pcluster_t qtail[NR_JOBQUEUES];
1270*4882a593Smuzhiyun struct z_erofs_decompressqueue *q[NR_JOBQUEUES];
1271*4882a593Smuzhiyun void *bi_private;
1272*4882a593Smuzhiyun z_erofs_next_pcluster_t owned_head = f->clt.owned_head;
1273*4882a593Smuzhiyun /* since bio will be NULL, no need to initialize last_index */
1274*4882a593Smuzhiyun pgoff_t last_index;
1275*4882a593Smuzhiyun unsigned int nr_bios = 0;
1276*4882a593Smuzhiyun struct bio *bio = NULL;
1277*4882a593Smuzhiyun
1278*4882a593Smuzhiyun bi_private = jobqueueset_init(sb, q, fgq, force_fg);
1279*4882a593Smuzhiyun qtail[JQ_BYPASS] = &q[JQ_BYPASS]->head;
1280*4882a593Smuzhiyun qtail[JQ_SUBMIT] = &q[JQ_SUBMIT]->head;
1281*4882a593Smuzhiyun
1282*4882a593Smuzhiyun /* by default, all need io submission */
1283*4882a593Smuzhiyun q[JQ_SUBMIT]->head = owned_head;
1284*4882a593Smuzhiyun
1285*4882a593Smuzhiyun do {
1286*4882a593Smuzhiyun struct z_erofs_pcluster *pcl;
1287*4882a593Smuzhiyun pgoff_t cur, end;
1288*4882a593Smuzhiyun unsigned int i = 0;
1289*4882a593Smuzhiyun bool bypass = true;
1290*4882a593Smuzhiyun
1291*4882a593Smuzhiyun /* no possible 'owned_head' equals the following */
1292*4882a593Smuzhiyun DBG_BUGON(owned_head == Z_EROFS_PCLUSTER_TAIL_CLOSED);
1293*4882a593Smuzhiyun DBG_BUGON(owned_head == Z_EROFS_PCLUSTER_NIL);
1294*4882a593Smuzhiyun
1295*4882a593Smuzhiyun pcl = container_of(owned_head, struct z_erofs_pcluster, next);
1296*4882a593Smuzhiyun
1297*4882a593Smuzhiyun cur = pcl->obj.index;
1298*4882a593Smuzhiyun end = cur + pcl->pclusterpages;
1299*4882a593Smuzhiyun
1300*4882a593Smuzhiyun /* close the main owned chain at first */
1301*4882a593Smuzhiyun owned_head = cmpxchg(&pcl->next, Z_EROFS_PCLUSTER_TAIL,
1302*4882a593Smuzhiyun Z_EROFS_PCLUSTER_TAIL_CLOSED);
1303*4882a593Smuzhiyun
1304*4882a593Smuzhiyun do {
1305*4882a593Smuzhiyun struct page *page;
1306*4882a593Smuzhiyun
1307*4882a593Smuzhiyun page = pickup_page_for_submission(pcl, i++, pagepool,
1308*4882a593Smuzhiyun MNGD_MAPPING(sbi),
1309*4882a593Smuzhiyun GFP_NOFS);
1310*4882a593Smuzhiyun if (!page)
1311*4882a593Smuzhiyun continue;
1312*4882a593Smuzhiyun
1313*4882a593Smuzhiyun if (bio && cur != last_index + 1) {
1314*4882a593Smuzhiyun submit_bio_retry:
1315*4882a593Smuzhiyun submit_bio(bio);
1316*4882a593Smuzhiyun bio = NULL;
1317*4882a593Smuzhiyun }
1318*4882a593Smuzhiyun
1319*4882a593Smuzhiyun if (!bio) {
1320*4882a593Smuzhiyun bio = bio_alloc(GFP_NOIO, BIO_MAX_PAGES);
1321*4882a593Smuzhiyun
1322*4882a593Smuzhiyun bio->bi_end_io = z_erofs_decompressqueue_endio;
1323*4882a593Smuzhiyun bio_set_dev(bio, sb->s_bdev);
1324*4882a593Smuzhiyun bio->bi_iter.bi_sector = (sector_t)cur <<
1325*4882a593Smuzhiyun LOG_SECTORS_PER_BLOCK;
1326*4882a593Smuzhiyun bio->bi_private = bi_private;
1327*4882a593Smuzhiyun bio->bi_opf = REQ_OP_READ;
1328*4882a593Smuzhiyun if (f->readahead)
1329*4882a593Smuzhiyun bio->bi_opf |= REQ_RAHEAD;
1330*4882a593Smuzhiyun ++nr_bios;
1331*4882a593Smuzhiyun }
1332*4882a593Smuzhiyun
1333*4882a593Smuzhiyun if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE)
1334*4882a593Smuzhiyun goto submit_bio_retry;
1335*4882a593Smuzhiyun
1336*4882a593Smuzhiyun last_index = cur;
1337*4882a593Smuzhiyun bypass = false;
1338*4882a593Smuzhiyun } while (++cur < end);
1339*4882a593Smuzhiyun
1340*4882a593Smuzhiyun if (!bypass)
1341*4882a593Smuzhiyun qtail[JQ_SUBMIT] = &pcl->next;
1342*4882a593Smuzhiyun else
1343*4882a593Smuzhiyun move_to_bypass_jobqueue(pcl, qtail, owned_head);
1344*4882a593Smuzhiyun } while (owned_head != Z_EROFS_PCLUSTER_TAIL);
1345*4882a593Smuzhiyun
1346*4882a593Smuzhiyun if (bio)
1347*4882a593Smuzhiyun submit_bio(bio);
1348*4882a593Smuzhiyun
1349*4882a593Smuzhiyun /*
1350*4882a593Smuzhiyun * although background is preferred, no one is pending for submission.
1351*4882a593Smuzhiyun * don't issue workqueue for decompression but drop it directly instead.
1352*4882a593Smuzhiyun */
1353*4882a593Smuzhiyun if (!*force_fg && !nr_bios) {
1354*4882a593Smuzhiyun kvfree(q[JQ_SUBMIT]);
1355*4882a593Smuzhiyun return;
1356*4882a593Smuzhiyun }
1357*4882a593Smuzhiyun z_erofs_decompress_kickoff(q[JQ_SUBMIT], *force_fg, nr_bios);
1358*4882a593Smuzhiyun }
1359*4882a593Smuzhiyun
z_erofs_runqueue(struct super_block * sb,struct z_erofs_decompress_frontend * f,struct list_head * pagepool,bool force_fg)1360*4882a593Smuzhiyun static void z_erofs_runqueue(struct super_block *sb,
1361*4882a593Smuzhiyun struct z_erofs_decompress_frontend *f,
1362*4882a593Smuzhiyun struct list_head *pagepool, bool force_fg)
1363*4882a593Smuzhiyun {
1364*4882a593Smuzhiyun struct z_erofs_decompressqueue io[NR_JOBQUEUES];
1365*4882a593Smuzhiyun
1366*4882a593Smuzhiyun if (f->clt.owned_head == Z_EROFS_PCLUSTER_TAIL)
1367*4882a593Smuzhiyun return;
1368*4882a593Smuzhiyun z_erofs_submit_queue(sb, f, pagepool, io, &force_fg);
1369*4882a593Smuzhiyun
1370*4882a593Smuzhiyun /* handle bypass queue (no i/o pclusters) immediately */
1371*4882a593Smuzhiyun z_erofs_decompress_queue(&io[JQ_BYPASS], pagepool);
1372*4882a593Smuzhiyun
1373*4882a593Smuzhiyun if (!force_fg)
1374*4882a593Smuzhiyun return;
1375*4882a593Smuzhiyun
1376*4882a593Smuzhiyun /* wait until all bios are completed */
1377*4882a593Smuzhiyun wait_for_completion_io(&io[JQ_SUBMIT].u.done);
1378*4882a593Smuzhiyun
1379*4882a593Smuzhiyun /* handle synchronous decompress queue in the caller context */
1380*4882a593Smuzhiyun z_erofs_decompress_queue(&io[JQ_SUBMIT], pagepool);
1381*4882a593Smuzhiyun }
1382*4882a593Smuzhiyun
z_erofs_readpage(struct file * file,struct page * page)1383*4882a593Smuzhiyun static int z_erofs_readpage(struct file *file, struct page *page)
1384*4882a593Smuzhiyun {
1385*4882a593Smuzhiyun struct inode *const inode = page->mapping->host;
1386*4882a593Smuzhiyun struct z_erofs_decompress_frontend f = DECOMPRESS_FRONTEND_INIT(inode);
1387*4882a593Smuzhiyun int err;
1388*4882a593Smuzhiyun LIST_HEAD(pagepool);
1389*4882a593Smuzhiyun
1390*4882a593Smuzhiyun trace_erofs_readpage(page, false);
1391*4882a593Smuzhiyun
1392*4882a593Smuzhiyun f.headoffset = (erofs_off_t)page->index << PAGE_SHIFT;
1393*4882a593Smuzhiyun
1394*4882a593Smuzhiyun err = z_erofs_do_read_page(&f, page, &pagepool);
1395*4882a593Smuzhiyun (void)z_erofs_collector_end(&f.clt);
1396*4882a593Smuzhiyun
1397*4882a593Smuzhiyun /* if some compressed cluster ready, need submit them anyway */
1398*4882a593Smuzhiyun z_erofs_runqueue(inode->i_sb, &f, &pagepool, true);
1399*4882a593Smuzhiyun
1400*4882a593Smuzhiyun if (err)
1401*4882a593Smuzhiyun erofs_err(inode->i_sb, "failed to read, err [%d]", err);
1402*4882a593Smuzhiyun
1403*4882a593Smuzhiyun if (f.map.mpage)
1404*4882a593Smuzhiyun put_page(f.map.mpage);
1405*4882a593Smuzhiyun
1406*4882a593Smuzhiyun /* clean up the remaining free pages */
1407*4882a593Smuzhiyun put_pages_list(&pagepool);
1408*4882a593Smuzhiyun return err;
1409*4882a593Smuzhiyun }
1410*4882a593Smuzhiyun
z_erofs_readahead(struct readahead_control * rac)1411*4882a593Smuzhiyun static void z_erofs_readahead(struct readahead_control *rac)
1412*4882a593Smuzhiyun {
1413*4882a593Smuzhiyun struct inode *const inode = rac->mapping->host;
1414*4882a593Smuzhiyun struct erofs_sb_info *const sbi = EROFS_I_SB(inode);
1415*4882a593Smuzhiyun
1416*4882a593Smuzhiyun unsigned int nr_pages = readahead_count(rac);
1417*4882a593Smuzhiyun bool sync = (sbi->ctx.readahead_sync_decompress &&
1418*4882a593Smuzhiyun nr_pages <= sbi->ctx.max_sync_decompress_pages);
1419*4882a593Smuzhiyun struct z_erofs_decompress_frontend f = DECOMPRESS_FRONTEND_INIT(inode);
1420*4882a593Smuzhiyun struct page *page, *head = NULL;
1421*4882a593Smuzhiyun LIST_HEAD(pagepool);
1422*4882a593Smuzhiyun
1423*4882a593Smuzhiyun trace_erofs_readpages(inode, readahead_index(rac), nr_pages, false);
1424*4882a593Smuzhiyun
1425*4882a593Smuzhiyun f.readahead = true;
1426*4882a593Smuzhiyun f.headoffset = readahead_pos(rac);
1427*4882a593Smuzhiyun
1428*4882a593Smuzhiyun while ((page = readahead_page(rac))) {
1429*4882a593Smuzhiyun prefetchw(&page->flags);
1430*4882a593Smuzhiyun
1431*4882a593Smuzhiyun /*
1432*4882a593Smuzhiyun * A pure asynchronous readahead is indicated if
1433*4882a593Smuzhiyun * a PG_readahead marked page is hitted at first.
1434*4882a593Smuzhiyun * Let's also do asynchronous decompression for this case.
1435*4882a593Smuzhiyun */
1436*4882a593Smuzhiyun sync &= !(PageReadahead(page) && !head);
1437*4882a593Smuzhiyun
1438*4882a593Smuzhiyun set_page_private(page, (unsigned long)head);
1439*4882a593Smuzhiyun head = page;
1440*4882a593Smuzhiyun }
1441*4882a593Smuzhiyun
1442*4882a593Smuzhiyun while (head) {
1443*4882a593Smuzhiyun struct page *page = head;
1444*4882a593Smuzhiyun int err;
1445*4882a593Smuzhiyun
1446*4882a593Smuzhiyun /* traversal in reverse order */
1447*4882a593Smuzhiyun head = (void *)page_private(page);
1448*4882a593Smuzhiyun
1449*4882a593Smuzhiyun err = z_erofs_do_read_page(&f, page, &pagepool);
1450*4882a593Smuzhiyun if (err)
1451*4882a593Smuzhiyun erofs_err(inode->i_sb,
1452*4882a593Smuzhiyun "readahead error at page %lu @ nid %llu",
1453*4882a593Smuzhiyun page->index, EROFS_I(inode)->nid);
1454*4882a593Smuzhiyun put_page(page);
1455*4882a593Smuzhiyun }
1456*4882a593Smuzhiyun
1457*4882a593Smuzhiyun (void)z_erofs_collector_end(&f.clt);
1458*4882a593Smuzhiyun
1459*4882a593Smuzhiyun z_erofs_runqueue(inode->i_sb, &f, &pagepool, sync);
1460*4882a593Smuzhiyun
1461*4882a593Smuzhiyun if (f.map.mpage)
1462*4882a593Smuzhiyun put_page(f.map.mpage);
1463*4882a593Smuzhiyun
1464*4882a593Smuzhiyun /* clean up the remaining free pages */
1465*4882a593Smuzhiyun put_pages_list(&pagepool);
1466*4882a593Smuzhiyun }
1467*4882a593Smuzhiyun
1468*4882a593Smuzhiyun const struct address_space_operations z_erofs_aops = {
1469*4882a593Smuzhiyun .readpage = z_erofs_readpage,
1470*4882a593Smuzhiyun .readahead = z_erofs_readahead,
1471*4882a593Smuzhiyun };
1472*4882a593Smuzhiyun
1473