xref: /aosp_15_r20/external/erofs-utils/lib/zmap.c (revision 33b1fccf6a0fada2c2875d400ed01119b7676ee5)
1*33b1fccfSAndroid Build Coastguard Worker // SPDX-License-Identifier: GPL-2.0+ OR Apache-2.0
2*33b1fccfSAndroid Build Coastguard Worker /*
3*33b1fccfSAndroid Build Coastguard Worker  * (a large amount of code was adapted from Linux kernel. )
4*33b1fccfSAndroid Build Coastguard Worker  *
5*33b1fccfSAndroid Build Coastguard Worker  * Copyright (C) 2018-2019 HUAWEI, Inc.
6*33b1fccfSAndroid Build Coastguard Worker  *             https://www.huawei.com/
7*33b1fccfSAndroid Build Coastguard Worker  * Created by Gao Xiang <[email protected]>
8*33b1fccfSAndroid Build Coastguard Worker  * Modified by Huang Jianan <[email protected]>
9*33b1fccfSAndroid Build Coastguard Worker  */
10*33b1fccfSAndroid Build Coastguard Worker #include "erofs/internal.h"
11*33b1fccfSAndroid Build Coastguard Worker #include "erofs/print.h"
12*33b1fccfSAndroid Build Coastguard Worker 
13*33b1fccfSAndroid Build Coastguard Worker static int z_erofs_do_map_blocks(struct erofs_inode *vi,
14*33b1fccfSAndroid Build Coastguard Worker 				 struct erofs_map_blocks *map,
15*33b1fccfSAndroid Build Coastguard Worker 				 int flags);
16*33b1fccfSAndroid Build Coastguard Worker 
z_erofs_fill_inode(struct erofs_inode * vi)17*33b1fccfSAndroid Build Coastguard Worker int z_erofs_fill_inode(struct erofs_inode *vi)
18*33b1fccfSAndroid Build Coastguard Worker {
19*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_sb_info *sbi = vi->sbi;
20*33b1fccfSAndroid Build Coastguard Worker 
21*33b1fccfSAndroid Build Coastguard Worker 	if (!erofs_sb_has_big_pcluster(sbi) &&
22*33b1fccfSAndroid Build Coastguard Worker 	    !erofs_sb_has_ztailpacking(sbi) && !erofs_sb_has_fragments(sbi) &&
23*33b1fccfSAndroid Build Coastguard Worker 	    vi->datalayout == EROFS_INODE_COMPRESSED_FULL) {
24*33b1fccfSAndroid Build Coastguard Worker 		vi->z_advise = 0;
25*33b1fccfSAndroid Build Coastguard Worker 		vi->z_algorithmtype[0] = 0;
26*33b1fccfSAndroid Build Coastguard Worker 		vi->z_algorithmtype[1] = 0;
27*33b1fccfSAndroid Build Coastguard Worker 		vi->z_logical_clusterbits = sbi->blkszbits;
28*33b1fccfSAndroid Build Coastguard Worker 
29*33b1fccfSAndroid Build Coastguard Worker 		vi->flags |= EROFS_I_Z_INITED;
30*33b1fccfSAndroid Build Coastguard Worker 	}
31*33b1fccfSAndroid Build Coastguard Worker 	return 0;
32*33b1fccfSAndroid Build Coastguard Worker }
33*33b1fccfSAndroid Build Coastguard Worker 
z_erofs_fill_inode_lazy(struct erofs_inode * vi)34*33b1fccfSAndroid Build Coastguard Worker static int z_erofs_fill_inode_lazy(struct erofs_inode *vi)
35*33b1fccfSAndroid Build Coastguard Worker {
36*33b1fccfSAndroid Build Coastguard Worker 	int ret;
37*33b1fccfSAndroid Build Coastguard Worker 	erofs_off_t pos;
38*33b1fccfSAndroid Build Coastguard Worker 	struct z_erofs_map_header *h;
39*33b1fccfSAndroid Build Coastguard Worker 	char buf[sizeof(struct z_erofs_map_header)];
40*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_sb_info *sbi = vi->sbi;
41*33b1fccfSAndroid Build Coastguard Worker 
42*33b1fccfSAndroid Build Coastguard Worker 	if (vi->flags & EROFS_I_Z_INITED)
43*33b1fccfSAndroid Build Coastguard Worker 		return 0;
44*33b1fccfSAndroid Build Coastguard Worker 
45*33b1fccfSAndroid Build Coastguard Worker 	pos = round_up(erofs_iloc(vi) + vi->inode_isize + vi->xattr_isize, 8);
46*33b1fccfSAndroid Build Coastguard Worker 	ret = erofs_dev_read(sbi, 0, buf, pos, sizeof(buf));
47*33b1fccfSAndroid Build Coastguard Worker 	if (ret < 0)
48*33b1fccfSAndroid Build Coastguard Worker 		return -EIO;
49*33b1fccfSAndroid Build Coastguard Worker 
50*33b1fccfSAndroid Build Coastguard Worker 	h = (struct z_erofs_map_header *)buf;
51*33b1fccfSAndroid Build Coastguard Worker 	/*
52*33b1fccfSAndroid Build Coastguard Worker 	 * if the highest bit of the 8-byte map header is set, the whole file
53*33b1fccfSAndroid Build Coastguard Worker 	 * is stored in the packed inode. The rest bits keeps z_fragmentoff.
54*33b1fccfSAndroid Build Coastguard Worker 	 */
55*33b1fccfSAndroid Build Coastguard Worker 	if (h->h_clusterbits >> Z_EROFS_FRAGMENT_INODE_BIT) {
56*33b1fccfSAndroid Build Coastguard Worker 		vi->z_advise = Z_EROFS_ADVISE_FRAGMENT_PCLUSTER;
57*33b1fccfSAndroid Build Coastguard Worker 		vi->fragmentoff = le64_to_cpu(*(__le64 *)h) ^ (1ULL << 63);
58*33b1fccfSAndroid Build Coastguard Worker 		vi->z_tailextent_headlcn = 0;
59*33b1fccfSAndroid Build Coastguard Worker 		goto out;
60*33b1fccfSAndroid Build Coastguard Worker 	}
61*33b1fccfSAndroid Build Coastguard Worker 
62*33b1fccfSAndroid Build Coastguard Worker 	vi->z_advise = le16_to_cpu(h->h_advise);
63*33b1fccfSAndroid Build Coastguard Worker 	vi->z_algorithmtype[0] = h->h_algorithmtype & 15;
64*33b1fccfSAndroid Build Coastguard Worker 	vi->z_algorithmtype[1] = h->h_algorithmtype >> 4;
65*33b1fccfSAndroid Build Coastguard Worker 
66*33b1fccfSAndroid Build Coastguard Worker 	if (vi->z_algorithmtype[0] >= Z_EROFS_COMPRESSION_MAX) {
67*33b1fccfSAndroid Build Coastguard Worker 		erofs_err("unknown compression format %u for nid %llu",
68*33b1fccfSAndroid Build Coastguard Worker 			  vi->z_algorithmtype[0], (unsigned long long)vi->nid);
69*33b1fccfSAndroid Build Coastguard Worker 		return -EOPNOTSUPP;
70*33b1fccfSAndroid Build Coastguard Worker 	}
71*33b1fccfSAndroid Build Coastguard Worker 
72*33b1fccfSAndroid Build Coastguard Worker 	vi->z_logical_clusterbits = sbi->blkszbits + (h->h_clusterbits & 7);
73*33b1fccfSAndroid Build Coastguard Worker 	if (vi->datalayout == EROFS_INODE_COMPRESSED_COMPACT &&
74*33b1fccfSAndroid Build Coastguard Worker 	    !(vi->z_advise & Z_EROFS_ADVISE_BIG_PCLUSTER_1) ^
75*33b1fccfSAndroid Build Coastguard Worker 	    !(vi->z_advise & Z_EROFS_ADVISE_BIG_PCLUSTER_2)) {
76*33b1fccfSAndroid Build Coastguard Worker 		erofs_err("big pcluster head1/2 of compact indexes should be consistent for nid %llu",
77*33b1fccfSAndroid Build Coastguard Worker 			  vi->nid * 1ULL);
78*33b1fccfSAndroid Build Coastguard Worker 		return -EFSCORRUPTED;
79*33b1fccfSAndroid Build Coastguard Worker 	}
80*33b1fccfSAndroid Build Coastguard Worker 
81*33b1fccfSAndroid Build Coastguard Worker 	if (vi->z_advise & Z_EROFS_ADVISE_INLINE_PCLUSTER) {
82*33b1fccfSAndroid Build Coastguard Worker 		struct erofs_map_blocks map = { .index = UINT_MAX };
83*33b1fccfSAndroid Build Coastguard Worker 
84*33b1fccfSAndroid Build Coastguard Worker 		vi->idata_size = le16_to_cpu(h->h_idata_size);
85*33b1fccfSAndroid Build Coastguard Worker 		ret = z_erofs_do_map_blocks(vi, &map,
86*33b1fccfSAndroid Build Coastguard Worker 					    EROFS_GET_BLOCKS_FINDTAIL);
87*33b1fccfSAndroid Build Coastguard Worker 		if (!map.m_plen ||
88*33b1fccfSAndroid Build Coastguard Worker 		    erofs_blkoff(sbi, map.m_pa) + map.m_plen > erofs_blksiz(sbi)) {
89*33b1fccfSAndroid Build Coastguard Worker 			erofs_err("invalid tail-packing pclustersize %llu",
90*33b1fccfSAndroid Build Coastguard Worker 				  map.m_plen | 0ULL);
91*33b1fccfSAndroid Build Coastguard Worker 			return -EFSCORRUPTED;
92*33b1fccfSAndroid Build Coastguard Worker 		}
93*33b1fccfSAndroid Build Coastguard Worker 		if (ret < 0)
94*33b1fccfSAndroid Build Coastguard Worker 			return ret;
95*33b1fccfSAndroid Build Coastguard Worker 	}
96*33b1fccfSAndroid Build Coastguard Worker 	if (vi->z_advise & Z_EROFS_ADVISE_FRAGMENT_PCLUSTER &&
97*33b1fccfSAndroid Build Coastguard Worker 	    !(h->h_clusterbits >> Z_EROFS_FRAGMENT_INODE_BIT)) {
98*33b1fccfSAndroid Build Coastguard Worker 		struct erofs_map_blocks map = { .index = UINT_MAX };
99*33b1fccfSAndroid Build Coastguard Worker 
100*33b1fccfSAndroid Build Coastguard Worker 		vi->fragmentoff = le32_to_cpu(h->h_fragmentoff);
101*33b1fccfSAndroid Build Coastguard Worker 		ret = z_erofs_do_map_blocks(vi, &map,
102*33b1fccfSAndroid Build Coastguard Worker 					    EROFS_GET_BLOCKS_FINDTAIL);
103*33b1fccfSAndroid Build Coastguard Worker 		if (ret < 0)
104*33b1fccfSAndroid Build Coastguard Worker 			return ret;
105*33b1fccfSAndroid Build Coastguard Worker 	}
106*33b1fccfSAndroid Build Coastguard Worker out:
107*33b1fccfSAndroid Build Coastguard Worker 	vi->flags |= EROFS_I_Z_INITED;
108*33b1fccfSAndroid Build Coastguard Worker 	return 0;
109*33b1fccfSAndroid Build Coastguard Worker }
110*33b1fccfSAndroid Build Coastguard Worker 
111*33b1fccfSAndroid Build Coastguard Worker struct z_erofs_maprecorder {
112*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_inode *inode;
113*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_map_blocks *map;
114*33b1fccfSAndroid Build Coastguard Worker 	void *kaddr;
115*33b1fccfSAndroid Build Coastguard Worker 
116*33b1fccfSAndroid Build Coastguard Worker 	unsigned long lcn;
117*33b1fccfSAndroid Build Coastguard Worker 	/* compression extent information gathered */
118*33b1fccfSAndroid Build Coastguard Worker 	u8  type, headtype;
119*33b1fccfSAndroid Build Coastguard Worker 	u16 clusterofs;
120*33b1fccfSAndroid Build Coastguard Worker 	u16 delta[2];
121*33b1fccfSAndroid Build Coastguard Worker 	erofs_blk_t pblk, compressedblks;
122*33b1fccfSAndroid Build Coastguard Worker 	erofs_off_t nextpackoff;
123*33b1fccfSAndroid Build Coastguard Worker 	bool partialref;
124*33b1fccfSAndroid Build Coastguard Worker };
125*33b1fccfSAndroid Build Coastguard Worker 
z_erofs_reload_indexes(struct z_erofs_maprecorder * m,erofs_blk_t eblk)126*33b1fccfSAndroid Build Coastguard Worker static int z_erofs_reload_indexes(struct z_erofs_maprecorder *m,
127*33b1fccfSAndroid Build Coastguard Worker 				  erofs_blk_t eblk)
128*33b1fccfSAndroid Build Coastguard Worker {
129*33b1fccfSAndroid Build Coastguard Worker 	int ret;
130*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_map_blocks *const map = m->map;
131*33b1fccfSAndroid Build Coastguard Worker 	char *mpage = map->mpage;
132*33b1fccfSAndroid Build Coastguard Worker 
133*33b1fccfSAndroid Build Coastguard Worker 	if (map->index == eblk)
134*33b1fccfSAndroid Build Coastguard Worker 		return 0;
135*33b1fccfSAndroid Build Coastguard Worker 
136*33b1fccfSAndroid Build Coastguard Worker 	ret = erofs_blk_read(m->inode->sbi, 0, mpage, eblk, 1);
137*33b1fccfSAndroid Build Coastguard Worker 	if (ret < 0)
138*33b1fccfSAndroid Build Coastguard Worker 		return -EIO;
139*33b1fccfSAndroid Build Coastguard Worker 
140*33b1fccfSAndroid Build Coastguard Worker 	map->index = eblk;
141*33b1fccfSAndroid Build Coastguard Worker 
142*33b1fccfSAndroid Build Coastguard Worker 	return 0;
143*33b1fccfSAndroid Build Coastguard Worker }
144*33b1fccfSAndroid Build Coastguard Worker 
legacy_load_cluster_from_disk(struct z_erofs_maprecorder * m,unsigned long lcn)145*33b1fccfSAndroid Build Coastguard Worker static int legacy_load_cluster_from_disk(struct z_erofs_maprecorder *m,
146*33b1fccfSAndroid Build Coastguard Worker 					 unsigned long lcn)
147*33b1fccfSAndroid Build Coastguard Worker {
148*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_inode *const vi = m->inode;
149*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_sb_info *sbi = vi->sbi;
150*33b1fccfSAndroid Build Coastguard Worker 	const erofs_off_t ibase = erofs_iloc(vi);
151*33b1fccfSAndroid Build Coastguard Worker 	const erofs_off_t pos = Z_EROFS_FULL_INDEX_ALIGN(ibase +
152*33b1fccfSAndroid Build Coastguard Worker 			vi->inode_isize + vi->xattr_isize) +
153*33b1fccfSAndroid Build Coastguard Worker 		lcn * sizeof(struct z_erofs_lcluster_index);
154*33b1fccfSAndroid Build Coastguard Worker 	struct z_erofs_lcluster_index *di;
155*33b1fccfSAndroid Build Coastguard Worker 	unsigned int advise, type;
156*33b1fccfSAndroid Build Coastguard Worker 	int err;
157*33b1fccfSAndroid Build Coastguard Worker 
158*33b1fccfSAndroid Build Coastguard Worker 	err = z_erofs_reload_indexes(m, erofs_blknr(sbi, pos));
159*33b1fccfSAndroid Build Coastguard Worker 	if (err)
160*33b1fccfSAndroid Build Coastguard Worker 		return err;
161*33b1fccfSAndroid Build Coastguard Worker 
162*33b1fccfSAndroid Build Coastguard Worker 	m->nextpackoff = pos + sizeof(struct z_erofs_lcluster_index);
163*33b1fccfSAndroid Build Coastguard Worker 	m->lcn = lcn;
164*33b1fccfSAndroid Build Coastguard Worker 	di = m->kaddr + erofs_blkoff(sbi, pos);
165*33b1fccfSAndroid Build Coastguard Worker 
166*33b1fccfSAndroid Build Coastguard Worker 	advise = le16_to_cpu(di->di_advise);
167*33b1fccfSAndroid Build Coastguard Worker 	type = (advise >> Z_EROFS_LI_LCLUSTER_TYPE_BIT) &
168*33b1fccfSAndroid Build Coastguard Worker 		((1 << Z_EROFS_LI_LCLUSTER_TYPE_BITS) - 1);
169*33b1fccfSAndroid Build Coastguard Worker 	switch (type) {
170*33b1fccfSAndroid Build Coastguard Worker 	case Z_EROFS_LCLUSTER_TYPE_NONHEAD:
171*33b1fccfSAndroid Build Coastguard Worker 		m->clusterofs = 1 << vi->z_logical_clusterbits;
172*33b1fccfSAndroid Build Coastguard Worker 		m->delta[0] = le16_to_cpu(di->di_u.delta[0]);
173*33b1fccfSAndroid Build Coastguard Worker 		if (m->delta[0] & Z_EROFS_LI_D0_CBLKCNT) {
174*33b1fccfSAndroid Build Coastguard Worker 			if (!(vi->z_advise & Z_EROFS_ADVISE_BIG_PCLUSTER_1)) {
175*33b1fccfSAndroid Build Coastguard Worker 				DBG_BUGON(1);
176*33b1fccfSAndroid Build Coastguard Worker 				return -EFSCORRUPTED;
177*33b1fccfSAndroid Build Coastguard Worker 			}
178*33b1fccfSAndroid Build Coastguard Worker 			m->compressedblks = m->delta[0] &
179*33b1fccfSAndroid Build Coastguard Worker 				~Z_EROFS_LI_D0_CBLKCNT;
180*33b1fccfSAndroid Build Coastguard Worker 			m->delta[0] = 1;
181*33b1fccfSAndroid Build Coastguard Worker 		}
182*33b1fccfSAndroid Build Coastguard Worker 		m->delta[1] = le16_to_cpu(di->di_u.delta[1]);
183*33b1fccfSAndroid Build Coastguard Worker 		break;
184*33b1fccfSAndroid Build Coastguard Worker 	case Z_EROFS_LCLUSTER_TYPE_PLAIN:
185*33b1fccfSAndroid Build Coastguard Worker 	case Z_EROFS_LCLUSTER_TYPE_HEAD1:
186*33b1fccfSAndroid Build Coastguard Worker 		if (advise & Z_EROFS_LI_PARTIAL_REF)
187*33b1fccfSAndroid Build Coastguard Worker 			m->partialref = true;
188*33b1fccfSAndroid Build Coastguard Worker 		m->clusterofs = le16_to_cpu(di->di_clusterofs);
189*33b1fccfSAndroid Build Coastguard Worker 		m->pblk = le32_to_cpu(di->di_u.blkaddr);
190*33b1fccfSAndroid Build Coastguard Worker 		break;
191*33b1fccfSAndroid Build Coastguard Worker 	default:
192*33b1fccfSAndroid Build Coastguard Worker 		DBG_BUGON(1);
193*33b1fccfSAndroid Build Coastguard Worker 		return -EOPNOTSUPP;
194*33b1fccfSAndroid Build Coastguard Worker 	}
195*33b1fccfSAndroid Build Coastguard Worker 	m->type = type;
196*33b1fccfSAndroid Build Coastguard Worker 	return 0;
197*33b1fccfSAndroid Build Coastguard Worker }
198*33b1fccfSAndroid Build Coastguard Worker 
decode_compactedbits(unsigned int lobits,u8 * in,unsigned int pos,u8 * type)199*33b1fccfSAndroid Build Coastguard Worker static unsigned int decode_compactedbits(unsigned int lobits,
200*33b1fccfSAndroid Build Coastguard Worker 					 u8 *in, unsigned int pos, u8 *type)
201*33b1fccfSAndroid Build Coastguard Worker {
202*33b1fccfSAndroid Build Coastguard Worker 	const unsigned int v = get_unaligned_le32(in + pos / 8) >> (pos & 7);
203*33b1fccfSAndroid Build Coastguard Worker 	const unsigned int lo = v & ((1 << lobits) - 1);
204*33b1fccfSAndroid Build Coastguard Worker 
205*33b1fccfSAndroid Build Coastguard Worker 	*type = (v >> lobits) & 3;
206*33b1fccfSAndroid Build Coastguard Worker 	return lo;
207*33b1fccfSAndroid Build Coastguard Worker }
208*33b1fccfSAndroid Build Coastguard Worker 
get_compacted_la_distance(unsigned int lobits,unsigned int encodebits,unsigned int vcnt,u8 * in,int i)209*33b1fccfSAndroid Build Coastguard Worker static int get_compacted_la_distance(unsigned int lobits,
210*33b1fccfSAndroid Build Coastguard Worker 				     unsigned int encodebits,
211*33b1fccfSAndroid Build Coastguard Worker 				     unsigned int vcnt, u8 *in, int i)
212*33b1fccfSAndroid Build Coastguard Worker {
213*33b1fccfSAndroid Build Coastguard Worker 	unsigned int lo, d1 = 0;
214*33b1fccfSAndroid Build Coastguard Worker 	u8 type;
215*33b1fccfSAndroid Build Coastguard Worker 
216*33b1fccfSAndroid Build Coastguard Worker 	DBG_BUGON(i >= vcnt);
217*33b1fccfSAndroid Build Coastguard Worker 
218*33b1fccfSAndroid Build Coastguard Worker 	do {
219*33b1fccfSAndroid Build Coastguard Worker 		lo = decode_compactedbits(lobits, in, encodebits * i, &type);
220*33b1fccfSAndroid Build Coastguard Worker 
221*33b1fccfSAndroid Build Coastguard Worker 		if (type != Z_EROFS_LCLUSTER_TYPE_NONHEAD)
222*33b1fccfSAndroid Build Coastguard Worker 			return d1;
223*33b1fccfSAndroid Build Coastguard Worker 		++d1;
224*33b1fccfSAndroid Build Coastguard Worker 	} while (++i < vcnt);
225*33b1fccfSAndroid Build Coastguard Worker 
226*33b1fccfSAndroid Build Coastguard Worker 	/* vcnt - 1 (Z_EROFS_LCLUSTER_TYPE_NONHEAD) item */
227*33b1fccfSAndroid Build Coastguard Worker 	if (!(lo & Z_EROFS_LI_D0_CBLKCNT))
228*33b1fccfSAndroid Build Coastguard Worker 		d1 += lo - 1;
229*33b1fccfSAndroid Build Coastguard Worker 	return d1;
230*33b1fccfSAndroid Build Coastguard Worker }
231*33b1fccfSAndroid Build Coastguard Worker 
unpack_compacted_index(struct z_erofs_maprecorder * m,unsigned int amortizedshift,erofs_off_t pos,bool lookahead)232*33b1fccfSAndroid Build Coastguard Worker static int unpack_compacted_index(struct z_erofs_maprecorder *m,
233*33b1fccfSAndroid Build Coastguard Worker 				  unsigned int amortizedshift,
234*33b1fccfSAndroid Build Coastguard Worker 				  erofs_off_t pos, bool lookahead)
235*33b1fccfSAndroid Build Coastguard Worker {
236*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_inode *const vi = m->inode;
237*33b1fccfSAndroid Build Coastguard Worker 	const unsigned int lclusterbits = vi->z_logical_clusterbits;
238*33b1fccfSAndroid Build Coastguard Worker 	unsigned int vcnt, base, lo, lobits, encodebits, nblk, eofs;
239*33b1fccfSAndroid Build Coastguard Worker 	int i;
240*33b1fccfSAndroid Build Coastguard Worker 	u8 *in, type;
241*33b1fccfSAndroid Build Coastguard Worker 	bool big_pcluster;
242*33b1fccfSAndroid Build Coastguard Worker 
243*33b1fccfSAndroid Build Coastguard Worker 	if (1 << amortizedshift == 4 && lclusterbits <= 14)
244*33b1fccfSAndroid Build Coastguard Worker 		vcnt = 2;
245*33b1fccfSAndroid Build Coastguard Worker 	else if (1 << amortizedshift == 2 && lclusterbits <= 12)
246*33b1fccfSAndroid Build Coastguard Worker 		vcnt = 16;
247*33b1fccfSAndroid Build Coastguard Worker 	else
248*33b1fccfSAndroid Build Coastguard Worker 		return -EOPNOTSUPP;
249*33b1fccfSAndroid Build Coastguard Worker 
250*33b1fccfSAndroid Build Coastguard Worker 	/* it doesn't equal to round_up(..) */
251*33b1fccfSAndroid Build Coastguard Worker 	m->nextpackoff = round_down(pos, vcnt << amortizedshift) +
252*33b1fccfSAndroid Build Coastguard Worker 			 (vcnt << amortizedshift);
253*33b1fccfSAndroid Build Coastguard Worker 	big_pcluster = vi->z_advise & Z_EROFS_ADVISE_BIG_PCLUSTER_1;
254*33b1fccfSAndroid Build Coastguard Worker 	lobits = max(lclusterbits, ilog2(Z_EROFS_LI_D0_CBLKCNT) + 1U);
255*33b1fccfSAndroid Build Coastguard Worker 	encodebits = ((vcnt << amortizedshift) - sizeof(__le32)) * 8 / vcnt;
256*33b1fccfSAndroid Build Coastguard Worker 	eofs = erofs_blkoff(vi->sbi, pos);
257*33b1fccfSAndroid Build Coastguard Worker 	base = round_down(eofs, vcnt << amortizedshift);
258*33b1fccfSAndroid Build Coastguard Worker 	in = m->kaddr + base;
259*33b1fccfSAndroid Build Coastguard Worker 
260*33b1fccfSAndroid Build Coastguard Worker 	i = (eofs - base) >> amortizedshift;
261*33b1fccfSAndroid Build Coastguard Worker 
262*33b1fccfSAndroid Build Coastguard Worker 	lo = decode_compactedbits(lobits, in, encodebits * i, &type);
263*33b1fccfSAndroid Build Coastguard Worker 	m->type = type;
264*33b1fccfSAndroid Build Coastguard Worker 	if (type == Z_EROFS_LCLUSTER_TYPE_NONHEAD) {
265*33b1fccfSAndroid Build Coastguard Worker 		m->clusterofs = 1 << lclusterbits;
266*33b1fccfSAndroid Build Coastguard Worker 
267*33b1fccfSAndroid Build Coastguard Worker 		/* figure out lookahead_distance: delta[1] if needed */
268*33b1fccfSAndroid Build Coastguard Worker 		if (lookahead)
269*33b1fccfSAndroid Build Coastguard Worker 			m->delta[1] = get_compacted_la_distance(lobits,
270*33b1fccfSAndroid Build Coastguard Worker 						encodebits, vcnt, in, i);
271*33b1fccfSAndroid Build Coastguard Worker 		if (lo & Z_EROFS_LI_D0_CBLKCNT) {
272*33b1fccfSAndroid Build Coastguard Worker 			if (!big_pcluster) {
273*33b1fccfSAndroid Build Coastguard Worker 				DBG_BUGON(1);
274*33b1fccfSAndroid Build Coastguard Worker 				return -EFSCORRUPTED;
275*33b1fccfSAndroid Build Coastguard Worker 			}
276*33b1fccfSAndroid Build Coastguard Worker 			m->compressedblks = lo & ~Z_EROFS_LI_D0_CBLKCNT;
277*33b1fccfSAndroid Build Coastguard Worker 			m->delta[0] = 1;
278*33b1fccfSAndroid Build Coastguard Worker 			return 0;
279*33b1fccfSAndroid Build Coastguard Worker 		} else if (i + 1 != (int)vcnt) {
280*33b1fccfSAndroid Build Coastguard Worker 			m->delta[0] = lo;
281*33b1fccfSAndroid Build Coastguard Worker 			return 0;
282*33b1fccfSAndroid Build Coastguard Worker 		}
283*33b1fccfSAndroid Build Coastguard Worker 		/*
284*33b1fccfSAndroid Build Coastguard Worker 		 * since the last lcluster in the pack is special,
285*33b1fccfSAndroid Build Coastguard Worker 		 * of which lo saves delta[1] rather than delta[0].
286*33b1fccfSAndroid Build Coastguard Worker 		 * Hence, get delta[0] by the previous lcluster indirectly.
287*33b1fccfSAndroid Build Coastguard Worker 		 */
288*33b1fccfSAndroid Build Coastguard Worker 		lo = decode_compactedbits(lobits, in,
289*33b1fccfSAndroid Build Coastguard Worker 					  encodebits * (i - 1), &type);
290*33b1fccfSAndroid Build Coastguard Worker 		if (type != Z_EROFS_LCLUSTER_TYPE_NONHEAD)
291*33b1fccfSAndroid Build Coastguard Worker 			lo = 0;
292*33b1fccfSAndroid Build Coastguard Worker 		else if (lo & Z_EROFS_LI_D0_CBLKCNT)
293*33b1fccfSAndroid Build Coastguard Worker 			lo = 1;
294*33b1fccfSAndroid Build Coastguard Worker 		m->delta[0] = lo + 1;
295*33b1fccfSAndroid Build Coastguard Worker 		return 0;
296*33b1fccfSAndroid Build Coastguard Worker 	}
297*33b1fccfSAndroid Build Coastguard Worker 	m->clusterofs = lo;
298*33b1fccfSAndroid Build Coastguard Worker 	m->delta[0] = 0;
299*33b1fccfSAndroid Build Coastguard Worker 	/* figout out blkaddr (pblk) for HEAD lclusters */
300*33b1fccfSAndroid Build Coastguard Worker 	if (!big_pcluster) {
301*33b1fccfSAndroid Build Coastguard Worker 		nblk = 1;
302*33b1fccfSAndroid Build Coastguard Worker 		while (i > 0) {
303*33b1fccfSAndroid Build Coastguard Worker 			--i;
304*33b1fccfSAndroid Build Coastguard Worker 			lo = decode_compactedbits(lobits, in,
305*33b1fccfSAndroid Build Coastguard Worker 						  encodebits * i, &type);
306*33b1fccfSAndroid Build Coastguard Worker 			if (type == Z_EROFS_LCLUSTER_TYPE_NONHEAD)
307*33b1fccfSAndroid Build Coastguard Worker 				i -= lo;
308*33b1fccfSAndroid Build Coastguard Worker 
309*33b1fccfSAndroid Build Coastguard Worker 			if (i >= 0)
310*33b1fccfSAndroid Build Coastguard Worker 				++nblk;
311*33b1fccfSAndroid Build Coastguard Worker 		}
312*33b1fccfSAndroid Build Coastguard Worker 	} else {
313*33b1fccfSAndroid Build Coastguard Worker 		nblk = 0;
314*33b1fccfSAndroid Build Coastguard Worker 		while (i > 0) {
315*33b1fccfSAndroid Build Coastguard Worker 			--i;
316*33b1fccfSAndroid Build Coastguard Worker 			lo = decode_compactedbits(lobits, in,
317*33b1fccfSAndroid Build Coastguard Worker 						  encodebits * i, &type);
318*33b1fccfSAndroid Build Coastguard Worker 			if (type == Z_EROFS_LCLUSTER_TYPE_NONHEAD) {
319*33b1fccfSAndroid Build Coastguard Worker 				if (lo & Z_EROFS_LI_D0_CBLKCNT) {
320*33b1fccfSAndroid Build Coastguard Worker 					--i;
321*33b1fccfSAndroid Build Coastguard Worker 					nblk += lo & ~Z_EROFS_LI_D0_CBLKCNT;
322*33b1fccfSAndroid Build Coastguard Worker 					continue;
323*33b1fccfSAndroid Build Coastguard Worker 				}
324*33b1fccfSAndroid Build Coastguard Worker 				if (lo <= 1) {
325*33b1fccfSAndroid Build Coastguard Worker 					DBG_BUGON(1);
326*33b1fccfSAndroid Build Coastguard Worker 					/* --i; ++nblk;	continue; */
327*33b1fccfSAndroid Build Coastguard Worker 					return -EFSCORRUPTED;
328*33b1fccfSAndroid Build Coastguard Worker 				}
329*33b1fccfSAndroid Build Coastguard Worker 				i -= lo - 2;
330*33b1fccfSAndroid Build Coastguard Worker 				continue;
331*33b1fccfSAndroid Build Coastguard Worker 			}
332*33b1fccfSAndroid Build Coastguard Worker 			++nblk;
333*33b1fccfSAndroid Build Coastguard Worker 		}
334*33b1fccfSAndroid Build Coastguard Worker 	}
335*33b1fccfSAndroid Build Coastguard Worker 	in += (vcnt << amortizedshift) - sizeof(__le32);
336*33b1fccfSAndroid Build Coastguard Worker 	m->pblk = le32_to_cpu(*(__le32 *)in) + nblk;
337*33b1fccfSAndroid Build Coastguard Worker 	return 0;
338*33b1fccfSAndroid Build Coastguard Worker }
339*33b1fccfSAndroid Build Coastguard Worker 
compacted_load_cluster_from_disk(struct z_erofs_maprecorder * m,unsigned long lcn,bool lookahead)340*33b1fccfSAndroid Build Coastguard Worker static int compacted_load_cluster_from_disk(struct z_erofs_maprecorder *m,
341*33b1fccfSAndroid Build Coastguard Worker 					    unsigned long lcn, bool lookahead)
342*33b1fccfSAndroid Build Coastguard Worker {
343*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_inode *const vi = m->inode;
344*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_sb_info *sbi = vi->sbi;
345*33b1fccfSAndroid Build Coastguard Worker 	const erofs_off_t ebase = round_up(erofs_iloc(vi) + vi->inode_isize +
346*33b1fccfSAndroid Build Coastguard Worker 					   vi->xattr_isize, 8) +
347*33b1fccfSAndroid Build Coastguard Worker 		sizeof(struct z_erofs_map_header);
348*33b1fccfSAndroid Build Coastguard Worker 	const unsigned int totalidx = BLK_ROUND_UP(sbi, vi->i_size);
349*33b1fccfSAndroid Build Coastguard Worker 	unsigned int compacted_4b_initial, compacted_2b;
350*33b1fccfSAndroid Build Coastguard Worker 	unsigned int amortizedshift;
351*33b1fccfSAndroid Build Coastguard Worker 	erofs_off_t pos;
352*33b1fccfSAndroid Build Coastguard Worker 	int err;
353*33b1fccfSAndroid Build Coastguard Worker 
354*33b1fccfSAndroid Build Coastguard Worker 	if (lcn >= totalidx)
355*33b1fccfSAndroid Build Coastguard Worker 		return -EINVAL;
356*33b1fccfSAndroid Build Coastguard Worker 
357*33b1fccfSAndroid Build Coastguard Worker 	m->lcn = lcn;
358*33b1fccfSAndroid Build Coastguard Worker 	/* used to align to 32-byte (compacted_2b) alignment */
359*33b1fccfSAndroid Build Coastguard Worker 	compacted_4b_initial = (32 - ebase % 32) / 4;
360*33b1fccfSAndroid Build Coastguard Worker 	if (compacted_4b_initial == 32 / 4)
361*33b1fccfSAndroid Build Coastguard Worker 		compacted_4b_initial = 0;
362*33b1fccfSAndroid Build Coastguard Worker 
363*33b1fccfSAndroid Build Coastguard Worker 	if ((vi->z_advise & Z_EROFS_ADVISE_COMPACTED_2B) &&
364*33b1fccfSAndroid Build Coastguard Worker 	    compacted_4b_initial < totalidx)
365*33b1fccfSAndroid Build Coastguard Worker 		compacted_2b = rounddown(totalidx - compacted_4b_initial, 16);
366*33b1fccfSAndroid Build Coastguard Worker 	else
367*33b1fccfSAndroid Build Coastguard Worker 		compacted_2b = 0;
368*33b1fccfSAndroid Build Coastguard Worker 
369*33b1fccfSAndroid Build Coastguard Worker 	pos = ebase;
370*33b1fccfSAndroid Build Coastguard Worker 	if (lcn < compacted_4b_initial) {
371*33b1fccfSAndroid Build Coastguard Worker 		amortizedshift = 2;
372*33b1fccfSAndroid Build Coastguard Worker 		goto out;
373*33b1fccfSAndroid Build Coastguard Worker 	}
374*33b1fccfSAndroid Build Coastguard Worker 	pos += compacted_4b_initial * 4;
375*33b1fccfSAndroid Build Coastguard Worker 	lcn -= compacted_4b_initial;
376*33b1fccfSAndroid Build Coastguard Worker 
377*33b1fccfSAndroid Build Coastguard Worker 	if (lcn < compacted_2b) {
378*33b1fccfSAndroid Build Coastguard Worker 		amortizedshift = 1;
379*33b1fccfSAndroid Build Coastguard Worker 		goto out;
380*33b1fccfSAndroid Build Coastguard Worker 	}
381*33b1fccfSAndroid Build Coastguard Worker 	pos += compacted_2b * 2;
382*33b1fccfSAndroid Build Coastguard Worker 	lcn -= compacted_2b;
383*33b1fccfSAndroid Build Coastguard Worker 	amortizedshift = 2;
384*33b1fccfSAndroid Build Coastguard Worker out:
385*33b1fccfSAndroid Build Coastguard Worker 	pos += lcn * (1 << amortizedshift);
386*33b1fccfSAndroid Build Coastguard Worker 	err = z_erofs_reload_indexes(m, erofs_blknr(sbi, pos));
387*33b1fccfSAndroid Build Coastguard Worker 	if (err)
388*33b1fccfSAndroid Build Coastguard Worker 		return err;
389*33b1fccfSAndroid Build Coastguard Worker 	return unpack_compacted_index(m, amortizedshift, pos, lookahead);
390*33b1fccfSAndroid Build Coastguard Worker }
391*33b1fccfSAndroid Build Coastguard Worker 
z_erofs_load_cluster_from_disk(struct z_erofs_maprecorder * m,unsigned int lcn,bool lookahead)392*33b1fccfSAndroid Build Coastguard Worker static int z_erofs_load_cluster_from_disk(struct z_erofs_maprecorder *m,
393*33b1fccfSAndroid Build Coastguard Worker 					  unsigned int lcn, bool lookahead)
394*33b1fccfSAndroid Build Coastguard Worker {
395*33b1fccfSAndroid Build Coastguard Worker 	const unsigned int datamode = m->inode->datalayout;
396*33b1fccfSAndroid Build Coastguard Worker 
397*33b1fccfSAndroid Build Coastguard Worker 	if (datamode == EROFS_INODE_COMPRESSED_FULL)
398*33b1fccfSAndroid Build Coastguard Worker 		return legacy_load_cluster_from_disk(m, lcn);
399*33b1fccfSAndroid Build Coastguard Worker 
400*33b1fccfSAndroid Build Coastguard Worker 	if (datamode == EROFS_INODE_COMPRESSED_COMPACT)
401*33b1fccfSAndroid Build Coastguard Worker 		return compacted_load_cluster_from_disk(m, lcn, lookahead);
402*33b1fccfSAndroid Build Coastguard Worker 
403*33b1fccfSAndroid Build Coastguard Worker 	return -EINVAL;
404*33b1fccfSAndroid Build Coastguard Worker }
405*33b1fccfSAndroid Build Coastguard Worker 
z_erofs_extent_lookback(struct z_erofs_maprecorder * m,unsigned int lookback_distance)406*33b1fccfSAndroid Build Coastguard Worker static int z_erofs_extent_lookback(struct z_erofs_maprecorder *m,
407*33b1fccfSAndroid Build Coastguard Worker 				   unsigned int lookback_distance)
408*33b1fccfSAndroid Build Coastguard Worker {
409*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_inode *const vi = m->inode;
410*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_map_blocks *const map = m->map;
411*33b1fccfSAndroid Build Coastguard Worker 	const unsigned int lclusterbits = vi->z_logical_clusterbits;
412*33b1fccfSAndroid Build Coastguard Worker 	unsigned long lcn = m->lcn;
413*33b1fccfSAndroid Build Coastguard Worker 	int err;
414*33b1fccfSAndroid Build Coastguard Worker 
415*33b1fccfSAndroid Build Coastguard Worker 	if (lcn < lookback_distance) {
416*33b1fccfSAndroid Build Coastguard Worker 		erofs_err("bogus lookback distance @ nid %llu",
417*33b1fccfSAndroid Build Coastguard Worker 			  (unsigned long long)vi->nid);
418*33b1fccfSAndroid Build Coastguard Worker 		DBG_BUGON(1);
419*33b1fccfSAndroid Build Coastguard Worker 		return -EFSCORRUPTED;
420*33b1fccfSAndroid Build Coastguard Worker 	}
421*33b1fccfSAndroid Build Coastguard Worker 
422*33b1fccfSAndroid Build Coastguard Worker 	/* load extent head logical cluster if needed */
423*33b1fccfSAndroid Build Coastguard Worker 	lcn -= lookback_distance;
424*33b1fccfSAndroid Build Coastguard Worker 	err = z_erofs_load_cluster_from_disk(m, lcn, false);
425*33b1fccfSAndroid Build Coastguard Worker 	if (err)
426*33b1fccfSAndroid Build Coastguard Worker 		return err;
427*33b1fccfSAndroid Build Coastguard Worker 
428*33b1fccfSAndroid Build Coastguard Worker 	switch (m->type) {
429*33b1fccfSAndroid Build Coastguard Worker 	case Z_EROFS_LCLUSTER_TYPE_NONHEAD:
430*33b1fccfSAndroid Build Coastguard Worker 		if (!m->delta[0]) {
431*33b1fccfSAndroid Build Coastguard Worker 			erofs_err("invalid lookback distance 0 @ nid %llu",
432*33b1fccfSAndroid Build Coastguard Worker 				  (unsigned long long)vi->nid);
433*33b1fccfSAndroid Build Coastguard Worker 			DBG_BUGON(1);
434*33b1fccfSAndroid Build Coastguard Worker 			return -EFSCORRUPTED;
435*33b1fccfSAndroid Build Coastguard Worker 		}
436*33b1fccfSAndroid Build Coastguard Worker 		return z_erofs_extent_lookback(m, m->delta[0]);
437*33b1fccfSAndroid Build Coastguard Worker 	case Z_EROFS_LCLUSTER_TYPE_PLAIN:
438*33b1fccfSAndroid Build Coastguard Worker 	case Z_EROFS_LCLUSTER_TYPE_HEAD1:
439*33b1fccfSAndroid Build Coastguard Worker 		m->headtype = m->type;
440*33b1fccfSAndroid Build Coastguard Worker 		map->m_la = (lcn << lclusterbits) | m->clusterofs;
441*33b1fccfSAndroid Build Coastguard Worker 		break;
442*33b1fccfSAndroid Build Coastguard Worker 	default:
443*33b1fccfSAndroid Build Coastguard Worker 		erofs_err("unknown type %u @ lcn %lu of nid %llu",
444*33b1fccfSAndroid Build Coastguard Worker 			  m->type, lcn, (unsigned long long)vi->nid);
445*33b1fccfSAndroid Build Coastguard Worker 		DBG_BUGON(1);
446*33b1fccfSAndroid Build Coastguard Worker 		return -EOPNOTSUPP;
447*33b1fccfSAndroid Build Coastguard Worker 	}
448*33b1fccfSAndroid Build Coastguard Worker 	return 0;
449*33b1fccfSAndroid Build Coastguard Worker }
450*33b1fccfSAndroid Build Coastguard Worker 
z_erofs_get_extent_compressedlen(struct z_erofs_maprecorder * m,unsigned int initial_lcn)451*33b1fccfSAndroid Build Coastguard Worker static int z_erofs_get_extent_compressedlen(struct z_erofs_maprecorder *m,
452*33b1fccfSAndroid Build Coastguard Worker 					    unsigned int initial_lcn)
453*33b1fccfSAndroid Build Coastguard Worker {
454*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_inode *const vi = m->inode;
455*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_sb_info *sbi = vi->sbi;
456*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_map_blocks *const map = m->map;
457*33b1fccfSAndroid Build Coastguard Worker 	const unsigned int lclusterbits = vi->z_logical_clusterbits;
458*33b1fccfSAndroid Build Coastguard Worker 	unsigned long lcn;
459*33b1fccfSAndroid Build Coastguard Worker 	int err;
460*33b1fccfSAndroid Build Coastguard Worker 
461*33b1fccfSAndroid Build Coastguard Worker 	DBG_BUGON(m->type != Z_EROFS_LCLUSTER_TYPE_PLAIN &&
462*33b1fccfSAndroid Build Coastguard Worker 		  m->type != Z_EROFS_LCLUSTER_TYPE_HEAD1);
463*33b1fccfSAndroid Build Coastguard Worker 
464*33b1fccfSAndroid Build Coastguard Worker 	if (m->headtype == Z_EROFS_LCLUSTER_TYPE_PLAIN ||
465*33b1fccfSAndroid Build Coastguard Worker 	    !(vi->z_advise & Z_EROFS_ADVISE_BIG_PCLUSTER_1)) {
466*33b1fccfSAndroid Build Coastguard Worker 		map->m_plen = 1 << lclusterbits;
467*33b1fccfSAndroid Build Coastguard Worker 		return 0;
468*33b1fccfSAndroid Build Coastguard Worker 	}
469*33b1fccfSAndroid Build Coastguard Worker 
470*33b1fccfSAndroid Build Coastguard Worker 	lcn = m->lcn + 1;
471*33b1fccfSAndroid Build Coastguard Worker 	if (m->compressedblks)
472*33b1fccfSAndroid Build Coastguard Worker 		goto out;
473*33b1fccfSAndroid Build Coastguard Worker 
474*33b1fccfSAndroid Build Coastguard Worker 	err = z_erofs_load_cluster_from_disk(m, lcn, false);
475*33b1fccfSAndroid Build Coastguard Worker 	if (err)
476*33b1fccfSAndroid Build Coastguard Worker 		return err;
477*33b1fccfSAndroid Build Coastguard Worker 
478*33b1fccfSAndroid Build Coastguard Worker 	/*
479*33b1fccfSAndroid Build Coastguard Worker 	 * If the 1st NONHEAD lcluster has already been handled initially w/o
480*33b1fccfSAndroid Build Coastguard Worker 	 * valid compressedblks, which means at least it mustn't be CBLKCNT, or
481*33b1fccfSAndroid Build Coastguard Worker 	 * an internal implemenatation error is detected.
482*33b1fccfSAndroid Build Coastguard Worker 	 *
483*33b1fccfSAndroid Build Coastguard Worker 	 * The following code can also handle it properly anyway, but let's
484*33b1fccfSAndroid Build Coastguard Worker 	 * BUG_ON in the debugging mode only for developers to notice that.
485*33b1fccfSAndroid Build Coastguard Worker 	 */
486*33b1fccfSAndroid Build Coastguard Worker 	DBG_BUGON(lcn == initial_lcn &&
487*33b1fccfSAndroid Build Coastguard Worker 		  m->type == Z_EROFS_LCLUSTER_TYPE_NONHEAD);
488*33b1fccfSAndroid Build Coastguard Worker 
489*33b1fccfSAndroid Build Coastguard Worker 	switch (m->type) {
490*33b1fccfSAndroid Build Coastguard Worker 	case Z_EROFS_LCLUSTER_TYPE_PLAIN:
491*33b1fccfSAndroid Build Coastguard Worker 	case Z_EROFS_LCLUSTER_TYPE_HEAD1:
492*33b1fccfSAndroid Build Coastguard Worker 		/*
493*33b1fccfSAndroid Build Coastguard Worker 		 * if the 1st NONHEAD lcluster is actually PLAIN or HEAD type
494*33b1fccfSAndroid Build Coastguard Worker 		 * rather than CBLKCNT, it's a 1 lcluster-sized pcluster.
495*33b1fccfSAndroid Build Coastguard Worker 		 */
496*33b1fccfSAndroid Build Coastguard Worker 		m->compressedblks = 1 << (lclusterbits - sbi->blkszbits);
497*33b1fccfSAndroid Build Coastguard Worker 		break;
498*33b1fccfSAndroid Build Coastguard Worker 	case Z_EROFS_LCLUSTER_TYPE_NONHEAD:
499*33b1fccfSAndroid Build Coastguard Worker 		if (m->delta[0] != 1)
500*33b1fccfSAndroid Build Coastguard Worker 			goto err_bonus_cblkcnt;
501*33b1fccfSAndroid Build Coastguard Worker 		if (m->compressedblks)
502*33b1fccfSAndroid Build Coastguard Worker 			break;
503*33b1fccfSAndroid Build Coastguard Worker 		/* fallthrough */
504*33b1fccfSAndroid Build Coastguard Worker 	default:
505*33b1fccfSAndroid Build Coastguard Worker 		erofs_err("cannot found CBLKCNT @ lcn %lu of nid %llu",
506*33b1fccfSAndroid Build Coastguard Worker 			  lcn, vi->nid | 0ULL);
507*33b1fccfSAndroid Build Coastguard Worker 		DBG_BUGON(1);
508*33b1fccfSAndroid Build Coastguard Worker 		return -EFSCORRUPTED;
509*33b1fccfSAndroid Build Coastguard Worker 	}
510*33b1fccfSAndroid Build Coastguard Worker out:
511*33b1fccfSAndroid Build Coastguard Worker 	map->m_plen = m->compressedblks << sbi->blkszbits;
512*33b1fccfSAndroid Build Coastguard Worker 	return 0;
513*33b1fccfSAndroid Build Coastguard Worker err_bonus_cblkcnt:
514*33b1fccfSAndroid Build Coastguard Worker 	erofs_err("bogus CBLKCNT @ lcn %lu of nid %llu",
515*33b1fccfSAndroid Build Coastguard Worker 		  lcn, vi->nid | 0ULL);
516*33b1fccfSAndroid Build Coastguard Worker 	DBG_BUGON(1);
517*33b1fccfSAndroid Build Coastguard Worker 	return -EFSCORRUPTED;
518*33b1fccfSAndroid Build Coastguard Worker }
519*33b1fccfSAndroid Build Coastguard Worker 
z_erofs_get_extent_decompressedlen(struct z_erofs_maprecorder * m)520*33b1fccfSAndroid Build Coastguard Worker static int z_erofs_get_extent_decompressedlen(struct z_erofs_maprecorder *m)
521*33b1fccfSAndroid Build Coastguard Worker {
522*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_inode *const vi = m->inode;
523*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_map_blocks *map = m->map;
524*33b1fccfSAndroid Build Coastguard Worker 	unsigned int lclusterbits = vi->z_logical_clusterbits;
525*33b1fccfSAndroid Build Coastguard Worker 	u64 lcn = m->lcn, headlcn = map->m_la >> lclusterbits;
526*33b1fccfSAndroid Build Coastguard Worker 	int err;
527*33b1fccfSAndroid Build Coastguard Worker 
528*33b1fccfSAndroid Build Coastguard Worker 	do {
529*33b1fccfSAndroid Build Coastguard Worker 		/* handle the last EOF pcluster (no next HEAD lcluster) */
530*33b1fccfSAndroid Build Coastguard Worker 		if ((lcn << lclusterbits) >= vi->i_size) {
531*33b1fccfSAndroid Build Coastguard Worker 			map->m_llen = vi->i_size - map->m_la;
532*33b1fccfSAndroid Build Coastguard Worker 			return 0;
533*33b1fccfSAndroid Build Coastguard Worker 		}
534*33b1fccfSAndroid Build Coastguard Worker 
535*33b1fccfSAndroid Build Coastguard Worker 		err = z_erofs_load_cluster_from_disk(m, lcn, true);
536*33b1fccfSAndroid Build Coastguard Worker 		if (err)
537*33b1fccfSAndroid Build Coastguard Worker 			return err;
538*33b1fccfSAndroid Build Coastguard Worker 
539*33b1fccfSAndroid Build Coastguard Worker 		if (m->type == Z_EROFS_LCLUSTER_TYPE_NONHEAD) {
540*33b1fccfSAndroid Build Coastguard Worker 			DBG_BUGON(!m->delta[1] &&
541*33b1fccfSAndroid Build Coastguard Worker 				  m->clusterofs != 1 << lclusterbits);
542*33b1fccfSAndroid Build Coastguard Worker 		} else if (m->type == Z_EROFS_LCLUSTER_TYPE_PLAIN ||
543*33b1fccfSAndroid Build Coastguard Worker 			   m->type == Z_EROFS_LCLUSTER_TYPE_HEAD1) {
544*33b1fccfSAndroid Build Coastguard Worker 			/* go on until the next HEAD lcluster */
545*33b1fccfSAndroid Build Coastguard Worker 			if (lcn != headlcn)
546*33b1fccfSAndroid Build Coastguard Worker 				break;
547*33b1fccfSAndroid Build Coastguard Worker 			m->delta[1] = 1;
548*33b1fccfSAndroid Build Coastguard Worker 		} else {
549*33b1fccfSAndroid Build Coastguard Worker 			erofs_err("unknown type %u @ lcn %llu of nid %llu",
550*33b1fccfSAndroid Build Coastguard Worker 				  m->type, lcn | 0ULL,
551*33b1fccfSAndroid Build Coastguard Worker 				  (unsigned long long)vi->nid);
552*33b1fccfSAndroid Build Coastguard Worker 			DBG_BUGON(1);
553*33b1fccfSAndroid Build Coastguard Worker 			return -EOPNOTSUPP;
554*33b1fccfSAndroid Build Coastguard Worker 		}
555*33b1fccfSAndroid Build Coastguard Worker 		lcn += m->delta[1];
556*33b1fccfSAndroid Build Coastguard Worker 	} while (m->delta[1]);
557*33b1fccfSAndroid Build Coastguard Worker 
558*33b1fccfSAndroid Build Coastguard Worker 	map->m_llen = (lcn << lclusterbits) + m->clusterofs - map->m_la;
559*33b1fccfSAndroid Build Coastguard Worker 	return 0;
560*33b1fccfSAndroid Build Coastguard Worker }
561*33b1fccfSAndroid Build Coastguard Worker 
z_erofs_do_map_blocks(struct erofs_inode * vi,struct erofs_map_blocks * map,int flags)562*33b1fccfSAndroid Build Coastguard Worker static int z_erofs_do_map_blocks(struct erofs_inode *vi,
563*33b1fccfSAndroid Build Coastguard Worker 				 struct erofs_map_blocks *map,
564*33b1fccfSAndroid Build Coastguard Worker 				 int flags)
565*33b1fccfSAndroid Build Coastguard Worker {
566*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_sb_info *sbi = vi->sbi;
567*33b1fccfSAndroid Build Coastguard Worker 	bool ztailpacking = vi->z_advise & Z_EROFS_ADVISE_INLINE_PCLUSTER;
568*33b1fccfSAndroid Build Coastguard Worker 	bool fragment = vi->z_advise & Z_EROFS_ADVISE_FRAGMENT_PCLUSTER;
569*33b1fccfSAndroid Build Coastguard Worker 	struct z_erofs_maprecorder m = {
570*33b1fccfSAndroid Build Coastguard Worker 		.inode = vi,
571*33b1fccfSAndroid Build Coastguard Worker 		.map = map,
572*33b1fccfSAndroid Build Coastguard Worker 		.kaddr = map->mpage,
573*33b1fccfSAndroid Build Coastguard Worker 	};
574*33b1fccfSAndroid Build Coastguard Worker 	int err = 0;
575*33b1fccfSAndroid Build Coastguard Worker 	unsigned int lclusterbits, endoff;
576*33b1fccfSAndroid Build Coastguard Worker 	unsigned long initial_lcn;
577*33b1fccfSAndroid Build Coastguard Worker 	unsigned long long ofs, end;
578*33b1fccfSAndroid Build Coastguard Worker 
579*33b1fccfSAndroid Build Coastguard Worker 	lclusterbits = vi->z_logical_clusterbits;
580*33b1fccfSAndroid Build Coastguard Worker 	ofs = flags & EROFS_GET_BLOCKS_FINDTAIL ? vi->i_size - 1 : map->m_la;
581*33b1fccfSAndroid Build Coastguard Worker 	initial_lcn = ofs >> lclusterbits;
582*33b1fccfSAndroid Build Coastguard Worker 	endoff = ofs & ((1 << lclusterbits) - 1);
583*33b1fccfSAndroid Build Coastguard Worker 
584*33b1fccfSAndroid Build Coastguard Worker 	err = z_erofs_load_cluster_from_disk(&m, initial_lcn, false);
585*33b1fccfSAndroid Build Coastguard Worker 	if (err)
586*33b1fccfSAndroid Build Coastguard Worker 		goto out;
587*33b1fccfSAndroid Build Coastguard Worker 
588*33b1fccfSAndroid Build Coastguard Worker 	if (ztailpacking && (flags & EROFS_GET_BLOCKS_FINDTAIL))
589*33b1fccfSAndroid Build Coastguard Worker 		vi->z_idataoff = m.nextpackoff;
590*33b1fccfSAndroid Build Coastguard Worker 
591*33b1fccfSAndroid Build Coastguard Worker 	map->m_flags = EROFS_MAP_MAPPED | EROFS_MAP_ENCODED;
592*33b1fccfSAndroid Build Coastguard Worker 	end = (m.lcn + 1ULL) << lclusterbits;
593*33b1fccfSAndroid Build Coastguard Worker 	switch (m.type) {
594*33b1fccfSAndroid Build Coastguard Worker 	case Z_EROFS_LCLUSTER_TYPE_PLAIN:
595*33b1fccfSAndroid Build Coastguard Worker 	case Z_EROFS_LCLUSTER_TYPE_HEAD1:
596*33b1fccfSAndroid Build Coastguard Worker 		if (endoff >= m.clusterofs) {
597*33b1fccfSAndroid Build Coastguard Worker 			m.headtype = m.type;
598*33b1fccfSAndroid Build Coastguard Worker 			map->m_la = (m.lcn << lclusterbits) | m.clusterofs;
599*33b1fccfSAndroid Build Coastguard Worker 			/*
600*33b1fccfSAndroid Build Coastguard Worker 			 * For ztailpacking files, in order to inline data more
601*33b1fccfSAndroid Build Coastguard Worker 			 * effectively, special EOF lclusters are now supported
602*33b1fccfSAndroid Build Coastguard Worker 			 * which can have three parts at most.
603*33b1fccfSAndroid Build Coastguard Worker 			 */
604*33b1fccfSAndroid Build Coastguard Worker 			if (ztailpacking && end > vi->i_size)
605*33b1fccfSAndroid Build Coastguard Worker 				end = vi->i_size;
606*33b1fccfSAndroid Build Coastguard Worker 			break;
607*33b1fccfSAndroid Build Coastguard Worker 		}
608*33b1fccfSAndroid Build Coastguard Worker 		/* m.lcn should be >= 1 if endoff < m.clusterofs */
609*33b1fccfSAndroid Build Coastguard Worker 		if (!m.lcn) {
610*33b1fccfSAndroid Build Coastguard Worker 			erofs_err("invalid logical cluster 0 at nid %llu",
611*33b1fccfSAndroid Build Coastguard Worker 				  (unsigned long long)vi->nid);
612*33b1fccfSAndroid Build Coastguard Worker 			err = -EFSCORRUPTED;
613*33b1fccfSAndroid Build Coastguard Worker 			goto out;
614*33b1fccfSAndroid Build Coastguard Worker 		}
615*33b1fccfSAndroid Build Coastguard Worker 		end = (m.lcn << lclusterbits) | m.clusterofs;
616*33b1fccfSAndroid Build Coastguard Worker 		map->m_flags |= EROFS_MAP_FULL_MAPPED;
617*33b1fccfSAndroid Build Coastguard Worker 		m.delta[0] = 1;
618*33b1fccfSAndroid Build Coastguard Worker 		/* fallthrough */
619*33b1fccfSAndroid Build Coastguard Worker 	case Z_EROFS_LCLUSTER_TYPE_NONHEAD:
620*33b1fccfSAndroid Build Coastguard Worker 		/* get the correspoinding first chunk */
621*33b1fccfSAndroid Build Coastguard Worker 		err = z_erofs_extent_lookback(&m, m.delta[0]);
622*33b1fccfSAndroid Build Coastguard Worker 		if (err)
623*33b1fccfSAndroid Build Coastguard Worker 			goto out;
624*33b1fccfSAndroid Build Coastguard Worker 		break;
625*33b1fccfSAndroid Build Coastguard Worker 	default:
626*33b1fccfSAndroid Build Coastguard Worker 		erofs_err("unknown type %u @ offset %llu of nid %llu",
627*33b1fccfSAndroid Build Coastguard Worker 			  m.type, ofs, (unsigned long long)vi->nid);
628*33b1fccfSAndroid Build Coastguard Worker 		err = -EOPNOTSUPP;
629*33b1fccfSAndroid Build Coastguard Worker 		goto out;
630*33b1fccfSAndroid Build Coastguard Worker 	}
631*33b1fccfSAndroid Build Coastguard Worker 	if (m.partialref)
632*33b1fccfSAndroid Build Coastguard Worker 		map->m_flags |= EROFS_MAP_PARTIAL_REF;
633*33b1fccfSAndroid Build Coastguard Worker 	map->m_llen = end - map->m_la;
634*33b1fccfSAndroid Build Coastguard Worker 	if (flags & EROFS_GET_BLOCKS_FINDTAIL) {
635*33b1fccfSAndroid Build Coastguard Worker 		vi->z_tailextent_headlcn = m.lcn;
636*33b1fccfSAndroid Build Coastguard Worker 		/* for non-compact indexes, fragmentoff is 64 bits */
637*33b1fccfSAndroid Build Coastguard Worker 		if (fragment && vi->datalayout == EROFS_INODE_COMPRESSED_FULL)
638*33b1fccfSAndroid Build Coastguard Worker 			vi->fragmentoff |= (u64)m.pblk << 32;
639*33b1fccfSAndroid Build Coastguard Worker 	}
640*33b1fccfSAndroid Build Coastguard Worker 	if (ztailpacking && m.lcn == vi->z_tailextent_headlcn) {
641*33b1fccfSAndroid Build Coastguard Worker 		map->m_flags |= EROFS_MAP_META;
642*33b1fccfSAndroid Build Coastguard Worker 		map->m_pa = vi->z_idataoff;
643*33b1fccfSAndroid Build Coastguard Worker 		map->m_plen = vi->z_idata_size;
644*33b1fccfSAndroid Build Coastguard Worker 	} else if (fragment && m.lcn == vi->z_tailextent_headlcn) {
645*33b1fccfSAndroid Build Coastguard Worker 		map->m_flags |= EROFS_MAP_FRAGMENT;
646*33b1fccfSAndroid Build Coastguard Worker 	} else {
647*33b1fccfSAndroid Build Coastguard Worker 		map->m_pa = erofs_pos(sbi, m.pblk);
648*33b1fccfSAndroid Build Coastguard Worker 		err = z_erofs_get_extent_compressedlen(&m, initial_lcn);
649*33b1fccfSAndroid Build Coastguard Worker 		if (err)
650*33b1fccfSAndroid Build Coastguard Worker 			goto out;
651*33b1fccfSAndroid Build Coastguard Worker 	}
652*33b1fccfSAndroid Build Coastguard Worker 
653*33b1fccfSAndroid Build Coastguard Worker 	if (m.headtype == Z_EROFS_LCLUSTER_TYPE_PLAIN) {
654*33b1fccfSAndroid Build Coastguard Worker 		if (map->m_llen > map->m_plen) {
655*33b1fccfSAndroid Build Coastguard Worker 			DBG_BUGON(1);
656*33b1fccfSAndroid Build Coastguard Worker 			err = -EFSCORRUPTED;
657*33b1fccfSAndroid Build Coastguard Worker 			goto out;
658*33b1fccfSAndroid Build Coastguard Worker 		}
659*33b1fccfSAndroid Build Coastguard Worker 		if (vi->z_advise & Z_EROFS_ADVISE_INTERLACED_PCLUSTER)
660*33b1fccfSAndroid Build Coastguard Worker 			map->m_algorithmformat =
661*33b1fccfSAndroid Build Coastguard Worker 				Z_EROFS_COMPRESSION_INTERLACED;
662*33b1fccfSAndroid Build Coastguard Worker 		else
663*33b1fccfSAndroid Build Coastguard Worker 			map->m_algorithmformat =
664*33b1fccfSAndroid Build Coastguard Worker 				Z_EROFS_COMPRESSION_SHIFTED;
665*33b1fccfSAndroid Build Coastguard Worker 	} else {
666*33b1fccfSAndroid Build Coastguard Worker 		map->m_algorithmformat = vi->z_algorithmtype[0];
667*33b1fccfSAndroid Build Coastguard Worker 	}
668*33b1fccfSAndroid Build Coastguard Worker 
669*33b1fccfSAndroid Build Coastguard Worker 	if (flags & EROFS_GET_BLOCKS_FIEMAP) {
670*33b1fccfSAndroid Build Coastguard Worker 		err = z_erofs_get_extent_decompressedlen(&m);
671*33b1fccfSAndroid Build Coastguard Worker 		if (!err)
672*33b1fccfSAndroid Build Coastguard Worker 			map->m_flags |= EROFS_MAP_FULL_MAPPED;
673*33b1fccfSAndroid Build Coastguard Worker 	}
674*33b1fccfSAndroid Build Coastguard Worker 
675*33b1fccfSAndroid Build Coastguard Worker out:
676*33b1fccfSAndroid Build Coastguard Worker 	erofs_dbg("m_la %" PRIu64 " m_pa %" PRIu64 " m_llen %" PRIu64 " m_plen %" PRIu64 " m_flags 0%o",
677*33b1fccfSAndroid Build Coastguard Worker 		  map->m_la, map->m_pa,
678*33b1fccfSAndroid Build Coastguard Worker 		  map->m_llen, map->m_plen, map->m_flags);
679*33b1fccfSAndroid Build Coastguard Worker 	return err;
680*33b1fccfSAndroid Build Coastguard Worker }
681*33b1fccfSAndroid Build Coastguard Worker 
z_erofs_map_blocks_iter(struct erofs_inode * vi,struct erofs_map_blocks * map,int flags)682*33b1fccfSAndroid Build Coastguard Worker int z_erofs_map_blocks_iter(struct erofs_inode *vi,
683*33b1fccfSAndroid Build Coastguard Worker 			    struct erofs_map_blocks *map,
684*33b1fccfSAndroid Build Coastguard Worker 			    int flags)
685*33b1fccfSAndroid Build Coastguard Worker {
686*33b1fccfSAndroid Build Coastguard Worker 	int err = 0;
687*33b1fccfSAndroid Build Coastguard Worker 
688*33b1fccfSAndroid Build Coastguard Worker 	/* when trying to read beyond EOF, leave it unmapped */
689*33b1fccfSAndroid Build Coastguard Worker 	if (map->m_la >= vi->i_size) {
690*33b1fccfSAndroid Build Coastguard Worker 		map->m_llen = map->m_la + 1 - vi->i_size;
691*33b1fccfSAndroid Build Coastguard Worker 		map->m_la = vi->i_size;
692*33b1fccfSAndroid Build Coastguard Worker 		map->m_flags = 0;
693*33b1fccfSAndroid Build Coastguard Worker 		goto out;
694*33b1fccfSAndroid Build Coastguard Worker 	}
695*33b1fccfSAndroid Build Coastguard Worker 
696*33b1fccfSAndroid Build Coastguard Worker 	err = z_erofs_fill_inode_lazy(vi);
697*33b1fccfSAndroid Build Coastguard Worker 	if (err)
698*33b1fccfSAndroid Build Coastguard Worker 		goto out;
699*33b1fccfSAndroid Build Coastguard Worker 
700*33b1fccfSAndroid Build Coastguard Worker 	if ((vi->z_advise & Z_EROFS_ADVISE_FRAGMENT_PCLUSTER) &&
701*33b1fccfSAndroid Build Coastguard Worker 	    !vi->z_tailextent_headlcn) {
702*33b1fccfSAndroid Build Coastguard Worker 		map->m_la = 0;
703*33b1fccfSAndroid Build Coastguard Worker 		map->m_llen = vi->i_size;
704*33b1fccfSAndroid Build Coastguard Worker 		map->m_flags = EROFS_MAP_MAPPED | EROFS_MAP_FULL_MAPPED |
705*33b1fccfSAndroid Build Coastguard Worker 				EROFS_MAP_FRAGMENT;
706*33b1fccfSAndroid Build Coastguard Worker 		goto out;
707*33b1fccfSAndroid Build Coastguard Worker 	}
708*33b1fccfSAndroid Build Coastguard Worker 
709*33b1fccfSAndroid Build Coastguard Worker 	err = z_erofs_do_map_blocks(vi, map, flags);
710*33b1fccfSAndroid Build Coastguard Worker out:
711*33b1fccfSAndroid Build Coastguard Worker 	DBG_BUGON(err < 0 && err != -ENOMEM);
712*33b1fccfSAndroid Build Coastguard Worker 	return err;
713*33b1fccfSAndroid Build Coastguard Worker }
714