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) && 20ab92184fSYue Hu !erofs_sb_has_ztailpacking(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 58cec6e93bSGao Xiang DBG_BUGON(!erofs_sb_has_big_pcluster(EROFS_SB(sb)) && 59ab92184fSYue Hu !erofs_sb_has_ztailpacking(EROFS_SB(sb)) && 60cec6e93bSGao Xiang vi->datalayout == EROFS_INODE_FLAT_COMPRESSION_LEGACY); 6147e4937aSGao Xiang 6247e4937aSGao Xiang pos = ALIGN(iloc(EROFS_SB(sb), vi->nid) + vi->inode_isize + 6347e4937aSGao Xiang vi->xattr_isize, 8); 6409c54379SGao Xiang kaddr = erofs_read_metabuf(&buf, sb, erofs_blknr(pos), 6509c54379SGao Xiang EROFS_KMAP_ATOMIC); 6609c54379SGao Xiang if (IS_ERR(kaddr)) { 6709c54379SGao Xiang err = PTR_ERR(kaddr); 6847e4937aSGao Xiang goto out_unlock; 6947e4937aSGao Xiang } 7047e4937aSGao Xiang 7147e4937aSGao Xiang h = kaddr + erofs_blkoff(pos); 7247e4937aSGao Xiang vi->z_advise = le16_to_cpu(h->h_advise); 7347e4937aSGao Xiang vi->z_algorithmtype[0] = h->h_algorithmtype & 15; 7447e4937aSGao Xiang vi->z_algorithmtype[1] = h->h_algorithmtype >> 4; 7547e4937aSGao Xiang 7672bb5262SGao Xiang headnr = 0; 7772bb5262SGao Xiang if (vi->z_algorithmtype[0] >= Z_EROFS_COMPRESSION_MAX || 7872bb5262SGao Xiang vi->z_algorithmtype[++headnr] >= Z_EROFS_COMPRESSION_MAX) { 7972bb5262SGao Xiang erofs_err(sb, "unknown HEAD%u format %u for nid %llu, please upgrade kernel", 8072bb5262SGao Xiang headnr + 1, vi->z_algorithmtype[headnr], vi->nid); 8147e4937aSGao Xiang err = -EOPNOTSUPP; 8247e4937aSGao Xiang goto unmap_done; 8347e4937aSGao Xiang } 8447e4937aSGao Xiang 8547e4937aSGao Xiang vi->z_logical_clusterbits = LOG_BLOCK_SIZE + (h->h_clusterbits & 7); 86b86269f4SGao Xiang if (!erofs_sb_has_big_pcluster(EROFS_SB(sb)) && 87b86269f4SGao Xiang vi->z_advise & (Z_EROFS_ADVISE_BIG_PCLUSTER_1 | 88b86269f4SGao Xiang Z_EROFS_ADVISE_BIG_PCLUSTER_2)) { 89b86269f4SGao Xiang erofs_err(sb, "per-inode big pcluster without sb feature for nid %llu", 90b86269f4SGao Xiang vi->nid); 91b86269f4SGao Xiang err = -EFSCORRUPTED; 92b86269f4SGao Xiang goto unmap_done; 93b86269f4SGao Xiang } 94b86269f4SGao Xiang if (vi->datalayout == EROFS_INODE_FLAT_COMPRESSION && 95b86269f4SGao Xiang !(vi->z_advise & Z_EROFS_ADVISE_BIG_PCLUSTER_1) ^ 96b86269f4SGao Xiang !(vi->z_advise & Z_EROFS_ADVISE_BIG_PCLUSTER_2)) { 97b86269f4SGao Xiang erofs_err(sb, "big pcluster head1/2 of compact indexes should be consistent for nid %llu", 98b86269f4SGao Xiang vi->nid); 99b86269f4SGao Xiang err = -EFSCORRUPTED; 100b86269f4SGao Xiang goto unmap_done; 101b86269f4SGao Xiang } 10247e4937aSGao Xiang unmap_done: 10309c54379SGao Xiang erofs_put_metabuf(&buf); 104ab92184fSYue Hu if (err) 105ab92184fSYue Hu goto out_unlock; 106ab92184fSYue Hu 107ab92184fSYue Hu if (vi->z_advise & Z_EROFS_ADVISE_INLINE_PCLUSTER) { 10809c54379SGao Xiang struct erofs_map_blocks map = { 10909c54379SGao Xiang .buf = __EROFS_BUF_INITIALIZER 11009c54379SGao Xiang }; 111ab92184fSYue Hu 112ab92184fSYue Hu vi->z_idata_size = le16_to_cpu(h->h_idata_size); 113ab92184fSYue Hu err = z_erofs_do_map_blocks(inode, &map, 114ab92184fSYue Hu EROFS_GET_BLOCKS_FINDTAIL); 11509c54379SGao Xiang erofs_put_metabuf(&map.buf); 116ab92184fSYue Hu 117ab92184fSYue Hu if (!map.m_plen || 118ab92184fSYue Hu erofs_blkoff(map.m_pa) + map.m_plen > EROFS_BLKSIZ) { 119ab92184fSYue Hu erofs_err(sb, "invalid tail-packing pclustersize %llu", 120ab92184fSYue Hu map.m_plen); 121ab92184fSYue Hu err = -EFSCORRUPTED; 122ab92184fSYue Hu } 123ab92184fSYue Hu if (err < 0) 124ab92184fSYue Hu goto out_unlock; 125ab92184fSYue Hu } 126ab92184fSYue Hu /* paired with smp_mb() at the beginning of the function */ 127ab92184fSYue Hu smp_mb(); 128ab92184fSYue Hu set_bit(EROFS_I_Z_INITED_BIT, &vi->flags); 12947e4937aSGao Xiang out_unlock: 130a5876e24SGao Xiang clear_and_wake_up_bit(EROFS_I_BL_Z_BIT, &vi->flags); 13147e4937aSGao Xiang return err; 13247e4937aSGao Xiang } 13347e4937aSGao Xiang 13447e4937aSGao Xiang struct z_erofs_maprecorder { 13547e4937aSGao Xiang struct inode *inode; 13647e4937aSGao Xiang struct erofs_map_blocks *map; 13747e4937aSGao Xiang void *kaddr; 13847e4937aSGao Xiang 13947e4937aSGao Xiang unsigned long lcn; 14047e4937aSGao Xiang /* compression extent information gathered */ 1418f899262SGao Xiang u8 type, headtype; 14247e4937aSGao Xiang u16 clusterofs; 14347e4937aSGao Xiang u16 delta[2]; 144cec6e93bSGao Xiang erofs_blk_t pblk, compressedlcs; 145ab92184fSYue Hu erofs_off_t nextpackoff; 14647e4937aSGao Xiang }; 14747e4937aSGao Xiang 14847e4937aSGao Xiang static int z_erofs_reload_indexes(struct z_erofs_maprecorder *m, 14947e4937aSGao Xiang erofs_blk_t eblk) 15047e4937aSGao Xiang { 15147e4937aSGao Xiang struct super_block *const sb = m->inode->i_sb; 15247e4937aSGao Xiang 15309c54379SGao Xiang m->kaddr = erofs_read_metabuf(&m->map->buf, sb, eblk, 15409c54379SGao Xiang EROFS_KMAP_ATOMIC); 15509c54379SGao Xiang if (IS_ERR(m->kaddr)) 15609c54379SGao Xiang return PTR_ERR(m->kaddr); 15747e4937aSGao Xiang return 0; 15847e4937aSGao Xiang } 15947e4937aSGao Xiang 1600c638f70SGao Xiang static int legacy_load_cluster_from_disk(struct z_erofs_maprecorder *m, 16147e4937aSGao Xiang unsigned long lcn) 16247e4937aSGao Xiang { 16347e4937aSGao Xiang struct inode *const inode = m->inode; 164a5876e24SGao Xiang struct erofs_inode *const vi = EROFS_I(inode); 16547e4937aSGao Xiang const erofs_off_t ibase = iloc(EROFS_I_SB(inode), vi->nid); 16647e4937aSGao Xiang const erofs_off_t pos = 16747e4937aSGao Xiang Z_EROFS_VLE_LEGACY_INDEX_ALIGN(ibase + vi->inode_isize + 16847e4937aSGao Xiang vi->xattr_isize) + 16947e4937aSGao Xiang lcn * sizeof(struct z_erofs_vle_decompressed_index); 17047e4937aSGao Xiang struct z_erofs_vle_decompressed_index *di; 17147e4937aSGao Xiang unsigned int advise, type; 17247e4937aSGao Xiang int err; 17347e4937aSGao Xiang 17447e4937aSGao Xiang err = z_erofs_reload_indexes(m, erofs_blknr(pos)); 17547e4937aSGao Xiang if (err) 17647e4937aSGao Xiang return err; 17747e4937aSGao Xiang 178ab92184fSYue Hu m->nextpackoff = pos + sizeof(struct z_erofs_vle_decompressed_index); 17947e4937aSGao Xiang m->lcn = lcn; 18047e4937aSGao Xiang di = m->kaddr + erofs_blkoff(pos); 18147e4937aSGao Xiang 18247e4937aSGao Xiang advise = le16_to_cpu(di->di_advise); 18347e4937aSGao Xiang type = (advise >> Z_EROFS_VLE_DI_CLUSTER_TYPE_BIT) & 18447e4937aSGao Xiang ((1 << Z_EROFS_VLE_DI_CLUSTER_TYPE_BITS) - 1); 18547e4937aSGao Xiang switch (type) { 18647e4937aSGao Xiang case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD: 18747e4937aSGao Xiang m->clusterofs = 1 << vi->z_logical_clusterbits; 18847e4937aSGao Xiang m->delta[0] = le16_to_cpu(di->di_u.delta[0]); 189cec6e93bSGao Xiang if (m->delta[0] & Z_EROFS_VLE_DI_D0_CBLKCNT) { 19072bb5262SGao Xiang if (!(vi->z_advise & (Z_EROFS_ADVISE_BIG_PCLUSTER_1 | 19172bb5262SGao Xiang Z_EROFS_ADVISE_BIG_PCLUSTER_2))) { 192cec6e93bSGao Xiang DBG_BUGON(1); 193cec6e93bSGao Xiang return -EFSCORRUPTED; 194cec6e93bSGao Xiang } 195cec6e93bSGao Xiang m->compressedlcs = m->delta[0] & 196cec6e93bSGao Xiang ~Z_EROFS_VLE_DI_D0_CBLKCNT; 197cec6e93bSGao Xiang m->delta[0] = 1; 198cec6e93bSGao Xiang } 19947e4937aSGao Xiang m->delta[1] = le16_to_cpu(di->di_u.delta[1]); 20047e4937aSGao Xiang break; 20147e4937aSGao Xiang case Z_EROFS_VLE_CLUSTER_TYPE_PLAIN: 20272bb5262SGao Xiang case Z_EROFS_VLE_CLUSTER_TYPE_HEAD1: 20372bb5262SGao Xiang case Z_EROFS_VLE_CLUSTER_TYPE_HEAD2: 20447e4937aSGao Xiang m->clusterofs = le16_to_cpu(di->di_clusterofs); 20547e4937aSGao Xiang m->pblk = le32_to_cpu(di->di_u.blkaddr); 20647e4937aSGao Xiang break; 20747e4937aSGao Xiang default: 20847e4937aSGao Xiang DBG_BUGON(1); 20947e4937aSGao Xiang return -EOPNOTSUPP; 21047e4937aSGao Xiang } 21147e4937aSGao Xiang m->type = type; 21247e4937aSGao Xiang return 0; 21347e4937aSGao Xiang } 21447e4937aSGao Xiang 21547e4937aSGao Xiang static unsigned int decode_compactedbits(unsigned int lobits, 21647e4937aSGao Xiang unsigned int lomask, 21747e4937aSGao Xiang u8 *in, unsigned int pos, u8 *type) 21847e4937aSGao Xiang { 21947e4937aSGao Xiang const unsigned int v = get_unaligned_le32(in + pos / 8) >> (pos & 7); 22047e4937aSGao Xiang const unsigned int lo = v & lomask; 22147e4937aSGao Xiang 22247e4937aSGao Xiang *type = (v >> lobits) & 3; 22347e4937aSGao Xiang return lo; 22447e4937aSGao Xiang } 22547e4937aSGao Xiang 226d95ae5e2SGao Xiang static int get_compacted_la_distance(unsigned int lclusterbits, 227d95ae5e2SGao Xiang unsigned int encodebits, 228d95ae5e2SGao Xiang unsigned int vcnt, u8 *in, int i) 229d95ae5e2SGao Xiang { 230d95ae5e2SGao Xiang const unsigned int lomask = (1 << lclusterbits) - 1; 231d95ae5e2SGao Xiang unsigned int lo, d1 = 0; 232d95ae5e2SGao Xiang u8 type; 233d95ae5e2SGao Xiang 234d95ae5e2SGao Xiang DBG_BUGON(i >= vcnt); 235d95ae5e2SGao Xiang 236d95ae5e2SGao Xiang do { 237d95ae5e2SGao Xiang lo = decode_compactedbits(lclusterbits, lomask, 238d95ae5e2SGao Xiang in, encodebits * i, &type); 239d95ae5e2SGao Xiang 240d95ae5e2SGao Xiang if (type != Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD) 241d95ae5e2SGao Xiang return d1; 242d95ae5e2SGao Xiang ++d1; 243d95ae5e2SGao Xiang } while (++i < vcnt); 244d95ae5e2SGao Xiang 245d95ae5e2SGao Xiang /* vcnt - 1 (Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD) item */ 246d95ae5e2SGao Xiang if (!(lo & Z_EROFS_VLE_DI_D0_CBLKCNT)) 247d95ae5e2SGao Xiang d1 += lo - 1; 248d95ae5e2SGao Xiang return d1; 249d95ae5e2SGao Xiang } 250d95ae5e2SGao Xiang 25147e4937aSGao Xiang static int unpack_compacted_index(struct z_erofs_maprecorder *m, 25247e4937aSGao Xiang unsigned int amortizedshift, 253ab92184fSYue Hu erofs_off_t pos, bool lookahead) 25447e4937aSGao Xiang { 255a5876e24SGao Xiang struct erofs_inode *const vi = EROFS_I(m->inode); 25647e4937aSGao Xiang const unsigned int lclusterbits = vi->z_logical_clusterbits; 25747e4937aSGao Xiang const unsigned int lomask = (1 << lclusterbits) - 1; 258ab92184fSYue Hu unsigned int vcnt, base, lo, encodebits, nblk, eofs; 25947e4937aSGao Xiang int i; 26047e4937aSGao Xiang u8 *in, type; 261b86269f4SGao Xiang bool big_pcluster; 26247e4937aSGao Xiang 26347e4937aSGao Xiang if (1 << amortizedshift == 4) 26447e4937aSGao Xiang vcnt = 2; 26547e4937aSGao Xiang else if (1 << amortizedshift == 2 && lclusterbits == 12) 26647e4937aSGao Xiang vcnt = 16; 26747e4937aSGao Xiang else 26847e4937aSGao Xiang return -EOPNOTSUPP; 26947e4937aSGao Xiang 270ab92184fSYue Hu /* it doesn't equal to round_up(..) */ 271ab92184fSYue Hu m->nextpackoff = round_down(pos, vcnt << amortizedshift) + 272ab92184fSYue Hu (vcnt << amortizedshift); 273b86269f4SGao Xiang big_pcluster = vi->z_advise & Z_EROFS_ADVISE_BIG_PCLUSTER_1; 27447e4937aSGao Xiang encodebits = ((vcnt << amortizedshift) - sizeof(__le32)) * 8 / vcnt; 275ab92184fSYue Hu eofs = erofs_blkoff(pos); 27647e4937aSGao Xiang base = round_down(eofs, vcnt << amortizedshift); 27747e4937aSGao Xiang in = m->kaddr + base; 27847e4937aSGao Xiang 27947e4937aSGao Xiang i = (eofs - base) >> amortizedshift; 28047e4937aSGao Xiang 28147e4937aSGao Xiang lo = decode_compactedbits(lclusterbits, lomask, 28247e4937aSGao Xiang in, encodebits * i, &type); 28347e4937aSGao Xiang m->type = type; 28447e4937aSGao Xiang if (type == Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD) { 28547e4937aSGao Xiang m->clusterofs = 1 << lclusterbits; 286d95ae5e2SGao Xiang 287d95ae5e2SGao Xiang /* figure out lookahead_distance: delta[1] if needed */ 288d95ae5e2SGao Xiang if (lookahead) 289d95ae5e2SGao Xiang m->delta[1] = get_compacted_la_distance(lclusterbits, 290d95ae5e2SGao Xiang encodebits, vcnt, in, i); 291b86269f4SGao Xiang if (lo & Z_EROFS_VLE_DI_D0_CBLKCNT) { 292b86269f4SGao Xiang if (!big_pcluster) { 293b86269f4SGao Xiang DBG_BUGON(1); 294b86269f4SGao Xiang return -EFSCORRUPTED; 295b86269f4SGao Xiang } 296b86269f4SGao Xiang m->compressedlcs = lo & ~Z_EROFS_VLE_DI_D0_CBLKCNT; 297b86269f4SGao Xiang m->delta[0] = 1; 298b86269f4SGao Xiang return 0; 299b86269f4SGao Xiang } else if (i + 1 != (int)vcnt) { 30047e4937aSGao Xiang m->delta[0] = lo; 30147e4937aSGao Xiang return 0; 30247e4937aSGao Xiang } 30347e4937aSGao Xiang /* 30447e4937aSGao Xiang * since the last lcluster in the pack is special, 30547e4937aSGao Xiang * of which lo saves delta[1] rather than delta[0]. 30647e4937aSGao Xiang * Hence, get delta[0] by the previous lcluster indirectly. 30747e4937aSGao Xiang */ 30847e4937aSGao Xiang lo = decode_compactedbits(lclusterbits, lomask, 30947e4937aSGao Xiang in, encodebits * (i - 1), &type); 31047e4937aSGao Xiang if (type != Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD) 31147e4937aSGao Xiang lo = 0; 312b86269f4SGao Xiang else if (lo & Z_EROFS_VLE_DI_D0_CBLKCNT) 313b86269f4SGao Xiang lo = 1; 31447e4937aSGao Xiang m->delta[0] = lo + 1; 31547e4937aSGao Xiang return 0; 31647e4937aSGao Xiang } 31747e4937aSGao Xiang m->clusterofs = lo; 31847e4937aSGao Xiang m->delta[0] = 0; 31947e4937aSGao Xiang /* figout out blkaddr (pblk) for HEAD lclusters */ 320b86269f4SGao Xiang if (!big_pcluster) { 32147e4937aSGao Xiang nblk = 1; 32247e4937aSGao Xiang while (i > 0) { 32347e4937aSGao Xiang --i; 32447e4937aSGao Xiang lo = decode_compactedbits(lclusterbits, lomask, 32547e4937aSGao Xiang in, encodebits * i, &type); 32647e4937aSGao Xiang if (type == Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD) 32747e4937aSGao Xiang i -= lo; 32847e4937aSGao Xiang 32947e4937aSGao Xiang if (i >= 0) 33047e4937aSGao Xiang ++nblk; 33147e4937aSGao Xiang } 332b86269f4SGao Xiang } else { 333b86269f4SGao Xiang nblk = 0; 334b86269f4SGao Xiang while (i > 0) { 335b86269f4SGao Xiang --i; 336b86269f4SGao Xiang lo = decode_compactedbits(lclusterbits, lomask, 337b86269f4SGao Xiang in, encodebits * i, &type); 338b86269f4SGao Xiang if (type == Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD) { 339b86269f4SGao Xiang if (lo & Z_EROFS_VLE_DI_D0_CBLKCNT) { 340b86269f4SGao Xiang --i; 341b86269f4SGao Xiang nblk += lo & ~Z_EROFS_VLE_DI_D0_CBLKCNT; 342b86269f4SGao Xiang continue; 343b86269f4SGao Xiang } 344b86269f4SGao Xiang /* bigpcluster shouldn't have plain d0 == 1 */ 345b86269f4SGao Xiang if (lo <= 1) { 346b86269f4SGao Xiang DBG_BUGON(1); 347b86269f4SGao Xiang return -EFSCORRUPTED; 348b86269f4SGao Xiang } 349b86269f4SGao Xiang i -= lo - 2; 350b86269f4SGao Xiang continue; 351b86269f4SGao Xiang } 352b86269f4SGao Xiang ++nblk; 353b86269f4SGao Xiang } 354b86269f4SGao Xiang } 35547e4937aSGao Xiang in += (vcnt << amortizedshift) - sizeof(__le32); 35647e4937aSGao Xiang m->pblk = le32_to_cpu(*(__le32 *)in) + nblk; 35747e4937aSGao Xiang return 0; 35847e4937aSGao Xiang } 35947e4937aSGao Xiang 36047e4937aSGao Xiang static int compacted_load_cluster_from_disk(struct z_erofs_maprecorder *m, 361d95ae5e2SGao Xiang unsigned long lcn, bool lookahead) 36247e4937aSGao Xiang { 36347e4937aSGao Xiang struct inode *const inode = m->inode; 364a5876e24SGao Xiang struct erofs_inode *const vi = EROFS_I(inode); 36547e4937aSGao Xiang const unsigned int lclusterbits = vi->z_logical_clusterbits; 36647e4937aSGao Xiang const erofs_off_t ebase = ALIGN(iloc(EROFS_I_SB(inode), vi->nid) + 36747e4937aSGao Xiang vi->inode_isize + vi->xattr_isize, 8) + 36847e4937aSGao Xiang sizeof(struct z_erofs_map_header); 36947e4937aSGao Xiang const unsigned int totalidx = DIV_ROUND_UP(inode->i_size, EROFS_BLKSIZ); 37047e4937aSGao Xiang unsigned int compacted_4b_initial, compacted_2b; 37147e4937aSGao Xiang unsigned int amortizedshift; 37247e4937aSGao Xiang erofs_off_t pos; 37347e4937aSGao Xiang int err; 37447e4937aSGao Xiang 37547e4937aSGao Xiang if (lclusterbits != 12) 37647e4937aSGao Xiang return -EOPNOTSUPP; 37747e4937aSGao Xiang 37847e4937aSGao Xiang if (lcn >= totalidx) 37947e4937aSGao Xiang return -EINVAL; 38047e4937aSGao Xiang 38147e4937aSGao Xiang m->lcn = lcn; 38247e4937aSGao Xiang /* used to align to 32-byte (compacted_2b) alignment */ 38347e4937aSGao Xiang compacted_4b_initial = (32 - ebase % 32) / 4; 38447e4937aSGao Xiang if (compacted_4b_initial == 32 / 4) 38547e4937aSGao Xiang compacted_4b_initial = 0; 38647e4937aSGao Xiang 387c40dd3caSYue Hu if ((vi->z_advise & Z_EROFS_ADVISE_COMPACTED_2B) && 388c40dd3caSYue Hu compacted_4b_initial < totalidx) 38947e4937aSGao Xiang compacted_2b = rounddown(totalidx - compacted_4b_initial, 16); 39047e4937aSGao Xiang else 39147e4937aSGao Xiang compacted_2b = 0; 39247e4937aSGao Xiang 39347e4937aSGao Xiang pos = ebase; 39447e4937aSGao Xiang if (lcn < compacted_4b_initial) { 39547e4937aSGao Xiang amortizedshift = 2; 39647e4937aSGao Xiang goto out; 39747e4937aSGao Xiang } 39847e4937aSGao Xiang pos += compacted_4b_initial * 4; 39947e4937aSGao Xiang lcn -= compacted_4b_initial; 40047e4937aSGao Xiang 40147e4937aSGao Xiang if (lcn < compacted_2b) { 40247e4937aSGao Xiang amortizedshift = 1; 40347e4937aSGao Xiang goto out; 40447e4937aSGao Xiang } 40547e4937aSGao Xiang pos += compacted_2b * 2; 40647e4937aSGao Xiang lcn -= compacted_2b; 40747e4937aSGao Xiang amortizedshift = 2; 40847e4937aSGao Xiang out: 40947e4937aSGao Xiang pos += lcn * (1 << amortizedshift); 41047e4937aSGao Xiang err = z_erofs_reload_indexes(m, erofs_blknr(pos)); 41147e4937aSGao Xiang if (err) 41247e4937aSGao Xiang return err; 413ab92184fSYue Hu return unpack_compacted_index(m, amortizedshift, pos, lookahead); 41447e4937aSGao Xiang } 41547e4937aSGao Xiang 4160c638f70SGao Xiang static int z_erofs_load_cluster_from_disk(struct z_erofs_maprecorder *m, 417d95ae5e2SGao Xiang unsigned int lcn, bool lookahead) 41847e4937aSGao Xiang { 419a5876e24SGao Xiang const unsigned int datamode = EROFS_I(m->inode)->datalayout; 42047e4937aSGao Xiang 42147e4937aSGao Xiang if (datamode == EROFS_INODE_FLAT_COMPRESSION_LEGACY) 4220c638f70SGao Xiang return legacy_load_cluster_from_disk(m, lcn); 42347e4937aSGao Xiang 42447e4937aSGao Xiang if (datamode == EROFS_INODE_FLAT_COMPRESSION) 425d95ae5e2SGao Xiang return compacted_load_cluster_from_disk(m, lcn, lookahead); 42647e4937aSGao Xiang 42747e4937aSGao Xiang return -EINVAL; 42847e4937aSGao Xiang } 42947e4937aSGao Xiang 4300c638f70SGao Xiang static int z_erofs_extent_lookback(struct z_erofs_maprecorder *m, 43147e4937aSGao Xiang unsigned int lookback_distance) 43247e4937aSGao Xiang { 433a5876e24SGao Xiang struct erofs_inode *const vi = EROFS_I(m->inode); 43447e4937aSGao Xiang const unsigned int lclusterbits = vi->z_logical_clusterbits; 435*ab474fccSGao Xiang 436*ab474fccSGao Xiang while (m->lcn >= lookback_distance) { 437*ab474fccSGao Xiang unsigned long lcn = m->lcn - lookback_distance; 43847e4937aSGao Xiang int err; 43947e4937aSGao Xiang 44047e4937aSGao Xiang /* load extent head logical cluster if needed */ 441d95ae5e2SGao Xiang err = z_erofs_load_cluster_from_disk(m, lcn, false); 44247e4937aSGao Xiang if (err) 44347e4937aSGao Xiang return err; 44447e4937aSGao Xiang 44547e4937aSGao Xiang switch (m->type) { 44647e4937aSGao Xiang case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD: 4478d8a09b0SGao Xiang if (!m->delta[0]) { 4484f761fa2SGao Xiang erofs_err(m->inode->i_sb, 4494f761fa2SGao Xiang "invalid lookback distance 0 @ nid %llu", 45047e4937aSGao Xiang vi->nid); 45147e4937aSGao Xiang DBG_BUGON(1); 45247e4937aSGao Xiang return -EFSCORRUPTED; 45347e4937aSGao Xiang } 454*ab474fccSGao Xiang lookback_distance = m->delta[0]; 455*ab474fccSGao Xiang continue; 45647e4937aSGao Xiang case Z_EROFS_VLE_CLUSTER_TYPE_PLAIN: 45772bb5262SGao Xiang case Z_EROFS_VLE_CLUSTER_TYPE_HEAD1: 45872bb5262SGao Xiang case Z_EROFS_VLE_CLUSTER_TYPE_HEAD2: 4598f899262SGao Xiang m->headtype = m->type; 460*ab474fccSGao Xiang m->map->m_la = (lcn << lclusterbits) | m->clusterofs; 461*ab474fccSGao Xiang return 0; 46247e4937aSGao Xiang default: 4634f761fa2SGao Xiang erofs_err(m->inode->i_sb, 4644f761fa2SGao Xiang "unknown type %u @ lcn %lu of nid %llu", 46547e4937aSGao Xiang m->type, lcn, vi->nid); 46647e4937aSGao Xiang DBG_BUGON(1); 46747e4937aSGao Xiang return -EOPNOTSUPP; 46847e4937aSGao Xiang } 469*ab474fccSGao Xiang } 470*ab474fccSGao Xiang 471*ab474fccSGao Xiang erofs_err(m->inode->i_sb, "bogus lookback distance @ nid %llu", 472*ab474fccSGao Xiang vi->nid); 473*ab474fccSGao Xiang DBG_BUGON(1); 474*ab474fccSGao Xiang return -EFSCORRUPTED; 47547e4937aSGao Xiang } 47647e4937aSGao Xiang 477cec6e93bSGao Xiang static int z_erofs_get_extent_compressedlen(struct z_erofs_maprecorder *m, 478cec6e93bSGao Xiang unsigned int initial_lcn) 479cec6e93bSGao Xiang { 480cec6e93bSGao Xiang struct erofs_inode *const vi = EROFS_I(m->inode); 481cec6e93bSGao Xiang struct erofs_map_blocks *const map = m->map; 482cec6e93bSGao Xiang const unsigned int lclusterbits = vi->z_logical_clusterbits; 483cec6e93bSGao Xiang unsigned long lcn; 484cec6e93bSGao Xiang int err; 485cec6e93bSGao Xiang 486cec6e93bSGao Xiang DBG_BUGON(m->type != Z_EROFS_VLE_CLUSTER_TYPE_PLAIN && 48772bb5262SGao Xiang m->type != Z_EROFS_VLE_CLUSTER_TYPE_HEAD1 && 48872bb5262SGao Xiang m->type != Z_EROFS_VLE_CLUSTER_TYPE_HEAD2); 48972bb5262SGao Xiang DBG_BUGON(m->type != m->headtype); 49072bb5262SGao Xiang 4918f899262SGao Xiang if (m->headtype == Z_EROFS_VLE_CLUSTER_TYPE_PLAIN || 49272bb5262SGao Xiang ((m->headtype == Z_EROFS_VLE_CLUSTER_TYPE_HEAD1) && 49372bb5262SGao Xiang !(vi->z_advise & Z_EROFS_ADVISE_BIG_PCLUSTER_1)) || 49472bb5262SGao Xiang ((m->headtype == Z_EROFS_VLE_CLUSTER_TYPE_HEAD2) && 49572bb5262SGao Xiang !(vi->z_advise & Z_EROFS_ADVISE_BIG_PCLUSTER_2))) { 496d467e980SGao Xiang map->m_plen = 1ULL << lclusterbits; 497cec6e93bSGao Xiang return 0; 498cec6e93bSGao Xiang } 499cec6e93bSGao Xiang lcn = m->lcn + 1; 500cec6e93bSGao Xiang if (m->compressedlcs) 501cec6e93bSGao Xiang goto out; 502cec6e93bSGao Xiang 503d95ae5e2SGao Xiang err = z_erofs_load_cluster_from_disk(m, lcn, false); 504cec6e93bSGao Xiang if (err) 505cec6e93bSGao Xiang return err; 506cec6e93bSGao Xiang 5070852b6caSGao Xiang /* 5080852b6caSGao Xiang * If the 1st NONHEAD lcluster has already been handled initially w/o 5090852b6caSGao Xiang * valid compressedlcs, which means at least it mustn't be CBLKCNT, or 5100852b6caSGao Xiang * an internal implemenatation error is detected. 5110852b6caSGao Xiang * 5120852b6caSGao Xiang * The following code can also handle it properly anyway, but let's 5130852b6caSGao Xiang * BUG_ON in the debugging mode only for developers to notice that. 5140852b6caSGao Xiang */ 5150852b6caSGao Xiang DBG_BUGON(lcn == initial_lcn && 5160852b6caSGao Xiang m->type == Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD); 5170852b6caSGao Xiang 518cec6e93bSGao Xiang switch (m->type) { 5190852b6caSGao Xiang case Z_EROFS_VLE_CLUSTER_TYPE_PLAIN: 52072bb5262SGao Xiang case Z_EROFS_VLE_CLUSTER_TYPE_HEAD1: 52172bb5262SGao Xiang case Z_EROFS_VLE_CLUSTER_TYPE_HEAD2: 5220852b6caSGao Xiang /* 5230852b6caSGao Xiang * if the 1st NONHEAD lcluster is actually PLAIN or HEAD type 5240852b6caSGao Xiang * rather than CBLKCNT, it's a 1 lcluster-sized pcluster. 5250852b6caSGao Xiang */ 5260852b6caSGao Xiang m->compressedlcs = 1; 5270852b6caSGao Xiang break; 528cec6e93bSGao Xiang case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD: 529cec6e93bSGao Xiang if (m->delta[0] != 1) 530cec6e93bSGao Xiang goto err_bonus_cblkcnt; 531cec6e93bSGao Xiang if (m->compressedlcs) 532cec6e93bSGao Xiang break; 533cec6e93bSGao Xiang fallthrough; 534cec6e93bSGao Xiang default: 535cec6e93bSGao Xiang erofs_err(m->inode->i_sb, 536cec6e93bSGao Xiang "cannot found CBLKCNT @ lcn %lu of nid %llu", 537cec6e93bSGao Xiang lcn, vi->nid); 538cec6e93bSGao Xiang DBG_BUGON(1); 539cec6e93bSGao Xiang return -EFSCORRUPTED; 540cec6e93bSGao Xiang } 541cec6e93bSGao Xiang out: 542d467e980SGao Xiang map->m_plen = (u64)m->compressedlcs << lclusterbits; 543cec6e93bSGao Xiang return 0; 544cec6e93bSGao Xiang err_bonus_cblkcnt: 545cec6e93bSGao Xiang erofs_err(m->inode->i_sb, 546cec6e93bSGao Xiang "bogus CBLKCNT @ lcn %lu of nid %llu", 547cec6e93bSGao Xiang lcn, vi->nid); 548cec6e93bSGao Xiang DBG_BUGON(1); 549cec6e93bSGao Xiang return -EFSCORRUPTED; 550cec6e93bSGao Xiang } 551cec6e93bSGao Xiang 552d95ae5e2SGao Xiang static int z_erofs_get_extent_decompressedlen(struct z_erofs_maprecorder *m) 553d95ae5e2SGao Xiang { 554d95ae5e2SGao Xiang struct inode *inode = m->inode; 555d95ae5e2SGao Xiang struct erofs_inode *vi = EROFS_I(inode); 556d95ae5e2SGao Xiang struct erofs_map_blocks *map = m->map; 557d95ae5e2SGao Xiang unsigned int lclusterbits = vi->z_logical_clusterbits; 558d95ae5e2SGao Xiang u64 lcn = m->lcn, headlcn = map->m_la >> lclusterbits; 559d95ae5e2SGao Xiang int err; 560d95ae5e2SGao Xiang 561d95ae5e2SGao Xiang do { 562d95ae5e2SGao Xiang /* handle the last EOF pcluster (no next HEAD lcluster) */ 563d95ae5e2SGao Xiang if ((lcn << lclusterbits) >= inode->i_size) { 564d95ae5e2SGao Xiang map->m_llen = inode->i_size - map->m_la; 565d95ae5e2SGao Xiang return 0; 566d95ae5e2SGao Xiang } 567d95ae5e2SGao Xiang 568d95ae5e2SGao Xiang err = z_erofs_load_cluster_from_disk(m, lcn, true); 569d95ae5e2SGao Xiang if (err) 570d95ae5e2SGao Xiang return err; 571d95ae5e2SGao Xiang 572d95ae5e2SGao Xiang if (m->type == Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD) { 573d95ae5e2SGao Xiang DBG_BUGON(!m->delta[1] && 574d95ae5e2SGao Xiang m->clusterofs != 1 << lclusterbits); 575d95ae5e2SGao Xiang } else if (m->type == Z_EROFS_VLE_CLUSTER_TYPE_PLAIN || 57672bb5262SGao Xiang m->type == Z_EROFS_VLE_CLUSTER_TYPE_HEAD1 || 57772bb5262SGao Xiang m->type == Z_EROFS_VLE_CLUSTER_TYPE_HEAD2) { 578d95ae5e2SGao Xiang /* go on until the next HEAD lcluster */ 579d95ae5e2SGao Xiang if (lcn != headlcn) 580d95ae5e2SGao Xiang break; 581d95ae5e2SGao Xiang m->delta[1] = 1; 582d95ae5e2SGao Xiang } else { 583d95ae5e2SGao Xiang erofs_err(inode->i_sb, "unknown type %u @ lcn %llu of nid %llu", 584d95ae5e2SGao Xiang m->type, lcn, vi->nid); 585d95ae5e2SGao Xiang DBG_BUGON(1); 586d95ae5e2SGao Xiang return -EOPNOTSUPP; 587d95ae5e2SGao Xiang } 588d95ae5e2SGao Xiang lcn += m->delta[1]; 589d95ae5e2SGao Xiang } while (m->delta[1]); 590d95ae5e2SGao Xiang 591d95ae5e2SGao Xiang map->m_llen = (lcn << lclusterbits) + m->clusterofs - map->m_la; 592d95ae5e2SGao Xiang return 0; 593d95ae5e2SGao Xiang } 594d95ae5e2SGao Xiang 595ab92184fSYue Hu static int z_erofs_do_map_blocks(struct inode *inode, 59647e4937aSGao Xiang struct erofs_map_blocks *map, 59747e4937aSGao Xiang int flags) 59847e4937aSGao Xiang { 599a5876e24SGao Xiang struct erofs_inode *const vi = EROFS_I(inode); 600ab92184fSYue Hu bool ztailpacking = vi->z_advise & Z_EROFS_ADVISE_INLINE_PCLUSTER; 60147e4937aSGao Xiang struct z_erofs_maprecorder m = { 60247e4937aSGao Xiang .inode = inode, 60347e4937aSGao Xiang .map = map, 60447e4937aSGao Xiang }; 60547e4937aSGao Xiang int err = 0; 60647e4937aSGao Xiang unsigned int lclusterbits, endoff; 607cec6e93bSGao Xiang unsigned long initial_lcn; 60847e4937aSGao Xiang unsigned long long ofs, end; 60947e4937aSGao Xiang 61047e4937aSGao Xiang lclusterbits = vi->z_logical_clusterbits; 611ab92184fSYue Hu ofs = flags & EROFS_GET_BLOCKS_FINDTAIL ? inode->i_size - 1 : map->m_la; 612cec6e93bSGao Xiang initial_lcn = ofs >> lclusterbits; 61347e4937aSGao Xiang endoff = ofs & ((1 << lclusterbits) - 1); 61447e4937aSGao Xiang 615d95ae5e2SGao Xiang err = z_erofs_load_cluster_from_disk(&m, initial_lcn, false); 61647e4937aSGao Xiang if (err) 61747e4937aSGao Xiang goto unmap_out; 61847e4937aSGao Xiang 619ab92184fSYue Hu if (ztailpacking && (flags & EROFS_GET_BLOCKS_FINDTAIL)) 620ab92184fSYue Hu vi->z_idataoff = m.nextpackoff; 621ab92184fSYue Hu 6228f899262SGao Xiang map->m_flags = EROFS_MAP_MAPPED | EROFS_MAP_ENCODED; 62347e4937aSGao Xiang end = (m.lcn + 1ULL) << lclusterbits; 62447e4937aSGao Xiang 62547e4937aSGao Xiang switch (m.type) { 62647e4937aSGao Xiang case Z_EROFS_VLE_CLUSTER_TYPE_PLAIN: 62772bb5262SGao Xiang case Z_EROFS_VLE_CLUSTER_TYPE_HEAD1: 62872bb5262SGao Xiang case Z_EROFS_VLE_CLUSTER_TYPE_HEAD2: 62947e4937aSGao Xiang if (endoff >= m.clusterofs) { 6308f899262SGao Xiang m.headtype = m.type; 63147e4937aSGao Xiang map->m_la = (m.lcn << lclusterbits) | m.clusterofs; 63224331050SGao Xiang /* 63324331050SGao Xiang * For ztailpacking files, in order to inline data more 63424331050SGao Xiang * effectively, special EOF lclusters are now supported 63524331050SGao Xiang * which can have three parts at most. 63624331050SGao Xiang */ 63724331050SGao Xiang if (ztailpacking && end > inode->i_size) 63824331050SGao Xiang end = inode->i_size; 63947e4937aSGao Xiang break; 64047e4937aSGao Xiang } 64147e4937aSGao Xiang /* m.lcn should be >= 1 if endoff < m.clusterofs */ 6428d8a09b0SGao Xiang if (!m.lcn) { 6434f761fa2SGao Xiang erofs_err(inode->i_sb, 6444f761fa2SGao Xiang "invalid logical cluster 0 at nid %llu", 64547e4937aSGao Xiang vi->nid); 64647e4937aSGao Xiang err = -EFSCORRUPTED; 64747e4937aSGao Xiang goto unmap_out; 64847e4937aSGao Xiang } 64947e4937aSGao Xiang end = (m.lcn << lclusterbits) | m.clusterofs; 65047e4937aSGao Xiang map->m_flags |= EROFS_MAP_FULL_MAPPED; 65147e4937aSGao Xiang m.delta[0] = 1; 652df561f66SGustavo A. R. Silva fallthrough; 65347e4937aSGao Xiang case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD: 654fe6adcceSRuiqi Gong /* get the corresponding first chunk */ 6550c638f70SGao Xiang err = z_erofs_extent_lookback(&m, m.delta[0]); 6568d8a09b0SGao Xiang if (err) 65747e4937aSGao Xiang goto unmap_out; 65847e4937aSGao Xiang break; 65947e4937aSGao Xiang default: 6604f761fa2SGao Xiang erofs_err(inode->i_sb, 6614f761fa2SGao Xiang "unknown type %u @ offset %llu of nid %llu", 66247e4937aSGao Xiang m.type, ofs, vi->nid); 66347e4937aSGao Xiang err = -EOPNOTSUPP; 66447e4937aSGao Xiang goto unmap_out; 66547e4937aSGao Xiang } 66647e4937aSGao Xiang 66747e4937aSGao Xiang map->m_llen = end - map->m_la; 66847e4937aSGao Xiang 669ab92184fSYue Hu if (flags & EROFS_GET_BLOCKS_FINDTAIL) 670ab92184fSYue Hu vi->z_tailextent_headlcn = m.lcn; 671ab92184fSYue Hu if (ztailpacking && m.lcn == vi->z_tailextent_headlcn) { 672ab92184fSYue Hu map->m_flags |= EROFS_MAP_META; 673ab92184fSYue Hu map->m_pa = vi->z_idataoff; 674ab92184fSYue Hu map->m_plen = vi->z_idata_size; 675ab92184fSYue Hu } else { 676ab92184fSYue Hu map->m_pa = blknr_to_addr(m.pblk); 677cec6e93bSGao Xiang err = z_erofs_get_extent_compressedlen(&m, initial_lcn); 678cec6e93bSGao Xiang if (err) 679cec6e93bSGao Xiang goto out; 680ab92184fSYue Hu } 681d95ae5e2SGao Xiang 6828f899262SGao Xiang if (m.headtype == Z_EROFS_VLE_CLUSTER_TYPE_PLAIN) 6838f899262SGao Xiang map->m_algorithmformat = Z_EROFS_COMPRESSION_SHIFTED; 68472bb5262SGao Xiang else if (m.headtype == Z_EROFS_VLE_CLUSTER_TYPE_HEAD2) 68572bb5262SGao Xiang map->m_algorithmformat = vi->z_algorithmtype[1]; 6868f899262SGao Xiang else 6878f899262SGao Xiang map->m_algorithmformat = vi->z_algorithmtype[0]; 6888f899262SGao Xiang 689622ceaddSGao Xiang if ((flags & EROFS_GET_BLOCKS_FIEMAP) || 690622ceaddSGao Xiang ((flags & EROFS_GET_BLOCKS_READMORE) && 691622ceaddSGao Xiang map->m_algorithmformat == Z_EROFS_COMPRESSION_LZMA && 692622ceaddSGao Xiang map->m_llen >= EROFS_BLKSIZ)) { 693d95ae5e2SGao Xiang err = z_erofs_get_extent_decompressedlen(&m); 694d95ae5e2SGao Xiang if (!err) 695d95ae5e2SGao Xiang map->m_flags |= EROFS_MAP_FULL_MAPPED; 696d95ae5e2SGao Xiang } 69747e4937aSGao Xiang unmap_out: 69809c54379SGao Xiang erofs_unmap_metabuf(&m.map->buf); 69947e4937aSGao Xiang 70047e4937aSGao Xiang out: 7014f761fa2SGao Xiang erofs_dbg("%s, m_la %llu m_pa %llu m_llen %llu m_plen %llu m_flags 0%o", 70247e4937aSGao Xiang __func__, map->m_la, map->m_pa, 70347e4937aSGao Xiang map->m_llen, map->m_plen, map->m_flags); 70447e4937aSGao Xiang 705ab92184fSYue Hu return err; 706ab92184fSYue Hu } 707ab92184fSYue Hu 708ab92184fSYue Hu int z_erofs_map_blocks_iter(struct inode *inode, 709ab92184fSYue Hu struct erofs_map_blocks *map, 710ab92184fSYue Hu int flags) 711ab92184fSYue Hu { 712ab92184fSYue Hu int err = 0; 713ab92184fSYue Hu 714ab92184fSYue Hu trace_z_erofs_map_blocks_iter_enter(inode, map, flags); 715ab92184fSYue Hu 716ab92184fSYue Hu /* when trying to read beyond EOF, leave it unmapped */ 717ab92184fSYue Hu if (map->m_la >= inode->i_size) { 718ab92184fSYue Hu map->m_llen = map->m_la + 1 - inode->i_size; 719ab92184fSYue Hu map->m_la = inode->i_size; 720ab92184fSYue Hu map->m_flags = 0; 721ab92184fSYue Hu goto out; 722ab92184fSYue Hu } 723ab92184fSYue Hu 724ab92184fSYue Hu err = z_erofs_fill_inode_lazy(inode); 725ab92184fSYue Hu if (err) 726ab92184fSYue Hu goto out; 727ab92184fSYue Hu 728ab92184fSYue Hu err = z_erofs_do_map_blocks(inode, map, flags); 729ab92184fSYue Hu out: 73047e4937aSGao Xiang trace_z_erofs_map_blocks_iter_exit(inode, map, flags, err); 73147e4937aSGao Xiang 73247e4937aSGao Xiang /* aggressively BUG_ON iff CONFIG_EROFS_FS_DEBUG is on */ 73347e4937aSGao Xiang DBG_BUGON(err < 0 && err != -ENOMEM); 73447e4937aSGao Xiang return err; 73547e4937aSGao Xiang } 736eadcd6b5SGao Xiang 737eadcd6b5SGao Xiang static int z_erofs_iomap_begin_report(struct inode *inode, loff_t offset, 738eadcd6b5SGao Xiang loff_t length, unsigned int flags, 739eadcd6b5SGao Xiang struct iomap *iomap, struct iomap *srcmap) 740eadcd6b5SGao Xiang { 741eadcd6b5SGao Xiang int ret; 742eadcd6b5SGao Xiang struct erofs_map_blocks map = { .m_la = offset }; 743eadcd6b5SGao Xiang 744eadcd6b5SGao Xiang ret = z_erofs_map_blocks_iter(inode, &map, EROFS_GET_BLOCKS_FIEMAP); 74509c54379SGao Xiang erofs_put_metabuf(&map.buf); 746eadcd6b5SGao Xiang if (ret < 0) 747eadcd6b5SGao Xiang return ret; 748eadcd6b5SGao Xiang 749eadcd6b5SGao Xiang iomap->bdev = inode->i_sb->s_bdev; 750eadcd6b5SGao Xiang iomap->offset = map.m_la; 751eadcd6b5SGao Xiang iomap->length = map.m_llen; 752eadcd6b5SGao Xiang if (map.m_flags & EROFS_MAP_MAPPED) { 753eadcd6b5SGao Xiang iomap->type = IOMAP_MAPPED; 754eadcd6b5SGao Xiang iomap->addr = map.m_pa; 755eadcd6b5SGao Xiang } else { 756eadcd6b5SGao Xiang iomap->type = IOMAP_HOLE; 757eadcd6b5SGao Xiang iomap->addr = IOMAP_NULL_ADDR; 758eadcd6b5SGao Xiang /* 759eadcd6b5SGao Xiang * No strict rule how to describe extents for post EOF, yet 760eadcd6b5SGao Xiang * we need do like below. Otherwise, iomap itself will get 761eadcd6b5SGao Xiang * into an endless loop on post EOF. 762eadcd6b5SGao Xiang */ 763eadcd6b5SGao Xiang if (iomap->offset >= inode->i_size) 764eadcd6b5SGao Xiang iomap->length = length + map.m_la - offset; 765eadcd6b5SGao Xiang } 766eadcd6b5SGao Xiang iomap->flags = 0; 767eadcd6b5SGao Xiang return 0; 768eadcd6b5SGao Xiang } 769eadcd6b5SGao Xiang 770eadcd6b5SGao Xiang const struct iomap_ops z_erofs_iomap_report_ops = { 771eadcd6b5SGao Xiang .iomap_begin = z_erofs_iomap_begin_report, 772eadcd6b5SGao Xiang }; 773