147e4937aSGao Xiang // SPDX-License-Identifier: GPL-2.0-only 247e4937aSGao Xiang /* 347e4937aSGao Xiang * Copyright (C) 2018-2019 HUAWEI, Inc. 447e4937aSGao Xiang * http://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 { 1347e4937aSGao Xiang struct erofs_vnode *const vi = EROFS_V(inode); 1447e4937aSGao Xiang 1547e4937aSGao Xiang if (vi->datamode == EROFS_INODE_FLAT_COMPRESSION_LEGACY) { 1647e4937aSGao Xiang vi->z_advise = 0; 1747e4937aSGao Xiang vi->z_algorithmtype[0] = 0; 1847e4937aSGao Xiang vi->z_algorithmtype[1] = 0; 1947e4937aSGao Xiang vi->z_logical_clusterbits = LOG_BLOCK_SIZE; 2047e4937aSGao Xiang vi->z_physical_clusterbits[0] = vi->z_logical_clusterbits; 2147e4937aSGao Xiang vi->z_physical_clusterbits[1] = vi->z_logical_clusterbits; 2247e4937aSGao Xiang set_bit(EROFS_V_Z_INITED_BIT, &vi->flags); 2347e4937aSGao Xiang } 2447e4937aSGao Xiang 2547e4937aSGao Xiang inode->i_mapping->a_ops = &z_erofs_vle_normalaccess_aops; 2647e4937aSGao Xiang return 0; 2747e4937aSGao Xiang } 2847e4937aSGao Xiang 2947e4937aSGao Xiang static int fill_inode_lazy(struct inode *inode) 3047e4937aSGao Xiang { 3147e4937aSGao Xiang struct erofs_vnode *const vi = EROFS_V(inode); 3247e4937aSGao Xiang struct super_block *const sb = inode->i_sb; 3347e4937aSGao Xiang int err; 3447e4937aSGao Xiang erofs_off_t pos; 3547e4937aSGao Xiang struct page *page; 3647e4937aSGao Xiang void *kaddr; 3747e4937aSGao Xiang struct z_erofs_map_header *h; 3847e4937aSGao Xiang 3947e4937aSGao Xiang if (test_bit(EROFS_V_Z_INITED_BIT, &vi->flags)) 4047e4937aSGao Xiang return 0; 4147e4937aSGao Xiang 4247e4937aSGao Xiang if (wait_on_bit_lock(&vi->flags, EROFS_V_BL_Z_BIT, TASK_KILLABLE)) 4347e4937aSGao Xiang return -ERESTARTSYS; 4447e4937aSGao Xiang 4547e4937aSGao Xiang err = 0; 4647e4937aSGao Xiang if (test_bit(EROFS_V_Z_INITED_BIT, &vi->flags)) 4747e4937aSGao Xiang goto out_unlock; 4847e4937aSGao Xiang 4947e4937aSGao Xiang DBG_BUGON(vi->datamode == EROFS_INODE_FLAT_COMPRESSION_LEGACY); 5047e4937aSGao Xiang 5147e4937aSGao Xiang pos = ALIGN(iloc(EROFS_SB(sb), vi->nid) + vi->inode_isize + 5247e4937aSGao Xiang vi->xattr_isize, 8); 5347e4937aSGao Xiang page = erofs_get_meta_page(sb, erofs_blknr(pos), false); 5447e4937aSGao Xiang if (IS_ERR(page)) { 5547e4937aSGao Xiang err = PTR_ERR(page); 5647e4937aSGao Xiang goto out_unlock; 5747e4937aSGao Xiang } 5847e4937aSGao Xiang 5947e4937aSGao Xiang kaddr = kmap_atomic(page); 6047e4937aSGao Xiang 6147e4937aSGao Xiang h = kaddr + erofs_blkoff(pos); 6247e4937aSGao Xiang vi->z_advise = le16_to_cpu(h->h_advise); 6347e4937aSGao Xiang vi->z_algorithmtype[0] = h->h_algorithmtype & 15; 6447e4937aSGao Xiang vi->z_algorithmtype[1] = h->h_algorithmtype >> 4; 6547e4937aSGao Xiang 6647e4937aSGao Xiang if (vi->z_algorithmtype[0] >= Z_EROFS_COMPRESSION_MAX) { 6747e4937aSGao Xiang errln("unknown compression format %u for nid %llu, please upgrade kernel", 6847e4937aSGao Xiang vi->z_algorithmtype[0], vi->nid); 6947e4937aSGao Xiang err = -EOPNOTSUPP; 7047e4937aSGao Xiang goto unmap_done; 7147e4937aSGao Xiang } 7247e4937aSGao Xiang 7347e4937aSGao Xiang vi->z_logical_clusterbits = LOG_BLOCK_SIZE + (h->h_clusterbits & 7); 7447e4937aSGao Xiang vi->z_physical_clusterbits[0] = vi->z_logical_clusterbits + 7547e4937aSGao Xiang ((h->h_clusterbits >> 3) & 3); 7647e4937aSGao Xiang 7747e4937aSGao Xiang if (vi->z_physical_clusterbits[0] != LOG_BLOCK_SIZE) { 7847e4937aSGao Xiang errln("unsupported physical clusterbits %u for nid %llu, please upgrade kernel", 7947e4937aSGao Xiang vi->z_physical_clusterbits[0], vi->nid); 8047e4937aSGao Xiang err = -EOPNOTSUPP; 8147e4937aSGao Xiang goto unmap_done; 8247e4937aSGao Xiang } 8347e4937aSGao Xiang 8447e4937aSGao Xiang vi->z_physical_clusterbits[1] = vi->z_logical_clusterbits + 8547e4937aSGao Xiang ((h->h_clusterbits >> 5) & 7); 8647e4937aSGao Xiang set_bit(EROFS_V_Z_INITED_BIT, &vi->flags); 8747e4937aSGao Xiang unmap_done: 8847e4937aSGao Xiang kunmap_atomic(kaddr); 8947e4937aSGao Xiang unlock_page(page); 9047e4937aSGao Xiang put_page(page); 9147e4937aSGao Xiang out_unlock: 9247e4937aSGao Xiang clear_and_wake_up_bit(EROFS_V_BL_Z_BIT, &vi->flags); 9347e4937aSGao Xiang return err; 9447e4937aSGao Xiang } 9547e4937aSGao Xiang 9647e4937aSGao Xiang struct z_erofs_maprecorder { 9747e4937aSGao Xiang struct inode *inode; 9847e4937aSGao Xiang struct erofs_map_blocks *map; 9947e4937aSGao Xiang void *kaddr; 10047e4937aSGao Xiang 10147e4937aSGao Xiang unsigned long lcn; 10247e4937aSGao Xiang /* compression extent information gathered */ 10347e4937aSGao Xiang u8 type; 10447e4937aSGao Xiang u16 clusterofs; 10547e4937aSGao Xiang u16 delta[2]; 10647e4937aSGao Xiang erofs_blk_t pblk; 10747e4937aSGao Xiang }; 10847e4937aSGao Xiang 10947e4937aSGao Xiang static int z_erofs_reload_indexes(struct z_erofs_maprecorder *m, 11047e4937aSGao Xiang erofs_blk_t eblk) 11147e4937aSGao Xiang { 11247e4937aSGao Xiang struct super_block *const sb = m->inode->i_sb; 11347e4937aSGao Xiang struct erofs_map_blocks *const map = m->map; 11447e4937aSGao Xiang struct page *mpage = map->mpage; 11547e4937aSGao Xiang 11647e4937aSGao Xiang if (mpage) { 11747e4937aSGao Xiang if (mpage->index == eblk) { 11847e4937aSGao Xiang if (!m->kaddr) 11947e4937aSGao Xiang m->kaddr = kmap_atomic(mpage); 12047e4937aSGao Xiang return 0; 12147e4937aSGao Xiang } 12247e4937aSGao Xiang 12347e4937aSGao Xiang if (m->kaddr) { 12447e4937aSGao Xiang kunmap_atomic(m->kaddr); 12547e4937aSGao Xiang m->kaddr = NULL; 12647e4937aSGao Xiang } 12747e4937aSGao Xiang put_page(mpage); 12847e4937aSGao Xiang } 12947e4937aSGao Xiang 13047e4937aSGao Xiang mpage = erofs_get_meta_page(sb, eblk, false); 13147e4937aSGao Xiang if (IS_ERR(mpage)) { 13247e4937aSGao Xiang map->mpage = NULL; 13347e4937aSGao Xiang return PTR_ERR(mpage); 13447e4937aSGao Xiang } 13547e4937aSGao Xiang m->kaddr = kmap_atomic(mpage); 13647e4937aSGao Xiang unlock_page(mpage); 13747e4937aSGao Xiang map->mpage = mpage; 13847e4937aSGao Xiang return 0; 13947e4937aSGao Xiang } 14047e4937aSGao Xiang 14147e4937aSGao Xiang static int vle_legacy_load_cluster_from_disk(struct z_erofs_maprecorder *m, 14247e4937aSGao Xiang unsigned long lcn) 14347e4937aSGao Xiang { 14447e4937aSGao Xiang struct inode *const inode = m->inode; 14547e4937aSGao Xiang struct erofs_vnode *const vi = EROFS_V(inode); 14647e4937aSGao Xiang const erofs_off_t ibase = iloc(EROFS_I_SB(inode), vi->nid); 14747e4937aSGao Xiang const erofs_off_t pos = 14847e4937aSGao Xiang Z_EROFS_VLE_LEGACY_INDEX_ALIGN(ibase + vi->inode_isize + 14947e4937aSGao Xiang vi->xattr_isize) + 15047e4937aSGao Xiang lcn * sizeof(struct z_erofs_vle_decompressed_index); 15147e4937aSGao Xiang struct z_erofs_vle_decompressed_index *di; 15247e4937aSGao Xiang unsigned int advise, type; 15347e4937aSGao Xiang int err; 15447e4937aSGao Xiang 15547e4937aSGao Xiang err = z_erofs_reload_indexes(m, erofs_blknr(pos)); 15647e4937aSGao Xiang if (err) 15747e4937aSGao Xiang return err; 15847e4937aSGao Xiang 15947e4937aSGao Xiang m->lcn = lcn; 16047e4937aSGao Xiang di = m->kaddr + erofs_blkoff(pos); 16147e4937aSGao Xiang 16247e4937aSGao Xiang advise = le16_to_cpu(di->di_advise); 16347e4937aSGao Xiang type = (advise >> Z_EROFS_VLE_DI_CLUSTER_TYPE_BIT) & 16447e4937aSGao Xiang ((1 << Z_EROFS_VLE_DI_CLUSTER_TYPE_BITS) - 1); 16547e4937aSGao Xiang switch (type) { 16647e4937aSGao Xiang case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD: 16747e4937aSGao Xiang m->clusterofs = 1 << vi->z_logical_clusterbits; 16847e4937aSGao Xiang m->delta[0] = le16_to_cpu(di->di_u.delta[0]); 16947e4937aSGao Xiang m->delta[1] = le16_to_cpu(di->di_u.delta[1]); 17047e4937aSGao Xiang break; 17147e4937aSGao Xiang case Z_EROFS_VLE_CLUSTER_TYPE_PLAIN: 17247e4937aSGao Xiang case Z_EROFS_VLE_CLUSTER_TYPE_HEAD: 17347e4937aSGao Xiang m->clusterofs = le16_to_cpu(di->di_clusterofs); 17447e4937aSGao Xiang m->pblk = le32_to_cpu(di->di_u.blkaddr); 17547e4937aSGao Xiang break; 17647e4937aSGao Xiang default: 17747e4937aSGao Xiang DBG_BUGON(1); 17847e4937aSGao Xiang return -EOPNOTSUPP; 17947e4937aSGao Xiang } 18047e4937aSGao Xiang m->type = type; 18147e4937aSGao Xiang return 0; 18247e4937aSGao Xiang } 18347e4937aSGao Xiang 18447e4937aSGao Xiang static unsigned int decode_compactedbits(unsigned int lobits, 18547e4937aSGao Xiang unsigned int lomask, 18647e4937aSGao Xiang u8 *in, unsigned int pos, u8 *type) 18747e4937aSGao Xiang { 18847e4937aSGao Xiang const unsigned int v = get_unaligned_le32(in + pos / 8) >> (pos & 7); 18947e4937aSGao Xiang const unsigned int lo = v & lomask; 19047e4937aSGao Xiang 19147e4937aSGao Xiang *type = (v >> lobits) & 3; 19247e4937aSGao Xiang return lo; 19347e4937aSGao Xiang } 19447e4937aSGao Xiang 19547e4937aSGao Xiang static int unpack_compacted_index(struct z_erofs_maprecorder *m, 19647e4937aSGao Xiang unsigned int amortizedshift, 19747e4937aSGao Xiang unsigned int eofs) 19847e4937aSGao Xiang { 19947e4937aSGao Xiang struct erofs_vnode *const vi = EROFS_V(m->inode); 20047e4937aSGao Xiang const unsigned int lclusterbits = vi->z_logical_clusterbits; 20147e4937aSGao Xiang const unsigned int lomask = (1 << lclusterbits) - 1; 20247e4937aSGao Xiang unsigned int vcnt, base, lo, encodebits, nblk; 20347e4937aSGao Xiang int i; 20447e4937aSGao Xiang u8 *in, type; 20547e4937aSGao Xiang 20647e4937aSGao Xiang if (1 << amortizedshift == 4) 20747e4937aSGao Xiang vcnt = 2; 20847e4937aSGao Xiang else if (1 << amortizedshift == 2 && lclusterbits == 12) 20947e4937aSGao Xiang vcnt = 16; 21047e4937aSGao Xiang else 21147e4937aSGao Xiang return -EOPNOTSUPP; 21247e4937aSGao Xiang 21347e4937aSGao Xiang encodebits = ((vcnt << amortizedshift) - sizeof(__le32)) * 8 / vcnt; 21447e4937aSGao Xiang base = round_down(eofs, vcnt << amortizedshift); 21547e4937aSGao Xiang in = m->kaddr + base; 21647e4937aSGao Xiang 21747e4937aSGao Xiang i = (eofs - base) >> amortizedshift; 21847e4937aSGao Xiang 21947e4937aSGao Xiang lo = decode_compactedbits(lclusterbits, lomask, 22047e4937aSGao Xiang in, encodebits * i, &type); 22147e4937aSGao Xiang m->type = type; 22247e4937aSGao Xiang if (type == Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD) { 22347e4937aSGao Xiang m->clusterofs = 1 << lclusterbits; 22447e4937aSGao Xiang if (i + 1 != vcnt) { 22547e4937aSGao Xiang m->delta[0] = lo; 22647e4937aSGao Xiang return 0; 22747e4937aSGao Xiang } 22847e4937aSGao Xiang /* 22947e4937aSGao Xiang * since the last lcluster in the pack is special, 23047e4937aSGao Xiang * of which lo saves delta[1] rather than delta[0]. 23147e4937aSGao Xiang * Hence, get delta[0] by the previous lcluster indirectly. 23247e4937aSGao Xiang */ 23347e4937aSGao Xiang lo = decode_compactedbits(lclusterbits, lomask, 23447e4937aSGao Xiang in, encodebits * (i - 1), &type); 23547e4937aSGao Xiang if (type != Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD) 23647e4937aSGao Xiang lo = 0; 23747e4937aSGao Xiang m->delta[0] = lo + 1; 23847e4937aSGao Xiang return 0; 23947e4937aSGao Xiang } 24047e4937aSGao Xiang m->clusterofs = lo; 24147e4937aSGao Xiang m->delta[0] = 0; 24247e4937aSGao Xiang /* figout out blkaddr (pblk) for HEAD lclusters */ 24347e4937aSGao Xiang nblk = 1; 24447e4937aSGao Xiang while (i > 0) { 24547e4937aSGao Xiang --i; 24647e4937aSGao Xiang lo = decode_compactedbits(lclusterbits, lomask, 24747e4937aSGao Xiang in, encodebits * i, &type); 24847e4937aSGao Xiang if (type == Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD) 24947e4937aSGao Xiang i -= lo; 25047e4937aSGao Xiang 25147e4937aSGao Xiang if (i >= 0) 25247e4937aSGao Xiang ++nblk; 25347e4937aSGao Xiang } 25447e4937aSGao Xiang in += (vcnt << amortizedshift) - sizeof(__le32); 25547e4937aSGao Xiang m->pblk = le32_to_cpu(*(__le32 *)in) + nblk; 25647e4937aSGao Xiang return 0; 25747e4937aSGao Xiang } 25847e4937aSGao Xiang 25947e4937aSGao Xiang static int compacted_load_cluster_from_disk(struct z_erofs_maprecorder *m, 26047e4937aSGao Xiang unsigned long lcn) 26147e4937aSGao Xiang { 26247e4937aSGao Xiang struct inode *const inode = m->inode; 26347e4937aSGao Xiang struct erofs_vnode *const vi = EROFS_V(inode); 26447e4937aSGao Xiang const unsigned int lclusterbits = vi->z_logical_clusterbits; 26547e4937aSGao Xiang const erofs_off_t ebase = ALIGN(iloc(EROFS_I_SB(inode), vi->nid) + 26647e4937aSGao Xiang vi->inode_isize + vi->xattr_isize, 8) + 26747e4937aSGao Xiang sizeof(struct z_erofs_map_header); 26847e4937aSGao Xiang const unsigned int totalidx = DIV_ROUND_UP(inode->i_size, EROFS_BLKSIZ); 26947e4937aSGao Xiang unsigned int compacted_4b_initial, compacted_2b; 27047e4937aSGao Xiang unsigned int amortizedshift; 27147e4937aSGao Xiang erofs_off_t pos; 27247e4937aSGao Xiang int err; 27347e4937aSGao Xiang 27447e4937aSGao Xiang if (lclusterbits != 12) 27547e4937aSGao Xiang return -EOPNOTSUPP; 27647e4937aSGao Xiang 27747e4937aSGao Xiang if (lcn >= totalidx) 27847e4937aSGao Xiang return -EINVAL; 27947e4937aSGao Xiang 28047e4937aSGao Xiang m->lcn = lcn; 28147e4937aSGao Xiang /* used to align to 32-byte (compacted_2b) alignment */ 28247e4937aSGao Xiang compacted_4b_initial = (32 - ebase % 32) / 4; 28347e4937aSGao Xiang if (compacted_4b_initial == 32 / 4) 28447e4937aSGao Xiang compacted_4b_initial = 0; 28547e4937aSGao Xiang 28647e4937aSGao Xiang if (vi->z_advise & Z_EROFS_ADVISE_COMPACTED_2B) 28747e4937aSGao Xiang compacted_2b = rounddown(totalidx - compacted_4b_initial, 16); 28847e4937aSGao Xiang else 28947e4937aSGao Xiang compacted_2b = 0; 29047e4937aSGao Xiang 29147e4937aSGao Xiang pos = ebase; 29247e4937aSGao Xiang if (lcn < compacted_4b_initial) { 29347e4937aSGao Xiang amortizedshift = 2; 29447e4937aSGao Xiang goto out; 29547e4937aSGao Xiang } 29647e4937aSGao Xiang pos += compacted_4b_initial * 4; 29747e4937aSGao Xiang lcn -= compacted_4b_initial; 29847e4937aSGao Xiang 29947e4937aSGao Xiang if (lcn < compacted_2b) { 30047e4937aSGao Xiang amortizedshift = 1; 30147e4937aSGao Xiang goto out; 30247e4937aSGao Xiang } 30347e4937aSGao Xiang pos += compacted_2b * 2; 30447e4937aSGao Xiang lcn -= compacted_2b; 30547e4937aSGao Xiang amortizedshift = 2; 30647e4937aSGao Xiang out: 30747e4937aSGao Xiang pos += lcn * (1 << amortizedshift); 30847e4937aSGao Xiang err = z_erofs_reload_indexes(m, erofs_blknr(pos)); 30947e4937aSGao Xiang if (err) 31047e4937aSGao Xiang return err; 31147e4937aSGao Xiang return unpack_compacted_index(m, amortizedshift, erofs_blkoff(pos)); 31247e4937aSGao Xiang } 31347e4937aSGao Xiang 31447e4937aSGao Xiang static int vle_load_cluster_from_disk(struct z_erofs_maprecorder *m, 31547e4937aSGao Xiang unsigned int lcn) 31647e4937aSGao Xiang { 31747e4937aSGao Xiang const unsigned int datamode = EROFS_V(m->inode)->datamode; 31847e4937aSGao Xiang 31947e4937aSGao Xiang if (datamode == EROFS_INODE_FLAT_COMPRESSION_LEGACY) 32047e4937aSGao Xiang return vle_legacy_load_cluster_from_disk(m, lcn); 32147e4937aSGao Xiang 32247e4937aSGao Xiang if (datamode == EROFS_INODE_FLAT_COMPRESSION) 32347e4937aSGao Xiang return compacted_load_cluster_from_disk(m, lcn); 32447e4937aSGao Xiang 32547e4937aSGao Xiang return -EINVAL; 32647e4937aSGao Xiang } 32747e4937aSGao Xiang 32847e4937aSGao Xiang static int vle_extent_lookback(struct z_erofs_maprecorder *m, 32947e4937aSGao Xiang unsigned int lookback_distance) 33047e4937aSGao Xiang { 33147e4937aSGao Xiang struct erofs_vnode *const vi = EROFS_V(m->inode); 33247e4937aSGao Xiang struct erofs_map_blocks *const map = m->map; 33347e4937aSGao Xiang const unsigned int lclusterbits = vi->z_logical_clusterbits; 33447e4937aSGao Xiang unsigned long lcn = m->lcn; 33547e4937aSGao Xiang int err; 33647e4937aSGao Xiang 33747e4937aSGao Xiang if (lcn < lookback_distance) { 33847e4937aSGao Xiang errln("bogus lookback distance @ nid %llu", vi->nid); 33947e4937aSGao Xiang DBG_BUGON(1); 34047e4937aSGao Xiang return -EFSCORRUPTED; 34147e4937aSGao Xiang } 34247e4937aSGao Xiang 34347e4937aSGao Xiang /* load extent head logical cluster if needed */ 34447e4937aSGao Xiang lcn -= lookback_distance; 34547e4937aSGao Xiang err = vle_load_cluster_from_disk(m, lcn); 34647e4937aSGao Xiang if (err) 34747e4937aSGao Xiang return err; 34847e4937aSGao Xiang 34947e4937aSGao Xiang switch (m->type) { 35047e4937aSGao Xiang case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD: 351*8d8a09b0SGao Xiang if (!m->delta[0]) { 35247e4937aSGao Xiang errln("invalid lookback distance 0 at nid %llu", 35347e4937aSGao Xiang vi->nid); 35447e4937aSGao Xiang DBG_BUGON(1); 35547e4937aSGao Xiang return -EFSCORRUPTED; 35647e4937aSGao Xiang } 35747e4937aSGao Xiang return vle_extent_lookback(m, m->delta[0]); 35847e4937aSGao Xiang case Z_EROFS_VLE_CLUSTER_TYPE_PLAIN: 35947e4937aSGao Xiang map->m_flags &= ~EROFS_MAP_ZIPPED; 36047e4937aSGao Xiang /* fallthrough */ 36147e4937aSGao Xiang case Z_EROFS_VLE_CLUSTER_TYPE_HEAD: 36247e4937aSGao Xiang map->m_la = (lcn << lclusterbits) | m->clusterofs; 36347e4937aSGao Xiang break; 36447e4937aSGao Xiang default: 36547e4937aSGao Xiang errln("unknown type %u at lcn %lu of nid %llu", 36647e4937aSGao Xiang m->type, lcn, vi->nid); 36747e4937aSGao Xiang DBG_BUGON(1); 36847e4937aSGao Xiang return -EOPNOTSUPP; 36947e4937aSGao Xiang } 37047e4937aSGao Xiang return 0; 37147e4937aSGao Xiang } 37247e4937aSGao Xiang 37347e4937aSGao Xiang int z_erofs_map_blocks_iter(struct inode *inode, 37447e4937aSGao Xiang struct erofs_map_blocks *map, 37547e4937aSGao Xiang int flags) 37647e4937aSGao Xiang { 37747e4937aSGao Xiang struct erofs_vnode *const vi = EROFS_V(inode); 37847e4937aSGao Xiang struct z_erofs_maprecorder m = { 37947e4937aSGao Xiang .inode = inode, 38047e4937aSGao Xiang .map = map, 38147e4937aSGao Xiang }; 38247e4937aSGao Xiang int err = 0; 38347e4937aSGao Xiang unsigned int lclusterbits, endoff; 38447e4937aSGao Xiang unsigned long long ofs, end; 38547e4937aSGao Xiang 38647e4937aSGao Xiang trace_z_erofs_map_blocks_iter_enter(inode, map, flags); 38747e4937aSGao Xiang 38847e4937aSGao Xiang /* when trying to read beyond EOF, leave it unmapped */ 389*8d8a09b0SGao Xiang if (map->m_la >= inode->i_size) { 39047e4937aSGao Xiang map->m_llen = map->m_la + 1 - inode->i_size; 39147e4937aSGao Xiang map->m_la = inode->i_size; 39247e4937aSGao Xiang map->m_flags = 0; 39347e4937aSGao Xiang goto out; 39447e4937aSGao Xiang } 39547e4937aSGao Xiang 39647e4937aSGao Xiang err = fill_inode_lazy(inode); 39747e4937aSGao Xiang if (err) 39847e4937aSGao Xiang goto out; 39947e4937aSGao Xiang 40047e4937aSGao Xiang lclusterbits = vi->z_logical_clusterbits; 40147e4937aSGao Xiang ofs = map->m_la; 40247e4937aSGao Xiang m.lcn = ofs >> lclusterbits; 40347e4937aSGao Xiang endoff = ofs & ((1 << lclusterbits) - 1); 40447e4937aSGao Xiang 40547e4937aSGao Xiang err = vle_load_cluster_from_disk(&m, m.lcn); 40647e4937aSGao Xiang if (err) 40747e4937aSGao Xiang goto unmap_out; 40847e4937aSGao Xiang 40947e4937aSGao Xiang map->m_flags = EROFS_MAP_ZIPPED; /* by default, compressed */ 41047e4937aSGao Xiang end = (m.lcn + 1ULL) << lclusterbits; 41147e4937aSGao Xiang 41247e4937aSGao Xiang switch (m.type) { 41347e4937aSGao Xiang case Z_EROFS_VLE_CLUSTER_TYPE_PLAIN: 41447e4937aSGao Xiang if (endoff >= m.clusterofs) 41547e4937aSGao Xiang map->m_flags &= ~EROFS_MAP_ZIPPED; 41647e4937aSGao Xiang /* fallthrough */ 41747e4937aSGao Xiang case Z_EROFS_VLE_CLUSTER_TYPE_HEAD: 41847e4937aSGao Xiang if (endoff >= m.clusterofs) { 41947e4937aSGao Xiang map->m_la = (m.lcn << lclusterbits) | m.clusterofs; 42047e4937aSGao Xiang break; 42147e4937aSGao Xiang } 42247e4937aSGao Xiang /* m.lcn should be >= 1 if endoff < m.clusterofs */ 423*8d8a09b0SGao Xiang if (!m.lcn) { 42447e4937aSGao Xiang errln("invalid logical cluster 0 at nid %llu", 42547e4937aSGao Xiang vi->nid); 42647e4937aSGao Xiang err = -EFSCORRUPTED; 42747e4937aSGao Xiang goto unmap_out; 42847e4937aSGao Xiang } 42947e4937aSGao Xiang end = (m.lcn << lclusterbits) | m.clusterofs; 43047e4937aSGao Xiang map->m_flags |= EROFS_MAP_FULL_MAPPED; 43147e4937aSGao Xiang m.delta[0] = 1; 43247e4937aSGao Xiang /* fallthrough */ 43347e4937aSGao Xiang case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD: 43447e4937aSGao Xiang /* get the correspoinding first chunk */ 43547e4937aSGao Xiang err = vle_extent_lookback(&m, m.delta[0]); 436*8d8a09b0SGao Xiang if (err) 43747e4937aSGao Xiang goto unmap_out; 43847e4937aSGao Xiang break; 43947e4937aSGao Xiang default: 44047e4937aSGao Xiang errln("unknown type %u at offset %llu of nid %llu", 44147e4937aSGao Xiang m.type, ofs, vi->nid); 44247e4937aSGao Xiang err = -EOPNOTSUPP; 44347e4937aSGao Xiang goto unmap_out; 44447e4937aSGao Xiang } 44547e4937aSGao Xiang 44647e4937aSGao Xiang map->m_llen = end - map->m_la; 44747e4937aSGao Xiang map->m_plen = 1 << lclusterbits; 44847e4937aSGao Xiang map->m_pa = blknr_to_addr(m.pblk); 44947e4937aSGao Xiang map->m_flags |= EROFS_MAP_MAPPED; 45047e4937aSGao Xiang 45147e4937aSGao Xiang unmap_out: 45247e4937aSGao Xiang if (m.kaddr) 45347e4937aSGao Xiang kunmap_atomic(m.kaddr); 45447e4937aSGao Xiang 45547e4937aSGao Xiang out: 45647e4937aSGao Xiang debugln("%s, m_la %llu m_pa %llu m_llen %llu m_plen %llu m_flags 0%o", 45747e4937aSGao Xiang __func__, map->m_la, map->m_pa, 45847e4937aSGao Xiang map->m_llen, map->m_plen, map->m_flags); 45947e4937aSGao Xiang 46047e4937aSGao Xiang trace_z_erofs_map_blocks_iter_exit(inode, map, flags, err); 46147e4937aSGao Xiang 46247e4937aSGao Xiang /* aggressively BUG_ON iff CONFIG_EROFS_FS_DEBUG is on */ 46347e4937aSGao Xiang DBG_BUGON(err < 0 && err != -ENOMEM); 46447e4937aSGao Xiang return err; 46547e4937aSGao Xiang } 46647e4937aSGao Xiang 467