29b24f6ca112d drivers/staging/erofs/decompressor.c (Gao Xiang 2019-07-31 23:57:31 +0800 1) // SPDX-License-Identifier: GPL-2.0-only
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 2) /*
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 3) * Copyright (C) 2019 HUAWEI, Inc.
592e7cd00bb9d fs/erofs/decompressor.c (Alexander A. Klimov 2020-07-13 15:09:44 +0200 4) * https://www.huawei.com/
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 5) * Created by Gao Xiang <gaoxiang25@huawei.com>
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 6) */
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 7) #include "compress.h"
46c2d1494332e drivers/staging/erofs/decompressor.c (Gao Xiang 2019-07-31 23:57:44 +0800 8) #include <linux/module.h>
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 9) #include <linux/lz4.h>
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 10)
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 11) #ifndef LZ4_DISTANCE_MAX /* history window size */
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 12) #define LZ4_DISTANCE_MAX 65535 /* set to maximum value by default */
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 13) #endif
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 14)
af89bcef55ff6 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-07-03 14:52:09 +0800 15) #define LZ4_MAX_DISTANCE_PAGES (DIV_ROUND_UP(LZ4_DISTANCE_MAX, PAGE_SIZE) + 1)
0ffd71bcc3a03 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:56 +0800 16) #ifndef LZ4_DECOMPRESS_INPLACE_MARGIN
0ffd71bcc3a03 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:56 +0800 17) #define LZ4_DECOMPRESS_INPLACE_MARGIN(srcsize) (((srcsize) >> 8) + 32)
0ffd71bcc3a03 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:56 +0800 18) #endif
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 19)
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 20) struct z_erofs_decompressor {
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 21) /*
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 22) * if destpages have sparsed pages, fill them with bounce pages.
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 23) * it also check whether destpages indicate continuous physical memory.
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 24) */
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 25) int (*prepare_destpages)(struct z_erofs_decompress_req *rq,
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 26) struct list_head *pagepool);
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 27) int (*decompress)(struct z_erofs_decompress_req *rq, u8 *out);
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 28) char *name;
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 29) };
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 30)
5d50538fc567c fs/erofs/decompressor.c (Huang Jianan 2021-03-29 09:23:06 +0800 31) int z_erofs_load_lz4_config(struct super_block *sb,
46249cded18ac fs/erofs/decompressor.c (Gao Xiang 2021-03-29 09:23:07 +0800 32) struct erofs_super_block *dsb,
46249cded18ac fs/erofs/decompressor.c (Gao Xiang 2021-03-29 09:23:07 +0800 33) struct z_erofs_lz4_cfgs *lz4, int size)
5d50538fc567c fs/erofs/decompressor.c (Huang Jianan 2021-03-29 09:23:06 +0800 34) {
4fea63f7d76e4 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:23 +0800 35) struct erofs_sb_info *sbi = EROFS_SB(sb);
46249cded18ac fs/erofs/decompressor.c (Gao Xiang 2021-03-29 09:23:07 +0800 36) u16 distance;
46249cded18ac fs/erofs/decompressor.c (Gao Xiang 2021-03-29 09:23:07 +0800 37)
46249cded18ac fs/erofs/decompressor.c (Gao Xiang 2021-03-29 09:23:07 +0800 38) if (lz4) {
46249cded18ac fs/erofs/decompressor.c (Gao Xiang 2021-03-29 09:23:07 +0800 39) if (size < sizeof(struct z_erofs_lz4_cfgs)) {
46249cded18ac fs/erofs/decompressor.c (Gao Xiang 2021-03-29 09:23:07 +0800 40) erofs_err(sb, "invalid lz4 cfgs, size=%u", size);
46249cded18ac fs/erofs/decompressor.c (Gao Xiang 2021-03-29 09:23:07 +0800 41) return -EINVAL;
46249cded18ac fs/erofs/decompressor.c (Gao Xiang 2021-03-29 09:23:07 +0800 42) }
46249cded18ac fs/erofs/decompressor.c (Gao Xiang 2021-03-29 09:23:07 +0800 43) distance = le16_to_cpu(lz4->max_distance);
4fea63f7d76e4 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:23 +0800 44)
4fea63f7d76e4 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:23 +0800 45) sbi->lz4.max_pclusterblks = le16_to_cpu(lz4->max_pclusterblks);
4fea63f7d76e4 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:23 +0800 46) if (!sbi->lz4.max_pclusterblks) {
4fea63f7d76e4 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:23 +0800 47) sbi->lz4.max_pclusterblks = 1; /* reserved case */
4fea63f7d76e4 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:23 +0800 48) } else if (sbi->lz4.max_pclusterblks >
4fea63f7d76e4 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:23 +0800 49) Z_EROFS_PCLUSTER_MAX_SIZE / EROFS_BLKSIZ) {
4fea63f7d76e4 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:23 +0800 50) erofs_err(sb, "too large lz4 pclusterblks %u",
4fea63f7d76e4 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:23 +0800 51) sbi->lz4.max_pclusterblks);
4fea63f7d76e4 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:23 +0800 52) return -EINVAL;
4fea63f7d76e4 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:23 +0800 53) } else if (sbi->lz4.max_pclusterblks >= 2) {
4fea63f7d76e4 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:23 +0800 54) erofs_info(sb, "EXPERIMENTAL big pcluster feature in use. Use at your own risk!");
4fea63f7d76e4 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:23 +0800 55) }
46249cded18ac fs/erofs/decompressor.c (Gao Xiang 2021-03-29 09:23:07 +0800 56) } else {
14373711dd54b fs/erofs/decompressor.c (Gao Xiang 2021-03-29 18:00:12 +0800 57) distance = le16_to_cpu(dsb->u1.lz4_max_distance);
4fea63f7d76e4 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:23 +0800 58) sbi->lz4.max_pclusterblks = 1;
46249cded18ac fs/erofs/decompressor.c (Gao Xiang 2021-03-29 09:23:07 +0800 59) }
5d50538fc567c fs/erofs/decompressor.c (Huang Jianan 2021-03-29 09:23:06 +0800 60)
4fea63f7d76e4 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:23 +0800 61) sbi->lz4.max_distance_pages = distance ?
5d50538fc567c fs/erofs/decompressor.c (Huang Jianan 2021-03-29 09:23:06 +0800 62) DIV_ROUND_UP(distance, PAGE_SIZE) + 1 :
5d50538fc567c fs/erofs/decompressor.c (Huang Jianan 2021-03-29 09:23:06 +0800 63) LZ4_MAX_DISTANCE_PAGES;
4fea63f7d76e4 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:23 +0800 64) return erofs_pcpubuf_growsize(sbi->lz4.max_pclusterblks);
5d50538fc567c fs/erofs/decompressor.c (Huang Jianan 2021-03-29 09:23:06 +0800 65) }
5d50538fc567c fs/erofs/decompressor.c (Huang Jianan 2021-03-29 09:23:06 +0800 66)
99634bf388db0 fs/erofs/decompressor.c (Gao Xiang 2019-09-04 10:09:05 +0800 67) static int z_erofs_lz4_prepare_destpages(struct z_erofs_decompress_req *rq,
99634bf388db0 fs/erofs/decompressor.c (Gao Xiang 2019-09-04 10:09:05 +0800 68) struct list_head *pagepool)
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 69) {
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 70) const unsigned int nr =
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 71) PAGE_ALIGN(rq->pageofs_out + rq->outputsize) >> PAGE_SHIFT;
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 72) struct page *availables[LZ4_MAX_DISTANCE_PAGES] = { NULL };
af89bcef55ff6 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-07-03 14:52:09 +0800 73) unsigned long bounced[DIV_ROUND_UP(LZ4_MAX_DISTANCE_PAGES,
af89bcef55ff6 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-07-03 14:52:09 +0800 74) BITS_PER_LONG)] = { 0 };
5d50538fc567c fs/erofs/decompressor.c (Huang Jianan 2021-03-29 09:23:06 +0800 75) unsigned int lz4_max_distance_pages =
5d50538fc567c fs/erofs/decompressor.c (Huang Jianan 2021-03-29 09:23:06 +0800 76) EROFS_SB(rq->sb)->lz4.max_distance_pages;
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 77) void *kaddr = NULL;
af89bcef55ff6 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-07-03 14:52:09 +0800 78) unsigned int i, j, top;
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 79)
af89bcef55ff6 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-07-03 14:52:09 +0800 80) top = 0;
af89bcef55ff6 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-07-03 14:52:09 +0800 81) for (i = j = 0; i < nr; ++i, ++j) {
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 82) struct page *const page = rq->out[i];
af89bcef55ff6 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-07-03 14:52:09 +0800 83) struct page *victim;
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 84)
5d50538fc567c fs/erofs/decompressor.c (Huang Jianan 2021-03-29 09:23:06 +0800 85) if (j >= lz4_max_distance_pages)
af89bcef55ff6 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-07-03 14:52:09 +0800 86) j = 0;
af89bcef55ff6 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-07-03 14:52:09 +0800 87)
af89bcef55ff6 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-07-03 14:52:09 +0800 88) /* 'valid' bounced can only be tested after a complete round */
af89bcef55ff6 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-07-03 14:52:09 +0800 89) if (test_bit(j, bounced)) {
5d50538fc567c fs/erofs/decompressor.c (Huang Jianan 2021-03-29 09:23:06 +0800 90) DBG_BUGON(i < lz4_max_distance_pages);
5d50538fc567c fs/erofs/decompressor.c (Huang Jianan 2021-03-29 09:23:06 +0800 91) DBG_BUGON(top >= lz4_max_distance_pages);
5d50538fc567c fs/erofs/decompressor.c (Huang Jianan 2021-03-29 09:23:06 +0800 92) availables[top++] = rq->out[i - lz4_max_distance_pages];
af89bcef55ff6 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-07-03 14:52:09 +0800 93) }
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 94)
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 95) if (page) {
af89bcef55ff6 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-07-03 14:52:09 +0800 96) __clear_bit(j, bounced);
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 97) if (kaddr) {
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 98) if (kaddr + PAGE_SIZE == page_address(page))
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 99) kaddr += PAGE_SIZE;
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 100) else
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 101) kaddr = NULL;
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 102) } else if (!i) {
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 103) kaddr = page_address(page);
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 104) }
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 105) continue;
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 106) }
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 107) kaddr = NULL;
af89bcef55ff6 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-07-03 14:52:09 +0800 108) __set_bit(j, bounced);
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 109)
af89bcef55ff6 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-07-03 14:52:09 +0800 110) if (top) {
af89bcef55ff6 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-07-03 14:52:09 +0800 111) victim = availables[--top];
af89bcef55ff6 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-07-03 14:52:09 +0800 112) get_page(victim);
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 113) } else {
b4892fa3e7fd6 fs/erofs/decompressor.c (Huang Jianan 2021-03-16 11:15:14 +0800 114) victim = erofs_allocpage(pagepool,
b4892fa3e7fd6 fs/erofs/decompressor.c (Huang Jianan 2021-03-16 11:15:14 +0800 115) GFP_KERNEL | __GFP_NOFAIL);
6aaa7b0664e68 fs/erofs/decompressor.c (Gao Xiang 2020-12-08 17:58:32 +0800 116) set_page_private(victim, Z_EROFS_SHORTLIVED_PAGE);
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 117) }
af89bcef55ff6 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-07-03 14:52:09 +0800 118) rq->out[i] = victim;
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 119) }
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 120) return kaddr ? 1 : 0;
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 121) }
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 122)
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 123) static void *z_erofs_handle_inplace_io(struct z_erofs_decompress_req *rq,
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 124) void *inpage, unsigned int *inputmargin, int *maptype,
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 125) bool support_0padding)
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 126) {
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 127) unsigned int nrpages_in, nrpages_out;
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 128) unsigned int ofull, oend, inputsize, total, i, j;
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 129) struct page **in;
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 130) void *src, *tmp;
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 131)
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 132) inputsize = rq->inputsize;
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 133) nrpages_in = PAGE_ALIGN(inputsize) >> PAGE_SHIFT;
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 134) oend = rq->pageofs_out + rq->outputsize;
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 135) ofull = PAGE_ALIGN(oend);
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 136) nrpages_out = ofull >> PAGE_SHIFT;
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 137)
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 138) if (rq->inplace_io) {
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 139) if (rq->partial_decoding || !support_0padding ||
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 140) ofull - oend < LZ4_DECOMPRESS_INPLACE_MARGIN(inputsize))
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 141) goto docopy;
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 142)
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 143) for (i = 0; i < nrpages_in; ++i) {
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 144) DBG_BUGON(rq->in[i] == NULL);
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 145) for (j = 0; j < nrpages_out - nrpages_in + i; ++j)
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 146) if (rq->out[j] == rq->in[i])
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 147) goto docopy;
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 148) }
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 149) }
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 150)
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 151) if (nrpages_in <= 1) {
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 152) *maptype = 0;
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 153) return inpage;
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 154) }
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 155) kunmap_atomic(inpage);
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 156) might_sleep();
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 157) src = erofs_vm_map_ram(rq->in, nrpages_in);
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 158) if (!src)
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 159) return ERR_PTR(-ENOMEM);
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 160) *maptype = 1;
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 161) return src;
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 162)
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 163) docopy:
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 164) /* Or copy compressed data which can be overlapped to per-CPU buffer */
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 165) in = rq->in;
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 166) src = erofs_get_pcpubuf(nrpages_in);
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 167) if (!src) {
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 168) DBG_BUGON(1);
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 169) kunmap_atomic(inpage);
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 170) return ERR_PTR(-EFAULT);
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 171) }
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 172)
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 173) tmp = src;
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 174) total = rq->inputsize;
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 175) while (total) {
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 176) unsigned int page_copycnt =
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 177) min_t(unsigned int, total, PAGE_SIZE - *inputmargin);
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 178)
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 179) if (!inpage)
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 180) inpage = kmap_atomic(*in);
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 181) memcpy(tmp, inpage + *inputmargin, page_copycnt);
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 182) kunmap_atomic(inpage);
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 183) inpage = NULL;
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 184) tmp += page_copycnt;
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 185) total -= page_copycnt;
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 186) ++in;
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 187) *inputmargin = 0;
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 188) }
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 189) *maptype = 2;
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 190) return src;
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 191) }
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 192)
99634bf388db0 fs/erofs/decompressor.c (Gao Xiang 2019-09-04 10:09:05 +0800 193) static int z_erofs_lz4_decompress(struct z_erofs_decompress_req *rq, u8 *out)
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 194) {
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 195) unsigned int inputmargin;
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 196) u8 *headpage, *src;
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 197) bool support_0padding;
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 198) int ret, maptype;
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 199)
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 200) DBG_BUGON(*rq->in == NULL);
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 201) headpage = kmap_atomic(*rq->in);
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 202) inputmargin = 0;
0ffd71bcc3a03 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:56 +0800 203) support_0padding = false;
0ffd71bcc3a03 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:56 +0800 204)
0ffd71bcc3a03 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:56 +0800 205) /* decompression inplace is only safe when 0padding is enabled */
de06a6a375414 fs/erofs/decompressor.c (Gao Xiang 2021-03-29 09:23:05 +0800 206) if (erofs_sb_has_lz4_0padding(EROFS_SB(rq->sb))) {
0ffd71bcc3a03 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:56 +0800 207) support_0padding = true;
0ffd71bcc3a03 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:56 +0800 208)
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 209) while (!headpage[inputmargin & ~PAGE_MASK])
0ffd71bcc3a03 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:56 +0800 210) if (!(++inputmargin & ~PAGE_MASK))
0ffd71bcc3a03 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:56 +0800 211) break;
0ffd71bcc3a03 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:56 +0800 212)
0ffd71bcc3a03 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:56 +0800 213) if (inputmargin >= rq->inputsize) {
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 214) kunmap_atomic(headpage);
0ffd71bcc3a03 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:56 +0800 215) return -EIO;
0ffd71bcc3a03 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:56 +0800 216) }
0ffd71bcc3a03 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:56 +0800 217) }
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 218)
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 219) rq->inputsize -= inputmargin;
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 220) src = z_erofs_handle_inplace_io(rq, headpage, &inputmargin, &maptype,
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 221) support_0padding);
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 222) if (IS_ERR(src))
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 223) return PTR_ERR(src);
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 224)
af1038abbd144 fs/erofs/decompressor.c (Gao Xiang 2020-02-26 16:10:07 +0800 225) /* legacy format could compress extra data in a pcluster. */
af1038abbd144 fs/erofs/decompressor.c (Gao Xiang 2020-02-26 16:10:07 +0800 226) if (rq->partial_decoding || !support_0padding)
af1038abbd144 fs/erofs/decompressor.c (Gao Xiang 2020-02-26 16:10:07 +0800 227) ret = LZ4_decompress_safe_partial(src + inputmargin, out,
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 228) rq->inputsize, rq->outputsize, rq->outputsize);
af1038abbd144 fs/erofs/decompressor.c (Gao Xiang 2020-02-26 16:10:07 +0800 229) else
af1038abbd144 fs/erofs/decompressor.c (Gao Xiang 2020-02-26 16:10:07 +0800 230) ret = LZ4_decompress_safe(src + inputmargin, out,
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 231) rq->inputsize, rq->outputsize);
af1038abbd144 fs/erofs/decompressor.c (Gao Xiang 2020-02-26 16:10:07 +0800 232)
aa99a76b40d64 fs/erofs/decompressor.c (Gao Xiang 2020-02-26 16:10:08 +0800 233) if (ret != rq->outputsize) {
aa99a76b40d64 fs/erofs/decompressor.c (Gao Xiang 2020-02-26 16:10:08 +0800 234) erofs_err(rq->sb, "failed to decompress %d in[%u, %u] out[%u]",
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 235) ret, rq->inputsize, inputmargin, rq->outputsize);
aa99a76b40d64 fs/erofs/decompressor.c (Gao Xiang 2020-02-26 16:10:08 +0800 236)
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 237) WARN_ON(1);
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 238) print_hex_dump(KERN_DEBUG, "[ in]: ", DUMP_PREFIX_OFFSET,
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 239) 16, 1, src + inputmargin, rq->inputsize, true);
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 240) print_hex_dump(KERN_DEBUG, "[out]: ", DUMP_PREFIX_OFFSET,
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 241) 16, 1, out, rq->outputsize, true);
aa99a76b40d64 fs/erofs/decompressor.c (Gao Xiang 2020-02-26 16:10:08 +0800 242)
aa99a76b40d64 fs/erofs/decompressor.c (Gao Xiang 2020-02-26 16:10:08 +0800 243) if (ret >= 0)
aa99a76b40d64 fs/erofs/decompressor.c (Gao Xiang 2020-02-26 16:10:08 +0800 244) memset(out + ret, 0, rq->outputsize - ret);
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 245) ret = -EIO;
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 246) }
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 247)
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 248) if (maptype == 0) {
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 249) kunmap_atomic(src);
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 250) } else if (maptype == 1) {
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 251) vm_unmap_ram(src, PAGE_ALIGN(rq->inputsize) >> PAGE_SHIFT);
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 252) } else if (maptype == 2) {
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 253) erofs_put_pcpubuf(src);
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 254) } else {
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 255) DBG_BUGON(1);
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 256) return -EFAULT;
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 257) }
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 258) return ret;
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 259) }
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 260)
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 261) static struct z_erofs_decompressor decompressors[] = {
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 262) [Z_EROFS_COMPRESSION_SHIFTED] = {
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 263) .name = "shifted"
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 264) },
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 265) [Z_EROFS_COMPRESSION_LZ4] = {
99634bf388db0 fs/erofs/decompressor.c (Gao Xiang 2019-09-04 10:09:05 +0800 266) .prepare_destpages = z_erofs_lz4_prepare_destpages,
99634bf388db0 fs/erofs/decompressor.c (Gao Xiang 2019-09-04 10:09:05 +0800 267) .decompress = z_erofs_lz4_decompress,
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 268) .name = "lz4"
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 269) },
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 270) };
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 271)
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 272) static void copy_from_pcpubuf(struct page **out, const char *dst,
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 273) unsigned short pageofs_out,
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 274) unsigned int outputsize)
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 275) {
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 276) const char *end = dst + outputsize;
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 277) const unsigned int righthalf = PAGE_SIZE - pageofs_out;
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 278) const char *cur = dst - pageofs_out;
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 279)
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 280) while (cur < end) {
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 281) struct page *const page = *out++;
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 282)
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 283) if (page) {
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 284) char *buf = kmap_atomic(page);
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 285)
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 286) if (cur >= dst) {
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 287) memcpy(buf, cur, min_t(uint, PAGE_SIZE,
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 288) end - cur));
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 289) } else {
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 290) memcpy(buf + pageofs_out, cur + pageofs_out,
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 291) min_t(uint, righthalf, end - cur));
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 292) }
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 293) kunmap_atomic(buf);
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 294) }
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 295) cur += PAGE_SIZE;
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 296) }
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 297) }
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 298)
99634bf388db0 fs/erofs/decompressor.c (Gao Xiang 2019-09-04 10:09:05 +0800 299) static int z_erofs_decompress_generic(struct z_erofs_decompress_req *rq,
99634bf388db0 fs/erofs/decompressor.c (Gao Xiang 2019-09-04 10:09:05 +0800 300) struct list_head *pagepool)
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 301) {
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 302) const unsigned int nrpages_out =
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 303) PAGE_ALIGN(rq->pageofs_out + rq->outputsize) >> PAGE_SHIFT;
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 304) const struct z_erofs_decompressor *alg = decompressors + rq->alg;
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 305) unsigned int dst_maptype;
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 306) void *dst;
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 307) int ret;
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 308)
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 309) /* two optimized fast paths only for non bigpcluster cases yet */
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 310) if (rq->inputsize <= PAGE_SIZE) {
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 311) if (nrpages_out == 1 && !rq->inplace_io) {
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 312) DBG_BUGON(!*rq->out);
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 313) dst = kmap_atomic(*rq->out);
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 314) dst_maptype = 0;
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 315) goto dstmap_out;
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 316) }
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 317)
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 318) /*
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 319) * For the case of small output size (especially much less
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 320) * than PAGE_SIZE), memcpy the decompressed data rather than
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 321) * compressed data is preferred.
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 322) */
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 323) if (rq->outputsize <= PAGE_SIZE * 7 / 8) {
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 324) dst = erofs_get_pcpubuf(1);
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 325) if (IS_ERR(dst))
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 326) return PTR_ERR(dst);
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 327)
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 328) rq->inplace_io = false;
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 329) ret = alg->decompress(rq, dst);
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 330) if (!ret)
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 331) copy_from_pcpubuf(rq->out, dst, rq->pageofs_out,
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 332) rq->outputsize);
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 333)
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 334) erofs_put_pcpubuf(dst);
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 335) return ret;
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 336) }
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 337) }
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 338)
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 339) /* general decoding path which can be used for all cases */
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 340) ret = alg->prepare_destpages(rq, pagepool);
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 341) if (ret < 0)
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 342) return ret;
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 343) if (ret) {
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 344) dst = page_address(*rq->out);
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 345) dst_maptype = 1;
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 346) goto dstmap_out;
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 347) }
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 348)
598162d050801 fs/erofs/decompressor.c (Gao Xiang 2021-04-07 12:39:26 +0800 349) dst = erofs_vm_map_ram(rq->out, nrpages_out);
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 350) if (!dst)
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 351) return -ENOMEM;
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 352) dst_maptype = 2;
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 353)
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 354) dstmap_out:
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 355) ret = alg->decompress(rq, dst + rq->pageofs_out);
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 356)
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 357) if (!dst_maptype)
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 358) kunmap_atomic(dst);
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 359) else if (dst_maptype == 2)
73d03931be2ff fs/erofs/decompressor.c (Gao Xiang 2019-09-04 10:09:07 +0800 360) vm_unmap_ram(dst, nrpages_out);
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 361) return ret;
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 362) }
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 363)
99634bf388db0 fs/erofs/decompressor.c (Gao Xiang 2019-09-04 10:09:05 +0800 364) static int z_erofs_shifted_transform(const struct z_erofs_decompress_req *rq,
99634bf388db0 fs/erofs/decompressor.c (Gao Xiang 2019-09-04 10:09:05 +0800 365) struct list_head *pagepool)
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 366) {
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 367) const unsigned int nrpages_out =
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 368) PAGE_ALIGN(rq->pageofs_out + rq->outputsize) >> PAGE_SHIFT;
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 369) const unsigned int righthalf = PAGE_SIZE - rq->pageofs_out;
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 370) unsigned char *src, *dst;
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 371)
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 372) if (nrpages_out > 2) {
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 373) DBG_BUGON(1);
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 374) return -EIO;
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 375) }
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 376)
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 377) if (rq->out[0] == *rq->in) {
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 378) DBG_BUGON(nrpages_out != 1);
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 379) return 0;
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 380) }
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 381)
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 382) src = kmap_atomic(*rq->in);
4d2024370d877 fs/erofs/decompressor.c (Gao Xiang 2020-01-07 10:25:46 +0800 383) if (rq->out[0]) {
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 384) dst = kmap_atomic(rq->out[0]);
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 385) memcpy(dst + rq->pageofs_out, src, righthalf);
4d2024370d877 fs/erofs/decompressor.c (Gao Xiang 2020-01-07 10:25:46 +0800 386) kunmap_atomic(dst);
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 387) }
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 388)
4d2024370d877 fs/erofs/decompressor.c (Gao Xiang 2020-01-07 10:25:46 +0800 389) if (nrpages_out == 2) {
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 390) DBG_BUGON(!rq->out[1]);
4d2024370d877 fs/erofs/decompressor.c (Gao Xiang 2020-01-07 10:25:46 +0800 391) if (rq->out[1] == *rq->in) {
4d2024370d877 fs/erofs/decompressor.c (Gao Xiang 2020-01-07 10:25:46 +0800 392) memmove(src, src + righthalf, rq->pageofs_out);
4d2024370d877 fs/erofs/decompressor.c (Gao Xiang 2020-01-07 10:25:46 +0800 393) } else {
4d2024370d877 fs/erofs/decompressor.c (Gao Xiang 2020-01-07 10:25:46 +0800 394) dst = kmap_atomic(rq->out[1]);
4d2024370d877 fs/erofs/decompressor.c (Gao Xiang 2020-01-07 10:25:46 +0800 395) memcpy(dst, src + righthalf, rq->pageofs_out);
4d2024370d877 fs/erofs/decompressor.c (Gao Xiang 2020-01-07 10:25:46 +0800 396) kunmap_atomic(dst);
4d2024370d877 fs/erofs/decompressor.c (Gao Xiang 2020-01-07 10:25:46 +0800 397) }
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 398) }
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 399) kunmap_atomic(src);
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 400) return 0;
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 401) }
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 402)
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 403) int z_erofs_decompress(struct z_erofs_decompress_req *rq,
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 404) struct list_head *pagepool)
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 405) {
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 406) if (rq->alg == Z_EROFS_COMPRESSION_SHIFTED)
99634bf388db0 fs/erofs/decompressor.c (Gao Xiang 2019-09-04 10:09:05 +0800 407) return z_erofs_shifted_transform(rq, pagepool);
99634bf388db0 fs/erofs/decompressor.c (Gao Xiang 2019-09-04 10:09:05 +0800 408) return z_erofs_decompress_generic(rq, pagepool);
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 409) }
7fc45dbc938a2 drivers/staging/erofs/decompressor.c (Gao Xiang 2019-06-24 15:22:55 +0800 410)