xref: /openbmc/linux/fs/erofs/zmap.c (revision 6acd87d5)
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) {
701c505febaSGao Xiang 		if (map->m_llen > map->m_plen) {
702c505febaSGao Xiang 			DBG_BUGON(1);
703c505febaSGao Xiang 			err = -EFSCORRUPTED;
704c505febaSGao Xiang 			goto unmap_out;
705c505febaSGao 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 		/*
796*6acd87d5SSiddh Raman Pant 		 * No strict rule on how to describe extents for post EOF, yet
797*6acd87d5SSiddh Raman Pant 		 * we need to do like below. Otherwise, iomap itself will get
798eadcd6b5SGao Xiang 		 * into an endless loop on post EOF.
799*6acd87d5SSiddh Raman Pant 		 *
800*6acd87d5SSiddh Raman Pant 		 * Calculate the effective offset by subtracting extent start
801*6acd87d5SSiddh Raman Pant 		 * (map.m_la) from the requested offset, and add it to length.
802*6acd87d5SSiddh Raman Pant 		 * (NB: offset >= map.m_la always)
803eadcd6b5SGao Xiang 		 */
804eadcd6b5SGao Xiang 		if (iomap->offset >= inode->i_size)
805*6acd87d5SSiddh Raman Pant 			iomap->length = length + offset - map.m_la;
806eadcd6b5SGao Xiang 	}
807eadcd6b5SGao Xiang 	iomap->flags = 0;
808eadcd6b5SGao Xiang 	return 0;
809eadcd6b5SGao Xiang }
810eadcd6b5SGao Xiang 
811eadcd6b5SGao Xiang const struct iomap_ops z_erofs_iomap_report_ops = {
812eadcd6b5SGao Xiang 	.iomap_begin = z_erofs_iomap_begin_report,
813eadcd6b5SGao Xiang };
814