2
2
/*
3
3
* Copyright (C) 2019 HUAWEI, Inc.
4
4
* https://www.huawei.com/
5
+ * Copyright (C) 2024 Alibaba Cloud
5
6
*/
6
7
#include "compress.h"
7
8
#include <linux/lz4.h>
@@ -109,7 +110,6 @@ static int z_erofs_lz4_prepare_dstpages(struct z_erofs_lz4_decompress_ctx *ctx,
109
110
110
111
if (top ) {
111
112
victim = availables [-- top ];
112
- get_page (victim );
113
113
} else {
114
114
victim = __erofs_allocpage (pagepool , rq -> gfp , true);
115
115
if (!victim )
@@ -371,40 +371,113 @@ static int z_erofs_transform_plain(struct z_erofs_decompress_req *rq,
371
371
return 0 ;
372
372
}
373
373
374
- const struct z_erofs_decompressor erofs_decompressors [] = {
375
- [Z_EROFS_COMPRESSION_SHIFTED ] = {
374
+ int z_erofs_stream_switch_bufs (struct z_erofs_stream_dctx * dctx , void * * dst ,
375
+ void * * src , struct page * * pgpl )
376
+ {
377
+ struct z_erofs_decompress_req * rq = dctx -> rq ;
378
+ struct super_block * sb = rq -> sb ;
379
+ struct page * * pgo , * tmppage ;
380
+ unsigned int j ;
381
+
382
+ if (!dctx -> avail_out ) {
383
+ if (++ dctx -> no >= dctx -> outpages || !rq -> outputsize ) {
384
+ erofs_err (sb , "insufficient space for decompressed data" );
385
+ return - EFSCORRUPTED ;
386
+ }
387
+
388
+ if (dctx -> kout )
389
+ kunmap_local (dctx -> kout );
390
+ dctx -> avail_out = min (rq -> outputsize , PAGE_SIZE - rq -> pageofs_out );
391
+ rq -> outputsize -= dctx -> avail_out ;
392
+ pgo = & rq -> out [dctx -> no ];
393
+ if (!* pgo && rq -> fillgaps ) { /* deduped */
394
+ * pgo = erofs_allocpage (pgpl , rq -> gfp );
395
+ if (!* pgo ) {
396
+ dctx -> kout = NULL ;
397
+ return - ENOMEM ;
398
+ }
399
+ set_page_private (* pgo , Z_EROFS_SHORTLIVED_PAGE );
400
+ }
401
+ if (* pgo ) {
402
+ dctx -> kout = kmap_local_page (* pgo );
403
+ * dst = dctx -> kout + rq -> pageofs_out ;
404
+ } else {
405
+ * dst = dctx -> kout = NULL ;
406
+ }
407
+ rq -> pageofs_out = 0 ;
408
+ }
409
+
410
+ if (dctx -> inbuf_pos == dctx -> inbuf_sz && rq -> inputsize ) {
411
+ if (++ dctx -> ni >= dctx -> inpages ) {
412
+ erofs_err (sb , "invalid compressed data" );
413
+ return - EFSCORRUPTED ;
414
+ }
415
+ if (dctx -> kout ) /* unlike kmap(), take care of the orders */
416
+ kunmap_local (dctx -> kout );
417
+ kunmap_local (dctx -> kin );
418
+
419
+ dctx -> inbuf_sz = min_t (u32 , rq -> inputsize , PAGE_SIZE );
420
+ rq -> inputsize -= dctx -> inbuf_sz ;
421
+ dctx -> kin = kmap_local_page (rq -> in [dctx -> ni ]);
422
+ * src = dctx -> kin ;
423
+ dctx -> bounced = false;
424
+ if (dctx -> kout ) {
425
+ j = (u8 * )* dst - dctx -> kout ;
426
+ dctx -> kout = kmap_local_page (rq -> out [dctx -> no ]);
427
+ * dst = dctx -> kout + j ;
428
+ }
429
+ dctx -> inbuf_pos = 0 ;
430
+ }
431
+
432
+ /*
433
+ * Handle overlapping: Use the given bounce buffer if the input data is
434
+ * under processing; Or utilize short-lived pages from the on-stack page
435
+ * pool, where pages are shared among the same request. Note that only
436
+ * a few inplace I/O pages need to be doubled.
437
+ */
438
+ if (!dctx -> bounced && rq -> out [dctx -> no ] == rq -> in [dctx -> ni ]) {
439
+ memcpy (dctx -> bounce , * src , dctx -> inbuf_sz );
440
+ * src = dctx -> bounce ;
441
+ dctx -> bounced = true;
442
+ }
443
+
444
+ for (j = dctx -> ni + 1 ; j < dctx -> inpages ; ++ j ) {
445
+ if (rq -> out [dctx -> no ] != rq -> in [j ])
446
+ continue ;
447
+ tmppage = erofs_allocpage (pgpl , rq -> gfp );
448
+ if (!tmppage )
449
+ return - ENOMEM ;
450
+ set_page_private (tmppage , Z_EROFS_SHORTLIVED_PAGE );
451
+ copy_highpage (tmppage , rq -> in [j ]);
452
+ rq -> in [j ] = tmppage ;
453
+ }
454
+ return 0 ;
455
+ }
456
+
457
+ const struct z_erofs_decompressor * z_erofs_decomp [] = {
458
+ [Z_EROFS_COMPRESSION_SHIFTED ] = & (const struct z_erofs_decompressor ) {
376
459
.decompress = z_erofs_transform_plain ,
377
460
.name = "shifted"
378
461
},
379
- [Z_EROFS_COMPRESSION_INTERLACED ] = {
462
+ [Z_EROFS_COMPRESSION_INTERLACED ] = & ( const struct z_erofs_decompressor ) {
380
463
.decompress = z_erofs_transform_plain ,
381
464
.name = "interlaced"
382
465
},
383
- [Z_EROFS_COMPRESSION_LZ4 ] = {
466
+ [Z_EROFS_COMPRESSION_LZ4 ] = & ( const struct z_erofs_decompressor ) {
384
467
.config = z_erofs_load_lz4_config ,
385
468
.decompress = z_erofs_lz4_decompress ,
469
+ .init = z_erofs_gbuf_init ,
470
+ .exit = z_erofs_gbuf_exit ,
386
471
.name = "lz4"
387
472
},
388
473
#ifdef CONFIG_EROFS_FS_ZIP_LZMA
389
- [Z_EROFS_COMPRESSION_LZMA ] = {
390
- .config = z_erofs_load_lzma_config ,
391
- .decompress = z_erofs_lzma_decompress ,
392
- .name = "lzma"
393
- },
474
+ [Z_EROFS_COMPRESSION_LZMA ] = & z_erofs_lzma_decomp ,
394
475
#endif
395
476
#ifdef CONFIG_EROFS_FS_ZIP_DEFLATE
396
- [Z_EROFS_COMPRESSION_DEFLATE ] = {
397
- .config = z_erofs_load_deflate_config ,
398
- .decompress = z_erofs_deflate_decompress ,
399
- .name = "deflate"
400
- },
477
+ [Z_EROFS_COMPRESSION_DEFLATE ] = & z_erofs_deflate_decomp ,
401
478
#endif
402
479
#ifdef CONFIG_EROFS_FS_ZIP_ZSTD
403
- [Z_EROFS_COMPRESSION_ZSTD ] = {
404
- .config = z_erofs_load_zstd_config ,
405
- .decompress = z_erofs_zstd_decompress ,
406
- .name = "zstd"
407
- },
480
+ [Z_EROFS_COMPRESSION_ZSTD ] = & z_erofs_zstd_decomp ,
408
481
#endif
409
482
};
410
483
@@ -432,6 +505,7 @@ int z_erofs_parse_cfgs(struct super_block *sb, struct erofs_super_block *dsb)
432
505
offset = EROFS_SUPER_OFFSET + sbi -> sb_size ;
433
506
alg = 0 ;
434
507
for (algs = sbi -> available_compr_algs ; algs ; algs >>= 1 , ++ alg ) {
508
+ const struct z_erofs_decompressor * dec = z_erofs_decomp [alg ];
435
509
void * data ;
436
510
437
511
if (!(algs & 1 ))
@@ -443,20 +517,42 @@ int z_erofs_parse_cfgs(struct super_block *sb, struct erofs_super_block *dsb)
443
517
break ;
444
518
}
445
519
446
- if (alg >= ARRAY_SIZE (erofs_decompressors ) ||
447
- !erofs_decompressors [alg ].config ) {
520
+ if (alg < Z_EROFS_COMPRESSION_MAX && dec && dec -> config ) {
521
+ ret = dec -> config (sb , dsb , data , size );
522
+ } else {
448
523
erofs_err (sb , "algorithm %d isn't enabled on this kernel" ,
449
524
alg );
450
525
ret = - EOPNOTSUPP ;
451
- } else {
452
- ret = erofs_decompressors [alg ].config (sb ,
453
- dsb , data , size );
454
526
}
455
-
456
527
kfree (data );
457
528
if (ret )
458
529
break ;
459
530
}
460
531
erofs_put_metabuf (& buf );
461
532
return ret ;
462
533
}
534
+
535
+ int __init z_erofs_init_decompressor (void )
536
+ {
537
+ int i , err ;
538
+
539
+ for (i = 0 ; i < Z_EROFS_COMPRESSION_MAX ; ++ i ) {
540
+ err = z_erofs_decomp [i ] ? z_erofs_decomp [i ]-> init () : 0 ;
541
+ if (err ) {
542
+ while (-- i )
543
+ if (z_erofs_decomp [i ])
544
+ z_erofs_decomp [i ]-> exit ();
545
+ return err ;
546
+ }
547
+ }
548
+ return 0 ;
549
+ }
550
+
551
+ void z_erofs_exit_decompressor (void )
552
+ {
553
+ int i ;
554
+
555
+ for (i = 0 ; i < Z_EROFS_COMPRESSION_MAX ; ++ i )
556
+ if (z_erofs_decomp [i ])
557
+ z_erofs_decomp [i ]-> exit ();
558
+ }
0 commit comments