xref: /openbmc/linux/fs/erofs/zmap.c (revision ea0b7b0d)
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];
144*ea0b7b0dSYue Hu 	erofs_blk_t pblk, compressedblks;
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 			}
195*ea0b7b0dSYue Hu 			m->compressedblks = 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 			}
296*ea0b7b0dSYue Hu 			m->compressedblks = 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;
435ab474fccSGao Xiang 
436ab474fccSGao Xiang 	while (m->lcn >= lookback_distance) {
437ab474fccSGao 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 			}
454ab474fccSGao Xiang 			lookback_distance = m->delta[0];
455ab474fccSGao 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;
460ab474fccSGao Xiang 			m->map->m_la = (lcn << lclusterbits) | m->clusterofs;
461ab474fccSGao 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 		}
469ab474fccSGao Xiang 	}
470ab474fccSGao Xiang 
471ab474fccSGao Xiang 	erofs_err(m->inode->i_sb, "bogus lookback distance @ nid %llu",
472ab474fccSGao Xiang 		  vi->nid);
473ab474fccSGao Xiang 	DBG_BUGON(1);
474ab474fccSGao 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;
500*ea0b7b0dSYue Hu 	if (m->compressedblks)
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
509*ea0b7b0dSYue Hu 	 * valid compressedblks, 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 		 */
526*ea0b7b0dSYue Hu 		m->compressedblks = 1 << (lclusterbits - LOG_BLOCK_SIZE);
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;
531*ea0b7b0dSYue Hu 		if (m->compressedblks)
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:
542*ea0b7b0dSYue Hu 	map->m_plen = (u64)m->compressedblks << LOG_BLOCK_SIZE;
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