@@ -105,94 +105,102 @@ static int z_erofs_lz4_prepare_dstpages(struct z_erofs_decompress_req *rq,
105105 return kaddr ? 1 : 0 ;
106106}
107107
108- static void * z_erofs_lz4_handle_overlap (struct z_erofs_decompress_req * rq ,
108+ static void * z_erofs_lz4_handle_overlap (const struct z_erofs_decompress_req * rq ,
109109 void * inpage , void * out , unsigned int * inputmargin ,
110110 int * maptype , bool may_inplace )
111111{
112- unsigned int oend , omargin , total , i ;
112+ unsigned int oend , omargin , cnt , i ;
113113 struct page * * in ;
114- void * src , * tmp ;
115-
116- if (rq -> inplace_io ) {
117- oend = rq -> pageofs_out + rq -> outputsize ;
118- omargin = PAGE_ALIGN (oend ) - oend ;
119- if (rq -> partial_decoding || !may_inplace ||
120- omargin < LZ4_DECOMPRESS_INPLACE_MARGIN (rq -> inputsize ))
121- goto docopy ;
114+ void * src ;
122115
116+ /*
117+ * If in-place I/O isn't used, for example, the bounce compressed cache
118+ * can hold data for incomplete read requests. Just map the compressed
119+ * buffer as well and decompress directly.
120+ */
121+ if (!rq -> inplace_io ) {
122+ if (rq -> inpages <= 1 ) {
123+ * maptype = 0 ;
124+ return inpage ;
125+ }
126+ kunmap_local (inpage );
127+ src = erofs_vm_map_ram (rq -> in , rq -> inpages );
128+ if (!src )
129+ return ERR_PTR (- ENOMEM );
130+ * maptype = 1 ;
131+ return src ;
132+ }
133+ /*
134+ * Then, deal with in-place I/Os. The reasons why in-place I/O is useful
135+ * are: (1) It minimizes memory footprint during the I/O submission,
136+ * which is useful for slow storage (including network devices and
137+ * low-end HDDs/eMMCs) but with a lot inflight I/Os; (2) If in-place
138+ * decompression can also be applied, it will reuse the unique buffer so
139+ * that no extra CPU D-cache is polluted with temporary compressed data
140+ * for extreme performance.
141+ */
142+ oend = rq -> pageofs_out + rq -> outputsize ;
143+ omargin = PAGE_ALIGN (oend ) - oend ;
144+ if (!rq -> partial_decoding && may_inplace &&
145+ omargin >= LZ4_DECOMPRESS_INPLACE_MARGIN (rq -> inputsize )) {
123146 for (i = 0 ; i < rq -> inpages ; ++ i )
124147 if (rq -> out [rq -> outpages - rq -> inpages + i ] !=
125148 rq -> in [i ])
126- goto docopy ;
127- kunmap_local (inpage );
128- * maptype = 3 ;
129- return out + ((rq -> outpages - rq -> inpages ) << PAGE_SHIFT );
130- }
131-
132- if (rq -> inpages <= 1 ) {
133- * maptype = 0 ;
134- return inpage ;
149+ break ;
150+ if (i >= rq -> inpages ) {
151+ kunmap_local (inpage );
152+ * maptype = 3 ;
153+ return out + ((rq -> outpages - rq -> inpages ) << PAGE_SHIFT );
154+ }
135155 }
136- kunmap_local (inpage );
137- src = erofs_vm_map_ram (rq -> in , rq -> inpages );
138- if (!src )
139- return ERR_PTR (- ENOMEM );
140- * maptype = 1 ;
141- return src ;
142-
143- docopy :
144- /* Or copy compressed data which can be overlapped to per-CPU buffer */
145- in = rq -> in ;
156+ /*
157+ * If in-place decompression can't be applied, copy compressed data that
158+ * may potentially overlap during decompression to a per-CPU buffer.
159+ */
146160 src = z_erofs_get_gbuf (rq -> inpages );
147161 if (!src ) {
148162 DBG_BUGON (1 );
149163 kunmap_local (inpage );
150164 return ERR_PTR (- EFAULT );
151165 }
152166
153- tmp = src ;
154- total = rq -> inputsize ;
155- while (total ) {
156- unsigned int page_copycnt =
157- min_t (unsigned int , total , PAGE_SIZE - * inputmargin );
158-
167+ for (i = 0 , in = rq -> in ; i < rq -> inputsize ; i += cnt , ++ in ) {
168+ cnt = min_t (u32 , rq -> inputsize - i , PAGE_SIZE - * inputmargin );
159169 if (!inpage )
160170 inpage = kmap_local_page (* in );
161- memcpy (tmp , inpage + * inputmargin , page_copycnt );
171+ memcpy (src + i , inpage + * inputmargin , cnt );
162172 kunmap_local (inpage );
163173 inpage = NULL ;
164- tmp += page_copycnt ;
165- total -= page_copycnt ;
166- ++ in ;
167174 * inputmargin = 0 ;
168175 }
169176 * maptype = 2 ;
170177 return src ;
171178}
172179
173180/*
174- * Get the exact inputsize with zero_padding feature.
175- * - For LZ4, it should work if zero_padding feature is on (5.3+);
176- * - For MicroLZMA, it'd be enabled all the time.
181+ * Get the exact on-disk size of the compressed data:
182+ * - For LZ4, it should apply if the zero_padding feature is on (5.3+);
183+ * - For others, zero_padding is enabled all the time.
177184 */
178- int z_erofs_fixup_insize (struct z_erofs_decompress_req * rq , const char * padbuf ,
179- unsigned int padbufsize )
185+ const char * z_erofs_fixup_insize (struct z_erofs_decompress_req * rq ,
186+ const char * padbuf , unsigned int padbufsize )
180187{
181188 const char * padend ;
182189
183190 padend = memchr_inv (padbuf , 0 , padbufsize );
184191 if (!padend )
185- return - EFSCORRUPTED ;
192+ return "compressed data start not found" ;
186193 rq -> inputsize -= padend - padbuf ;
187194 rq -> pageofs_in += padend - padbuf ;
188- return 0 ;
195+ return NULL ;
189196}
190197
191198static int z_erofs_lz4_decompress_mem (struct z_erofs_decompress_req * rq , u8 * dst )
192199{
193200 bool support_0padding = false, may_inplace = false;
194201 unsigned int inputmargin ;
195202 u8 * out , * headpage , * src ;
203+ const char * reason ;
196204 int ret , maptype ;
197205
198206 DBG_BUGON (* rq -> in == NULL );
@@ -201,12 +209,12 @@ static int z_erofs_lz4_decompress_mem(struct z_erofs_decompress_req *rq, u8 *dst
201209 /* LZ4 decompression inplace is only safe if zero_padding is enabled */
202210 if (erofs_sb_has_zero_padding (EROFS_SB (rq -> sb ))) {
203211 support_0padding = true;
204- ret = z_erofs_fixup_insize (rq , headpage + rq -> pageofs_in ,
212+ reason = z_erofs_fixup_insize (rq , headpage + rq -> pageofs_in ,
205213 min_t (unsigned int , rq -> inputsize ,
206214 rq -> sb -> s_blocksize - rq -> pageofs_in ));
207- if (ret ) {
215+ if (reason ) {
208216 kunmap_local (headpage );
209- return ret ;
217+ return IS_ERR ( reason ) ? PTR_ERR ( reason ) : - EFSCORRUPTED ;
210218 }
211219 may_inplace = !((rq -> pageofs_in + rq -> inputsize ) &
212220 (rq -> sb -> s_blocksize - 1 ));
@@ -228,8 +236,6 @@ static int z_erofs_lz4_decompress_mem(struct z_erofs_decompress_req *rq, u8 *dst
228236 rq -> inputsize , rq -> outputsize );
229237
230238 if (ret != rq -> outputsize ) {
231- erofs_err (rq -> sb , "failed to decompress %d in[%u, %u] out[%u]" ,
232- ret , rq -> inputsize , inputmargin , rq -> outputsize );
233239 if (ret >= 0 )
234240 memset (out + ret , 0 , rq -> outputsize - ret );
235241 ret = - EFSCORRUPTED ;
@@ -250,8 +256,8 @@ static int z_erofs_lz4_decompress_mem(struct z_erofs_decompress_req *rq, u8 *dst
250256 return ret ;
251257}
252258
253- static int z_erofs_lz4_decompress (struct z_erofs_decompress_req * rq ,
254- struct page * * pagepool )
259+ static const char * z_erofs_lz4_decompress (struct z_erofs_decompress_req * rq ,
260+ struct page * * pagepool )
255261{
256262 unsigned int dst_maptype ;
257263 void * dst ;
@@ -266,14 +272,14 @@ static int z_erofs_lz4_decompress(struct z_erofs_decompress_req *rq,
266272 /* general decoding path which can be used for all cases */
267273 ret = z_erofs_lz4_prepare_dstpages (rq , pagepool );
268274 if (ret < 0 )
269- return ret ;
275+ return ERR_PTR ( ret ) ;
270276 if (ret > 0 ) {
271277 dst = page_address (* rq -> out );
272278 dst_maptype = 1 ;
273279 } else {
274280 dst = erofs_vm_map_ram (rq -> out , rq -> outpages );
275281 if (!dst )
276- return - ENOMEM ;
282+ return ERR_PTR ( - ENOMEM ) ;
277283 dst_maptype = 2 ;
278284 }
279285 }
@@ -282,19 +288,19 @@ static int z_erofs_lz4_decompress(struct z_erofs_decompress_req *rq,
282288 kunmap_local (dst );
283289 else if (dst_maptype == 2 )
284290 vm_unmap_ram (dst , rq -> outpages );
285- return ret ;
291+ return ERR_PTR ( ret ) ;
286292}
287293
288- static int z_erofs_transform_plain (struct z_erofs_decompress_req * rq ,
289- struct page * * pagepool )
294+ static const char * z_erofs_transform_plain (struct z_erofs_decompress_req * rq ,
295+ struct page * * pagepool )
290296{
291297 const unsigned int nrpages_in = rq -> inpages , nrpages_out = rq -> outpages ;
292298 const unsigned int bs = rq -> sb -> s_blocksize ;
293299 unsigned int cur = 0 , ni = 0 , no , pi , po , insz , cnt ;
294300 u8 * kin ;
295301
296302 if (rq -> outputsize > rq -> inputsize )
297- return - EOPNOTSUPP ;
303+ return ERR_PTR ( - EOPNOTSUPP ) ;
298304 if (rq -> alg == Z_EROFS_COMPRESSION_INTERLACED ) {
299305 cur = bs - (rq -> pageofs_out & (bs - 1 ));
300306 pi = (rq -> pageofs_in + rq -> inputsize - cur ) & ~PAGE_MASK ;
@@ -334,22 +340,19 @@ static int z_erofs_transform_plain(struct z_erofs_decompress_req *rq,
334340 kunmap_local (kin );
335341 }
336342 DBG_BUGON (ni > nrpages_in );
337- return 0 ;
343+ return NULL ;
338344}
339345
340- int z_erofs_stream_switch_bufs (struct z_erofs_stream_dctx * dctx , void * * dst ,
341- void * * src , struct page * * pgpl )
346+ const char * z_erofs_stream_switch_bufs (struct z_erofs_stream_dctx * dctx ,
347+ void * * dst , void * * src , struct page * * pgpl )
342348{
343349 struct z_erofs_decompress_req * rq = dctx -> rq ;
344- struct super_block * sb = rq -> sb ;
345350 struct page * * pgo , * tmppage ;
346351 unsigned int j ;
347352
348353 if (!dctx -> avail_out ) {
349- if (++ dctx -> no >= rq -> outpages || !rq -> outputsize ) {
350- erofs_err (sb , "insufficient space for decompressed data" );
351- return - EFSCORRUPTED ;
352- }
354+ if (++ dctx -> no >= rq -> outpages || !rq -> outputsize )
355+ return "insufficient space for decompressed data" ;
353356
354357 if (dctx -> kout )
355358 kunmap_local (dctx -> kout );
@@ -360,7 +363,7 @@ int z_erofs_stream_switch_bufs(struct z_erofs_stream_dctx *dctx, void **dst,
360363 * pgo = erofs_allocpage (pgpl , rq -> gfp );
361364 if (!* pgo ) {
362365 dctx -> kout = NULL ;
363- return - ENOMEM ;
366+ return ERR_PTR ( - ENOMEM ) ;
364367 }
365368 set_page_private (* pgo , Z_EROFS_SHORTLIVED_PAGE );
366369 }
@@ -374,10 +377,8 @@ int z_erofs_stream_switch_bufs(struct z_erofs_stream_dctx *dctx, void **dst,
374377 }
375378
376379 if (dctx -> inbuf_pos == dctx -> inbuf_sz && rq -> inputsize ) {
377- if (++ dctx -> ni >= rq -> inpages ) {
378- erofs_err (sb , "invalid compressed data" );
379- return - EFSCORRUPTED ;
380- }
380+ if (++ dctx -> ni >= rq -> inpages )
381+ return "invalid compressed data" ;
381382 if (dctx -> kout ) /* unlike kmap(), take care of the orders */
382383 kunmap_local (dctx -> kout );
383384 kunmap_local (dctx -> kin );
@@ -412,12 +413,12 @@ int z_erofs_stream_switch_bufs(struct z_erofs_stream_dctx *dctx, void **dst,
412413 continue ;
413414 tmppage = erofs_allocpage (pgpl , rq -> gfp );
414415 if (!tmppage )
415- return - ENOMEM ;
416+ return ERR_PTR ( - ENOMEM ) ;
416417 set_page_private (tmppage , Z_EROFS_SHORTLIVED_PAGE );
417418 copy_highpage (tmppage , rq -> in [j ]);
418419 rq -> in [j ] = tmppage ;
419420 }
420- return 0 ;
421+ return NULL ;
421422}
422423
423424const struct z_erofs_decompressor * z_erofs_decomp [] = {
0 commit comments