147e4937aSGao Xiang // SPDX-License-Identifier: GPL-2.0-only 247e4937aSGao Xiang /* 347e4937aSGao Xiang * Copyright (C) 2018-2019 HUAWEI, Inc. 4592e7cd0SAlexander A. Klimov * https://www.huawei.com/ 547e4937aSGao Xiang * Created by Gao Xiang <gaoxiang25@huawei.com> 647e4937aSGao Xiang */ 747e4937aSGao Xiang #include "internal.h" 847e4937aSGao Xiang #include <asm/unaligned.h> 947e4937aSGao Xiang #include <trace/events/erofs.h> 1047e4937aSGao Xiang 1147e4937aSGao Xiang int z_erofs_fill_inode(struct inode *inode) 1247e4937aSGao Xiang { 13a5876e24SGao Xiang struct erofs_inode *const vi = EROFS_I(inode); 14*cec6e93bSGao Xiang struct erofs_sb_info *sbi = EROFS_SB(inode->i_sb); 1547e4937aSGao Xiang 16*cec6e93bSGao Xiang if (!erofs_sb_has_big_pcluster(sbi) && 17*cec6e93bSGao Xiang vi->datalayout == EROFS_INODE_FLAT_COMPRESSION_LEGACY) { 1847e4937aSGao Xiang vi->z_advise = 0; 1947e4937aSGao Xiang vi->z_algorithmtype[0] = 0; 2047e4937aSGao Xiang vi->z_algorithmtype[1] = 0; 2147e4937aSGao Xiang vi->z_logical_clusterbits = LOG_BLOCK_SIZE; 22a5876e24SGao Xiang set_bit(EROFS_I_Z_INITED_BIT, &vi->flags); 2347e4937aSGao Xiang } 240c638f70SGao Xiang inode->i_mapping->a_ops = &z_erofs_aops; 2547e4937aSGao Xiang return 0; 2647e4937aSGao Xiang } 2747e4937aSGao Xiang 280c638f70SGao Xiang static int z_erofs_fill_inode_lazy(struct inode *inode) 2947e4937aSGao Xiang { 30a5876e24SGao Xiang struct erofs_inode *const vi = EROFS_I(inode); 3147e4937aSGao Xiang struct super_block *const sb = inode->i_sb; 3247e4937aSGao Xiang int err; 3347e4937aSGao Xiang erofs_off_t pos; 3447e4937aSGao Xiang struct page *page; 3547e4937aSGao Xiang void *kaddr; 3647e4937aSGao Xiang struct z_erofs_map_header *h; 3747e4937aSGao Xiang 38ce063129SGao Xiang if (test_bit(EROFS_I_Z_INITED_BIT, &vi->flags)) { 39ce063129SGao Xiang /* 40ce063129SGao Xiang * paired with smp_mb() at the end of the function to ensure 41ce063129SGao Xiang * fields will only be observed after the bit is set. 42ce063129SGao Xiang */ 43ce063129SGao Xiang smp_mb(); 4447e4937aSGao Xiang return 0; 45ce063129SGao Xiang } 4647e4937aSGao Xiang 47a5876e24SGao Xiang if (wait_on_bit_lock(&vi->flags, EROFS_I_BL_Z_BIT, TASK_KILLABLE)) 4847e4937aSGao Xiang return -ERESTARTSYS; 4947e4937aSGao Xiang 5047e4937aSGao Xiang err = 0; 51a5876e24SGao Xiang if (test_bit(EROFS_I_Z_INITED_BIT, &vi->flags)) 5247e4937aSGao Xiang goto out_unlock; 5347e4937aSGao Xiang 54*cec6e93bSGao Xiang DBG_BUGON(!erofs_sb_has_big_pcluster(EROFS_SB(sb)) && 55*cec6e93bSGao Xiang vi->datalayout == EROFS_INODE_FLAT_COMPRESSION_LEGACY); 5647e4937aSGao Xiang 5747e4937aSGao Xiang pos = ALIGN(iloc(EROFS_SB(sb), vi->nid) + vi->inode_isize + 5847e4937aSGao Xiang vi->xattr_isize, 8); 59e655b5b3SGao Xiang page = erofs_get_meta_page(sb, erofs_blknr(pos)); 6047e4937aSGao Xiang if (IS_ERR(page)) { 6147e4937aSGao Xiang err = PTR_ERR(page); 6247e4937aSGao Xiang goto out_unlock; 6347e4937aSGao Xiang } 6447e4937aSGao Xiang 6547e4937aSGao Xiang kaddr = kmap_atomic(page); 6647e4937aSGao Xiang 6747e4937aSGao Xiang h = kaddr + erofs_blkoff(pos); 6847e4937aSGao Xiang vi->z_advise = le16_to_cpu(h->h_advise); 6947e4937aSGao Xiang vi->z_algorithmtype[0] = h->h_algorithmtype & 15; 7047e4937aSGao Xiang vi->z_algorithmtype[1] = h->h_algorithmtype >> 4; 7147e4937aSGao Xiang 7247e4937aSGao Xiang if (vi->z_algorithmtype[0] >= Z_EROFS_COMPRESSION_MAX) { 734f761fa2SGao Xiang erofs_err(sb, "unknown compression format %u for nid %llu, please upgrade kernel", 7447e4937aSGao Xiang vi->z_algorithmtype[0], vi->nid); 7547e4937aSGao Xiang err = -EOPNOTSUPP; 7647e4937aSGao Xiang goto unmap_done; 7747e4937aSGao Xiang } 7847e4937aSGao Xiang 7947e4937aSGao Xiang vi->z_logical_clusterbits = LOG_BLOCK_SIZE + (h->h_clusterbits & 7); 80ce063129SGao Xiang /* paired with smp_mb() at the beginning of the function */ 81ce063129SGao Xiang smp_mb(); 82a5876e24SGao Xiang set_bit(EROFS_I_Z_INITED_BIT, &vi->flags); 8347e4937aSGao Xiang unmap_done: 8447e4937aSGao Xiang kunmap_atomic(kaddr); 8547e4937aSGao Xiang unlock_page(page); 8647e4937aSGao Xiang put_page(page); 8747e4937aSGao Xiang out_unlock: 88a5876e24SGao Xiang clear_and_wake_up_bit(EROFS_I_BL_Z_BIT, &vi->flags); 8947e4937aSGao Xiang return err; 9047e4937aSGao Xiang } 9147e4937aSGao Xiang 9247e4937aSGao Xiang struct z_erofs_maprecorder { 9347e4937aSGao Xiang struct inode *inode; 9447e4937aSGao Xiang struct erofs_map_blocks *map; 9547e4937aSGao Xiang void *kaddr; 9647e4937aSGao Xiang 9747e4937aSGao Xiang unsigned long lcn; 9847e4937aSGao Xiang /* compression extent information gathered */ 9947e4937aSGao Xiang u8 type; 10047e4937aSGao Xiang u16 clusterofs; 10147e4937aSGao Xiang u16 delta[2]; 102*cec6e93bSGao Xiang erofs_blk_t pblk, compressedlcs; 10347e4937aSGao Xiang }; 10447e4937aSGao Xiang 10547e4937aSGao Xiang static int z_erofs_reload_indexes(struct z_erofs_maprecorder *m, 10647e4937aSGao Xiang erofs_blk_t eblk) 10747e4937aSGao Xiang { 10847e4937aSGao Xiang struct super_block *const sb = m->inode->i_sb; 10947e4937aSGao Xiang struct erofs_map_blocks *const map = m->map; 11047e4937aSGao Xiang struct page *mpage = map->mpage; 11147e4937aSGao Xiang 11247e4937aSGao Xiang if (mpage) { 11347e4937aSGao Xiang if (mpage->index == eblk) { 11447e4937aSGao Xiang if (!m->kaddr) 11547e4937aSGao Xiang m->kaddr = kmap_atomic(mpage); 11647e4937aSGao Xiang return 0; 11747e4937aSGao Xiang } 11847e4937aSGao Xiang 11947e4937aSGao Xiang if (m->kaddr) { 12047e4937aSGao Xiang kunmap_atomic(m->kaddr); 12147e4937aSGao Xiang m->kaddr = NULL; 12247e4937aSGao Xiang } 12347e4937aSGao Xiang put_page(mpage); 12447e4937aSGao Xiang } 12547e4937aSGao Xiang 126e655b5b3SGao Xiang mpage = erofs_get_meta_page(sb, eblk); 12747e4937aSGao Xiang if (IS_ERR(mpage)) { 12847e4937aSGao Xiang map->mpage = NULL; 12947e4937aSGao Xiang return PTR_ERR(mpage); 13047e4937aSGao Xiang } 13147e4937aSGao Xiang m->kaddr = kmap_atomic(mpage); 13247e4937aSGao Xiang unlock_page(mpage); 13347e4937aSGao Xiang map->mpage = mpage; 13447e4937aSGao Xiang return 0; 13547e4937aSGao Xiang } 13647e4937aSGao Xiang 1370c638f70SGao Xiang static int legacy_load_cluster_from_disk(struct z_erofs_maprecorder *m, 13847e4937aSGao Xiang unsigned long lcn) 13947e4937aSGao Xiang { 14047e4937aSGao Xiang struct inode *const inode = m->inode; 141a5876e24SGao Xiang struct erofs_inode *const vi = EROFS_I(inode); 14247e4937aSGao Xiang const erofs_off_t ibase = iloc(EROFS_I_SB(inode), vi->nid); 14347e4937aSGao Xiang const erofs_off_t pos = 14447e4937aSGao Xiang Z_EROFS_VLE_LEGACY_INDEX_ALIGN(ibase + vi->inode_isize + 14547e4937aSGao Xiang vi->xattr_isize) + 14647e4937aSGao Xiang lcn * sizeof(struct z_erofs_vle_decompressed_index); 14747e4937aSGao Xiang struct z_erofs_vle_decompressed_index *di; 14847e4937aSGao Xiang unsigned int advise, type; 14947e4937aSGao Xiang int err; 15047e4937aSGao Xiang 15147e4937aSGao Xiang err = z_erofs_reload_indexes(m, erofs_blknr(pos)); 15247e4937aSGao Xiang if (err) 15347e4937aSGao Xiang return err; 15447e4937aSGao Xiang 15547e4937aSGao Xiang m->lcn = lcn; 15647e4937aSGao Xiang di = m->kaddr + erofs_blkoff(pos); 15747e4937aSGao Xiang 15847e4937aSGao Xiang advise = le16_to_cpu(di->di_advise); 15947e4937aSGao Xiang type = (advise >> Z_EROFS_VLE_DI_CLUSTER_TYPE_BIT) & 16047e4937aSGao Xiang ((1 << Z_EROFS_VLE_DI_CLUSTER_TYPE_BITS) - 1); 16147e4937aSGao Xiang switch (type) { 16247e4937aSGao Xiang case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD: 16347e4937aSGao Xiang m->clusterofs = 1 << vi->z_logical_clusterbits; 16447e4937aSGao Xiang m->delta[0] = le16_to_cpu(di->di_u.delta[0]); 165*cec6e93bSGao Xiang if (m->delta[0] & Z_EROFS_VLE_DI_D0_CBLKCNT) { 166*cec6e93bSGao Xiang if (!(vi->z_advise & Z_EROFS_ADVISE_BIG_PCLUSTER_1)) { 167*cec6e93bSGao Xiang DBG_BUGON(1); 168*cec6e93bSGao Xiang return -EFSCORRUPTED; 169*cec6e93bSGao Xiang } 170*cec6e93bSGao Xiang m->compressedlcs = m->delta[0] & 171*cec6e93bSGao Xiang ~Z_EROFS_VLE_DI_D0_CBLKCNT; 172*cec6e93bSGao Xiang m->delta[0] = 1; 173*cec6e93bSGao Xiang } 17447e4937aSGao Xiang m->delta[1] = le16_to_cpu(di->di_u.delta[1]); 17547e4937aSGao Xiang break; 17647e4937aSGao Xiang case Z_EROFS_VLE_CLUSTER_TYPE_PLAIN: 17747e4937aSGao Xiang case Z_EROFS_VLE_CLUSTER_TYPE_HEAD: 17847e4937aSGao Xiang m->clusterofs = le16_to_cpu(di->di_clusterofs); 17947e4937aSGao Xiang m->pblk = le32_to_cpu(di->di_u.blkaddr); 18047e4937aSGao Xiang break; 18147e4937aSGao Xiang default: 18247e4937aSGao Xiang DBG_BUGON(1); 18347e4937aSGao Xiang return -EOPNOTSUPP; 18447e4937aSGao Xiang } 18547e4937aSGao Xiang m->type = type; 18647e4937aSGao Xiang return 0; 18747e4937aSGao Xiang } 18847e4937aSGao Xiang 18947e4937aSGao Xiang static unsigned int decode_compactedbits(unsigned int lobits, 19047e4937aSGao Xiang unsigned int lomask, 19147e4937aSGao Xiang u8 *in, unsigned int pos, u8 *type) 19247e4937aSGao Xiang { 19347e4937aSGao Xiang const unsigned int v = get_unaligned_le32(in + pos / 8) >> (pos & 7); 19447e4937aSGao Xiang const unsigned int lo = v & lomask; 19547e4937aSGao Xiang 19647e4937aSGao Xiang *type = (v >> lobits) & 3; 19747e4937aSGao Xiang return lo; 19847e4937aSGao Xiang } 19947e4937aSGao Xiang 20047e4937aSGao Xiang static int unpack_compacted_index(struct z_erofs_maprecorder *m, 20147e4937aSGao Xiang unsigned int amortizedshift, 20247e4937aSGao Xiang unsigned int eofs) 20347e4937aSGao Xiang { 204a5876e24SGao Xiang struct erofs_inode *const vi = EROFS_I(m->inode); 20547e4937aSGao Xiang const unsigned int lclusterbits = vi->z_logical_clusterbits; 20647e4937aSGao Xiang const unsigned int lomask = (1 << lclusterbits) - 1; 20747e4937aSGao Xiang unsigned int vcnt, base, lo, encodebits, nblk; 20847e4937aSGao Xiang int i; 20947e4937aSGao Xiang u8 *in, type; 21047e4937aSGao Xiang 21147e4937aSGao Xiang if (1 << amortizedshift == 4) 21247e4937aSGao Xiang vcnt = 2; 21347e4937aSGao Xiang else if (1 << amortizedshift == 2 && lclusterbits == 12) 21447e4937aSGao Xiang vcnt = 16; 21547e4937aSGao Xiang else 21647e4937aSGao Xiang return -EOPNOTSUPP; 21747e4937aSGao Xiang 21847e4937aSGao Xiang encodebits = ((vcnt << amortizedshift) - sizeof(__le32)) * 8 / vcnt; 21947e4937aSGao Xiang base = round_down(eofs, vcnt << amortizedshift); 22047e4937aSGao Xiang in = m->kaddr + base; 22147e4937aSGao Xiang 22247e4937aSGao Xiang i = (eofs - base) >> amortizedshift; 22347e4937aSGao Xiang 22447e4937aSGao Xiang lo = decode_compactedbits(lclusterbits, lomask, 22547e4937aSGao Xiang in, encodebits * i, &type); 22647e4937aSGao Xiang m->type = type; 22747e4937aSGao Xiang if (type == Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD) { 22847e4937aSGao Xiang m->clusterofs = 1 << lclusterbits; 22947e4937aSGao Xiang if (i + 1 != vcnt) { 23047e4937aSGao Xiang m->delta[0] = lo; 23147e4937aSGao Xiang return 0; 23247e4937aSGao Xiang } 23347e4937aSGao Xiang /* 23447e4937aSGao Xiang * since the last lcluster in the pack is special, 23547e4937aSGao Xiang * of which lo saves delta[1] rather than delta[0]. 23647e4937aSGao Xiang * Hence, get delta[0] by the previous lcluster indirectly. 23747e4937aSGao Xiang */ 23847e4937aSGao Xiang lo = decode_compactedbits(lclusterbits, lomask, 23947e4937aSGao Xiang in, encodebits * (i - 1), &type); 24047e4937aSGao Xiang if (type != Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD) 24147e4937aSGao Xiang lo = 0; 24247e4937aSGao Xiang m->delta[0] = lo + 1; 24347e4937aSGao Xiang return 0; 24447e4937aSGao Xiang } 24547e4937aSGao Xiang m->clusterofs = lo; 24647e4937aSGao Xiang m->delta[0] = 0; 24747e4937aSGao Xiang /* figout out blkaddr (pblk) for HEAD lclusters */ 24847e4937aSGao Xiang nblk = 1; 24947e4937aSGao Xiang while (i > 0) { 25047e4937aSGao Xiang --i; 25147e4937aSGao Xiang lo = decode_compactedbits(lclusterbits, lomask, 25247e4937aSGao Xiang in, encodebits * i, &type); 25347e4937aSGao Xiang if (type == Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD) 25447e4937aSGao Xiang i -= lo; 25547e4937aSGao Xiang 25647e4937aSGao Xiang if (i >= 0) 25747e4937aSGao Xiang ++nblk; 25847e4937aSGao Xiang } 25947e4937aSGao Xiang in += (vcnt << amortizedshift) - sizeof(__le32); 26047e4937aSGao Xiang m->pblk = le32_to_cpu(*(__le32 *)in) + nblk; 26147e4937aSGao Xiang return 0; 26247e4937aSGao Xiang } 26347e4937aSGao Xiang 26447e4937aSGao Xiang static int compacted_load_cluster_from_disk(struct z_erofs_maprecorder *m, 26547e4937aSGao Xiang unsigned long lcn) 26647e4937aSGao Xiang { 26747e4937aSGao Xiang struct inode *const inode = m->inode; 268a5876e24SGao Xiang struct erofs_inode *const vi = EROFS_I(inode); 26947e4937aSGao Xiang const unsigned int lclusterbits = vi->z_logical_clusterbits; 27047e4937aSGao Xiang const erofs_off_t ebase = ALIGN(iloc(EROFS_I_SB(inode), vi->nid) + 27147e4937aSGao Xiang vi->inode_isize + vi->xattr_isize, 8) + 27247e4937aSGao Xiang sizeof(struct z_erofs_map_header); 27347e4937aSGao Xiang const unsigned int totalidx = DIV_ROUND_UP(inode->i_size, EROFS_BLKSIZ); 27447e4937aSGao Xiang unsigned int compacted_4b_initial, compacted_2b; 27547e4937aSGao Xiang unsigned int amortizedshift; 27647e4937aSGao Xiang erofs_off_t pos; 27747e4937aSGao Xiang int err; 27847e4937aSGao Xiang 27947e4937aSGao Xiang if (lclusterbits != 12) 28047e4937aSGao Xiang return -EOPNOTSUPP; 28147e4937aSGao Xiang 28247e4937aSGao Xiang if (lcn >= totalidx) 28347e4937aSGao Xiang return -EINVAL; 28447e4937aSGao Xiang 28547e4937aSGao Xiang m->lcn = lcn; 28647e4937aSGao Xiang /* used to align to 32-byte (compacted_2b) alignment */ 28747e4937aSGao Xiang compacted_4b_initial = (32 - ebase % 32) / 4; 28847e4937aSGao Xiang if (compacted_4b_initial == 32 / 4) 28947e4937aSGao Xiang compacted_4b_initial = 0; 29047e4937aSGao Xiang 29147e4937aSGao Xiang if (vi->z_advise & Z_EROFS_ADVISE_COMPACTED_2B) 29247e4937aSGao Xiang compacted_2b = rounddown(totalidx - compacted_4b_initial, 16); 29347e4937aSGao Xiang else 29447e4937aSGao Xiang compacted_2b = 0; 29547e4937aSGao Xiang 29647e4937aSGao Xiang pos = ebase; 29747e4937aSGao Xiang if (lcn < compacted_4b_initial) { 29847e4937aSGao Xiang amortizedshift = 2; 29947e4937aSGao Xiang goto out; 30047e4937aSGao Xiang } 30147e4937aSGao Xiang pos += compacted_4b_initial * 4; 30247e4937aSGao Xiang lcn -= compacted_4b_initial; 30347e4937aSGao Xiang 30447e4937aSGao Xiang if (lcn < compacted_2b) { 30547e4937aSGao Xiang amortizedshift = 1; 30647e4937aSGao Xiang goto out; 30747e4937aSGao Xiang } 30847e4937aSGao Xiang pos += compacted_2b * 2; 30947e4937aSGao Xiang lcn -= compacted_2b; 31047e4937aSGao Xiang amortizedshift = 2; 31147e4937aSGao Xiang out: 31247e4937aSGao Xiang pos += lcn * (1 << amortizedshift); 31347e4937aSGao Xiang err = z_erofs_reload_indexes(m, erofs_blknr(pos)); 31447e4937aSGao Xiang if (err) 31547e4937aSGao Xiang return err; 31647e4937aSGao Xiang return unpack_compacted_index(m, amortizedshift, erofs_blkoff(pos)); 31747e4937aSGao Xiang } 31847e4937aSGao Xiang 3190c638f70SGao Xiang static int z_erofs_load_cluster_from_disk(struct z_erofs_maprecorder *m, 32047e4937aSGao Xiang unsigned int lcn) 32147e4937aSGao Xiang { 322a5876e24SGao Xiang const unsigned int datamode = EROFS_I(m->inode)->datalayout; 32347e4937aSGao Xiang 32447e4937aSGao Xiang if (datamode == EROFS_INODE_FLAT_COMPRESSION_LEGACY) 3250c638f70SGao Xiang return legacy_load_cluster_from_disk(m, lcn); 32647e4937aSGao Xiang 32747e4937aSGao Xiang if (datamode == EROFS_INODE_FLAT_COMPRESSION) 32847e4937aSGao Xiang return compacted_load_cluster_from_disk(m, lcn); 32947e4937aSGao Xiang 33047e4937aSGao Xiang return -EINVAL; 33147e4937aSGao Xiang } 33247e4937aSGao Xiang 3330c638f70SGao Xiang static int z_erofs_extent_lookback(struct z_erofs_maprecorder *m, 33447e4937aSGao Xiang unsigned int lookback_distance) 33547e4937aSGao Xiang { 336a5876e24SGao Xiang struct erofs_inode *const vi = EROFS_I(m->inode); 33747e4937aSGao Xiang struct erofs_map_blocks *const map = m->map; 33847e4937aSGao Xiang const unsigned int lclusterbits = vi->z_logical_clusterbits; 33947e4937aSGao Xiang unsigned long lcn = m->lcn; 34047e4937aSGao Xiang int err; 34147e4937aSGao Xiang 34247e4937aSGao Xiang if (lcn < lookback_distance) { 3434f761fa2SGao Xiang erofs_err(m->inode->i_sb, 3444f761fa2SGao Xiang "bogus lookback distance @ nid %llu", vi->nid); 34547e4937aSGao Xiang DBG_BUGON(1); 34647e4937aSGao Xiang return -EFSCORRUPTED; 34747e4937aSGao Xiang } 34847e4937aSGao Xiang 34947e4937aSGao Xiang /* load extent head logical cluster if needed */ 35047e4937aSGao Xiang lcn -= lookback_distance; 3510c638f70SGao Xiang err = z_erofs_load_cluster_from_disk(m, lcn); 35247e4937aSGao Xiang if (err) 35347e4937aSGao Xiang return err; 35447e4937aSGao Xiang 35547e4937aSGao Xiang switch (m->type) { 35647e4937aSGao Xiang case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD: 3578d8a09b0SGao Xiang if (!m->delta[0]) { 3584f761fa2SGao Xiang erofs_err(m->inode->i_sb, 3594f761fa2SGao Xiang "invalid lookback distance 0 @ nid %llu", 36047e4937aSGao Xiang vi->nid); 36147e4937aSGao Xiang DBG_BUGON(1); 36247e4937aSGao Xiang return -EFSCORRUPTED; 36347e4937aSGao Xiang } 3640c638f70SGao Xiang return z_erofs_extent_lookback(m, m->delta[0]); 36547e4937aSGao Xiang case Z_EROFS_VLE_CLUSTER_TYPE_PLAIN: 36647e4937aSGao Xiang map->m_flags &= ~EROFS_MAP_ZIPPED; 367df561f66SGustavo A. R. Silva fallthrough; 36847e4937aSGao Xiang case Z_EROFS_VLE_CLUSTER_TYPE_HEAD: 36947e4937aSGao Xiang map->m_la = (lcn << lclusterbits) | m->clusterofs; 37047e4937aSGao Xiang break; 37147e4937aSGao Xiang default: 3724f761fa2SGao Xiang erofs_err(m->inode->i_sb, 3734f761fa2SGao Xiang "unknown type %u @ lcn %lu of nid %llu", 37447e4937aSGao Xiang m->type, lcn, vi->nid); 37547e4937aSGao Xiang DBG_BUGON(1); 37647e4937aSGao Xiang return -EOPNOTSUPP; 37747e4937aSGao Xiang } 37847e4937aSGao Xiang return 0; 37947e4937aSGao Xiang } 38047e4937aSGao Xiang 381*cec6e93bSGao Xiang static int z_erofs_get_extent_compressedlen(struct z_erofs_maprecorder *m, 382*cec6e93bSGao Xiang unsigned int initial_lcn) 383*cec6e93bSGao Xiang { 384*cec6e93bSGao Xiang struct erofs_inode *const vi = EROFS_I(m->inode); 385*cec6e93bSGao Xiang struct erofs_map_blocks *const map = m->map; 386*cec6e93bSGao Xiang const unsigned int lclusterbits = vi->z_logical_clusterbits; 387*cec6e93bSGao Xiang unsigned long lcn; 388*cec6e93bSGao Xiang int err; 389*cec6e93bSGao Xiang 390*cec6e93bSGao Xiang DBG_BUGON(m->type != Z_EROFS_VLE_CLUSTER_TYPE_PLAIN && 391*cec6e93bSGao Xiang m->type != Z_EROFS_VLE_CLUSTER_TYPE_HEAD); 392*cec6e93bSGao Xiang if (!(map->m_flags & EROFS_MAP_ZIPPED) || 393*cec6e93bSGao Xiang !(vi->z_advise & Z_EROFS_ADVISE_BIG_PCLUSTER_1)) { 394*cec6e93bSGao Xiang map->m_plen = 1 << lclusterbits; 395*cec6e93bSGao Xiang return 0; 396*cec6e93bSGao Xiang } 397*cec6e93bSGao Xiang 398*cec6e93bSGao Xiang lcn = m->lcn + 1; 399*cec6e93bSGao Xiang if (m->compressedlcs) 400*cec6e93bSGao Xiang goto out; 401*cec6e93bSGao Xiang if (lcn == initial_lcn) 402*cec6e93bSGao Xiang goto err_bonus_cblkcnt; 403*cec6e93bSGao Xiang 404*cec6e93bSGao Xiang err = z_erofs_load_cluster_from_disk(m, lcn); 405*cec6e93bSGao Xiang if (err) 406*cec6e93bSGao Xiang return err; 407*cec6e93bSGao Xiang 408*cec6e93bSGao Xiang switch (m->type) { 409*cec6e93bSGao Xiang case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD: 410*cec6e93bSGao Xiang if (m->delta[0] != 1) 411*cec6e93bSGao Xiang goto err_bonus_cblkcnt; 412*cec6e93bSGao Xiang if (m->compressedlcs) 413*cec6e93bSGao Xiang break; 414*cec6e93bSGao Xiang fallthrough; 415*cec6e93bSGao Xiang default: 416*cec6e93bSGao Xiang erofs_err(m->inode->i_sb, 417*cec6e93bSGao Xiang "cannot found CBLKCNT @ lcn %lu of nid %llu", 418*cec6e93bSGao Xiang lcn, vi->nid); 419*cec6e93bSGao Xiang DBG_BUGON(1); 420*cec6e93bSGao Xiang return -EFSCORRUPTED; 421*cec6e93bSGao Xiang } 422*cec6e93bSGao Xiang out: 423*cec6e93bSGao Xiang map->m_plen = m->compressedlcs << lclusterbits; 424*cec6e93bSGao Xiang return 0; 425*cec6e93bSGao Xiang err_bonus_cblkcnt: 426*cec6e93bSGao Xiang erofs_err(m->inode->i_sb, 427*cec6e93bSGao Xiang "bogus CBLKCNT @ lcn %lu of nid %llu", 428*cec6e93bSGao Xiang lcn, vi->nid); 429*cec6e93bSGao Xiang DBG_BUGON(1); 430*cec6e93bSGao Xiang return -EFSCORRUPTED; 431*cec6e93bSGao Xiang } 432*cec6e93bSGao Xiang 43347e4937aSGao Xiang int z_erofs_map_blocks_iter(struct inode *inode, 43447e4937aSGao Xiang struct erofs_map_blocks *map, 43547e4937aSGao Xiang int flags) 43647e4937aSGao Xiang { 437a5876e24SGao Xiang struct erofs_inode *const vi = EROFS_I(inode); 43847e4937aSGao Xiang struct z_erofs_maprecorder m = { 43947e4937aSGao Xiang .inode = inode, 44047e4937aSGao Xiang .map = map, 44147e4937aSGao Xiang }; 44247e4937aSGao Xiang int err = 0; 44347e4937aSGao Xiang unsigned int lclusterbits, endoff; 444*cec6e93bSGao Xiang unsigned long initial_lcn; 44547e4937aSGao Xiang unsigned long long ofs, end; 44647e4937aSGao Xiang 44747e4937aSGao Xiang trace_z_erofs_map_blocks_iter_enter(inode, map, flags); 44847e4937aSGao Xiang 44947e4937aSGao Xiang /* when trying to read beyond EOF, leave it unmapped */ 4508d8a09b0SGao Xiang if (map->m_la >= inode->i_size) { 45147e4937aSGao Xiang map->m_llen = map->m_la + 1 - inode->i_size; 45247e4937aSGao Xiang map->m_la = inode->i_size; 45347e4937aSGao Xiang map->m_flags = 0; 45447e4937aSGao Xiang goto out; 45547e4937aSGao Xiang } 45647e4937aSGao Xiang 4570c638f70SGao Xiang err = z_erofs_fill_inode_lazy(inode); 45847e4937aSGao Xiang if (err) 45947e4937aSGao Xiang goto out; 46047e4937aSGao Xiang 46147e4937aSGao Xiang lclusterbits = vi->z_logical_clusterbits; 46247e4937aSGao Xiang ofs = map->m_la; 463*cec6e93bSGao Xiang initial_lcn = ofs >> lclusterbits; 46447e4937aSGao Xiang endoff = ofs & ((1 << lclusterbits) - 1); 46547e4937aSGao Xiang 466*cec6e93bSGao Xiang err = z_erofs_load_cluster_from_disk(&m, initial_lcn); 46747e4937aSGao Xiang if (err) 46847e4937aSGao Xiang goto unmap_out; 46947e4937aSGao Xiang 47047e4937aSGao Xiang map->m_flags = EROFS_MAP_ZIPPED; /* by default, compressed */ 47147e4937aSGao Xiang end = (m.lcn + 1ULL) << lclusterbits; 47247e4937aSGao Xiang 47347e4937aSGao Xiang switch (m.type) { 47447e4937aSGao Xiang case Z_EROFS_VLE_CLUSTER_TYPE_PLAIN: 47547e4937aSGao Xiang if (endoff >= m.clusterofs) 47647e4937aSGao Xiang map->m_flags &= ~EROFS_MAP_ZIPPED; 477df561f66SGustavo A. R. Silva fallthrough; 47847e4937aSGao Xiang case Z_EROFS_VLE_CLUSTER_TYPE_HEAD: 47947e4937aSGao Xiang if (endoff >= m.clusterofs) { 48047e4937aSGao Xiang map->m_la = (m.lcn << lclusterbits) | m.clusterofs; 48147e4937aSGao Xiang break; 48247e4937aSGao Xiang } 48347e4937aSGao Xiang /* m.lcn should be >= 1 if endoff < m.clusterofs */ 4848d8a09b0SGao Xiang if (!m.lcn) { 4854f761fa2SGao Xiang erofs_err(inode->i_sb, 4864f761fa2SGao Xiang "invalid logical cluster 0 at nid %llu", 48747e4937aSGao Xiang vi->nid); 48847e4937aSGao Xiang err = -EFSCORRUPTED; 48947e4937aSGao Xiang goto unmap_out; 49047e4937aSGao Xiang } 49147e4937aSGao Xiang end = (m.lcn << lclusterbits) | m.clusterofs; 49247e4937aSGao Xiang map->m_flags |= EROFS_MAP_FULL_MAPPED; 49347e4937aSGao Xiang m.delta[0] = 1; 494df561f66SGustavo A. R. Silva fallthrough; 49547e4937aSGao Xiang case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD: 496fe6adcceSRuiqi Gong /* get the corresponding first chunk */ 4970c638f70SGao Xiang err = z_erofs_extent_lookback(&m, m.delta[0]); 4988d8a09b0SGao Xiang if (err) 49947e4937aSGao Xiang goto unmap_out; 50047e4937aSGao Xiang break; 50147e4937aSGao Xiang default: 5024f761fa2SGao Xiang erofs_err(inode->i_sb, 5034f761fa2SGao Xiang "unknown type %u @ offset %llu of nid %llu", 50447e4937aSGao Xiang m.type, ofs, vi->nid); 50547e4937aSGao Xiang err = -EOPNOTSUPP; 50647e4937aSGao Xiang goto unmap_out; 50747e4937aSGao Xiang } 50847e4937aSGao Xiang 50947e4937aSGao Xiang map->m_llen = end - map->m_la; 51047e4937aSGao Xiang map->m_pa = blknr_to_addr(m.pblk); 51147e4937aSGao Xiang map->m_flags |= EROFS_MAP_MAPPED; 51247e4937aSGao Xiang 513*cec6e93bSGao Xiang err = z_erofs_get_extent_compressedlen(&m, initial_lcn); 514*cec6e93bSGao Xiang if (err) 515*cec6e93bSGao Xiang goto out; 51647e4937aSGao Xiang unmap_out: 51747e4937aSGao Xiang if (m.kaddr) 51847e4937aSGao Xiang kunmap_atomic(m.kaddr); 51947e4937aSGao Xiang 52047e4937aSGao Xiang out: 5214f761fa2SGao Xiang erofs_dbg("%s, m_la %llu m_pa %llu m_llen %llu m_plen %llu m_flags 0%o", 52247e4937aSGao Xiang __func__, map->m_la, map->m_pa, 52347e4937aSGao Xiang map->m_llen, map->m_plen, map->m_flags); 52447e4937aSGao Xiang 52547e4937aSGao Xiang trace_z_erofs_map_blocks_iter_exit(inode, map, flags, err); 52647e4937aSGao Xiang 52747e4937aSGao Xiang /* aggressively BUG_ON iff CONFIG_EROFS_FS_DEBUG is on */ 52847e4937aSGao Xiang DBG_BUGON(err < 0 && err != -ENOMEM); 52947e4937aSGao Xiang return err; 53047e4937aSGao Xiang } 53147e4937aSGao Xiang 532