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 */ 647e4937aSGao Xiang #include "internal.h" 747e4937aSGao Xiang #include <asm/unaligned.h> 847e4937aSGao Xiang #include <trace/events/erofs.h> 947e4937aSGao Xiang 10ab92184fSYue Hu static int z_erofs_do_map_blocks(struct inode *inode, 11ab92184fSYue Hu struct erofs_map_blocks *map, 12ab92184fSYue Hu int flags); 13ab92184fSYue Hu 1447e4937aSGao Xiang int z_erofs_fill_inode(struct inode *inode) 1547e4937aSGao Xiang { 16a5876e24SGao Xiang struct erofs_inode *const vi = EROFS_I(inode); 17cec6e93bSGao Xiang struct erofs_sb_info *sbi = EROFS_SB(inode->i_sb); 1847e4937aSGao Xiang 19cec6e93bSGao Xiang if (!erofs_sb_has_big_pcluster(sbi) && 20b15b2e30SYue Hu !erofs_sb_has_ztailpacking(sbi) && !erofs_sb_has_fragments(sbi) && 21cec6e93bSGao Xiang vi->datalayout == EROFS_INODE_FLAT_COMPRESSION_LEGACY) { 2247e4937aSGao Xiang vi->z_advise = 0; 2347e4937aSGao Xiang vi->z_algorithmtype[0] = 0; 2447e4937aSGao Xiang vi->z_algorithmtype[1] = 0; 2547e4937aSGao Xiang vi->z_logical_clusterbits = LOG_BLOCK_SIZE; 26a5876e24SGao Xiang set_bit(EROFS_I_Z_INITED_BIT, &vi->flags); 2747e4937aSGao Xiang } 280c638f70SGao Xiang inode->i_mapping->a_ops = &z_erofs_aops; 2947e4937aSGao Xiang return 0; 3047e4937aSGao Xiang } 3147e4937aSGao Xiang 320c638f70SGao Xiang static int z_erofs_fill_inode_lazy(struct inode *inode) 3347e4937aSGao Xiang { 34a5876e24SGao Xiang struct erofs_inode *const vi = EROFS_I(inode); 3547e4937aSGao Xiang struct super_block *const sb = inode->i_sb; 3672bb5262SGao Xiang int err, headnr; 3747e4937aSGao Xiang erofs_off_t pos; 3809c54379SGao Xiang struct erofs_buf buf = __EROFS_BUF_INITIALIZER; 3947e4937aSGao Xiang void *kaddr; 4047e4937aSGao Xiang struct z_erofs_map_header *h; 4147e4937aSGao Xiang 42ce063129SGao Xiang if (test_bit(EROFS_I_Z_INITED_BIT, &vi->flags)) { 43ce063129SGao Xiang /* 44ce063129SGao Xiang * paired with smp_mb() at the end of the function to ensure 45ce063129SGao Xiang * fields will only be observed after the bit is set. 46ce063129SGao Xiang */ 47ce063129SGao Xiang smp_mb(); 4847e4937aSGao Xiang return 0; 49ce063129SGao Xiang } 5047e4937aSGao Xiang 51a5876e24SGao Xiang if (wait_on_bit_lock(&vi->flags, EROFS_I_BL_Z_BIT, TASK_KILLABLE)) 5247e4937aSGao Xiang return -ERESTARTSYS; 5347e4937aSGao Xiang 5447e4937aSGao Xiang err = 0; 55a5876e24SGao Xiang if (test_bit(EROFS_I_Z_INITED_BIT, &vi->flags)) 5647e4937aSGao Xiang goto out_unlock; 5747e4937aSGao Xiang 5847e4937aSGao Xiang pos = ALIGN(iloc(EROFS_SB(sb), vi->nid) + vi->inode_isize + 5947e4937aSGao Xiang vi->xattr_isize, 8); 60664609e4SYue Hu kaddr = erofs_read_metabuf(&buf, sb, erofs_blknr(pos), EROFS_KMAP); 6109c54379SGao Xiang if (IS_ERR(kaddr)) { 6209c54379SGao Xiang err = PTR_ERR(kaddr); 6347e4937aSGao Xiang goto out_unlock; 6447e4937aSGao Xiang } 6547e4937aSGao Xiang 6647e4937aSGao Xiang h = kaddr + erofs_blkoff(pos); 67b15b2e30SYue Hu /* 68b15b2e30SYue Hu * if the highest bit of the 8-byte map header is set, the whole file 69b15b2e30SYue Hu * is stored in the packed inode. The rest bits keeps z_fragmentoff. 70b15b2e30SYue Hu */ 71b15b2e30SYue Hu if (h->h_clusterbits >> Z_EROFS_FRAGMENT_INODE_BIT) { 72b15b2e30SYue Hu vi->z_advise = Z_EROFS_ADVISE_FRAGMENT_PCLUSTER; 73b15b2e30SYue Hu vi->z_fragmentoff = le64_to_cpu(*(__le64 *)h) ^ (1ULL << 63); 74b15b2e30SYue Hu vi->z_tailextent_headlcn = 0; 75664609e4SYue Hu goto done; 76b15b2e30SYue Hu } 7747e4937aSGao Xiang vi->z_advise = le16_to_cpu(h->h_advise); 7847e4937aSGao Xiang vi->z_algorithmtype[0] = h->h_algorithmtype & 15; 7947e4937aSGao Xiang vi->z_algorithmtype[1] = h->h_algorithmtype >> 4; 8047e4937aSGao Xiang 8172bb5262SGao Xiang headnr = 0; 8272bb5262SGao Xiang if (vi->z_algorithmtype[0] >= Z_EROFS_COMPRESSION_MAX || 8372bb5262SGao Xiang vi->z_algorithmtype[++headnr] >= Z_EROFS_COMPRESSION_MAX) { 8472bb5262SGao Xiang erofs_err(sb, "unknown HEAD%u format %u for nid %llu, please upgrade kernel", 8572bb5262SGao Xiang headnr + 1, vi->z_algorithmtype[headnr], vi->nid); 8647e4937aSGao Xiang err = -EOPNOTSUPP; 87664609e4SYue Hu goto out_put_metabuf; 8847e4937aSGao Xiang } 8947e4937aSGao Xiang 9047e4937aSGao Xiang vi->z_logical_clusterbits = LOG_BLOCK_SIZE + (h->h_clusterbits & 7); 91b86269f4SGao Xiang if (!erofs_sb_has_big_pcluster(EROFS_SB(sb)) && 92b86269f4SGao Xiang vi->z_advise & (Z_EROFS_ADVISE_BIG_PCLUSTER_1 | 93b86269f4SGao Xiang Z_EROFS_ADVISE_BIG_PCLUSTER_2)) { 94b86269f4SGao Xiang erofs_err(sb, "per-inode big pcluster without sb feature for nid %llu", 95b86269f4SGao Xiang vi->nid); 96b86269f4SGao Xiang err = -EFSCORRUPTED; 97664609e4SYue Hu goto out_put_metabuf; 98b86269f4SGao Xiang } 99b86269f4SGao Xiang if (vi->datalayout == EROFS_INODE_FLAT_COMPRESSION && 100b86269f4SGao Xiang !(vi->z_advise & Z_EROFS_ADVISE_BIG_PCLUSTER_1) ^ 101b86269f4SGao Xiang !(vi->z_advise & Z_EROFS_ADVISE_BIG_PCLUSTER_2)) { 102b86269f4SGao Xiang erofs_err(sb, "big pcluster head1/2 of compact indexes should be consistent for nid %llu", 103b86269f4SGao Xiang vi->nid); 104b86269f4SGao Xiang err = -EFSCORRUPTED; 105664609e4SYue Hu goto out_put_metabuf; 106b86269f4SGao Xiang } 107ab92184fSYue Hu 108ab92184fSYue Hu if (vi->z_advise & Z_EROFS_ADVISE_INLINE_PCLUSTER) { 10909c54379SGao Xiang struct erofs_map_blocks map = { 11009c54379SGao Xiang .buf = __EROFS_BUF_INITIALIZER 11109c54379SGao Xiang }; 112ab92184fSYue Hu 113ab92184fSYue Hu vi->z_idata_size = le16_to_cpu(h->h_idata_size); 114ab92184fSYue Hu err = z_erofs_do_map_blocks(inode, &map, 115ab92184fSYue Hu EROFS_GET_BLOCKS_FINDTAIL); 11609c54379SGao Xiang erofs_put_metabuf(&map.buf); 117ab92184fSYue Hu 118ab92184fSYue Hu if (!map.m_plen || 119ab92184fSYue Hu erofs_blkoff(map.m_pa) + map.m_plen > EROFS_BLKSIZ) { 120ab92184fSYue Hu erofs_err(sb, "invalid tail-packing pclustersize %llu", 121ab92184fSYue Hu map.m_plen); 122ab92184fSYue Hu err = -EFSCORRUPTED; 123ab92184fSYue Hu } 124ab92184fSYue Hu if (err < 0) 125664609e4SYue Hu goto out_put_metabuf; 126ab92184fSYue Hu } 127b15b2e30SYue Hu 128b15b2e30SYue Hu if (vi->z_advise & Z_EROFS_ADVISE_FRAGMENT_PCLUSTER && 129b15b2e30SYue Hu !(h->h_clusterbits >> Z_EROFS_FRAGMENT_INODE_BIT)) { 130b15b2e30SYue Hu struct erofs_map_blocks map = { 131b15b2e30SYue Hu .buf = __EROFS_BUF_INITIALIZER 132b15b2e30SYue Hu }; 133b15b2e30SYue Hu 134b15b2e30SYue Hu vi->z_fragmentoff = le32_to_cpu(h->h_fragmentoff); 135b15b2e30SYue Hu err = z_erofs_do_map_blocks(inode, &map, 136b15b2e30SYue Hu EROFS_GET_BLOCKS_FINDTAIL); 137b15b2e30SYue Hu erofs_put_metabuf(&map.buf); 138b15b2e30SYue Hu if (err < 0) 139664609e4SYue Hu goto out_put_metabuf; 140b15b2e30SYue Hu } 141664609e4SYue Hu done: 142ab92184fSYue Hu /* paired with smp_mb() at the beginning of the function */ 143ab92184fSYue Hu smp_mb(); 144ab92184fSYue Hu set_bit(EROFS_I_Z_INITED_BIT, &vi->flags); 145664609e4SYue Hu out_put_metabuf: 146664609e4SYue Hu erofs_put_metabuf(&buf); 14747e4937aSGao Xiang out_unlock: 148a5876e24SGao Xiang clear_and_wake_up_bit(EROFS_I_BL_Z_BIT, &vi->flags); 14947e4937aSGao Xiang return err; 15047e4937aSGao Xiang } 15147e4937aSGao Xiang 15247e4937aSGao Xiang struct z_erofs_maprecorder { 15347e4937aSGao Xiang struct inode *inode; 15447e4937aSGao Xiang struct erofs_map_blocks *map; 15547e4937aSGao Xiang void *kaddr; 15647e4937aSGao Xiang 15747e4937aSGao Xiang unsigned long lcn; 15847e4937aSGao Xiang /* compression extent information gathered */ 1598f899262SGao Xiang u8 type, headtype; 16047e4937aSGao Xiang u16 clusterofs; 16147e4937aSGao Xiang u16 delta[2]; 162ea0b7b0dSYue Hu erofs_blk_t pblk, compressedblks; 163ab92184fSYue Hu erofs_off_t nextpackoff; 1645c2a6425SGao Xiang bool partialref; 16547e4937aSGao Xiang }; 16647e4937aSGao Xiang 1670c638f70SGao Xiang static int legacy_load_cluster_from_disk(struct z_erofs_maprecorder *m, 16847e4937aSGao Xiang unsigned long lcn) 16947e4937aSGao Xiang { 17047e4937aSGao Xiang struct inode *const inode = m->inode; 171a5876e24SGao Xiang struct erofs_inode *const vi = EROFS_I(inode); 17247e4937aSGao Xiang const erofs_off_t ibase = iloc(EROFS_I_SB(inode), vi->nid); 17347e4937aSGao Xiang const erofs_off_t pos = 17447e4937aSGao Xiang Z_EROFS_VLE_LEGACY_INDEX_ALIGN(ibase + vi->inode_isize + 17547e4937aSGao Xiang vi->xattr_isize) + 17647e4937aSGao Xiang lcn * sizeof(struct z_erofs_vle_decompressed_index); 17747e4937aSGao Xiang struct z_erofs_vle_decompressed_index *di; 17847e4937aSGao Xiang unsigned int advise, type; 17947e4937aSGao Xiang 18031da107fSYue Hu m->kaddr = erofs_read_metabuf(&m->map->buf, inode->i_sb, 181927e5010SGao Xiang erofs_blknr(pos), EROFS_KMAP); 18231da107fSYue Hu if (IS_ERR(m->kaddr)) 18331da107fSYue Hu return PTR_ERR(m->kaddr); 18447e4937aSGao Xiang 185ab92184fSYue Hu m->nextpackoff = pos + sizeof(struct z_erofs_vle_decompressed_index); 18647e4937aSGao Xiang m->lcn = lcn; 18747e4937aSGao Xiang di = m->kaddr + erofs_blkoff(pos); 18847e4937aSGao Xiang 18947e4937aSGao Xiang advise = le16_to_cpu(di->di_advise); 19047e4937aSGao Xiang type = (advise >> Z_EROFS_VLE_DI_CLUSTER_TYPE_BIT) & 19147e4937aSGao Xiang ((1 << Z_EROFS_VLE_DI_CLUSTER_TYPE_BITS) - 1); 19247e4937aSGao Xiang switch (type) { 19347e4937aSGao Xiang case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD: 19447e4937aSGao Xiang m->clusterofs = 1 << vi->z_logical_clusterbits; 19547e4937aSGao Xiang m->delta[0] = le16_to_cpu(di->di_u.delta[0]); 196cec6e93bSGao Xiang if (m->delta[0] & Z_EROFS_VLE_DI_D0_CBLKCNT) { 19772bb5262SGao Xiang if (!(vi->z_advise & (Z_EROFS_ADVISE_BIG_PCLUSTER_1 | 19872bb5262SGao Xiang Z_EROFS_ADVISE_BIG_PCLUSTER_2))) { 199cec6e93bSGao Xiang DBG_BUGON(1); 200cec6e93bSGao Xiang return -EFSCORRUPTED; 201cec6e93bSGao Xiang } 202ea0b7b0dSYue Hu m->compressedblks = m->delta[0] & 203cec6e93bSGao Xiang ~Z_EROFS_VLE_DI_D0_CBLKCNT; 204cec6e93bSGao Xiang m->delta[0] = 1; 205cec6e93bSGao Xiang } 20647e4937aSGao Xiang m->delta[1] = le16_to_cpu(di->di_u.delta[1]); 20747e4937aSGao Xiang break; 20847e4937aSGao Xiang case Z_EROFS_VLE_CLUSTER_TYPE_PLAIN: 20972bb5262SGao Xiang case Z_EROFS_VLE_CLUSTER_TYPE_HEAD1: 21072bb5262SGao Xiang case Z_EROFS_VLE_CLUSTER_TYPE_HEAD2: 2115c2a6425SGao Xiang if (advise & Z_EROFS_VLE_DI_PARTIAL_REF) 2125c2a6425SGao Xiang m->partialref = true; 21347e4937aSGao Xiang m->clusterofs = le16_to_cpu(di->di_clusterofs); 21447e4937aSGao Xiang m->pblk = le32_to_cpu(di->di_u.blkaddr); 21547e4937aSGao Xiang break; 21647e4937aSGao Xiang default: 21747e4937aSGao Xiang DBG_BUGON(1); 21847e4937aSGao Xiang return -EOPNOTSUPP; 21947e4937aSGao Xiang } 22047e4937aSGao Xiang m->type = type; 22147e4937aSGao Xiang return 0; 22247e4937aSGao Xiang } 22347e4937aSGao Xiang 22447e4937aSGao Xiang static unsigned int decode_compactedbits(unsigned int lobits, 22547e4937aSGao Xiang unsigned int lomask, 22647e4937aSGao Xiang u8 *in, unsigned int pos, u8 *type) 22747e4937aSGao Xiang { 22847e4937aSGao Xiang const unsigned int v = get_unaligned_le32(in + pos / 8) >> (pos & 7); 22947e4937aSGao Xiang const unsigned int lo = v & lomask; 23047e4937aSGao Xiang 23147e4937aSGao Xiang *type = (v >> lobits) & 3; 23247e4937aSGao Xiang return lo; 23347e4937aSGao Xiang } 23447e4937aSGao Xiang 235d95ae5e2SGao Xiang static int get_compacted_la_distance(unsigned int lclusterbits, 236d95ae5e2SGao Xiang unsigned int encodebits, 237d95ae5e2SGao Xiang unsigned int vcnt, u8 *in, int i) 238d95ae5e2SGao Xiang { 239d95ae5e2SGao Xiang const unsigned int lomask = (1 << lclusterbits) - 1; 240d95ae5e2SGao Xiang unsigned int lo, d1 = 0; 241d95ae5e2SGao Xiang u8 type; 242d95ae5e2SGao Xiang 243d95ae5e2SGao Xiang DBG_BUGON(i >= vcnt); 244d95ae5e2SGao Xiang 245d95ae5e2SGao Xiang do { 246d95ae5e2SGao Xiang lo = decode_compactedbits(lclusterbits, lomask, 247d95ae5e2SGao Xiang in, encodebits * i, &type); 248d95ae5e2SGao Xiang 249d95ae5e2SGao Xiang if (type != Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD) 250d95ae5e2SGao Xiang return d1; 251d95ae5e2SGao Xiang ++d1; 252d95ae5e2SGao Xiang } while (++i < vcnt); 253d95ae5e2SGao Xiang 254d95ae5e2SGao Xiang /* vcnt - 1 (Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD) item */ 255d95ae5e2SGao Xiang if (!(lo & Z_EROFS_VLE_DI_D0_CBLKCNT)) 256d95ae5e2SGao Xiang d1 += lo - 1; 257d95ae5e2SGao Xiang return d1; 258d95ae5e2SGao Xiang } 259d95ae5e2SGao Xiang 26047e4937aSGao Xiang static int unpack_compacted_index(struct z_erofs_maprecorder *m, 26147e4937aSGao Xiang unsigned int amortizedshift, 262ab92184fSYue Hu erofs_off_t pos, bool lookahead) 26347e4937aSGao Xiang { 264a5876e24SGao Xiang struct erofs_inode *const vi = EROFS_I(m->inode); 26547e4937aSGao Xiang const unsigned int lclusterbits = vi->z_logical_clusterbits; 26647e4937aSGao Xiang const unsigned int lomask = (1 << lclusterbits) - 1; 267ab92184fSYue Hu unsigned int vcnt, base, lo, encodebits, nblk, eofs; 26847e4937aSGao Xiang int i; 26947e4937aSGao Xiang u8 *in, type; 270b86269f4SGao Xiang bool big_pcluster; 27147e4937aSGao Xiang 27247e4937aSGao Xiang if (1 << amortizedshift == 4) 27347e4937aSGao Xiang vcnt = 2; 27447e4937aSGao Xiang else if (1 << amortizedshift == 2 && lclusterbits == 12) 27547e4937aSGao Xiang vcnt = 16; 27647e4937aSGao Xiang else 27747e4937aSGao Xiang return -EOPNOTSUPP; 27847e4937aSGao Xiang 279ab92184fSYue Hu /* it doesn't equal to round_up(..) */ 280ab92184fSYue Hu m->nextpackoff = round_down(pos, vcnt << amortizedshift) + 281ab92184fSYue Hu (vcnt << amortizedshift); 282b86269f4SGao Xiang big_pcluster = vi->z_advise & Z_EROFS_ADVISE_BIG_PCLUSTER_1; 28347e4937aSGao Xiang encodebits = ((vcnt << amortizedshift) - sizeof(__le32)) * 8 / vcnt; 284ab92184fSYue Hu eofs = erofs_blkoff(pos); 28547e4937aSGao Xiang base = round_down(eofs, vcnt << amortizedshift); 28647e4937aSGao Xiang in = m->kaddr + base; 28747e4937aSGao Xiang 28847e4937aSGao Xiang i = (eofs - base) >> amortizedshift; 28947e4937aSGao Xiang 29047e4937aSGao Xiang lo = decode_compactedbits(lclusterbits, lomask, 29147e4937aSGao Xiang in, encodebits * i, &type); 29247e4937aSGao Xiang m->type = type; 29347e4937aSGao Xiang if (type == Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD) { 29447e4937aSGao Xiang m->clusterofs = 1 << lclusterbits; 295d95ae5e2SGao Xiang 296d95ae5e2SGao Xiang /* figure out lookahead_distance: delta[1] if needed */ 297d95ae5e2SGao Xiang if (lookahead) 298d95ae5e2SGao Xiang m->delta[1] = get_compacted_la_distance(lclusterbits, 299d95ae5e2SGao Xiang encodebits, vcnt, in, i); 300b86269f4SGao Xiang if (lo & Z_EROFS_VLE_DI_D0_CBLKCNT) { 301b86269f4SGao Xiang if (!big_pcluster) { 302b86269f4SGao Xiang DBG_BUGON(1); 303b86269f4SGao Xiang return -EFSCORRUPTED; 304b86269f4SGao Xiang } 305ea0b7b0dSYue Hu m->compressedblks = lo & ~Z_EROFS_VLE_DI_D0_CBLKCNT; 306b86269f4SGao Xiang m->delta[0] = 1; 307b86269f4SGao Xiang return 0; 308b86269f4SGao Xiang } else if (i + 1 != (int)vcnt) { 30947e4937aSGao Xiang m->delta[0] = lo; 31047e4937aSGao Xiang return 0; 31147e4937aSGao Xiang } 31247e4937aSGao Xiang /* 31347e4937aSGao Xiang * since the last lcluster in the pack is special, 31447e4937aSGao Xiang * of which lo saves delta[1] rather than delta[0]. 31547e4937aSGao Xiang * Hence, get delta[0] by the previous lcluster indirectly. 31647e4937aSGao Xiang */ 31747e4937aSGao Xiang lo = decode_compactedbits(lclusterbits, lomask, 31847e4937aSGao Xiang in, encodebits * (i - 1), &type); 31947e4937aSGao Xiang if (type != Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD) 32047e4937aSGao Xiang lo = 0; 321b86269f4SGao Xiang else if (lo & Z_EROFS_VLE_DI_D0_CBLKCNT) 322b86269f4SGao Xiang lo = 1; 32347e4937aSGao Xiang m->delta[0] = lo + 1; 32447e4937aSGao Xiang return 0; 32547e4937aSGao Xiang } 32647e4937aSGao Xiang m->clusterofs = lo; 32747e4937aSGao Xiang m->delta[0] = 0; 32847e4937aSGao Xiang /* figout out blkaddr (pblk) for HEAD lclusters */ 329b86269f4SGao Xiang if (!big_pcluster) { 33047e4937aSGao Xiang nblk = 1; 33147e4937aSGao Xiang while (i > 0) { 33247e4937aSGao Xiang --i; 33347e4937aSGao Xiang lo = decode_compactedbits(lclusterbits, lomask, 33447e4937aSGao Xiang in, encodebits * i, &type); 33547e4937aSGao Xiang if (type == Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD) 33647e4937aSGao Xiang i -= lo; 33747e4937aSGao Xiang 33847e4937aSGao Xiang if (i >= 0) 33947e4937aSGao Xiang ++nblk; 34047e4937aSGao Xiang } 341b86269f4SGao Xiang } else { 342b86269f4SGao Xiang nblk = 0; 343b86269f4SGao Xiang while (i > 0) { 344b86269f4SGao Xiang --i; 345b86269f4SGao Xiang lo = decode_compactedbits(lclusterbits, lomask, 346b86269f4SGao Xiang in, encodebits * i, &type); 347b86269f4SGao Xiang if (type == Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD) { 348b86269f4SGao Xiang if (lo & Z_EROFS_VLE_DI_D0_CBLKCNT) { 349b86269f4SGao Xiang --i; 350b86269f4SGao Xiang nblk += lo & ~Z_EROFS_VLE_DI_D0_CBLKCNT; 351b86269f4SGao Xiang continue; 352b86269f4SGao Xiang } 353b86269f4SGao Xiang /* bigpcluster shouldn't have plain d0 == 1 */ 354b86269f4SGao Xiang if (lo <= 1) { 355b86269f4SGao Xiang DBG_BUGON(1); 356b86269f4SGao Xiang return -EFSCORRUPTED; 357b86269f4SGao Xiang } 358b86269f4SGao Xiang i -= lo - 2; 359b86269f4SGao Xiang continue; 360b86269f4SGao Xiang } 361b86269f4SGao Xiang ++nblk; 362b86269f4SGao Xiang } 363b86269f4SGao Xiang } 36447e4937aSGao Xiang in += (vcnt << amortizedshift) - sizeof(__le32); 36547e4937aSGao Xiang m->pblk = le32_to_cpu(*(__le32 *)in) + nblk; 36647e4937aSGao Xiang return 0; 36747e4937aSGao Xiang } 36847e4937aSGao Xiang 36947e4937aSGao Xiang static int compacted_load_cluster_from_disk(struct z_erofs_maprecorder *m, 370d95ae5e2SGao Xiang unsigned long lcn, bool lookahead) 37147e4937aSGao Xiang { 37247e4937aSGao Xiang struct inode *const inode = m->inode; 373a5876e24SGao Xiang struct erofs_inode *const vi = EROFS_I(inode); 37447e4937aSGao Xiang const unsigned int lclusterbits = vi->z_logical_clusterbits; 37547e4937aSGao Xiang const erofs_off_t ebase = ALIGN(iloc(EROFS_I_SB(inode), vi->nid) + 37647e4937aSGao Xiang vi->inode_isize + vi->xattr_isize, 8) + 37747e4937aSGao Xiang sizeof(struct z_erofs_map_header); 37847e4937aSGao Xiang const unsigned int totalidx = DIV_ROUND_UP(inode->i_size, EROFS_BLKSIZ); 37947e4937aSGao Xiang unsigned int compacted_4b_initial, compacted_2b; 38047e4937aSGao Xiang unsigned int amortizedshift; 38147e4937aSGao Xiang erofs_off_t pos; 38247e4937aSGao Xiang 38347e4937aSGao Xiang if (lclusterbits != 12) 38447e4937aSGao Xiang return -EOPNOTSUPP; 38547e4937aSGao Xiang 38647e4937aSGao Xiang if (lcn >= totalidx) 38747e4937aSGao Xiang return -EINVAL; 38847e4937aSGao Xiang 38947e4937aSGao Xiang m->lcn = lcn; 39047e4937aSGao Xiang /* used to align to 32-byte (compacted_2b) alignment */ 39147e4937aSGao Xiang compacted_4b_initial = (32 - ebase % 32) / 4; 39247e4937aSGao Xiang if (compacted_4b_initial == 32 / 4) 39347e4937aSGao Xiang compacted_4b_initial = 0; 39447e4937aSGao Xiang 395c40dd3caSYue Hu if ((vi->z_advise & Z_EROFS_ADVISE_COMPACTED_2B) && 396c40dd3caSYue Hu compacted_4b_initial < totalidx) 39747e4937aSGao Xiang compacted_2b = rounddown(totalidx - compacted_4b_initial, 16); 39847e4937aSGao Xiang else 39947e4937aSGao Xiang compacted_2b = 0; 40047e4937aSGao Xiang 40147e4937aSGao Xiang pos = ebase; 40247e4937aSGao Xiang if (lcn < compacted_4b_initial) { 40347e4937aSGao Xiang amortizedshift = 2; 40447e4937aSGao Xiang goto out; 40547e4937aSGao Xiang } 40647e4937aSGao Xiang pos += compacted_4b_initial * 4; 40747e4937aSGao Xiang lcn -= compacted_4b_initial; 40847e4937aSGao Xiang 40947e4937aSGao Xiang if (lcn < compacted_2b) { 41047e4937aSGao Xiang amortizedshift = 1; 41147e4937aSGao Xiang goto out; 41247e4937aSGao Xiang } 41347e4937aSGao Xiang pos += compacted_2b * 2; 41447e4937aSGao Xiang lcn -= compacted_2b; 41547e4937aSGao Xiang amortizedshift = 2; 41647e4937aSGao Xiang out: 41747e4937aSGao Xiang pos += lcn * (1 << amortizedshift); 41831da107fSYue Hu m->kaddr = erofs_read_metabuf(&m->map->buf, inode->i_sb, 419927e5010SGao Xiang erofs_blknr(pos), EROFS_KMAP); 42031da107fSYue Hu if (IS_ERR(m->kaddr)) 42131da107fSYue Hu return PTR_ERR(m->kaddr); 422ab92184fSYue Hu return unpack_compacted_index(m, amortizedshift, pos, lookahead); 42347e4937aSGao Xiang } 42447e4937aSGao Xiang 4250c638f70SGao Xiang static int z_erofs_load_cluster_from_disk(struct z_erofs_maprecorder *m, 426d95ae5e2SGao Xiang unsigned int lcn, bool lookahead) 42747e4937aSGao Xiang { 428a5876e24SGao Xiang const unsigned int datamode = EROFS_I(m->inode)->datalayout; 42947e4937aSGao Xiang 43047e4937aSGao Xiang if (datamode == EROFS_INODE_FLAT_COMPRESSION_LEGACY) 4310c638f70SGao Xiang return legacy_load_cluster_from_disk(m, lcn); 43247e4937aSGao Xiang 43347e4937aSGao Xiang if (datamode == EROFS_INODE_FLAT_COMPRESSION) 434d95ae5e2SGao Xiang return compacted_load_cluster_from_disk(m, lcn, lookahead); 43547e4937aSGao Xiang 43647e4937aSGao Xiang return -EINVAL; 43747e4937aSGao Xiang } 43847e4937aSGao Xiang 4390c638f70SGao Xiang static int z_erofs_extent_lookback(struct z_erofs_maprecorder *m, 44047e4937aSGao Xiang unsigned int lookback_distance) 44147e4937aSGao Xiang { 442a5876e24SGao Xiang struct erofs_inode *const vi = EROFS_I(m->inode); 44347e4937aSGao Xiang const unsigned int lclusterbits = vi->z_logical_clusterbits; 444ab474fccSGao Xiang 445ab474fccSGao Xiang while (m->lcn >= lookback_distance) { 446ab474fccSGao Xiang unsigned long lcn = m->lcn - lookback_distance; 44747e4937aSGao Xiang int err; 44847e4937aSGao Xiang 44947e4937aSGao Xiang /* load extent head logical cluster if needed */ 450d95ae5e2SGao Xiang err = z_erofs_load_cluster_from_disk(m, lcn, false); 45147e4937aSGao Xiang if (err) 45247e4937aSGao Xiang return err; 45347e4937aSGao Xiang 45447e4937aSGao Xiang switch (m->type) { 45547e4937aSGao Xiang case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD: 4568d8a09b0SGao Xiang if (!m->delta[0]) { 4574f761fa2SGao Xiang erofs_err(m->inode->i_sb, 4584f761fa2SGao Xiang "invalid lookback distance 0 @ nid %llu", 45947e4937aSGao Xiang vi->nid); 46047e4937aSGao Xiang DBG_BUGON(1); 46147e4937aSGao Xiang return -EFSCORRUPTED; 46247e4937aSGao Xiang } 463ab474fccSGao Xiang lookback_distance = m->delta[0]; 464ab474fccSGao Xiang continue; 46547e4937aSGao Xiang case Z_EROFS_VLE_CLUSTER_TYPE_PLAIN: 46672bb5262SGao Xiang case Z_EROFS_VLE_CLUSTER_TYPE_HEAD1: 46772bb5262SGao Xiang case Z_EROFS_VLE_CLUSTER_TYPE_HEAD2: 4688f899262SGao Xiang m->headtype = m->type; 469ab474fccSGao Xiang m->map->m_la = (lcn << lclusterbits) | m->clusterofs; 470ab474fccSGao Xiang return 0; 47147e4937aSGao Xiang default: 4724f761fa2SGao Xiang erofs_err(m->inode->i_sb, 4734f761fa2SGao Xiang "unknown type %u @ lcn %lu of nid %llu", 47447e4937aSGao Xiang m->type, lcn, vi->nid); 47547e4937aSGao Xiang DBG_BUGON(1); 47647e4937aSGao Xiang return -EOPNOTSUPP; 47747e4937aSGao Xiang } 478ab474fccSGao Xiang } 479ab474fccSGao Xiang 480ab474fccSGao Xiang erofs_err(m->inode->i_sb, "bogus lookback distance @ nid %llu", 481ab474fccSGao Xiang vi->nid); 482ab474fccSGao Xiang DBG_BUGON(1); 483ab474fccSGao Xiang return -EFSCORRUPTED; 48447e4937aSGao Xiang } 48547e4937aSGao Xiang 486cec6e93bSGao Xiang static int z_erofs_get_extent_compressedlen(struct z_erofs_maprecorder *m, 487cec6e93bSGao Xiang unsigned int initial_lcn) 488cec6e93bSGao Xiang { 489cec6e93bSGao Xiang struct erofs_inode *const vi = EROFS_I(m->inode); 490cec6e93bSGao Xiang struct erofs_map_blocks *const map = m->map; 491cec6e93bSGao Xiang const unsigned int lclusterbits = vi->z_logical_clusterbits; 492cec6e93bSGao Xiang unsigned long lcn; 493cec6e93bSGao Xiang int err; 494cec6e93bSGao Xiang 495cec6e93bSGao Xiang DBG_BUGON(m->type != Z_EROFS_VLE_CLUSTER_TYPE_PLAIN && 49672bb5262SGao Xiang m->type != Z_EROFS_VLE_CLUSTER_TYPE_HEAD1 && 49772bb5262SGao Xiang m->type != Z_EROFS_VLE_CLUSTER_TYPE_HEAD2); 49872bb5262SGao Xiang DBG_BUGON(m->type != m->headtype); 49972bb5262SGao Xiang 5008f899262SGao Xiang if (m->headtype == Z_EROFS_VLE_CLUSTER_TYPE_PLAIN || 50172bb5262SGao Xiang ((m->headtype == Z_EROFS_VLE_CLUSTER_TYPE_HEAD1) && 50272bb5262SGao Xiang !(vi->z_advise & Z_EROFS_ADVISE_BIG_PCLUSTER_1)) || 50372bb5262SGao Xiang ((m->headtype == Z_EROFS_VLE_CLUSTER_TYPE_HEAD2) && 50472bb5262SGao Xiang !(vi->z_advise & Z_EROFS_ADVISE_BIG_PCLUSTER_2))) { 505d467e980SGao Xiang map->m_plen = 1ULL << lclusterbits; 506cec6e93bSGao Xiang return 0; 507cec6e93bSGao Xiang } 508cec6e93bSGao Xiang lcn = m->lcn + 1; 509ea0b7b0dSYue Hu if (m->compressedblks) 510cec6e93bSGao Xiang goto out; 511cec6e93bSGao Xiang 512d95ae5e2SGao Xiang err = z_erofs_load_cluster_from_disk(m, lcn, false); 513cec6e93bSGao Xiang if (err) 514cec6e93bSGao Xiang return err; 515cec6e93bSGao Xiang 5160852b6caSGao Xiang /* 5170852b6caSGao Xiang * If the 1st NONHEAD lcluster has already been handled initially w/o 518ea0b7b0dSYue Hu * valid compressedblks, which means at least it mustn't be CBLKCNT, or 5190852b6caSGao Xiang * an internal implemenatation error is detected. 5200852b6caSGao Xiang * 5210852b6caSGao Xiang * The following code can also handle it properly anyway, but let's 5220852b6caSGao Xiang * BUG_ON in the debugging mode only for developers to notice that. 5230852b6caSGao Xiang */ 5240852b6caSGao Xiang DBG_BUGON(lcn == initial_lcn && 5250852b6caSGao Xiang m->type == Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD); 5260852b6caSGao Xiang 527cec6e93bSGao Xiang switch (m->type) { 5280852b6caSGao Xiang case Z_EROFS_VLE_CLUSTER_TYPE_PLAIN: 52972bb5262SGao Xiang case Z_EROFS_VLE_CLUSTER_TYPE_HEAD1: 53072bb5262SGao Xiang case Z_EROFS_VLE_CLUSTER_TYPE_HEAD2: 5310852b6caSGao Xiang /* 5320852b6caSGao Xiang * if the 1st NONHEAD lcluster is actually PLAIN or HEAD type 5330852b6caSGao Xiang * rather than CBLKCNT, it's a 1 lcluster-sized pcluster. 5340852b6caSGao Xiang */ 535ea0b7b0dSYue Hu m->compressedblks = 1 << (lclusterbits - LOG_BLOCK_SIZE); 5360852b6caSGao Xiang break; 537cec6e93bSGao Xiang case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD: 538cec6e93bSGao Xiang if (m->delta[0] != 1) 539cec6e93bSGao Xiang goto err_bonus_cblkcnt; 540ea0b7b0dSYue Hu if (m->compressedblks) 541cec6e93bSGao Xiang break; 542cec6e93bSGao Xiang fallthrough; 543cec6e93bSGao Xiang default: 544cec6e93bSGao Xiang erofs_err(m->inode->i_sb, 545cec6e93bSGao Xiang "cannot found CBLKCNT @ lcn %lu of nid %llu", 546cec6e93bSGao Xiang lcn, vi->nid); 547cec6e93bSGao Xiang DBG_BUGON(1); 548cec6e93bSGao Xiang return -EFSCORRUPTED; 549cec6e93bSGao Xiang } 550cec6e93bSGao Xiang out: 551ea0b7b0dSYue Hu map->m_plen = (u64)m->compressedblks << LOG_BLOCK_SIZE; 552cec6e93bSGao Xiang return 0; 553cec6e93bSGao Xiang err_bonus_cblkcnt: 554cec6e93bSGao Xiang erofs_err(m->inode->i_sb, 555cec6e93bSGao Xiang "bogus CBLKCNT @ lcn %lu of nid %llu", 556cec6e93bSGao Xiang lcn, vi->nid); 557cec6e93bSGao Xiang DBG_BUGON(1); 558cec6e93bSGao Xiang return -EFSCORRUPTED; 559cec6e93bSGao Xiang } 560cec6e93bSGao Xiang 561d95ae5e2SGao Xiang static int z_erofs_get_extent_decompressedlen(struct z_erofs_maprecorder *m) 562d95ae5e2SGao Xiang { 563d95ae5e2SGao Xiang struct inode *inode = m->inode; 564d95ae5e2SGao Xiang struct erofs_inode *vi = EROFS_I(inode); 565d95ae5e2SGao Xiang struct erofs_map_blocks *map = m->map; 566d95ae5e2SGao Xiang unsigned int lclusterbits = vi->z_logical_clusterbits; 567d95ae5e2SGao Xiang u64 lcn = m->lcn, headlcn = map->m_la >> lclusterbits; 568d95ae5e2SGao Xiang int err; 569d95ae5e2SGao Xiang 570d95ae5e2SGao Xiang do { 571d95ae5e2SGao Xiang /* handle the last EOF pcluster (no next HEAD lcluster) */ 572d95ae5e2SGao Xiang if ((lcn << lclusterbits) >= inode->i_size) { 573d95ae5e2SGao Xiang map->m_llen = inode->i_size - map->m_la; 574d95ae5e2SGao Xiang return 0; 575d95ae5e2SGao Xiang } 576d95ae5e2SGao Xiang 577d95ae5e2SGao Xiang err = z_erofs_load_cluster_from_disk(m, lcn, true); 578d95ae5e2SGao Xiang if (err) 579d95ae5e2SGao Xiang return err; 580d95ae5e2SGao Xiang 581d95ae5e2SGao Xiang if (m->type == Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD) { 582d95ae5e2SGao Xiang DBG_BUGON(!m->delta[1] && 583d95ae5e2SGao Xiang m->clusterofs != 1 << lclusterbits); 584d95ae5e2SGao Xiang } else if (m->type == Z_EROFS_VLE_CLUSTER_TYPE_PLAIN || 58572bb5262SGao Xiang m->type == Z_EROFS_VLE_CLUSTER_TYPE_HEAD1 || 58672bb5262SGao Xiang m->type == Z_EROFS_VLE_CLUSTER_TYPE_HEAD2) { 587d95ae5e2SGao Xiang /* go on until the next HEAD lcluster */ 588d95ae5e2SGao Xiang if (lcn != headlcn) 589d95ae5e2SGao Xiang break; 590d95ae5e2SGao Xiang m->delta[1] = 1; 591d95ae5e2SGao Xiang } else { 592d95ae5e2SGao Xiang erofs_err(inode->i_sb, "unknown type %u @ lcn %llu of nid %llu", 593d95ae5e2SGao Xiang m->type, lcn, vi->nid); 594d95ae5e2SGao Xiang DBG_BUGON(1); 595d95ae5e2SGao Xiang return -EOPNOTSUPP; 596d95ae5e2SGao Xiang } 597d95ae5e2SGao Xiang lcn += m->delta[1]; 598d95ae5e2SGao Xiang } while (m->delta[1]); 599d95ae5e2SGao Xiang 600d95ae5e2SGao Xiang map->m_llen = (lcn << lclusterbits) + m->clusterofs - map->m_la; 601d95ae5e2SGao Xiang return 0; 602d95ae5e2SGao Xiang } 603d95ae5e2SGao Xiang 604ab92184fSYue Hu static int z_erofs_do_map_blocks(struct inode *inode, 60547e4937aSGao Xiang struct erofs_map_blocks *map, 60647e4937aSGao Xiang int flags) 60747e4937aSGao Xiang { 608a5876e24SGao Xiang struct erofs_inode *const vi = EROFS_I(inode); 609ab92184fSYue Hu bool ztailpacking = vi->z_advise & Z_EROFS_ADVISE_INLINE_PCLUSTER; 610b15b2e30SYue Hu bool fragment = vi->z_advise & Z_EROFS_ADVISE_FRAGMENT_PCLUSTER; 61147e4937aSGao Xiang struct z_erofs_maprecorder m = { 61247e4937aSGao Xiang .inode = inode, 61347e4937aSGao Xiang .map = map, 61447e4937aSGao Xiang }; 61547e4937aSGao Xiang int err = 0; 61647e4937aSGao Xiang unsigned int lclusterbits, endoff; 617cec6e93bSGao Xiang unsigned long initial_lcn; 61847e4937aSGao Xiang unsigned long long ofs, end; 61947e4937aSGao Xiang 62047e4937aSGao Xiang lclusterbits = vi->z_logical_clusterbits; 621ab92184fSYue Hu ofs = flags & EROFS_GET_BLOCKS_FINDTAIL ? inode->i_size - 1 : map->m_la; 622cec6e93bSGao Xiang initial_lcn = ofs >> lclusterbits; 62347e4937aSGao Xiang endoff = ofs & ((1 << lclusterbits) - 1); 62447e4937aSGao Xiang 625d95ae5e2SGao Xiang err = z_erofs_load_cluster_from_disk(&m, initial_lcn, false); 62647e4937aSGao Xiang if (err) 62747e4937aSGao Xiang goto unmap_out; 62847e4937aSGao Xiang 629ab92184fSYue Hu if (ztailpacking && (flags & EROFS_GET_BLOCKS_FINDTAIL)) 630ab92184fSYue Hu vi->z_idataoff = m.nextpackoff; 631ab92184fSYue Hu 6328f899262SGao Xiang map->m_flags = EROFS_MAP_MAPPED | EROFS_MAP_ENCODED; 63347e4937aSGao Xiang end = (m.lcn + 1ULL) << lclusterbits; 63447e4937aSGao Xiang 63547e4937aSGao Xiang switch (m.type) { 63647e4937aSGao Xiang case Z_EROFS_VLE_CLUSTER_TYPE_PLAIN: 63772bb5262SGao Xiang case Z_EROFS_VLE_CLUSTER_TYPE_HEAD1: 63872bb5262SGao Xiang case Z_EROFS_VLE_CLUSTER_TYPE_HEAD2: 63947e4937aSGao Xiang if (endoff >= m.clusterofs) { 6408f899262SGao Xiang m.headtype = m.type; 64147e4937aSGao Xiang map->m_la = (m.lcn << lclusterbits) | m.clusterofs; 64224331050SGao Xiang /* 64324331050SGao Xiang * For ztailpacking files, in order to inline data more 64424331050SGao Xiang * effectively, special EOF lclusters are now supported 64524331050SGao Xiang * which can have three parts at most. 64624331050SGao Xiang */ 64724331050SGao Xiang if (ztailpacking && end > inode->i_size) 64824331050SGao Xiang end = inode->i_size; 64947e4937aSGao Xiang break; 65047e4937aSGao Xiang } 65147e4937aSGao Xiang /* m.lcn should be >= 1 if endoff < m.clusterofs */ 6528d8a09b0SGao Xiang if (!m.lcn) { 6534f761fa2SGao Xiang erofs_err(inode->i_sb, 6544f761fa2SGao Xiang "invalid logical cluster 0 at nid %llu", 65547e4937aSGao Xiang vi->nid); 65647e4937aSGao Xiang err = -EFSCORRUPTED; 65747e4937aSGao Xiang goto unmap_out; 65847e4937aSGao Xiang } 65947e4937aSGao Xiang end = (m.lcn << lclusterbits) | m.clusterofs; 66047e4937aSGao Xiang map->m_flags |= EROFS_MAP_FULL_MAPPED; 66147e4937aSGao Xiang m.delta[0] = 1; 662df561f66SGustavo A. R. Silva fallthrough; 66347e4937aSGao Xiang case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD: 664fe6adcceSRuiqi Gong /* get the corresponding first chunk */ 6650c638f70SGao Xiang err = z_erofs_extent_lookback(&m, m.delta[0]); 6668d8a09b0SGao Xiang if (err) 66747e4937aSGao Xiang goto unmap_out; 66847e4937aSGao Xiang break; 66947e4937aSGao Xiang default: 6704f761fa2SGao Xiang erofs_err(inode->i_sb, 6714f761fa2SGao Xiang "unknown type %u @ offset %llu of nid %llu", 67247e4937aSGao Xiang m.type, ofs, vi->nid); 67347e4937aSGao Xiang err = -EOPNOTSUPP; 67447e4937aSGao Xiang goto unmap_out; 67547e4937aSGao Xiang } 6765c2a6425SGao Xiang if (m.partialref) 6775c2a6425SGao Xiang map->m_flags |= EROFS_MAP_PARTIAL_REF; 67847e4937aSGao Xiang map->m_llen = end - map->m_la; 67947e4937aSGao Xiang 680b15b2e30SYue Hu if (flags & EROFS_GET_BLOCKS_FINDTAIL) { 681ab92184fSYue Hu vi->z_tailextent_headlcn = m.lcn; 682b15b2e30SYue Hu /* for non-compact indexes, fragmentoff is 64 bits */ 683b15b2e30SYue Hu if (fragment && 684b15b2e30SYue Hu vi->datalayout == EROFS_INODE_FLAT_COMPRESSION_LEGACY) 685b15b2e30SYue Hu vi->z_fragmentoff |= (u64)m.pblk << 32; 686b15b2e30SYue Hu } 687ab92184fSYue Hu if (ztailpacking && m.lcn == vi->z_tailextent_headlcn) { 688ab92184fSYue Hu map->m_flags |= EROFS_MAP_META; 689ab92184fSYue Hu map->m_pa = vi->z_idataoff; 690ab92184fSYue Hu map->m_plen = vi->z_idata_size; 691b15b2e30SYue Hu } else if (fragment && m.lcn == vi->z_tailextent_headlcn) { 692b15b2e30SYue Hu map->m_flags |= EROFS_MAP_FRAGMENT; 693ab92184fSYue Hu } else { 694ab92184fSYue Hu map->m_pa = blknr_to_addr(m.pblk); 695cec6e93bSGao Xiang err = z_erofs_get_extent_compressedlen(&m, initial_lcn); 696cec6e93bSGao Xiang if (err) 697d5d188b8SGao Xiang goto unmap_out; 698ab92184fSYue Hu } 699d95ae5e2SGao Xiang 700fdffc091SYue Hu if (m.headtype == Z_EROFS_VLE_CLUSTER_TYPE_PLAIN) { 701*c505febaSGao Xiang if (map->m_llen > map->m_plen) { 702*c505febaSGao Xiang DBG_BUGON(1); 703*c505febaSGao Xiang err = -EFSCORRUPTED; 704*c505febaSGao Xiang goto unmap_out; 705*c505febaSGao Xiang } 706fdffc091SYue Hu if (vi->z_advise & Z_EROFS_ADVISE_INTERLACED_PCLUSTER) 707fdffc091SYue Hu map->m_algorithmformat = 708fdffc091SYue Hu Z_EROFS_COMPRESSION_INTERLACED; 7098f899262SGao Xiang else 710fdffc091SYue Hu map->m_algorithmformat = 711fdffc091SYue Hu Z_EROFS_COMPRESSION_SHIFTED; 712fdffc091SYue Hu } else if (m.headtype == Z_EROFS_VLE_CLUSTER_TYPE_HEAD2) { 713fdffc091SYue Hu map->m_algorithmformat = vi->z_algorithmtype[1]; 714fdffc091SYue Hu } else { 7158f899262SGao Xiang map->m_algorithmformat = vi->z_algorithmtype[0]; 716fdffc091SYue Hu } 7178f899262SGao Xiang 718622ceaddSGao Xiang if ((flags & EROFS_GET_BLOCKS_FIEMAP) || 719622ceaddSGao Xiang ((flags & EROFS_GET_BLOCKS_READMORE) && 720622ceaddSGao Xiang map->m_algorithmformat == Z_EROFS_COMPRESSION_LZMA && 721622ceaddSGao Xiang map->m_llen >= EROFS_BLKSIZ)) { 722d95ae5e2SGao Xiang err = z_erofs_get_extent_decompressedlen(&m); 723d95ae5e2SGao Xiang if (!err) 724d95ae5e2SGao Xiang map->m_flags |= EROFS_MAP_FULL_MAPPED; 725d95ae5e2SGao Xiang } 726d5d188b8SGao Xiang 72747e4937aSGao Xiang unmap_out: 72809c54379SGao Xiang erofs_unmap_metabuf(&m.map->buf); 7294f761fa2SGao Xiang erofs_dbg("%s, m_la %llu m_pa %llu m_llen %llu m_plen %llu m_flags 0%o", 73047e4937aSGao Xiang __func__, map->m_la, map->m_pa, 73147e4937aSGao Xiang map->m_llen, map->m_plen, map->m_flags); 732ab92184fSYue Hu return err; 733ab92184fSYue Hu } 734ab92184fSYue Hu 73553a7f996SGao Xiang int z_erofs_map_blocks_iter(struct inode *inode, struct erofs_map_blocks *map, 736ab92184fSYue Hu int flags) 737ab92184fSYue Hu { 738b15b2e30SYue Hu struct erofs_inode *const vi = EROFS_I(inode); 739ab92184fSYue Hu int err = 0; 740ab92184fSYue Hu 741ab92184fSYue Hu trace_z_erofs_map_blocks_iter_enter(inode, map, flags); 742ab92184fSYue Hu 743ab92184fSYue Hu /* when trying to read beyond EOF, leave it unmapped */ 744ab92184fSYue Hu if (map->m_la >= inode->i_size) { 745ab92184fSYue Hu map->m_llen = map->m_la + 1 - inode->i_size; 746ab92184fSYue Hu map->m_la = inode->i_size; 747ab92184fSYue Hu map->m_flags = 0; 748ab92184fSYue Hu goto out; 749ab92184fSYue Hu } 750ab92184fSYue Hu 751ab92184fSYue Hu err = z_erofs_fill_inode_lazy(inode); 752ab92184fSYue Hu if (err) 753ab92184fSYue Hu goto out; 754ab92184fSYue Hu 755b15b2e30SYue Hu if ((vi->z_advise & Z_EROFS_ADVISE_FRAGMENT_PCLUSTER) && 756b15b2e30SYue Hu !vi->z_tailextent_headlcn) { 757b15b2e30SYue Hu map->m_la = 0; 758b15b2e30SYue Hu map->m_llen = inode->i_size; 759b15b2e30SYue Hu map->m_flags = EROFS_MAP_MAPPED | EROFS_MAP_FULL_MAPPED | 760b15b2e30SYue Hu EROFS_MAP_FRAGMENT; 761b15b2e30SYue Hu goto out; 762b15b2e30SYue Hu } 763b15b2e30SYue Hu 764ab92184fSYue Hu err = z_erofs_do_map_blocks(inode, map, flags); 765ab92184fSYue Hu out: 76647e4937aSGao Xiang trace_z_erofs_map_blocks_iter_exit(inode, map, flags, err); 76747e4937aSGao Xiang 76847e4937aSGao Xiang /* aggressively BUG_ON iff CONFIG_EROFS_FS_DEBUG is on */ 76947e4937aSGao Xiang DBG_BUGON(err < 0 && err != -ENOMEM); 77047e4937aSGao Xiang return err; 77147e4937aSGao Xiang } 772eadcd6b5SGao Xiang 773eadcd6b5SGao Xiang static int z_erofs_iomap_begin_report(struct inode *inode, loff_t offset, 774eadcd6b5SGao Xiang loff_t length, unsigned int flags, 775eadcd6b5SGao Xiang struct iomap *iomap, struct iomap *srcmap) 776eadcd6b5SGao Xiang { 777eadcd6b5SGao Xiang int ret; 778eadcd6b5SGao Xiang struct erofs_map_blocks map = { .m_la = offset }; 779eadcd6b5SGao Xiang 780eadcd6b5SGao Xiang ret = z_erofs_map_blocks_iter(inode, &map, EROFS_GET_BLOCKS_FIEMAP); 78109c54379SGao Xiang erofs_put_metabuf(&map.buf); 782eadcd6b5SGao Xiang if (ret < 0) 783eadcd6b5SGao Xiang return ret; 784eadcd6b5SGao Xiang 785eadcd6b5SGao Xiang iomap->bdev = inode->i_sb->s_bdev; 786eadcd6b5SGao Xiang iomap->offset = map.m_la; 787eadcd6b5SGao Xiang iomap->length = map.m_llen; 788eadcd6b5SGao Xiang if (map.m_flags & EROFS_MAP_MAPPED) { 789eadcd6b5SGao Xiang iomap->type = IOMAP_MAPPED; 790b15b2e30SYue Hu iomap->addr = map.m_flags & EROFS_MAP_FRAGMENT ? 791b15b2e30SYue Hu IOMAP_NULL_ADDR : map.m_pa; 792eadcd6b5SGao Xiang } else { 793eadcd6b5SGao Xiang iomap->type = IOMAP_HOLE; 794eadcd6b5SGao Xiang iomap->addr = IOMAP_NULL_ADDR; 795eadcd6b5SGao Xiang /* 796eadcd6b5SGao Xiang * No strict rule how to describe extents for post EOF, yet 797eadcd6b5SGao Xiang * we need do like below. Otherwise, iomap itself will get 798eadcd6b5SGao Xiang * into an endless loop on post EOF. 799eadcd6b5SGao Xiang */ 800eadcd6b5SGao Xiang if (iomap->offset >= inode->i_size) 801eadcd6b5SGao Xiang iomap->length = length + map.m_la - offset; 802eadcd6b5SGao Xiang } 803eadcd6b5SGao Xiang iomap->flags = 0; 804eadcd6b5SGao Xiang return 0; 805eadcd6b5SGao Xiang } 806eadcd6b5SGao Xiang 807eadcd6b5SGao Xiang const struct iomap_ops z_erofs_iomap_report_ops = { 808eadcd6b5SGao Xiang .iomap_begin = z_erofs_iomap_begin_report, 809eadcd6b5SGao Xiang }; 810