xref: /aosp_15_r20/external/erofs-utils/lib/compress.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  * Copyright (C) 2018-2019 HUAWEI, Inc.
4*33b1fccfSAndroid Build Coastguard Worker  *             http://www.huawei.com/
5*33b1fccfSAndroid Build Coastguard Worker  * Created by Miao Xie <[email protected]>
6*33b1fccfSAndroid Build Coastguard Worker  * with heavy changes by Gao Xiang <[email protected]>
7*33b1fccfSAndroid Build Coastguard Worker  */
8*33b1fccfSAndroid Build Coastguard Worker #ifndef _LARGEFILE64_SOURCE
9*33b1fccfSAndroid Build Coastguard Worker #define _LARGEFILE64_SOURCE
10*33b1fccfSAndroid Build Coastguard Worker #endif
11*33b1fccfSAndroid Build Coastguard Worker #include <string.h>
12*33b1fccfSAndroid Build Coastguard Worker #include <stdlib.h>
13*33b1fccfSAndroid Build Coastguard Worker #include <unistd.h>
14*33b1fccfSAndroid Build Coastguard Worker #include "erofs/print.h"
15*33b1fccfSAndroid Build Coastguard Worker #include "erofs/cache.h"
16*33b1fccfSAndroid Build Coastguard Worker #include "erofs/compress.h"
17*33b1fccfSAndroid Build Coastguard Worker #include "erofs/dedupe.h"
18*33b1fccfSAndroid Build Coastguard Worker #include "compressor.h"
19*33b1fccfSAndroid Build Coastguard Worker #include "erofs/block_list.h"
20*33b1fccfSAndroid Build Coastguard Worker #include "erofs/compress_hints.h"
21*33b1fccfSAndroid Build Coastguard Worker #include "erofs/fragments.h"
22*33b1fccfSAndroid Build Coastguard Worker #ifdef EROFS_MT_ENABLED
23*33b1fccfSAndroid Build Coastguard Worker #include "erofs/workqueue.h"
24*33b1fccfSAndroid Build Coastguard Worker #endif
25*33b1fccfSAndroid Build Coastguard Worker 
26*33b1fccfSAndroid Build Coastguard Worker /* compressing configuration specified by users */
27*33b1fccfSAndroid Build Coastguard Worker struct erofs_compress_cfg {
28*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_compress handle;
29*33b1fccfSAndroid Build Coastguard Worker 	unsigned int algorithmtype;
30*33b1fccfSAndroid Build Coastguard Worker 	bool enable;
31*33b1fccfSAndroid Build Coastguard Worker } erofs_ccfg[EROFS_MAX_COMPR_CFGS];
32*33b1fccfSAndroid Build Coastguard Worker 
33*33b1fccfSAndroid Build Coastguard Worker struct z_erofs_extent_item {
34*33b1fccfSAndroid Build Coastguard Worker 	struct list_head list;
35*33b1fccfSAndroid Build Coastguard Worker 	struct z_erofs_inmem_extent e;
36*33b1fccfSAndroid Build Coastguard Worker };
37*33b1fccfSAndroid Build Coastguard Worker 
38*33b1fccfSAndroid Build Coastguard Worker struct z_erofs_compress_ictx {		/* inode context */
39*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_inode *inode;
40*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_compress_cfg *ccfg;
41*33b1fccfSAndroid Build Coastguard Worker 	int fd;
42*33b1fccfSAndroid Build Coastguard Worker 	u64 fpos;
43*33b1fccfSAndroid Build Coastguard Worker 
44*33b1fccfSAndroid Build Coastguard Worker 	u32 tof_chksum;
45*33b1fccfSAndroid Build Coastguard Worker 	bool fix_dedupedfrag;
46*33b1fccfSAndroid Build Coastguard Worker 	bool fragemitted;
47*33b1fccfSAndroid Build Coastguard Worker 
48*33b1fccfSAndroid Build Coastguard Worker 	/* fields for write indexes */
49*33b1fccfSAndroid Build Coastguard Worker 	u8 *metacur;
50*33b1fccfSAndroid Build Coastguard Worker 	struct list_head extents;
51*33b1fccfSAndroid Build Coastguard Worker 	u16 clusterofs;
52*33b1fccfSAndroid Build Coastguard Worker 
53*33b1fccfSAndroid Build Coastguard Worker 	int seg_num;
54*33b1fccfSAndroid Build Coastguard Worker 
55*33b1fccfSAndroid Build Coastguard Worker #if EROFS_MT_ENABLED
56*33b1fccfSAndroid Build Coastguard Worker 	pthread_mutex_t mutex;
57*33b1fccfSAndroid Build Coastguard Worker 	pthread_cond_t cond;
58*33b1fccfSAndroid Build Coastguard Worker 	int nfini;
59*33b1fccfSAndroid Build Coastguard Worker 
60*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_compress_work *mtworks;
61*33b1fccfSAndroid Build Coastguard Worker #endif
62*33b1fccfSAndroid Build Coastguard Worker };
63*33b1fccfSAndroid Build Coastguard Worker 
64*33b1fccfSAndroid Build Coastguard Worker struct z_erofs_compress_sctx {		/* segment context */
65*33b1fccfSAndroid Build Coastguard Worker 	struct z_erofs_compress_ictx *ictx;
66*33b1fccfSAndroid Build Coastguard Worker 
67*33b1fccfSAndroid Build Coastguard Worker 	u8 *queue;
68*33b1fccfSAndroid Build Coastguard Worker 	struct list_head extents;
69*33b1fccfSAndroid Build Coastguard Worker 	struct z_erofs_extent_item *pivot;
70*33b1fccfSAndroid Build Coastguard Worker 
71*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_compress *chandle;
72*33b1fccfSAndroid Build Coastguard Worker 	char *destbuf;
73*33b1fccfSAndroid Build Coastguard Worker 
74*33b1fccfSAndroid Build Coastguard Worker 	erofs_off_t remaining;
75*33b1fccfSAndroid Build Coastguard Worker 	unsigned int head, tail;
76*33b1fccfSAndroid Build Coastguard Worker 
77*33b1fccfSAndroid Build Coastguard Worker 	unsigned int pclustersize;
78*33b1fccfSAndroid Build Coastguard Worker 	erofs_blk_t blkaddr;		/* pointing to the next blkaddr */
79*33b1fccfSAndroid Build Coastguard Worker 	u16 clusterofs;
80*33b1fccfSAndroid Build Coastguard Worker 
81*33b1fccfSAndroid Build Coastguard Worker 	int seg_idx;
82*33b1fccfSAndroid Build Coastguard Worker 
83*33b1fccfSAndroid Build Coastguard Worker 	void *membuf;
84*33b1fccfSAndroid Build Coastguard Worker 	erofs_off_t memoff;
85*33b1fccfSAndroid Build Coastguard Worker };
86*33b1fccfSAndroid Build Coastguard Worker 
87*33b1fccfSAndroid Build Coastguard Worker #ifdef EROFS_MT_ENABLED
88*33b1fccfSAndroid Build Coastguard Worker struct erofs_compress_wq_tls {
89*33b1fccfSAndroid Build Coastguard Worker 	u8 *queue;
90*33b1fccfSAndroid Build Coastguard Worker 	char *destbuf;
91*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_compress_cfg *ccfg;
92*33b1fccfSAndroid Build Coastguard Worker };
93*33b1fccfSAndroid Build Coastguard Worker 
94*33b1fccfSAndroid Build Coastguard Worker struct erofs_compress_work {
95*33b1fccfSAndroid Build Coastguard Worker 	/* Note: struct erofs_work must be the first member */
96*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_work work;
97*33b1fccfSAndroid Build Coastguard Worker 	struct z_erofs_compress_sctx ctx;
98*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_compress_work *next;
99*33b1fccfSAndroid Build Coastguard Worker 
100*33b1fccfSAndroid Build Coastguard Worker 	unsigned int alg_id;
101*33b1fccfSAndroid Build Coastguard Worker 	char *alg_name;
102*33b1fccfSAndroid Build Coastguard Worker 	unsigned int comp_level;
103*33b1fccfSAndroid Build Coastguard Worker 	unsigned int dict_size;
104*33b1fccfSAndroid Build Coastguard Worker 
105*33b1fccfSAndroid Build Coastguard Worker 	int errcode;
106*33b1fccfSAndroid Build Coastguard Worker };
107*33b1fccfSAndroid Build Coastguard Worker 
108*33b1fccfSAndroid Build Coastguard Worker static struct {
109*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_workqueue wq;
110*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_compress_work *idle;
111*33b1fccfSAndroid Build Coastguard Worker 	pthread_mutex_t mutex;
112*33b1fccfSAndroid Build Coastguard Worker } z_erofs_mt_ctrl;
113*33b1fccfSAndroid Build Coastguard Worker #endif
114*33b1fccfSAndroid Build Coastguard Worker 
115*33b1fccfSAndroid Build Coastguard Worker static bool z_erofs_mt_enabled;
116*33b1fccfSAndroid Build Coastguard Worker 
117*33b1fccfSAndroid Build Coastguard Worker #define Z_EROFS_LEGACY_MAP_HEADER_SIZE	Z_EROFS_FULL_INDEX_ALIGN(0)
118*33b1fccfSAndroid Build Coastguard Worker 
z_erofs_write_indexes_final(struct z_erofs_compress_ictx * ctx)119*33b1fccfSAndroid Build Coastguard Worker static void z_erofs_write_indexes_final(struct z_erofs_compress_ictx *ctx)
120*33b1fccfSAndroid Build Coastguard Worker {
121*33b1fccfSAndroid Build Coastguard Worker 	const unsigned int type = Z_EROFS_LCLUSTER_TYPE_PLAIN;
122*33b1fccfSAndroid Build Coastguard Worker 	struct z_erofs_lcluster_index di;
123*33b1fccfSAndroid Build Coastguard Worker 
124*33b1fccfSAndroid Build Coastguard Worker 	if (!ctx->clusterofs)
125*33b1fccfSAndroid Build Coastguard Worker 		return;
126*33b1fccfSAndroid Build Coastguard Worker 
127*33b1fccfSAndroid Build Coastguard Worker 	di.di_clusterofs = cpu_to_le16(ctx->clusterofs);
128*33b1fccfSAndroid Build Coastguard Worker 	di.di_u.blkaddr = 0;
129*33b1fccfSAndroid Build Coastguard Worker 	di.di_advise = cpu_to_le16(type << Z_EROFS_LI_LCLUSTER_TYPE_BIT);
130*33b1fccfSAndroid Build Coastguard Worker 
131*33b1fccfSAndroid Build Coastguard Worker 	memcpy(ctx->metacur, &di, sizeof(di));
132*33b1fccfSAndroid Build Coastguard Worker 	ctx->metacur += sizeof(di);
133*33b1fccfSAndroid Build Coastguard Worker }
134*33b1fccfSAndroid Build Coastguard Worker 
z_erofs_write_extent(struct z_erofs_compress_ictx * ctx,struct z_erofs_inmem_extent * e)135*33b1fccfSAndroid Build Coastguard Worker static void z_erofs_write_extent(struct z_erofs_compress_ictx *ctx,
136*33b1fccfSAndroid Build Coastguard Worker 				 struct z_erofs_inmem_extent *e)
137*33b1fccfSAndroid Build Coastguard Worker {
138*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_inode *inode = ctx->inode;
139*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_sb_info *sbi = inode->sbi;
140*33b1fccfSAndroid Build Coastguard Worker 	unsigned int clusterofs = ctx->clusterofs;
141*33b1fccfSAndroid Build Coastguard Worker 	unsigned int count = e->length;
142*33b1fccfSAndroid Build Coastguard Worker 	unsigned int d0 = 0, d1 = (clusterofs + count) / erofs_blksiz(sbi);
143*33b1fccfSAndroid Build Coastguard Worker 	struct z_erofs_lcluster_index di;
144*33b1fccfSAndroid Build Coastguard Worker 	unsigned int type, advise;
145*33b1fccfSAndroid Build Coastguard Worker 
146*33b1fccfSAndroid Build Coastguard Worker 	DBG_BUGON(!count);
147*33b1fccfSAndroid Build Coastguard Worker 	di.di_clusterofs = cpu_to_le16(ctx->clusterofs);
148*33b1fccfSAndroid Build Coastguard Worker 
149*33b1fccfSAndroid Build Coastguard Worker 	/* whether the tail-end (un)compressed block or not */
150*33b1fccfSAndroid Build Coastguard Worker 	if (!d1) {
151*33b1fccfSAndroid Build Coastguard Worker 		/*
152*33b1fccfSAndroid Build Coastguard Worker 		 * A lcluster cannot have three parts with the middle one which
153*33b1fccfSAndroid Build Coastguard Worker 		 * is well-compressed for !ztailpacking cases.
154*33b1fccfSAndroid Build Coastguard Worker 		 */
155*33b1fccfSAndroid Build Coastguard Worker 		DBG_BUGON(!e->raw && !cfg.c_ztailpacking && !cfg.c_fragments);
156*33b1fccfSAndroid Build Coastguard Worker 		DBG_BUGON(e->partial);
157*33b1fccfSAndroid Build Coastguard Worker 		type = e->raw ? Z_EROFS_LCLUSTER_TYPE_PLAIN :
158*33b1fccfSAndroid Build Coastguard Worker 			Z_EROFS_LCLUSTER_TYPE_HEAD1;
159*33b1fccfSAndroid Build Coastguard Worker 		advise = type << Z_EROFS_LI_LCLUSTER_TYPE_BIT;
160*33b1fccfSAndroid Build Coastguard Worker 		di.di_advise = cpu_to_le16(advise);
161*33b1fccfSAndroid Build Coastguard Worker 
162*33b1fccfSAndroid Build Coastguard Worker 		if (inode->datalayout == EROFS_INODE_COMPRESSED_FULL &&
163*33b1fccfSAndroid Build Coastguard Worker 		    !e->compressedblks)
164*33b1fccfSAndroid Build Coastguard Worker 			di.di_u.blkaddr = cpu_to_le32(inode->fragmentoff >> 32);
165*33b1fccfSAndroid Build Coastguard Worker 		else
166*33b1fccfSAndroid Build Coastguard Worker 			di.di_u.blkaddr = cpu_to_le32(e->blkaddr);
167*33b1fccfSAndroid Build Coastguard Worker 		memcpy(ctx->metacur, &di, sizeof(di));
168*33b1fccfSAndroid Build Coastguard Worker 		ctx->metacur += sizeof(di);
169*33b1fccfSAndroid Build Coastguard Worker 
170*33b1fccfSAndroid Build Coastguard Worker 		/* don't add the final index if the tail-end block exists */
171*33b1fccfSAndroid Build Coastguard Worker 		ctx->clusterofs = 0;
172*33b1fccfSAndroid Build Coastguard Worker 		return;
173*33b1fccfSAndroid Build Coastguard Worker 	}
174*33b1fccfSAndroid Build Coastguard Worker 
175*33b1fccfSAndroid Build Coastguard Worker 	do {
176*33b1fccfSAndroid Build Coastguard Worker 		advise = 0;
177*33b1fccfSAndroid Build Coastguard Worker 		/* XXX: big pcluster feature should be per-inode */
178*33b1fccfSAndroid Build Coastguard Worker 		if (d0 == 1 && erofs_sb_has_big_pcluster(sbi)) {
179*33b1fccfSAndroid Build Coastguard Worker 			type = Z_EROFS_LCLUSTER_TYPE_NONHEAD;
180*33b1fccfSAndroid Build Coastguard Worker 			di.di_u.delta[0] = cpu_to_le16(e->compressedblks |
181*33b1fccfSAndroid Build Coastguard Worker 						       Z_EROFS_LI_D0_CBLKCNT);
182*33b1fccfSAndroid Build Coastguard Worker 			di.di_u.delta[1] = cpu_to_le16(d1);
183*33b1fccfSAndroid Build Coastguard Worker 		} else if (d0) {
184*33b1fccfSAndroid Build Coastguard Worker 			type = Z_EROFS_LCLUSTER_TYPE_NONHEAD;
185*33b1fccfSAndroid Build Coastguard Worker 
186*33b1fccfSAndroid Build Coastguard Worker 			/*
187*33b1fccfSAndroid Build Coastguard Worker 			 * If the |Z_EROFS_VLE_DI_D0_CBLKCNT| bit is set, parser
188*33b1fccfSAndroid Build Coastguard Worker 			 * will interpret |delta[0]| as size of pcluster, rather
189*33b1fccfSAndroid Build Coastguard Worker 			 * than distance to last head cluster. Normally this
190*33b1fccfSAndroid Build Coastguard Worker 			 * isn't a problem, because uncompressed extent size are
191*33b1fccfSAndroid Build Coastguard Worker 			 * below Z_EROFS_VLE_DI_D0_CBLKCNT * BLOCK_SIZE = 8MB.
192*33b1fccfSAndroid Build Coastguard Worker 			 * But with large pcluster it's possible to go over this
193*33b1fccfSAndroid Build Coastguard Worker 			 * number, resulting in corrupted compressed indices.
194*33b1fccfSAndroid Build Coastguard Worker 			 * To solve this, we replace d0 with
195*33b1fccfSAndroid Build Coastguard Worker 			 * Z_EROFS_VLE_DI_D0_CBLKCNT-1.
196*33b1fccfSAndroid Build Coastguard Worker 			 */
197*33b1fccfSAndroid Build Coastguard Worker 			if (d0 >= Z_EROFS_LI_D0_CBLKCNT)
198*33b1fccfSAndroid Build Coastguard Worker 				di.di_u.delta[0] = cpu_to_le16(
199*33b1fccfSAndroid Build Coastguard Worker 						Z_EROFS_LI_D0_CBLKCNT - 1);
200*33b1fccfSAndroid Build Coastguard Worker 			else
201*33b1fccfSAndroid Build Coastguard Worker 				di.di_u.delta[0] = cpu_to_le16(d0);
202*33b1fccfSAndroid Build Coastguard Worker 			di.di_u.delta[1] = cpu_to_le16(d1);
203*33b1fccfSAndroid Build Coastguard Worker 		} else {
204*33b1fccfSAndroid Build Coastguard Worker 			type = e->raw ? Z_EROFS_LCLUSTER_TYPE_PLAIN :
205*33b1fccfSAndroid Build Coastguard Worker 				Z_EROFS_LCLUSTER_TYPE_HEAD1;
206*33b1fccfSAndroid Build Coastguard Worker 
207*33b1fccfSAndroid Build Coastguard Worker 			if (inode->datalayout == EROFS_INODE_COMPRESSED_FULL &&
208*33b1fccfSAndroid Build Coastguard Worker 			    !e->compressedblks)
209*33b1fccfSAndroid Build Coastguard Worker 				di.di_u.blkaddr = cpu_to_le32(inode->fragmentoff >> 32);
210*33b1fccfSAndroid Build Coastguard Worker 			else
211*33b1fccfSAndroid Build Coastguard Worker 				di.di_u.blkaddr = cpu_to_le32(e->blkaddr);
212*33b1fccfSAndroid Build Coastguard Worker 
213*33b1fccfSAndroid Build Coastguard Worker 			if (e->partial) {
214*33b1fccfSAndroid Build Coastguard Worker 				DBG_BUGON(e->raw);
215*33b1fccfSAndroid Build Coastguard Worker 				advise |= Z_EROFS_LI_PARTIAL_REF;
216*33b1fccfSAndroid Build Coastguard Worker 			}
217*33b1fccfSAndroid Build Coastguard Worker 		}
218*33b1fccfSAndroid Build Coastguard Worker 		advise |= type << Z_EROFS_LI_LCLUSTER_TYPE_BIT;
219*33b1fccfSAndroid Build Coastguard Worker 		di.di_advise = cpu_to_le16(advise);
220*33b1fccfSAndroid Build Coastguard Worker 
221*33b1fccfSAndroid Build Coastguard Worker 		memcpy(ctx->metacur, &di, sizeof(di));
222*33b1fccfSAndroid Build Coastguard Worker 		ctx->metacur += sizeof(di);
223*33b1fccfSAndroid Build Coastguard Worker 
224*33b1fccfSAndroid Build Coastguard Worker 		count -= erofs_blksiz(sbi) - clusterofs;
225*33b1fccfSAndroid Build Coastguard Worker 		clusterofs = 0;
226*33b1fccfSAndroid Build Coastguard Worker 
227*33b1fccfSAndroid Build Coastguard Worker 		++d0;
228*33b1fccfSAndroid Build Coastguard Worker 		--d1;
229*33b1fccfSAndroid Build Coastguard Worker 	} while (clusterofs + count >= erofs_blksiz(sbi));
230*33b1fccfSAndroid Build Coastguard Worker 
231*33b1fccfSAndroid Build Coastguard Worker 	ctx->clusterofs = clusterofs + count;
232*33b1fccfSAndroid Build Coastguard Worker }
233*33b1fccfSAndroid Build Coastguard Worker 
z_erofs_write_indexes(struct z_erofs_compress_ictx * ctx)234*33b1fccfSAndroid Build Coastguard Worker static void z_erofs_write_indexes(struct z_erofs_compress_ictx *ctx)
235*33b1fccfSAndroid Build Coastguard Worker {
236*33b1fccfSAndroid Build Coastguard Worker 	struct z_erofs_extent_item *ei, *n;
237*33b1fccfSAndroid Build Coastguard Worker 
238*33b1fccfSAndroid Build Coastguard Worker 	ctx->clusterofs = 0;
239*33b1fccfSAndroid Build Coastguard Worker 	list_for_each_entry_safe(ei, n, &ctx->extents, list) {
240*33b1fccfSAndroid Build Coastguard Worker 		z_erofs_write_extent(ctx, &ei->e);
241*33b1fccfSAndroid Build Coastguard Worker 
242*33b1fccfSAndroid Build Coastguard Worker 		list_del(&ei->list);
243*33b1fccfSAndroid Build Coastguard Worker 		free(ei);
244*33b1fccfSAndroid Build Coastguard Worker 	}
245*33b1fccfSAndroid Build Coastguard Worker 	z_erofs_write_indexes_final(ctx);
246*33b1fccfSAndroid Build Coastguard Worker }
247*33b1fccfSAndroid Build Coastguard Worker 
z_erofs_need_refill(struct z_erofs_compress_sctx * ctx)248*33b1fccfSAndroid Build Coastguard Worker static bool z_erofs_need_refill(struct z_erofs_compress_sctx *ctx)
249*33b1fccfSAndroid Build Coastguard Worker {
250*33b1fccfSAndroid Build Coastguard Worker 	const bool final = !ctx->remaining;
251*33b1fccfSAndroid Build Coastguard Worker 	unsigned int qh_aligned, qh_after;
252*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_inode *inode = ctx->ictx->inode;
253*33b1fccfSAndroid Build Coastguard Worker 
254*33b1fccfSAndroid Build Coastguard Worker 	if (final || ctx->head < EROFS_CONFIG_COMPR_MAX_SZ)
255*33b1fccfSAndroid Build Coastguard Worker 		return false;
256*33b1fccfSAndroid Build Coastguard Worker 
257*33b1fccfSAndroid Build Coastguard Worker 	qh_aligned = round_down(ctx->head, erofs_blksiz(inode->sbi));
258*33b1fccfSAndroid Build Coastguard Worker 	qh_after = ctx->head - qh_aligned;
259*33b1fccfSAndroid Build Coastguard Worker 	memmove(ctx->queue, ctx->queue + qh_aligned, ctx->tail - qh_aligned);
260*33b1fccfSAndroid Build Coastguard Worker 	ctx->tail -= qh_aligned;
261*33b1fccfSAndroid Build Coastguard Worker 	ctx->head = qh_after;
262*33b1fccfSAndroid Build Coastguard Worker 	return true;
263*33b1fccfSAndroid Build Coastguard Worker }
264*33b1fccfSAndroid Build Coastguard Worker 
265*33b1fccfSAndroid Build Coastguard Worker static struct z_erofs_extent_item dummy_pivot = {
266*33b1fccfSAndroid Build Coastguard Worker 	.e.length = 0
267*33b1fccfSAndroid Build Coastguard Worker };
268*33b1fccfSAndroid Build Coastguard Worker 
z_erofs_commit_extent(struct z_erofs_compress_sctx * ctx,struct z_erofs_extent_item * ei)269*33b1fccfSAndroid Build Coastguard Worker static void z_erofs_commit_extent(struct z_erofs_compress_sctx *ctx,
270*33b1fccfSAndroid Build Coastguard Worker 				  struct z_erofs_extent_item *ei)
271*33b1fccfSAndroid Build Coastguard Worker {
272*33b1fccfSAndroid Build Coastguard Worker 	if (ei == &dummy_pivot)
273*33b1fccfSAndroid Build Coastguard Worker 		return;
274*33b1fccfSAndroid Build Coastguard Worker 
275*33b1fccfSAndroid Build Coastguard Worker 	list_add_tail(&ei->list, &ctx->extents);
276*33b1fccfSAndroid Build Coastguard Worker 	ctx->clusterofs = (ctx->clusterofs + ei->e.length) &
277*33b1fccfSAndroid Build Coastguard Worker 			  (erofs_blksiz(ctx->ictx->inode->sbi) - 1);
278*33b1fccfSAndroid Build Coastguard Worker }
279*33b1fccfSAndroid Build Coastguard Worker 
z_erofs_compress_dedupe(struct z_erofs_compress_sctx * ctx,unsigned int * len)280*33b1fccfSAndroid Build Coastguard Worker static int z_erofs_compress_dedupe(struct z_erofs_compress_sctx *ctx,
281*33b1fccfSAndroid Build Coastguard Worker 				   unsigned int *len)
282*33b1fccfSAndroid Build Coastguard Worker {
283*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_inode *inode = ctx->ictx->inode;
284*33b1fccfSAndroid Build Coastguard Worker 	const unsigned int lclustermask = (1 << inode->z_logical_clusterbits) - 1;
285*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_sb_info *sbi = inode->sbi;
286*33b1fccfSAndroid Build Coastguard Worker 	struct z_erofs_extent_item *ei = ctx->pivot;
287*33b1fccfSAndroid Build Coastguard Worker 
288*33b1fccfSAndroid Build Coastguard Worker 	if (!ei)
289*33b1fccfSAndroid Build Coastguard Worker 		return 0;
290*33b1fccfSAndroid Build Coastguard Worker 
291*33b1fccfSAndroid Build Coastguard Worker 	/*
292*33b1fccfSAndroid Build Coastguard Worker 	 * No need dedupe for packed inode since it is composed of
293*33b1fccfSAndroid Build Coastguard Worker 	 * fragments which have already been deduplicated.
294*33b1fccfSAndroid Build Coastguard Worker 	 */
295*33b1fccfSAndroid Build Coastguard Worker 	if (erofs_is_packed_inode(inode))
296*33b1fccfSAndroid Build Coastguard Worker 		goto out;
297*33b1fccfSAndroid Build Coastguard Worker 
298*33b1fccfSAndroid Build Coastguard Worker 	do {
299*33b1fccfSAndroid Build Coastguard Worker 		struct z_erofs_dedupe_ctx dctx = {
300*33b1fccfSAndroid Build Coastguard Worker 			.start = ctx->queue + ctx->head - ({ int rc;
301*33b1fccfSAndroid Build Coastguard Worker 				if (ei->e.length <= erofs_blksiz(sbi))
302*33b1fccfSAndroid Build Coastguard Worker 					rc = 0;
303*33b1fccfSAndroid Build Coastguard Worker 				else if (ei->e.length - erofs_blksiz(sbi) >= ctx->head)
304*33b1fccfSAndroid Build Coastguard Worker 					rc = ctx->head;
305*33b1fccfSAndroid Build Coastguard Worker 				else
306*33b1fccfSAndroid Build Coastguard Worker 					rc = ei->e.length - erofs_blksiz(sbi);
307*33b1fccfSAndroid Build Coastguard Worker 				rc; }),
308*33b1fccfSAndroid Build Coastguard Worker 			.end = ctx->queue + ctx->head + *len,
309*33b1fccfSAndroid Build Coastguard Worker 			.cur = ctx->queue + ctx->head,
310*33b1fccfSAndroid Build Coastguard Worker 		};
311*33b1fccfSAndroid Build Coastguard Worker 		int delta;
312*33b1fccfSAndroid Build Coastguard Worker 
313*33b1fccfSAndroid Build Coastguard Worker 		if (z_erofs_dedupe_match(&dctx))
314*33b1fccfSAndroid Build Coastguard Worker 			break;
315*33b1fccfSAndroid Build Coastguard Worker 
316*33b1fccfSAndroid Build Coastguard Worker 		DBG_BUGON(dctx.e.inlined);
317*33b1fccfSAndroid Build Coastguard Worker 		delta = ctx->queue + ctx->head - dctx.cur;
318*33b1fccfSAndroid Build Coastguard Worker 		/*
319*33b1fccfSAndroid Build Coastguard Worker 		 * For big pcluster dedupe, leave two indices at least to store
320*33b1fccfSAndroid Build Coastguard Worker 		 * CBLKCNT as the first step.  Even laterly, an one-block
321*33b1fccfSAndroid Build Coastguard Worker 		 * decompresssion could be done as another try in practice.
322*33b1fccfSAndroid Build Coastguard Worker 		 */
323*33b1fccfSAndroid Build Coastguard Worker 		if (dctx.e.compressedblks > 1 &&
324*33b1fccfSAndroid Build Coastguard Worker 		    ((ctx->clusterofs + ei->e.length - delta) & lclustermask) +
325*33b1fccfSAndroid Build Coastguard Worker 			dctx.e.length < 2 * (lclustermask + 1))
326*33b1fccfSAndroid Build Coastguard Worker 			break;
327*33b1fccfSAndroid Build Coastguard Worker 
328*33b1fccfSAndroid Build Coastguard Worker 		ctx->pivot = malloc(sizeof(struct z_erofs_extent_item));
329*33b1fccfSAndroid Build Coastguard Worker 		if (!ctx->pivot) {
330*33b1fccfSAndroid Build Coastguard Worker 			z_erofs_commit_extent(ctx, ei);
331*33b1fccfSAndroid Build Coastguard Worker 			return -ENOMEM;
332*33b1fccfSAndroid Build Coastguard Worker 		}
333*33b1fccfSAndroid Build Coastguard Worker 
334*33b1fccfSAndroid Build Coastguard Worker 		if (delta) {
335*33b1fccfSAndroid Build Coastguard Worker 			DBG_BUGON(delta < 0);
336*33b1fccfSAndroid Build Coastguard Worker 			DBG_BUGON(!ei->e.length);
337*33b1fccfSAndroid Build Coastguard Worker 
338*33b1fccfSAndroid Build Coastguard Worker 			/*
339*33b1fccfSAndroid Build Coastguard Worker 			 * For big pcluster dedupe, if we decide to shorten the
340*33b1fccfSAndroid Build Coastguard Worker 			 * previous big pcluster, make sure that the previous
341*33b1fccfSAndroid Build Coastguard Worker 			 * CBLKCNT is still kept.
342*33b1fccfSAndroid Build Coastguard Worker 			 */
343*33b1fccfSAndroid Build Coastguard Worker 			if (ei->e.compressedblks > 1 &&
344*33b1fccfSAndroid Build Coastguard Worker 			    (ctx->clusterofs & lclustermask) + ei->e.length
345*33b1fccfSAndroid Build Coastguard Worker 				- delta < 2 * (lclustermask + 1))
346*33b1fccfSAndroid Build Coastguard Worker 				break;
347*33b1fccfSAndroid Build Coastguard Worker 			ei->e.partial = true;
348*33b1fccfSAndroid Build Coastguard Worker 			ei->e.length -= delta;
349*33b1fccfSAndroid Build Coastguard Worker 		}
350*33b1fccfSAndroid Build Coastguard Worker 
351*33b1fccfSAndroid Build Coastguard Worker 		/* fall back to noncompact indexes for deduplication */
352*33b1fccfSAndroid Build Coastguard Worker 		inode->z_advise &= ~Z_EROFS_ADVISE_COMPACTED_2B;
353*33b1fccfSAndroid Build Coastguard Worker 		inode->datalayout = EROFS_INODE_COMPRESSED_FULL;
354*33b1fccfSAndroid Build Coastguard Worker 		erofs_sb_set_dedupe(sbi);
355*33b1fccfSAndroid Build Coastguard Worker 
356*33b1fccfSAndroid Build Coastguard Worker 		sbi->saved_by_deduplication +=
357*33b1fccfSAndroid Build Coastguard Worker 			dctx.e.compressedblks * erofs_blksiz(sbi);
358*33b1fccfSAndroid Build Coastguard Worker 		erofs_dbg("Dedupe %u %scompressed data (delta %d) to %u of %u blocks",
359*33b1fccfSAndroid Build Coastguard Worker 			  dctx.e.length, dctx.e.raw ? "un" : "",
360*33b1fccfSAndroid Build Coastguard Worker 			  delta, dctx.e.blkaddr, dctx.e.compressedblks);
361*33b1fccfSAndroid Build Coastguard Worker 
362*33b1fccfSAndroid Build Coastguard Worker 		z_erofs_commit_extent(ctx, ei);
363*33b1fccfSAndroid Build Coastguard Worker 		ei = ctx->pivot;
364*33b1fccfSAndroid Build Coastguard Worker 		init_list_head(&ei->list);
365*33b1fccfSAndroid Build Coastguard Worker 		ei->e = dctx.e;
366*33b1fccfSAndroid Build Coastguard Worker 
367*33b1fccfSAndroid Build Coastguard Worker 		ctx->head += dctx.e.length - delta;
368*33b1fccfSAndroid Build Coastguard Worker 		DBG_BUGON(*len < dctx.e.length - delta);
369*33b1fccfSAndroid Build Coastguard Worker 		*len -= dctx.e.length - delta;
370*33b1fccfSAndroid Build Coastguard Worker 
371*33b1fccfSAndroid Build Coastguard Worker 		if (z_erofs_need_refill(ctx))
372*33b1fccfSAndroid Build Coastguard Worker 			return 1;
373*33b1fccfSAndroid Build Coastguard Worker 	} while (*len);
374*33b1fccfSAndroid Build Coastguard Worker out:
375*33b1fccfSAndroid Build Coastguard Worker 	z_erofs_commit_extent(ctx, ei);
376*33b1fccfSAndroid Build Coastguard Worker 	ctx->pivot = NULL;
377*33b1fccfSAndroid Build Coastguard Worker 	return 0;
378*33b1fccfSAndroid Build Coastguard Worker }
379*33b1fccfSAndroid Build Coastguard Worker 
write_uncompressed_extent(struct z_erofs_compress_sctx * ctx,unsigned int len,char * dst)380*33b1fccfSAndroid Build Coastguard Worker static int write_uncompressed_extent(struct z_erofs_compress_sctx *ctx,
381*33b1fccfSAndroid Build Coastguard Worker 				     unsigned int len, char *dst)
382*33b1fccfSAndroid Build Coastguard Worker {
383*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_inode *inode = ctx->ictx->inode;
384*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_sb_info *sbi = inode->sbi;
385*33b1fccfSAndroid Build Coastguard Worker 	unsigned int count = min(erofs_blksiz(sbi), len);
386*33b1fccfSAndroid Build Coastguard Worker 	unsigned int interlaced_offset, rightpart;
387*33b1fccfSAndroid Build Coastguard Worker 	int ret;
388*33b1fccfSAndroid Build Coastguard Worker 
389*33b1fccfSAndroid Build Coastguard Worker 	/* write interlaced uncompressed data if needed */
390*33b1fccfSAndroid Build Coastguard Worker 	if (inode->z_advise & Z_EROFS_ADVISE_INTERLACED_PCLUSTER)
391*33b1fccfSAndroid Build Coastguard Worker 		interlaced_offset = ctx->clusterofs;
392*33b1fccfSAndroid Build Coastguard Worker 	else
393*33b1fccfSAndroid Build Coastguard Worker 		interlaced_offset = 0;
394*33b1fccfSAndroid Build Coastguard Worker 	rightpart = min(erofs_blksiz(sbi) - interlaced_offset, count);
395*33b1fccfSAndroid Build Coastguard Worker 
396*33b1fccfSAndroid Build Coastguard Worker 	memset(dst, 0, erofs_blksiz(sbi));
397*33b1fccfSAndroid Build Coastguard Worker 
398*33b1fccfSAndroid Build Coastguard Worker 	memcpy(dst + interlaced_offset, ctx->queue + ctx->head, rightpart);
399*33b1fccfSAndroid Build Coastguard Worker 	memcpy(dst, ctx->queue + ctx->head + rightpart, count - rightpart);
400*33b1fccfSAndroid Build Coastguard Worker 
401*33b1fccfSAndroid Build Coastguard Worker 	if (ctx->membuf) {
402*33b1fccfSAndroid Build Coastguard Worker 		erofs_dbg("Writing %u uncompressed data of %s", count,
403*33b1fccfSAndroid Build Coastguard Worker 			  inode->i_srcpath);
404*33b1fccfSAndroid Build Coastguard Worker 		memcpy(ctx->membuf + ctx->memoff, dst, erofs_blksiz(sbi));
405*33b1fccfSAndroid Build Coastguard Worker 		ctx->memoff += erofs_blksiz(sbi);
406*33b1fccfSAndroid Build Coastguard Worker 	} else {
407*33b1fccfSAndroid Build Coastguard Worker 		erofs_dbg("Writing %u uncompressed data to block %u", count,
408*33b1fccfSAndroid Build Coastguard Worker 			  ctx->blkaddr);
409*33b1fccfSAndroid Build Coastguard Worker 		ret = erofs_blk_write(sbi, dst, ctx->blkaddr, 1);
410*33b1fccfSAndroid Build Coastguard Worker 		if (ret)
411*33b1fccfSAndroid Build Coastguard Worker 			return ret;
412*33b1fccfSAndroid Build Coastguard Worker 	}
413*33b1fccfSAndroid Build Coastguard Worker 	return count;
414*33b1fccfSAndroid Build Coastguard Worker }
415*33b1fccfSAndroid Build Coastguard Worker 
z_erofs_get_max_pclustersize(struct erofs_inode * inode)416*33b1fccfSAndroid Build Coastguard Worker static unsigned int z_erofs_get_max_pclustersize(struct erofs_inode *inode)
417*33b1fccfSAndroid Build Coastguard Worker {
418*33b1fccfSAndroid Build Coastguard Worker 	if (erofs_is_packed_inode(inode)) {
419*33b1fccfSAndroid Build Coastguard Worker 		return cfg.c_mkfs_pclustersize_packed;
420*33b1fccfSAndroid Build Coastguard Worker #ifndef NDEBUG
421*33b1fccfSAndroid Build Coastguard Worker 	} else if (cfg.c_random_pclusterblks) {
422*33b1fccfSAndroid Build Coastguard Worker 		unsigned int pclusterblks =
423*33b1fccfSAndroid Build Coastguard Worker 			cfg.c_mkfs_pclustersize_max >> inode->sbi->blkszbits;
424*33b1fccfSAndroid Build Coastguard Worker 
425*33b1fccfSAndroid Build Coastguard Worker 		return (1 + rand() % pclusterblks) << inode->sbi->blkszbits;
426*33b1fccfSAndroid Build Coastguard Worker #endif
427*33b1fccfSAndroid Build Coastguard Worker 	} else if (cfg.c_compress_hints_file) {
428*33b1fccfSAndroid Build Coastguard Worker 		z_erofs_apply_compress_hints(inode);
429*33b1fccfSAndroid Build Coastguard Worker 		DBG_BUGON(!inode->z_physical_clusterblks);
430*33b1fccfSAndroid Build Coastguard Worker 		return inode->z_physical_clusterblks << inode->sbi->blkszbits;
431*33b1fccfSAndroid Build Coastguard Worker 	}
432*33b1fccfSAndroid Build Coastguard Worker 	return cfg.c_mkfs_pclustersize_def;
433*33b1fccfSAndroid Build Coastguard Worker }
434*33b1fccfSAndroid Build Coastguard Worker 
z_erofs_fill_inline_data(struct erofs_inode * inode,void * data,unsigned int len,bool raw)435*33b1fccfSAndroid Build Coastguard Worker static int z_erofs_fill_inline_data(struct erofs_inode *inode, void *data,
436*33b1fccfSAndroid Build Coastguard Worker 				    unsigned int len, bool raw)
437*33b1fccfSAndroid Build Coastguard Worker {
438*33b1fccfSAndroid Build Coastguard Worker 	inode->z_advise |= Z_EROFS_ADVISE_INLINE_PCLUSTER;
439*33b1fccfSAndroid Build Coastguard Worker 	inode->idata_size = len;
440*33b1fccfSAndroid Build Coastguard Worker 	inode->compressed_idata = !raw;
441*33b1fccfSAndroid Build Coastguard Worker 
442*33b1fccfSAndroid Build Coastguard Worker 	inode->idata = malloc(inode->idata_size);
443*33b1fccfSAndroid Build Coastguard Worker 	if (!inode->idata)
444*33b1fccfSAndroid Build Coastguard Worker 		return -ENOMEM;
445*33b1fccfSAndroid Build Coastguard Worker 	erofs_dbg("Recording %u %scompressed inline data",
446*33b1fccfSAndroid Build Coastguard Worker 		  inode->idata_size, raw ? "un" : "");
447*33b1fccfSAndroid Build Coastguard Worker 	memcpy(inode->idata, data, inode->idata_size);
448*33b1fccfSAndroid Build Coastguard Worker 	return len;
449*33b1fccfSAndroid Build Coastguard Worker }
450*33b1fccfSAndroid Build Coastguard Worker 
tryrecompress_trailing(struct z_erofs_compress_sctx * ctx,struct erofs_compress * ec,void * in,unsigned int * insize,void * out,unsigned int * compressedsize)451*33b1fccfSAndroid Build Coastguard Worker static void tryrecompress_trailing(struct z_erofs_compress_sctx *ctx,
452*33b1fccfSAndroid Build Coastguard Worker 				   struct erofs_compress *ec,
453*33b1fccfSAndroid Build Coastguard Worker 				   void *in, unsigned int *insize,
454*33b1fccfSAndroid Build Coastguard Worker 				   void *out, unsigned int *compressedsize)
455*33b1fccfSAndroid Build Coastguard Worker {
456*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_sb_info *sbi = ctx->ictx->inode->sbi;
457*33b1fccfSAndroid Build Coastguard Worker 	char tmp[Z_EROFS_PCLUSTER_MAX_SIZE];
458*33b1fccfSAndroid Build Coastguard Worker 	unsigned int count;
459*33b1fccfSAndroid Build Coastguard Worker 	int ret = *compressedsize;
460*33b1fccfSAndroid Build Coastguard Worker 
461*33b1fccfSAndroid Build Coastguard Worker 	/* no need to recompress */
462*33b1fccfSAndroid Build Coastguard Worker 	if (!(ret & (erofs_blksiz(sbi) - 1)))
463*33b1fccfSAndroid Build Coastguard Worker 		return;
464*33b1fccfSAndroid Build Coastguard Worker 
465*33b1fccfSAndroid Build Coastguard Worker 	count = *insize;
466*33b1fccfSAndroid Build Coastguard Worker 	ret = erofs_compress_destsize(ec, in, &count, (void *)tmp,
467*33b1fccfSAndroid Build Coastguard Worker 				      rounddown(ret, erofs_blksiz(sbi)));
468*33b1fccfSAndroid Build Coastguard Worker 	if (ret <= 0 || ret + (*insize - count) >=
469*33b1fccfSAndroid Build Coastguard Worker 			roundup(*compressedsize, erofs_blksiz(sbi)))
470*33b1fccfSAndroid Build Coastguard Worker 		return;
471*33b1fccfSAndroid Build Coastguard Worker 
472*33b1fccfSAndroid Build Coastguard Worker 	/* replace the original compressed data if any gain */
473*33b1fccfSAndroid Build Coastguard Worker 	memcpy(out, tmp, ret);
474*33b1fccfSAndroid Build Coastguard Worker 	*insize = count;
475*33b1fccfSAndroid Build Coastguard Worker 	*compressedsize = ret;
476*33b1fccfSAndroid Build Coastguard Worker }
477*33b1fccfSAndroid Build Coastguard Worker 
z_erofs_fixup_deduped_fragment(struct z_erofs_compress_sctx * ctx,unsigned int len)478*33b1fccfSAndroid Build Coastguard Worker static bool z_erofs_fixup_deduped_fragment(struct z_erofs_compress_sctx *ctx,
479*33b1fccfSAndroid Build Coastguard Worker 					   unsigned int len)
480*33b1fccfSAndroid Build Coastguard Worker {
481*33b1fccfSAndroid Build Coastguard Worker 	struct z_erofs_compress_ictx *ictx = ctx->ictx;
482*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_inode *inode = ictx->inode;
483*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_sb_info *sbi = inode->sbi;
484*33b1fccfSAndroid Build Coastguard Worker 	const unsigned int newsize = ctx->remaining + len;
485*33b1fccfSAndroid Build Coastguard Worker 
486*33b1fccfSAndroid Build Coastguard Worker 	DBG_BUGON(!inode->fragment_size);
487*33b1fccfSAndroid Build Coastguard Worker 
488*33b1fccfSAndroid Build Coastguard Worker 	/* try to fix again if it gets larger (should be rare) */
489*33b1fccfSAndroid Build Coastguard Worker 	if (inode->fragment_size < newsize) {
490*33b1fccfSAndroid Build Coastguard Worker 		ctx->pclustersize = min_t(erofs_off_t,
491*33b1fccfSAndroid Build Coastguard Worker 				z_erofs_get_max_pclustersize(inode),
492*33b1fccfSAndroid Build Coastguard Worker 				roundup(newsize - inode->fragment_size,
493*33b1fccfSAndroid Build Coastguard Worker 					erofs_blksiz(sbi)));
494*33b1fccfSAndroid Build Coastguard Worker 		return false;
495*33b1fccfSAndroid Build Coastguard Worker 	}
496*33b1fccfSAndroid Build Coastguard Worker 
497*33b1fccfSAndroid Build Coastguard Worker 	inode->fragmentoff += inode->fragment_size - newsize;
498*33b1fccfSAndroid Build Coastguard Worker 	inode->fragment_size = newsize;
499*33b1fccfSAndroid Build Coastguard Worker 
500*33b1fccfSAndroid Build Coastguard Worker 	erofs_dbg("Reducing fragment size to %u at %llu",
501*33b1fccfSAndroid Build Coastguard Worker 		  inode->fragment_size, inode->fragmentoff | 0ULL);
502*33b1fccfSAndroid Build Coastguard Worker 
503*33b1fccfSAndroid Build Coastguard Worker 	/* it's the end */
504*33b1fccfSAndroid Build Coastguard Worker 	DBG_BUGON(ctx->tail - ctx->head + ctx->remaining != newsize);
505*33b1fccfSAndroid Build Coastguard Worker 	ctx->head = ctx->tail;
506*33b1fccfSAndroid Build Coastguard Worker 	ctx->remaining = 0;
507*33b1fccfSAndroid Build Coastguard Worker 	return true;
508*33b1fccfSAndroid Build Coastguard Worker }
509*33b1fccfSAndroid Build Coastguard Worker 
__z_erofs_compress_one(struct z_erofs_compress_sctx * ctx,struct z_erofs_inmem_extent * e)510*33b1fccfSAndroid Build Coastguard Worker static int __z_erofs_compress_one(struct z_erofs_compress_sctx *ctx,
511*33b1fccfSAndroid Build Coastguard Worker 				  struct z_erofs_inmem_extent *e)
512*33b1fccfSAndroid Build Coastguard Worker {
513*33b1fccfSAndroid Build Coastguard Worker 	static char g_dstbuf[EROFS_CONFIG_COMPR_MAX_SZ + EROFS_MAX_BLOCK_SIZE];
514*33b1fccfSAndroid Build Coastguard Worker 	char *dstbuf = ctx->destbuf ?: g_dstbuf;
515*33b1fccfSAndroid Build Coastguard Worker 	struct z_erofs_compress_ictx *ictx = ctx->ictx;
516*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_inode *inode = ictx->inode;
517*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_sb_info *sbi = inode->sbi;
518*33b1fccfSAndroid Build Coastguard Worker 	unsigned int blksz = erofs_blksiz(sbi);
519*33b1fccfSAndroid Build Coastguard Worker 	char *const dst = dstbuf + blksz;
520*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_compress *const h = ctx->chandle;
521*33b1fccfSAndroid Build Coastguard Worker 	unsigned int len = ctx->tail - ctx->head;
522*33b1fccfSAndroid Build Coastguard Worker 	bool is_packed_inode = erofs_is_packed_inode(inode);
523*33b1fccfSAndroid Build Coastguard Worker 	bool tsg = (ctx->seg_idx + 1 >= ictx->seg_num), final = !ctx->remaining;
524*33b1fccfSAndroid Build Coastguard Worker 	bool may_packing = (cfg.c_fragments && tsg && final &&
525*33b1fccfSAndroid Build Coastguard Worker 			    !is_packed_inode && !z_erofs_mt_enabled);
526*33b1fccfSAndroid Build Coastguard Worker 	bool may_inline = (cfg.c_ztailpacking && tsg && final && !may_packing);
527*33b1fccfSAndroid Build Coastguard Worker 	unsigned int compressedsize;
528*33b1fccfSAndroid Build Coastguard Worker 	int ret;
529*33b1fccfSAndroid Build Coastguard Worker 
530*33b1fccfSAndroid Build Coastguard Worker 	*e = (struct z_erofs_inmem_extent){};
531*33b1fccfSAndroid Build Coastguard Worker 	if (len <= ctx->pclustersize) {
532*33b1fccfSAndroid Build Coastguard Worker 		if (!final || !len)
533*33b1fccfSAndroid Build Coastguard Worker 			return 1;
534*33b1fccfSAndroid Build Coastguard Worker 		if (inode->fragment_size && !ictx->fix_dedupedfrag) {
535*33b1fccfSAndroid Build Coastguard Worker 			ctx->pclustersize = roundup(len, blksz);
536*33b1fccfSAndroid Build Coastguard Worker 			goto fix_dedupedfrag;
537*33b1fccfSAndroid Build Coastguard Worker 		}
538*33b1fccfSAndroid Build Coastguard Worker 		if (may_packing) {
539*33b1fccfSAndroid Build Coastguard Worker 			e->length = len;
540*33b1fccfSAndroid Build Coastguard Worker 			goto frag_packing;
541*33b1fccfSAndroid Build Coastguard Worker 		}
542*33b1fccfSAndroid Build Coastguard Worker 		if (!may_inline && len <= blksz)
543*33b1fccfSAndroid Build Coastguard Worker 			goto nocompression;
544*33b1fccfSAndroid Build Coastguard Worker 	}
545*33b1fccfSAndroid Build Coastguard Worker 
546*33b1fccfSAndroid Build Coastguard Worker 	e->length = min(len, cfg.c_max_decompressed_extent_bytes);
547*33b1fccfSAndroid Build Coastguard Worker 	ret = erofs_compress_destsize(h, ctx->queue + ctx->head,
548*33b1fccfSAndroid Build Coastguard Worker 				      &e->length, dst, ctx->pclustersize);
549*33b1fccfSAndroid Build Coastguard Worker 	if (ret <= 0) {
550*33b1fccfSAndroid Build Coastguard Worker 		erofs_err("failed to compress %s: %s", inode->i_srcpath,
551*33b1fccfSAndroid Build Coastguard Worker 			  erofs_strerror(ret));
552*33b1fccfSAndroid Build Coastguard Worker 		return ret;
553*33b1fccfSAndroid Build Coastguard Worker 	}
554*33b1fccfSAndroid Build Coastguard Worker 
555*33b1fccfSAndroid Build Coastguard Worker 	compressedsize = ret;
556*33b1fccfSAndroid Build Coastguard Worker 	/* even compressed size is smaller, there is no real gain */
557*33b1fccfSAndroid Build Coastguard Worker 	if (!(may_inline && e->length == len && ret < blksz))
558*33b1fccfSAndroid Build Coastguard Worker 		ret = roundup(ret, blksz);
559*33b1fccfSAndroid Build Coastguard Worker 
560*33b1fccfSAndroid Build Coastguard Worker 	/* check if there is enough gain to keep the compressed data */
561*33b1fccfSAndroid Build Coastguard Worker 	if (ret * h->compress_threshold / 100 >= e->length) {
562*33b1fccfSAndroid Build Coastguard Worker 		if (may_inline && len < blksz) {
563*33b1fccfSAndroid Build Coastguard Worker 			ret = z_erofs_fill_inline_data(inode,
564*33b1fccfSAndroid Build Coastguard Worker 					ctx->queue + ctx->head, len, true);
565*33b1fccfSAndroid Build Coastguard Worker 			if (ret < 0)
566*33b1fccfSAndroid Build Coastguard Worker 				return ret;
567*33b1fccfSAndroid Build Coastguard Worker 			e->inlined = true;
568*33b1fccfSAndroid Build Coastguard Worker 		} else {
569*33b1fccfSAndroid Build Coastguard Worker 			may_inline = false;
570*33b1fccfSAndroid Build Coastguard Worker 			may_packing = false;
571*33b1fccfSAndroid Build Coastguard Worker nocompression:
572*33b1fccfSAndroid Build Coastguard Worker 			/* TODO: reset clusterofs to 0 if permitted */
573*33b1fccfSAndroid Build Coastguard Worker 			ret = write_uncompressed_extent(ctx, len, dst);
574*33b1fccfSAndroid Build Coastguard Worker 			if (ret < 0)
575*33b1fccfSAndroid Build Coastguard Worker 				return ret;
576*33b1fccfSAndroid Build Coastguard Worker 		}
577*33b1fccfSAndroid Build Coastguard Worker 		e->length = ret;
578*33b1fccfSAndroid Build Coastguard Worker 
579*33b1fccfSAndroid Build Coastguard Worker 		/*
580*33b1fccfSAndroid Build Coastguard Worker 		 * XXX: For now, we have to leave `ctx->compressedblk = 1'
581*33b1fccfSAndroid Build Coastguard Worker 		 * since there is no way to generate compressed indexes after
582*33b1fccfSAndroid Build Coastguard Worker 		 * the time that ztailpacking is decided.
583*33b1fccfSAndroid Build Coastguard Worker 		 */
584*33b1fccfSAndroid Build Coastguard Worker 		e->compressedblks = 1;
585*33b1fccfSAndroid Build Coastguard Worker 		e->raw = true;
586*33b1fccfSAndroid Build Coastguard Worker 	} else if (may_packing && len == e->length &&
587*33b1fccfSAndroid Build Coastguard Worker 		   compressedsize < ctx->pclustersize &&
588*33b1fccfSAndroid Build Coastguard Worker 		   (!inode->fragment_size || ictx->fix_dedupedfrag)) {
589*33b1fccfSAndroid Build Coastguard Worker frag_packing:
590*33b1fccfSAndroid Build Coastguard Worker 		ret = z_erofs_pack_fragments(inode, ctx->queue + ctx->head,
591*33b1fccfSAndroid Build Coastguard Worker 					     len, ictx->tof_chksum);
592*33b1fccfSAndroid Build Coastguard Worker 		if (ret < 0)
593*33b1fccfSAndroid Build Coastguard Worker 			return ret;
594*33b1fccfSAndroid Build Coastguard Worker 		e->compressedblks = 0; /* indicate a fragment */
595*33b1fccfSAndroid Build Coastguard Worker 		e->raw = false;
596*33b1fccfSAndroid Build Coastguard Worker 		ictx->fragemitted = true;
597*33b1fccfSAndroid Build Coastguard Worker 	/* tailpcluster should be less than 1 block */
598*33b1fccfSAndroid Build Coastguard Worker 	} else if (may_inline && len == e->length && compressedsize < blksz) {
599*33b1fccfSAndroid Build Coastguard Worker 		if (ctx->clusterofs + len <= blksz) {
600*33b1fccfSAndroid Build Coastguard Worker 			inode->eof_tailraw = malloc(len);
601*33b1fccfSAndroid Build Coastguard Worker 			if (!inode->eof_tailraw)
602*33b1fccfSAndroid Build Coastguard Worker 				return -ENOMEM;
603*33b1fccfSAndroid Build Coastguard Worker 
604*33b1fccfSAndroid Build Coastguard Worker 			memcpy(inode->eof_tailraw, ctx->queue + ctx->head, len);
605*33b1fccfSAndroid Build Coastguard Worker 			inode->eof_tailrawsize = len;
606*33b1fccfSAndroid Build Coastguard Worker 		}
607*33b1fccfSAndroid Build Coastguard Worker 
608*33b1fccfSAndroid Build Coastguard Worker 		ret = z_erofs_fill_inline_data(inode, dst,
609*33b1fccfSAndroid Build Coastguard Worker 				compressedsize, false);
610*33b1fccfSAndroid Build Coastguard Worker 		if (ret < 0)
611*33b1fccfSAndroid Build Coastguard Worker 			return ret;
612*33b1fccfSAndroid Build Coastguard Worker 		e->inlined = true;
613*33b1fccfSAndroid Build Coastguard Worker 		e->compressedblks = 1;
614*33b1fccfSAndroid Build Coastguard Worker 		e->raw = false;
615*33b1fccfSAndroid Build Coastguard Worker 	} else {
616*33b1fccfSAndroid Build Coastguard Worker 		unsigned int tailused, padding;
617*33b1fccfSAndroid Build Coastguard Worker 
618*33b1fccfSAndroid Build Coastguard Worker 		/*
619*33b1fccfSAndroid Build Coastguard Worker 		 * If there's space left for the last round when deduping
620*33b1fccfSAndroid Build Coastguard Worker 		 * fragments, try to read the fragment and recompress a little
621*33b1fccfSAndroid Build Coastguard Worker 		 * more to check whether it can be filled up.  Fix the fragment
622*33b1fccfSAndroid Build Coastguard Worker 		 * if succeeds.  Otherwise, just drop it and go on packing.
623*33b1fccfSAndroid Build Coastguard Worker 		 */
624*33b1fccfSAndroid Build Coastguard Worker 		if (may_packing && len == e->length &&
625*33b1fccfSAndroid Build Coastguard Worker 		    (compressedsize & (blksz - 1)) &&
626*33b1fccfSAndroid Build Coastguard Worker 		    ctx->tail < Z_EROFS_COMPR_QUEUE_SZ) {
627*33b1fccfSAndroid Build Coastguard Worker 			ctx->pclustersize = roundup(compressedsize, blksz);
628*33b1fccfSAndroid Build Coastguard Worker 			goto fix_dedupedfrag;
629*33b1fccfSAndroid Build Coastguard Worker 		}
630*33b1fccfSAndroid Build Coastguard Worker 
631*33b1fccfSAndroid Build Coastguard Worker 		if (may_inline && len == e->length)
632*33b1fccfSAndroid Build Coastguard Worker 			tryrecompress_trailing(ctx, h, ctx->queue + ctx->head,
633*33b1fccfSAndroid Build Coastguard Worker 					&e->length, dst, &compressedsize);
634*33b1fccfSAndroid Build Coastguard Worker 
635*33b1fccfSAndroid Build Coastguard Worker 		e->compressedblks = BLK_ROUND_UP(sbi, compressedsize);
636*33b1fccfSAndroid Build Coastguard Worker 		DBG_BUGON(e->compressedblks * blksz >= e->length);
637*33b1fccfSAndroid Build Coastguard Worker 
638*33b1fccfSAndroid Build Coastguard Worker 		padding = 0;
639*33b1fccfSAndroid Build Coastguard Worker 		tailused = compressedsize & (blksz - 1);
640*33b1fccfSAndroid Build Coastguard Worker 		if (tailused)
641*33b1fccfSAndroid Build Coastguard Worker 			padding = blksz - tailused;
642*33b1fccfSAndroid Build Coastguard Worker 
643*33b1fccfSAndroid Build Coastguard Worker 		/* zero out garbage trailing data for non-0padding */
644*33b1fccfSAndroid Build Coastguard Worker 		if (!erofs_sb_has_lz4_0padding(sbi)) {
645*33b1fccfSAndroid Build Coastguard Worker 			memset(dst + compressedsize, 0, padding);
646*33b1fccfSAndroid Build Coastguard Worker 			padding = 0;
647*33b1fccfSAndroid Build Coastguard Worker 		}
648*33b1fccfSAndroid Build Coastguard Worker 
649*33b1fccfSAndroid Build Coastguard Worker 		/* write compressed data */
650*33b1fccfSAndroid Build Coastguard Worker 		if (ctx->membuf) {
651*33b1fccfSAndroid Build Coastguard Worker 			erofs_dbg("Writing %u compressed data of %u blocks of %s",
652*33b1fccfSAndroid Build Coastguard Worker 				  e->length, e->compressedblks, inode->i_srcpath);
653*33b1fccfSAndroid Build Coastguard Worker 
654*33b1fccfSAndroid Build Coastguard Worker 			memcpy(ctx->membuf + ctx->memoff, dst - padding,
655*33b1fccfSAndroid Build Coastguard Worker 			       e->compressedblks * blksz);
656*33b1fccfSAndroid Build Coastguard Worker 			ctx->memoff += e->compressedblks * blksz;
657*33b1fccfSAndroid Build Coastguard Worker 		} else {
658*33b1fccfSAndroid Build Coastguard Worker 			erofs_dbg("Writing %u compressed data to %u of %u blocks",
659*33b1fccfSAndroid Build Coastguard Worker 				  e->length, ctx->blkaddr, e->compressedblks);
660*33b1fccfSAndroid Build Coastguard Worker 
661*33b1fccfSAndroid Build Coastguard Worker 			ret = erofs_blk_write(sbi, dst - padding, ctx->blkaddr,
662*33b1fccfSAndroid Build Coastguard Worker 					      e->compressedblks);
663*33b1fccfSAndroid Build Coastguard Worker 			if (ret)
664*33b1fccfSAndroid Build Coastguard Worker 				return ret;
665*33b1fccfSAndroid Build Coastguard Worker 		}
666*33b1fccfSAndroid Build Coastguard Worker 		e->raw = false;
667*33b1fccfSAndroid Build Coastguard Worker 		may_inline = false;
668*33b1fccfSAndroid Build Coastguard Worker 		may_packing = false;
669*33b1fccfSAndroid Build Coastguard Worker 	}
670*33b1fccfSAndroid Build Coastguard Worker 	e->partial = false;
671*33b1fccfSAndroid Build Coastguard Worker 	e->blkaddr = ctx->blkaddr;
672*33b1fccfSAndroid Build Coastguard Worker 	if (ctx->blkaddr != EROFS_NULL_ADDR)
673*33b1fccfSAndroid Build Coastguard Worker 		ctx->blkaddr += e->compressedblks;
674*33b1fccfSAndroid Build Coastguard Worker 	if (!may_inline && !may_packing && !is_packed_inode)
675*33b1fccfSAndroid Build Coastguard Worker 		(void)z_erofs_dedupe_insert(e, ctx->queue + ctx->head);
676*33b1fccfSAndroid Build Coastguard Worker 	ctx->head += e->length;
677*33b1fccfSAndroid Build Coastguard Worker 	return 0;
678*33b1fccfSAndroid Build Coastguard Worker 
679*33b1fccfSAndroid Build Coastguard Worker fix_dedupedfrag:
680*33b1fccfSAndroid Build Coastguard Worker 	DBG_BUGON(!inode->fragment_size);
681*33b1fccfSAndroid Build Coastguard Worker 	ctx->remaining += inode->fragment_size;
682*33b1fccfSAndroid Build Coastguard Worker 	ictx->fix_dedupedfrag = true;
683*33b1fccfSAndroid Build Coastguard Worker 	return 1;
684*33b1fccfSAndroid Build Coastguard Worker }
685*33b1fccfSAndroid Build Coastguard Worker 
z_erofs_compress_one(struct z_erofs_compress_sctx * ctx)686*33b1fccfSAndroid Build Coastguard Worker static int z_erofs_compress_one(struct z_erofs_compress_sctx *ctx)
687*33b1fccfSAndroid Build Coastguard Worker {
688*33b1fccfSAndroid Build Coastguard Worker 	struct z_erofs_compress_ictx *ictx = ctx->ictx;
689*33b1fccfSAndroid Build Coastguard Worker 	unsigned int len = ctx->tail - ctx->head;
690*33b1fccfSAndroid Build Coastguard Worker 	struct z_erofs_extent_item *ei;
691*33b1fccfSAndroid Build Coastguard Worker 
692*33b1fccfSAndroid Build Coastguard Worker 	while (len) {
693*33b1fccfSAndroid Build Coastguard Worker 		int ret = z_erofs_compress_dedupe(ctx, &len);
694*33b1fccfSAndroid Build Coastguard Worker 
695*33b1fccfSAndroid Build Coastguard Worker 		if (ret > 0)
696*33b1fccfSAndroid Build Coastguard Worker 			break;
697*33b1fccfSAndroid Build Coastguard Worker 		else if (ret < 0)
698*33b1fccfSAndroid Build Coastguard Worker 			return ret;
699*33b1fccfSAndroid Build Coastguard Worker 
700*33b1fccfSAndroid Build Coastguard Worker 		DBG_BUGON(ctx->pivot);
701*33b1fccfSAndroid Build Coastguard Worker 		ei = malloc(sizeof(*ei));
702*33b1fccfSAndroid Build Coastguard Worker 		if (!ei)
703*33b1fccfSAndroid Build Coastguard Worker 			return -ENOMEM;
704*33b1fccfSAndroid Build Coastguard Worker 
705*33b1fccfSAndroid Build Coastguard Worker 		init_list_head(&ei->list);
706*33b1fccfSAndroid Build Coastguard Worker 		ret = __z_erofs_compress_one(ctx, &ei->e);
707*33b1fccfSAndroid Build Coastguard Worker 		if (ret) {
708*33b1fccfSAndroid Build Coastguard Worker 			free(ei);
709*33b1fccfSAndroid Build Coastguard Worker 			if (ret > 0)
710*33b1fccfSAndroid Build Coastguard Worker 				break;		/* need more data */
711*33b1fccfSAndroid Build Coastguard Worker 			return ret;
712*33b1fccfSAndroid Build Coastguard Worker 		}
713*33b1fccfSAndroid Build Coastguard Worker 
714*33b1fccfSAndroid Build Coastguard Worker 		len -= ei->e.length;
715*33b1fccfSAndroid Build Coastguard Worker 		ctx->pivot = ei;
716*33b1fccfSAndroid Build Coastguard Worker 		if (ictx->fix_dedupedfrag && !ictx->fragemitted &&
717*33b1fccfSAndroid Build Coastguard Worker 		    z_erofs_fixup_deduped_fragment(ctx, len))
718*33b1fccfSAndroid Build Coastguard Worker 			break;
719*33b1fccfSAndroid Build Coastguard Worker 
720*33b1fccfSAndroid Build Coastguard Worker 		if (z_erofs_need_refill(ctx))
721*33b1fccfSAndroid Build Coastguard Worker 			break;
722*33b1fccfSAndroid Build Coastguard Worker 	}
723*33b1fccfSAndroid Build Coastguard Worker 	return 0;
724*33b1fccfSAndroid Build Coastguard Worker }
725*33b1fccfSAndroid Build Coastguard Worker 
726*33b1fccfSAndroid Build Coastguard Worker struct z_erofs_compressindex_vec {
727*33b1fccfSAndroid Build Coastguard Worker 	union {
728*33b1fccfSAndroid Build Coastguard Worker 		erofs_blk_t blkaddr;
729*33b1fccfSAndroid Build Coastguard Worker 		u16 delta[2];
730*33b1fccfSAndroid Build Coastguard Worker 	} u;
731*33b1fccfSAndroid Build Coastguard Worker 	u16 clusterofs;
732*33b1fccfSAndroid Build Coastguard Worker 	u8  clustertype;
733*33b1fccfSAndroid Build Coastguard Worker };
734*33b1fccfSAndroid Build Coastguard Worker 
parse_legacy_indexes(struct z_erofs_compressindex_vec * cv,unsigned int nr,void * metacur)735*33b1fccfSAndroid Build Coastguard Worker static void *parse_legacy_indexes(struct z_erofs_compressindex_vec *cv,
736*33b1fccfSAndroid Build Coastguard Worker 				  unsigned int nr, void *metacur)
737*33b1fccfSAndroid Build Coastguard Worker {
738*33b1fccfSAndroid Build Coastguard Worker 	struct z_erofs_lcluster_index *const db = metacur;
739*33b1fccfSAndroid Build Coastguard Worker 	unsigned int i;
740*33b1fccfSAndroid Build Coastguard Worker 
741*33b1fccfSAndroid Build Coastguard Worker 	for (i = 0; i < nr; ++i, ++cv) {
742*33b1fccfSAndroid Build Coastguard Worker 		struct z_erofs_lcluster_index *const di = db + i;
743*33b1fccfSAndroid Build Coastguard Worker 		const unsigned int advise = le16_to_cpu(di->di_advise);
744*33b1fccfSAndroid Build Coastguard Worker 
745*33b1fccfSAndroid Build Coastguard Worker 		cv->clustertype = (advise >> Z_EROFS_LI_LCLUSTER_TYPE_BIT) &
746*33b1fccfSAndroid Build Coastguard Worker 			((1 << Z_EROFS_LI_LCLUSTER_TYPE_BITS) - 1);
747*33b1fccfSAndroid Build Coastguard Worker 		cv->clusterofs = le16_to_cpu(di->di_clusterofs);
748*33b1fccfSAndroid Build Coastguard Worker 
749*33b1fccfSAndroid Build Coastguard Worker 		if (cv->clustertype == Z_EROFS_LCLUSTER_TYPE_NONHEAD) {
750*33b1fccfSAndroid Build Coastguard Worker 			cv->u.delta[0] = le16_to_cpu(di->di_u.delta[0]);
751*33b1fccfSAndroid Build Coastguard Worker 			cv->u.delta[1] = le16_to_cpu(di->di_u.delta[1]);
752*33b1fccfSAndroid Build Coastguard Worker 		} else {
753*33b1fccfSAndroid Build Coastguard Worker 			cv->u.blkaddr = le32_to_cpu(di->di_u.blkaddr);
754*33b1fccfSAndroid Build Coastguard Worker 		}
755*33b1fccfSAndroid Build Coastguard Worker 	}
756*33b1fccfSAndroid Build Coastguard Worker 	return db + nr;
757*33b1fccfSAndroid Build Coastguard Worker }
758*33b1fccfSAndroid Build Coastguard Worker 
write_compacted_indexes(u8 * out,struct z_erofs_compressindex_vec * cv,erofs_blk_t * blkaddr_ret,unsigned int destsize,unsigned int lclusterbits,bool final,bool * dummy_head,bool update_blkaddr)759*33b1fccfSAndroid Build Coastguard Worker static void *write_compacted_indexes(u8 *out,
760*33b1fccfSAndroid Build Coastguard Worker 				     struct z_erofs_compressindex_vec *cv,
761*33b1fccfSAndroid Build Coastguard Worker 				     erofs_blk_t *blkaddr_ret,
762*33b1fccfSAndroid Build Coastguard Worker 				     unsigned int destsize,
763*33b1fccfSAndroid Build Coastguard Worker 				     unsigned int lclusterbits,
764*33b1fccfSAndroid Build Coastguard Worker 				     bool final, bool *dummy_head,
765*33b1fccfSAndroid Build Coastguard Worker 				     bool update_blkaddr)
766*33b1fccfSAndroid Build Coastguard Worker {
767*33b1fccfSAndroid Build Coastguard Worker 	unsigned int vcnt, lobits, encodebits, pos, i, cblks;
768*33b1fccfSAndroid Build Coastguard Worker 	erofs_blk_t blkaddr;
769*33b1fccfSAndroid Build Coastguard Worker 
770*33b1fccfSAndroid Build Coastguard Worker 	if (destsize == 4)
771*33b1fccfSAndroid Build Coastguard Worker 		vcnt = 2;
772*33b1fccfSAndroid Build Coastguard Worker 	else if (destsize == 2 && lclusterbits <= 12)
773*33b1fccfSAndroid Build Coastguard Worker 		vcnt = 16;
774*33b1fccfSAndroid Build Coastguard Worker 	else
775*33b1fccfSAndroid Build Coastguard Worker 		return ERR_PTR(-EINVAL);
776*33b1fccfSAndroid Build Coastguard Worker 	lobits = max(lclusterbits, ilog2(Z_EROFS_LI_D0_CBLKCNT) + 1U);
777*33b1fccfSAndroid Build Coastguard Worker 	encodebits = (vcnt * destsize * 8 - 32) / vcnt;
778*33b1fccfSAndroid Build Coastguard Worker 	blkaddr = *blkaddr_ret;
779*33b1fccfSAndroid Build Coastguard Worker 
780*33b1fccfSAndroid Build Coastguard Worker 	pos = 0;
781*33b1fccfSAndroid Build Coastguard Worker 	for (i = 0; i < vcnt; ++i) {
782*33b1fccfSAndroid Build Coastguard Worker 		unsigned int offset, v;
783*33b1fccfSAndroid Build Coastguard Worker 		u8 ch, rem;
784*33b1fccfSAndroid Build Coastguard Worker 
785*33b1fccfSAndroid Build Coastguard Worker 		if (cv[i].clustertype == Z_EROFS_LCLUSTER_TYPE_NONHEAD) {
786*33b1fccfSAndroid Build Coastguard Worker 			if (cv[i].u.delta[0] & Z_EROFS_LI_D0_CBLKCNT) {
787*33b1fccfSAndroid Build Coastguard Worker 				cblks = cv[i].u.delta[0] & ~Z_EROFS_LI_D0_CBLKCNT;
788*33b1fccfSAndroid Build Coastguard Worker 				offset = cv[i].u.delta[0];
789*33b1fccfSAndroid Build Coastguard Worker 				blkaddr += cblks;
790*33b1fccfSAndroid Build Coastguard Worker 				*dummy_head = false;
791*33b1fccfSAndroid Build Coastguard Worker 			} else if (i + 1 == vcnt) {
792*33b1fccfSAndroid Build Coastguard Worker 				offset = min_t(u16, cv[i].u.delta[1],
793*33b1fccfSAndroid Build Coastguard Worker 						(1 << lobits) - 1);
794*33b1fccfSAndroid Build Coastguard Worker 			} else {
795*33b1fccfSAndroid Build Coastguard Worker 				offset = cv[i].u.delta[0];
796*33b1fccfSAndroid Build Coastguard Worker 			}
797*33b1fccfSAndroid Build Coastguard Worker 		} else {
798*33b1fccfSAndroid Build Coastguard Worker 			offset = cv[i].clusterofs;
799*33b1fccfSAndroid Build Coastguard Worker 			if (*dummy_head) {
800*33b1fccfSAndroid Build Coastguard Worker 				++blkaddr;
801*33b1fccfSAndroid Build Coastguard Worker 				if (update_blkaddr)
802*33b1fccfSAndroid Build Coastguard Worker 					*blkaddr_ret = blkaddr;
803*33b1fccfSAndroid Build Coastguard Worker 			}
804*33b1fccfSAndroid Build Coastguard Worker 			*dummy_head = true;
805*33b1fccfSAndroid Build Coastguard Worker 			update_blkaddr = false;
806*33b1fccfSAndroid Build Coastguard Worker 
807*33b1fccfSAndroid Build Coastguard Worker 			if (cv[i].u.blkaddr != blkaddr) {
808*33b1fccfSAndroid Build Coastguard Worker 				if (i + 1 != vcnt)
809*33b1fccfSAndroid Build Coastguard Worker 					DBG_BUGON(!final);
810*33b1fccfSAndroid Build Coastguard Worker 				DBG_BUGON(cv[i].u.blkaddr);
811*33b1fccfSAndroid Build Coastguard Worker 			}
812*33b1fccfSAndroid Build Coastguard Worker 		}
813*33b1fccfSAndroid Build Coastguard Worker 		v = (cv[i].clustertype << lobits) | offset;
814*33b1fccfSAndroid Build Coastguard Worker 		rem = pos & 7;
815*33b1fccfSAndroid Build Coastguard Worker 		ch = out[pos / 8] & ((1 << rem) - 1);
816*33b1fccfSAndroid Build Coastguard Worker 		out[pos / 8] = (v << rem) | ch;
817*33b1fccfSAndroid Build Coastguard Worker 		out[pos / 8 + 1] = v >> (8 - rem);
818*33b1fccfSAndroid Build Coastguard Worker 		out[pos / 8 + 2] = v >> (16 - rem);
819*33b1fccfSAndroid Build Coastguard Worker 		pos += encodebits;
820*33b1fccfSAndroid Build Coastguard Worker 	}
821*33b1fccfSAndroid Build Coastguard Worker 	DBG_BUGON(destsize * vcnt * 8 != pos + 32);
822*33b1fccfSAndroid Build Coastguard Worker 	*(__le32 *)(out + destsize * vcnt - 4) = cpu_to_le32(*blkaddr_ret);
823*33b1fccfSAndroid Build Coastguard Worker 	*blkaddr_ret = blkaddr;
824*33b1fccfSAndroid Build Coastguard Worker 	return out + destsize * vcnt;
825*33b1fccfSAndroid Build Coastguard Worker }
826*33b1fccfSAndroid Build Coastguard Worker 
z_erofs_convert_to_compacted_format(struct erofs_inode * inode,erofs_blk_t blkaddr,unsigned int legacymetasize,void * compressmeta)827*33b1fccfSAndroid Build Coastguard Worker int z_erofs_convert_to_compacted_format(struct erofs_inode *inode,
828*33b1fccfSAndroid Build Coastguard Worker 					erofs_blk_t blkaddr,
829*33b1fccfSAndroid Build Coastguard Worker 					unsigned int legacymetasize,
830*33b1fccfSAndroid Build Coastguard Worker 					void *compressmeta)
831*33b1fccfSAndroid Build Coastguard Worker {
832*33b1fccfSAndroid Build Coastguard Worker 	const unsigned int mpos = roundup(inode->inode_isize +
833*33b1fccfSAndroid Build Coastguard Worker 					  inode->xattr_isize, 8) +
834*33b1fccfSAndroid Build Coastguard Worker 				  sizeof(struct z_erofs_map_header);
835*33b1fccfSAndroid Build Coastguard Worker 	const unsigned int totalidx = (legacymetasize -
836*33b1fccfSAndroid Build Coastguard Worker 			Z_EROFS_LEGACY_MAP_HEADER_SIZE) /
837*33b1fccfSAndroid Build Coastguard Worker 				sizeof(struct z_erofs_lcluster_index);
838*33b1fccfSAndroid Build Coastguard Worker 	const unsigned int logical_clusterbits = inode->z_logical_clusterbits;
839*33b1fccfSAndroid Build Coastguard Worker 	u8 *out, *in;
840*33b1fccfSAndroid Build Coastguard Worker 	struct z_erofs_compressindex_vec cv[16];
841*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_sb_info *sbi = inode->sbi;
842*33b1fccfSAndroid Build Coastguard Worker 	/* # of 8-byte units so that it can be aligned with 32 bytes */
843*33b1fccfSAndroid Build Coastguard Worker 	unsigned int compacted_4b_initial, compacted_4b_end;
844*33b1fccfSAndroid Build Coastguard Worker 	unsigned int compacted_2b;
845*33b1fccfSAndroid Build Coastguard Worker 	bool dummy_head;
846*33b1fccfSAndroid Build Coastguard Worker 	bool big_pcluster = erofs_sb_has_big_pcluster(sbi);
847*33b1fccfSAndroid Build Coastguard Worker 
848*33b1fccfSAndroid Build Coastguard Worker 	if (logical_clusterbits < sbi->blkszbits)
849*33b1fccfSAndroid Build Coastguard Worker 		return -EINVAL;
850*33b1fccfSAndroid Build Coastguard Worker 	if (logical_clusterbits > 14) {
851*33b1fccfSAndroid Build Coastguard Worker 		erofs_err("compact format is unsupported for lcluster size %u",
852*33b1fccfSAndroid Build Coastguard Worker 			  1 << logical_clusterbits);
853*33b1fccfSAndroid Build Coastguard Worker 		return -EOPNOTSUPP;
854*33b1fccfSAndroid Build Coastguard Worker 	}
855*33b1fccfSAndroid Build Coastguard Worker 
856*33b1fccfSAndroid Build Coastguard Worker 	if (inode->z_advise & Z_EROFS_ADVISE_COMPACTED_2B) {
857*33b1fccfSAndroid Build Coastguard Worker 		if (logical_clusterbits > 12) {
858*33b1fccfSAndroid Build Coastguard Worker 			erofs_err("compact 2B is unsupported for lcluster size %u",
859*33b1fccfSAndroid Build Coastguard Worker 				  1 << logical_clusterbits);
860*33b1fccfSAndroid Build Coastguard Worker 			return -EINVAL;
861*33b1fccfSAndroid Build Coastguard Worker 		}
862*33b1fccfSAndroid Build Coastguard Worker 
863*33b1fccfSAndroid Build Coastguard Worker 		compacted_4b_initial = (32 - mpos % 32) / 4;
864*33b1fccfSAndroid Build Coastguard Worker 		if (compacted_4b_initial == 32 / 4)
865*33b1fccfSAndroid Build Coastguard Worker 			compacted_4b_initial = 0;
866*33b1fccfSAndroid Build Coastguard Worker 
867*33b1fccfSAndroid Build Coastguard Worker 		if (compacted_4b_initial > totalidx) {
868*33b1fccfSAndroid Build Coastguard Worker 			compacted_4b_initial = compacted_2b = 0;
869*33b1fccfSAndroid Build Coastguard Worker 			compacted_4b_end = totalidx;
870*33b1fccfSAndroid Build Coastguard Worker 		} else {
871*33b1fccfSAndroid Build Coastguard Worker 			compacted_2b = rounddown(totalidx -
872*33b1fccfSAndroid Build Coastguard Worker 						 compacted_4b_initial, 16);
873*33b1fccfSAndroid Build Coastguard Worker 			compacted_4b_end = totalidx - compacted_4b_initial -
874*33b1fccfSAndroid Build Coastguard Worker 					   compacted_2b;
875*33b1fccfSAndroid Build Coastguard Worker 		}
876*33b1fccfSAndroid Build Coastguard Worker 	} else {
877*33b1fccfSAndroid Build Coastguard Worker 		compacted_2b = compacted_4b_initial = 0;
878*33b1fccfSAndroid Build Coastguard Worker 		compacted_4b_end = totalidx;
879*33b1fccfSAndroid Build Coastguard Worker 	}
880*33b1fccfSAndroid Build Coastguard Worker 
881*33b1fccfSAndroid Build Coastguard Worker 	out = in = compressmeta;
882*33b1fccfSAndroid Build Coastguard Worker 
883*33b1fccfSAndroid Build Coastguard Worker 	out += sizeof(struct z_erofs_map_header);
884*33b1fccfSAndroid Build Coastguard Worker 	in += Z_EROFS_LEGACY_MAP_HEADER_SIZE;
885*33b1fccfSAndroid Build Coastguard Worker 
886*33b1fccfSAndroid Build Coastguard Worker 	dummy_head = false;
887*33b1fccfSAndroid Build Coastguard Worker 	/* prior to bigpcluster, blkaddr was bumped up once coming into HEAD */
888*33b1fccfSAndroid Build Coastguard Worker 	if (!big_pcluster) {
889*33b1fccfSAndroid Build Coastguard Worker 		--blkaddr;
890*33b1fccfSAndroid Build Coastguard Worker 		dummy_head = true;
891*33b1fccfSAndroid Build Coastguard Worker 	}
892*33b1fccfSAndroid Build Coastguard Worker 
893*33b1fccfSAndroid Build Coastguard Worker 	/* generate compacted_4b_initial */
894*33b1fccfSAndroid Build Coastguard Worker 	while (compacted_4b_initial) {
895*33b1fccfSAndroid Build Coastguard Worker 		in = parse_legacy_indexes(cv, 2, in);
896*33b1fccfSAndroid Build Coastguard Worker 		out = write_compacted_indexes(out, cv, &blkaddr,
897*33b1fccfSAndroid Build Coastguard Worker 					      4, logical_clusterbits, false,
898*33b1fccfSAndroid Build Coastguard Worker 					      &dummy_head, big_pcluster);
899*33b1fccfSAndroid Build Coastguard Worker 		compacted_4b_initial -= 2;
900*33b1fccfSAndroid Build Coastguard Worker 	}
901*33b1fccfSAndroid Build Coastguard Worker 	DBG_BUGON(compacted_4b_initial);
902*33b1fccfSAndroid Build Coastguard Worker 
903*33b1fccfSAndroid Build Coastguard Worker 	/* generate compacted_2b */
904*33b1fccfSAndroid Build Coastguard Worker 	while (compacted_2b) {
905*33b1fccfSAndroid Build Coastguard Worker 		in = parse_legacy_indexes(cv, 16, in);
906*33b1fccfSAndroid Build Coastguard Worker 		out = write_compacted_indexes(out, cv, &blkaddr,
907*33b1fccfSAndroid Build Coastguard Worker 					      2, logical_clusterbits, false,
908*33b1fccfSAndroid Build Coastguard Worker 					      &dummy_head, big_pcluster);
909*33b1fccfSAndroid Build Coastguard Worker 		compacted_2b -= 16;
910*33b1fccfSAndroid Build Coastguard Worker 	}
911*33b1fccfSAndroid Build Coastguard Worker 	DBG_BUGON(compacted_2b);
912*33b1fccfSAndroid Build Coastguard Worker 
913*33b1fccfSAndroid Build Coastguard Worker 	/* generate compacted_4b_end */
914*33b1fccfSAndroid Build Coastguard Worker 	while (compacted_4b_end > 1) {
915*33b1fccfSAndroid Build Coastguard Worker 		in = parse_legacy_indexes(cv, 2, in);
916*33b1fccfSAndroid Build Coastguard Worker 		out = write_compacted_indexes(out, cv, &blkaddr,
917*33b1fccfSAndroid Build Coastguard Worker 					      4, logical_clusterbits, false,
918*33b1fccfSAndroid Build Coastguard Worker 					      &dummy_head, big_pcluster);
919*33b1fccfSAndroid Build Coastguard Worker 		compacted_4b_end -= 2;
920*33b1fccfSAndroid Build Coastguard Worker 	}
921*33b1fccfSAndroid Build Coastguard Worker 
922*33b1fccfSAndroid Build Coastguard Worker 	/* generate final compacted_4b_end if needed */
923*33b1fccfSAndroid Build Coastguard Worker 	if (compacted_4b_end) {
924*33b1fccfSAndroid Build Coastguard Worker 		memset(cv, 0, sizeof(cv));
925*33b1fccfSAndroid Build Coastguard Worker 		in = parse_legacy_indexes(cv, 1, in);
926*33b1fccfSAndroid Build Coastguard Worker 		out = write_compacted_indexes(out, cv, &blkaddr,
927*33b1fccfSAndroid Build Coastguard Worker 					      4, logical_clusterbits, true,
928*33b1fccfSAndroid Build Coastguard Worker 					      &dummy_head, big_pcluster);
929*33b1fccfSAndroid Build Coastguard Worker 	}
930*33b1fccfSAndroid Build Coastguard Worker 	inode->extent_isize = out - (u8 *)compressmeta;
931*33b1fccfSAndroid Build Coastguard Worker 	return 0;
932*33b1fccfSAndroid Build Coastguard Worker }
933*33b1fccfSAndroid Build Coastguard Worker 
z_erofs_write_mapheader(struct erofs_inode * inode,void * compressmeta)934*33b1fccfSAndroid Build Coastguard Worker static void z_erofs_write_mapheader(struct erofs_inode *inode,
935*33b1fccfSAndroid Build Coastguard Worker 				    void *compressmeta)
936*33b1fccfSAndroid Build Coastguard Worker {
937*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_sb_info *sbi = inode->sbi;
938*33b1fccfSAndroid Build Coastguard Worker 	struct z_erofs_map_header h = {
939*33b1fccfSAndroid Build Coastguard Worker 		.h_advise = cpu_to_le16(inode->z_advise),
940*33b1fccfSAndroid Build Coastguard Worker 		.h_algorithmtype = inode->z_algorithmtype[1] << 4 |
941*33b1fccfSAndroid Build Coastguard Worker 				   inode->z_algorithmtype[0],
942*33b1fccfSAndroid Build Coastguard Worker 		/* lclustersize */
943*33b1fccfSAndroid Build Coastguard Worker 		.h_clusterbits = inode->z_logical_clusterbits - sbi->blkszbits,
944*33b1fccfSAndroid Build Coastguard Worker 	};
945*33b1fccfSAndroid Build Coastguard Worker 
946*33b1fccfSAndroid Build Coastguard Worker 	if (inode->z_advise & Z_EROFS_ADVISE_FRAGMENT_PCLUSTER)
947*33b1fccfSAndroid Build Coastguard Worker 		h.h_fragmentoff = cpu_to_le32(inode->fragmentoff);
948*33b1fccfSAndroid Build Coastguard Worker 	else
949*33b1fccfSAndroid Build Coastguard Worker 		h.h_idata_size = cpu_to_le16(inode->idata_size);
950*33b1fccfSAndroid Build Coastguard Worker 
951*33b1fccfSAndroid Build Coastguard Worker 	memset(compressmeta, 0, Z_EROFS_LEGACY_MAP_HEADER_SIZE);
952*33b1fccfSAndroid Build Coastguard Worker 	/* write out map header */
953*33b1fccfSAndroid Build Coastguard Worker 	memcpy(compressmeta, &h, sizeof(struct z_erofs_map_header));
954*33b1fccfSAndroid Build Coastguard Worker }
955*33b1fccfSAndroid Build Coastguard Worker 
z_erofs_drop_inline_pcluster(struct erofs_inode * inode)956*33b1fccfSAndroid Build Coastguard Worker void z_erofs_drop_inline_pcluster(struct erofs_inode *inode)
957*33b1fccfSAndroid Build Coastguard Worker {
958*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_sb_info *sbi = inode->sbi;
959*33b1fccfSAndroid Build Coastguard Worker 	const unsigned int type = Z_EROFS_LCLUSTER_TYPE_PLAIN;
960*33b1fccfSAndroid Build Coastguard Worker 	struct z_erofs_map_header *h = inode->compressmeta;
961*33b1fccfSAndroid Build Coastguard Worker 
962*33b1fccfSAndroid Build Coastguard Worker 	h->h_advise = cpu_to_le16(le16_to_cpu(h->h_advise) &
963*33b1fccfSAndroid Build Coastguard Worker 				  ~Z_EROFS_ADVISE_INLINE_PCLUSTER);
964*33b1fccfSAndroid Build Coastguard Worker 	h->h_idata_size = 0;
965*33b1fccfSAndroid Build Coastguard Worker 	if (!inode->eof_tailraw)
966*33b1fccfSAndroid Build Coastguard Worker 		return;
967*33b1fccfSAndroid Build Coastguard Worker 	DBG_BUGON(inode->compressed_idata != true);
968*33b1fccfSAndroid Build Coastguard Worker 
969*33b1fccfSAndroid Build Coastguard Worker 	/* patch the EOF lcluster to uncompressed type first */
970*33b1fccfSAndroid Build Coastguard Worker 	if (inode->datalayout == EROFS_INODE_COMPRESSED_FULL) {
971*33b1fccfSAndroid Build Coastguard Worker 		struct z_erofs_lcluster_index *di =
972*33b1fccfSAndroid Build Coastguard Worker 			(inode->compressmeta + inode->extent_isize) -
973*33b1fccfSAndroid Build Coastguard Worker 			sizeof(struct z_erofs_lcluster_index);
974*33b1fccfSAndroid Build Coastguard Worker 		__le16 advise =
975*33b1fccfSAndroid Build Coastguard Worker 			cpu_to_le16(type << Z_EROFS_LI_LCLUSTER_TYPE_BIT);
976*33b1fccfSAndroid Build Coastguard Worker 
977*33b1fccfSAndroid Build Coastguard Worker 		di->di_advise = advise;
978*33b1fccfSAndroid Build Coastguard Worker 	} else if (inode->datalayout == EROFS_INODE_COMPRESSED_COMPACT) {
979*33b1fccfSAndroid Build Coastguard Worker 		/* handle the last compacted 4B pack */
980*33b1fccfSAndroid Build Coastguard Worker 		unsigned int eofs, base, pos, v, lo;
981*33b1fccfSAndroid Build Coastguard Worker 		u8 *out;
982*33b1fccfSAndroid Build Coastguard Worker 
983*33b1fccfSAndroid Build Coastguard Worker 		eofs = inode->extent_isize -
984*33b1fccfSAndroid Build Coastguard Worker 			(4 << (BLK_ROUND_UP(sbi, inode->i_size) & 1));
985*33b1fccfSAndroid Build Coastguard Worker 		base = round_down(eofs, 8);
986*33b1fccfSAndroid Build Coastguard Worker 		pos = 16 /* encodebits */ * ((eofs - base) / 4);
987*33b1fccfSAndroid Build Coastguard Worker 		out = inode->compressmeta + base;
988*33b1fccfSAndroid Build Coastguard Worker 		lo = erofs_blkoff(sbi, get_unaligned_le32(out + pos / 8));
989*33b1fccfSAndroid Build Coastguard Worker 		v = (type << sbi->blkszbits) | lo;
990*33b1fccfSAndroid Build Coastguard Worker 		out[pos / 8] = v & 0xff;
991*33b1fccfSAndroid Build Coastguard Worker 		out[pos / 8 + 1] = v >> 8;
992*33b1fccfSAndroid Build Coastguard Worker 	} else {
993*33b1fccfSAndroid Build Coastguard Worker 		DBG_BUGON(1);
994*33b1fccfSAndroid Build Coastguard Worker 		return;
995*33b1fccfSAndroid Build Coastguard Worker 	}
996*33b1fccfSAndroid Build Coastguard Worker 	free(inode->idata);
997*33b1fccfSAndroid Build Coastguard Worker 	/* replace idata with prepared uncompressed data */
998*33b1fccfSAndroid Build Coastguard Worker 	inode->idata = inode->eof_tailraw;
999*33b1fccfSAndroid Build Coastguard Worker 	inode->idata_size = inode->eof_tailrawsize;
1000*33b1fccfSAndroid Build Coastguard Worker 	inode->compressed_idata = false;
1001*33b1fccfSAndroid Build Coastguard Worker 	inode->eof_tailraw = NULL;
1002*33b1fccfSAndroid Build Coastguard Worker }
1003*33b1fccfSAndroid Build Coastguard Worker 
z_erofs_compress_segment(struct z_erofs_compress_sctx * ctx,u64 offset,erofs_blk_t blkaddr)1004*33b1fccfSAndroid Build Coastguard Worker int z_erofs_compress_segment(struct z_erofs_compress_sctx *ctx,
1005*33b1fccfSAndroid Build Coastguard Worker 			     u64 offset, erofs_blk_t blkaddr)
1006*33b1fccfSAndroid Build Coastguard Worker {
1007*33b1fccfSAndroid Build Coastguard Worker 	struct z_erofs_compress_ictx *ictx = ctx->ictx;
1008*33b1fccfSAndroid Build Coastguard Worker 	int fd = ictx->fd;
1009*33b1fccfSAndroid Build Coastguard Worker 
1010*33b1fccfSAndroid Build Coastguard Worker 	ctx->blkaddr = blkaddr;
1011*33b1fccfSAndroid Build Coastguard Worker 	while (ctx->remaining) {
1012*33b1fccfSAndroid Build Coastguard Worker 		const u64 rx = min_t(u64, ctx->remaining,
1013*33b1fccfSAndroid Build Coastguard Worker 				     Z_EROFS_COMPR_QUEUE_SZ - ctx->tail);
1014*33b1fccfSAndroid Build Coastguard Worker 		int ret;
1015*33b1fccfSAndroid Build Coastguard Worker 
1016*33b1fccfSAndroid Build Coastguard Worker 		ret = (offset == -1 ?
1017*33b1fccfSAndroid Build Coastguard Worker 			read(fd, ctx->queue + ctx->tail, rx) :
1018*33b1fccfSAndroid Build Coastguard Worker 			pread(fd, ctx->queue + ctx->tail, rx,
1019*33b1fccfSAndroid Build Coastguard Worker 			      ictx->fpos + offset));
1020*33b1fccfSAndroid Build Coastguard Worker 		if (ret != rx)
1021*33b1fccfSAndroid Build Coastguard Worker 			return -errno;
1022*33b1fccfSAndroid Build Coastguard Worker 
1023*33b1fccfSAndroid Build Coastguard Worker 		ctx->remaining -= rx;
1024*33b1fccfSAndroid Build Coastguard Worker 		ctx->tail += rx;
1025*33b1fccfSAndroid Build Coastguard Worker 		if (offset != -1)
1026*33b1fccfSAndroid Build Coastguard Worker 			offset += rx;
1027*33b1fccfSAndroid Build Coastguard Worker 
1028*33b1fccfSAndroid Build Coastguard Worker 		ret = z_erofs_compress_one(ctx);
1029*33b1fccfSAndroid Build Coastguard Worker 		if (ret)
1030*33b1fccfSAndroid Build Coastguard Worker 			return ret;
1031*33b1fccfSAndroid Build Coastguard Worker 	}
1032*33b1fccfSAndroid Build Coastguard Worker 	DBG_BUGON(ctx->head != ctx->tail);
1033*33b1fccfSAndroid Build Coastguard Worker 
1034*33b1fccfSAndroid Build Coastguard Worker 	if (ctx->pivot) {
1035*33b1fccfSAndroid Build Coastguard Worker 		z_erofs_commit_extent(ctx, ctx->pivot);
1036*33b1fccfSAndroid Build Coastguard Worker 		ctx->pivot = NULL;
1037*33b1fccfSAndroid Build Coastguard Worker 	}
1038*33b1fccfSAndroid Build Coastguard Worker 
1039*33b1fccfSAndroid Build Coastguard Worker 	/* generate an extra extent for the deduplicated fragment */
1040*33b1fccfSAndroid Build Coastguard Worker 	if (ctx->seg_idx >= ictx->seg_num - 1 &&
1041*33b1fccfSAndroid Build Coastguard Worker 	    ictx->inode->fragment_size && !ictx->fragemitted) {
1042*33b1fccfSAndroid Build Coastguard Worker 		struct z_erofs_extent_item *ei;
1043*33b1fccfSAndroid Build Coastguard Worker 
1044*33b1fccfSAndroid Build Coastguard Worker 		ei = malloc(sizeof(*ei));
1045*33b1fccfSAndroid Build Coastguard Worker 		if (!ei)
1046*33b1fccfSAndroid Build Coastguard Worker 			return -ENOMEM;
1047*33b1fccfSAndroid Build Coastguard Worker 
1048*33b1fccfSAndroid Build Coastguard Worker 		ei->e = (struct z_erofs_inmem_extent) {
1049*33b1fccfSAndroid Build Coastguard Worker 			.length = ictx->inode->fragment_size,
1050*33b1fccfSAndroid Build Coastguard Worker 			.compressedblks = 0,
1051*33b1fccfSAndroid Build Coastguard Worker 			.raw = false,
1052*33b1fccfSAndroid Build Coastguard Worker 			.partial = false,
1053*33b1fccfSAndroid Build Coastguard Worker 			.blkaddr = ctx->blkaddr,
1054*33b1fccfSAndroid Build Coastguard Worker 		};
1055*33b1fccfSAndroid Build Coastguard Worker 		init_list_head(&ei->list);
1056*33b1fccfSAndroid Build Coastguard Worker 		z_erofs_commit_extent(ctx, ei);
1057*33b1fccfSAndroid Build Coastguard Worker 	}
1058*33b1fccfSAndroid Build Coastguard Worker 	return 0;
1059*33b1fccfSAndroid Build Coastguard Worker }
1060*33b1fccfSAndroid Build Coastguard Worker 
erofs_commit_compressed_file(struct z_erofs_compress_ictx * ictx,struct erofs_buffer_head * bh,erofs_blk_t blkaddr,erofs_blk_t compressed_blocks)1061*33b1fccfSAndroid Build Coastguard Worker int erofs_commit_compressed_file(struct z_erofs_compress_ictx *ictx,
1062*33b1fccfSAndroid Build Coastguard Worker 				 struct erofs_buffer_head *bh,
1063*33b1fccfSAndroid Build Coastguard Worker 				 erofs_blk_t blkaddr,
1064*33b1fccfSAndroid Build Coastguard Worker 				 erofs_blk_t compressed_blocks)
1065*33b1fccfSAndroid Build Coastguard Worker {
1066*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_inode *inode = ictx->inode;
1067*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_sb_info *sbi = inode->sbi;
1068*33b1fccfSAndroid Build Coastguard Worker 	unsigned int legacymetasize;
1069*33b1fccfSAndroid Build Coastguard Worker 	u8 *compressmeta;
1070*33b1fccfSAndroid Build Coastguard Worker 	int ret;
1071*33b1fccfSAndroid Build Coastguard Worker 
1072*33b1fccfSAndroid Build Coastguard Worker 	z_erofs_fragments_commit(inode);
1073*33b1fccfSAndroid Build Coastguard Worker 
1074*33b1fccfSAndroid Build Coastguard Worker 	/* fall back to no compression mode */
1075*33b1fccfSAndroid Build Coastguard Worker 	DBG_BUGON(compressed_blocks < !!inode->idata_size);
1076*33b1fccfSAndroid Build Coastguard Worker 	compressed_blocks -= !!inode->idata_size;
1077*33b1fccfSAndroid Build Coastguard Worker 
1078*33b1fccfSAndroid Build Coastguard Worker 	compressmeta = malloc(BLK_ROUND_UP(sbi, inode->i_size) *
1079*33b1fccfSAndroid Build Coastguard Worker 			      sizeof(struct z_erofs_lcluster_index) +
1080*33b1fccfSAndroid Build Coastguard Worker 			      Z_EROFS_LEGACY_MAP_HEADER_SIZE);
1081*33b1fccfSAndroid Build Coastguard Worker 	if (!compressmeta) {
1082*33b1fccfSAndroid Build Coastguard Worker 		ret = -ENOMEM;
1083*33b1fccfSAndroid Build Coastguard Worker 		goto err_free_idata;
1084*33b1fccfSAndroid Build Coastguard Worker 	}
1085*33b1fccfSAndroid Build Coastguard Worker 	ictx->metacur = compressmeta + Z_EROFS_LEGACY_MAP_HEADER_SIZE;
1086*33b1fccfSAndroid Build Coastguard Worker 	z_erofs_write_indexes(ictx);
1087*33b1fccfSAndroid Build Coastguard Worker 
1088*33b1fccfSAndroid Build Coastguard Worker 	legacymetasize = ictx->metacur - compressmeta;
1089*33b1fccfSAndroid Build Coastguard Worker 	/* estimate if data compression saves space or not */
1090*33b1fccfSAndroid Build Coastguard Worker 	if (!inode->fragment_size &&
1091*33b1fccfSAndroid Build Coastguard Worker 	    compressed_blocks * erofs_blksiz(sbi) + inode->idata_size +
1092*33b1fccfSAndroid Build Coastguard Worker 	    legacymetasize >= inode->i_size) {
1093*33b1fccfSAndroid Build Coastguard Worker 		z_erofs_dedupe_commit(true);
1094*33b1fccfSAndroid Build Coastguard Worker 		ret = -ENOSPC;
1095*33b1fccfSAndroid Build Coastguard Worker 		goto err_free_meta;
1096*33b1fccfSAndroid Build Coastguard Worker 	}
1097*33b1fccfSAndroid Build Coastguard Worker 	z_erofs_dedupe_commit(false);
1098*33b1fccfSAndroid Build Coastguard Worker 	z_erofs_write_mapheader(inode, compressmeta);
1099*33b1fccfSAndroid Build Coastguard Worker 
1100*33b1fccfSAndroid Build Coastguard Worker 	if (!ictx->fragemitted)
1101*33b1fccfSAndroid Build Coastguard Worker 		sbi->saved_by_deduplication += inode->fragment_size;
1102*33b1fccfSAndroid Build Coastguard Worker 
1103*33b1fccfSAndroid Build Coastguard Worker 	/* if the entire file is a fragment, a simplified form is used. */
1104*33b1fccfSAndroid Build Coastguard Worker 	if (inode->i_size <= inode->fragment_size) {
1105*33b1fccfSAndroid Build Coastguard Worker 		DBG_BUGON(inode->i_size < inode->fragment_size);
1106*33b1fccfSAndroid Build Coastguard Worker 		DBG_BUGON(inode->fragmentoff >> 63);
1107*33b1fccfSAndroid Build Coastguard Worker 		*(__le64 *)compressmeta =
1108*33b1fccfSAndroid Build Coastguard Worker 			cpu_to_le64(inode->fragmentoff | 1ULL << 63);
1109*33b1fccfSAndroid Build Coastguard Worker 		inode->datalayout = EROFS_INODE_COMPRESSED_FULL;
1110*33b1fccfSAndroid Build Coastguard Worker 		legacymetasize = Z_EROFS_LEGACY_MAP_HEADER_SIZE;
1111*33b1fccfSAndroid Build Coastguard Worker 	}
1112*33b1fccfSAndroid Build Coastguard Worker 
1113*33b1fccfSAndroid Build Coastguard Worker 	if (compressed_blocks) {
1114*33b1fccfSAndroid Build Coastguard Worker 		ret = erofs_bh_balloon(bh, erofs_pos(sbi, compressed_blocks));
1115*33b1fccfSAndroid Build Coastguard Worker 		DBG_BUGON(ret != erofs_blksiz(sbi));
1116*33b1fccfSAndroid Build Coastguard Worker 	} else {
1117*33b1fccfSAndroid Build Coastguard Worker 		if (!cfg.c_fragments && !cfg.c_dedupe)
1118*33b1fccfSAndroid Build Coastguard Worker 			DBG_BUGON(!inode->idata_size);
1119*33b1fccfSAndroid Build Coastguard Worker 	}
1120*33b1fccfSAndroid Build Coastguard Worker 
1121*33b1fccfSAndroid Build Coastguard Worker 	erofs_info("compressed %s (%llu bytes) into %u blocks",
1122*33b1fccfSAndroid Build Coastguard Worker 		   inode->i_srcpath, (unsigned long long)inode->i_size,
1123*33b1fccfSAndroid Build Coastguard Worker 		   compressed_blocks);
1124*33b1fccfSAndroid Build Coastguard Worker 
1125*33b1fccfSAndroid Build Coastguard Worker 	if (inode->idata_size) {
1126*33b1fccfSAndroid Build Coastguard Worker 		bh->op = &erofs_skip_write_bhops;
1127*33b1fccfSAndroid Build Coastguard Worker 		inode->bh_data = bh;
1128*33b1fccfSAndroid Build Coastguard Worker 	} else {
1129*33b1fccfSAndroid Build Coastguard Worker 		erofs_bdrop(bh, false);
1130*33b1fccfSAndroid Build Coastguard Worker 	}
1131*33b1fccfSAndroid Build Coastguard Worker 
1132*33b1fccfSAndroid Build Coastguard Worker 	inode->u.i_blocks = compressed_blocks;
1133*33b1fccfSAndroid Build Coastguard Worker 
1134*33b1fccfSAndroid Build Coastguard Worker 	if (inode->datalayout == EROFS_INODE_COMPRESSED_FULL) {
1135*33b1fccfSAndroid Build Coastguard Worker 		inode->extent_isize = legacymetasize;
1136*33b1fccfSAndroid Build Coastguard Worker 	} else {
1137*33b1fccfSAndroid Build Coastguard Worker 		ret = z_erofs_convert_to_compacted_format(inode, blkaddr,
1138*33b1fccfSAndroid Build Coastguard Worker 							  legacymetasize,
1139*33b1fccfSAndroid Build Coastguard Worker 							  compressmeta);
1140*33b1fccfSAndroid Build Coastguard Worker 		DBG_BUGON(ret);
1141*33b1fccfSAndroid Build Coastguard Worker 	}
1142*33b1fccfSAndroid Build Coastguard Worker 	inode->compressmeta = compressmeta;
1143*33b1fccfSAndroid Build Coastguard Worker 	if (!erofs_is_packed_inode(inode))
1144*33b1fccfSAndroid Build Coastguard Worker 		erofs_droid_blocklist_write(inode, blkaddr, compressed_blocks);
1145*33b1fccfSAndroid Build Coastguard Worker 	return 0;
1146*33b1fccfSAndroid Build Coastguard Worker 
1147*33b1fccfSAndroid Build Coastguard Worker err_free_meta:
1148*33b1fccfSAndroid Build Coastguard Worker 	free(compressmeta);
1149*33b1fccfSAndroid Build Coastguard Worker 	inode->compressmeta = NULL;
1150*33b1fccfSAndroid Build Coastguard Worker err_free_idata:
1151*33b1fccfSAndroid Build Coastguard Worker 	erofs_bdrop(bh, true);	/* revoke buffer */
1152*33b1fccfSAndroid Build Coastguard Worker 	if (inode->idata) {
1153*33b1fccfSAndroid Build Coastguard Worker 		free(inode->idata);
1154*33b1fccfSAndroid Build Coastguard Worker 		inode->idata = NULL;
1155*33b1fccfSAndroid Build Coastguard Worker 	}
1156*33b1fccfSAndroid Build Coastguard Worker 	return ret;
1157*33b1fccfSAndroid Build Coastguard Worker }
1158*33b1fccfSAndroid Build Coastguard Worker 
1159*33b1fccfSAndroid Build Coastguard Worker #ifdef EROFS_MT_ENABLED
z_erofs_mt_wq_tls_alloc(struct erofs_workqueue * wq,void * ptr)1160*33b1fccfSAndroid Build Coastguard Worker void *z_erofs_mt_wq_tls_alloc(struct erofs_workqueue *wq, void *ptr)
1161*33b1fccfSAndroid Build Coastguard Worker {
1162*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_compress_wq_tls *tls;
1163*33b1fccfSAndroid Build Coastguard Worker 
1164*33b1fccfSAndroid Build Coastguard Worker 	tls = calloc(1, sizeof(*tls));
1165*33b1fccfSAndroid Build Coastguard Worker 	if (!tls)
1166*33b1fccfSAndroid Build Coastguard Worker 		return NULL;
1167*33b1fccfSAndroid Build Coastguard Worker 
1168*33b1fccfSAndroid Build Coastguard Worker 	tls->queue = malloc(Z_EROFS_COMPR_QUEUE_SZ);
1169*33b1fccfSAndroid Build Coastguard Worker 	if (!tls->queue)
1170*33b1fccfSAndroid Build Coastguard Worker 		goto err_free_priv;
1171*33b1fccfSAndroid Build Coastguard Worker 
1172*33b1fccfSAndroid Build Coastguard Worker 	tls->destbuf = calloc(1, EROFS_CONFIG_COMPR_MAX_SZ +
1173*33b1fccfSAndroid Build Coastguard Worker 			      EROFS_MAX_BLOCK_SIZE);
1174*33b1fccfSAndroid Build Coastguard Worker 	if (!tls->destbuf)
1175*33b1fccfSAndroid Build Coastguard Worker 		goto err_free_queue;
1176*33b1fccfSAndroid Build Coastguard Worker 
1177*33b1fccfSAndroid Build Coastguard Worker 	tls->ccfg = calloc(EROFS_MAX_COMPR_CFGS, sizeof(*tls->ccfg));
1178*33b1fccfSAndroid Build Coastguard Worker 	if (!tls->ccfg)
1179*33b1fccfSAndroid Build Coastguard Worker 		goto err_free_destbuf;
1180*33b1fccfSAndroid Build Coastguard Worker 	return tls;
1181*33b1fccfSAndroid Build Coastguard Worker 
1182*33b1fccfSAndroid Build Coastguard Worker err_free_destbuf:
1183*33b1fccfSAndroid Build Coastguard Worker 	free(tls->destbuf);
1184*33b1fccfSAndroid Build Coastguard Worker err_free_queue:
1185*33b1fccfSAndroid Build Coastguard Worker 	free(tls->queue);
1186*33b1fccfSAndroid Build Coastguard Worker err_free_priv:
1187*33b1fccfSAndroid Build Coastguard Worker 	free(tls);
1188*33b1fccfSAndroid Build Coastguard Worker 	return NULL;
1189*33b1fccfSAndroid Build Coastguard Worker }
1190*33b1fccfSAndroid Build Coastguard Worker 
z_erofs_mt_wq_tls_init_compr(struct erofs_sb_info * sbi,struct erofs_compress_wq_tls * tls,unsigned int alg_id,char * alg_name,unsigned int comp_level,unsigned int dict_size)1191*33b1fccfSAndroid Build Coastguard Worker int z_erofs_mt_wq_tls_init_compr(struct erofs_sb_info *sbi,
1192*33b1fccfSAndroid Build Coastguard Worker 				 struct erofs_compress_wq_tls *tls,
1193*33b1fccfSAndroid Build Coastguard Worker 				 unsigned int alg_id, char *alg_name,
1194*33b1fccfSAndroid Build Coastguard Worker 				 unsigned int comp_level,
1195*33b1fccfSAndroid Build Coastguard Worker 				 unsigned int dict_size)
1196*33b1fccfSAndroid Build Coastguard Worker {
1197*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_compress_cfg *lc = &tls->ccfg[alg_id];
1198*33b1fccfSAndroid Build Coastguard Worker 	int ret;
1199*33b1fccfSAndroid Build Coastguard Worker 
1200*33b1fccfSAndroid Build Coastguard Worker 	if (__erofs_likely(lc->enable))
1201*33b1fccfSAndroid Build Coastguard Worker 		return 0;
1202*33b1fccfSAndroid Build Coastguard Worker 
1203*33b1fccfSAndroid Build Coastguard Worker 	ret = erofs_compressor_init(sbi, &lc->handle, alg_name,
1204*33b1fccfSAndroid Build Coastguard Worker 				    comp_level, dict_size);
1205*33b1fccfSAndroid Build Coastguard Worker 	if (ret)
1206*33b1fccfSAndroid Build Coastguard Worker 		return ret;
1207*33b1fccfSAndroid Build Coastguard Worker 	lc->algorithmtype = alg_id;
1208*33b1fccfSAndroid Build Coastguard Worker 	lc->enable = true;
1209*33b1fccfSAndroid Build Coastguard Worker 	return 0;
1210*33b1fccfSAndroid Build Coastguard Worker }
1211*33b1fccfSAndroid Build Coastguard Worker 
z_erofs_mt_wq_tls_free(struct erofs_workqueue * wq,void * priv)1212*33b1fccfSAndroid Build Coastguard Worker void *z_erofs_mt_wq_tls_free(struct erofs_workqueue *wq, void *priv)
1213*33b1fccfSAndroid Build Coastguard Worker {
1214*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_compress_wq_tls *tls = priv;
1215*33b1fccfSAndroid Build Coastguard Worker 	int i;
1216*33b1fccfSAndroid Build Coastguard Worker 
1217*33b1fccfSAndroid Build Coastguard Worker 	for (i = 0; i < EROFS_MAX_COMPR_CFGS; i++)
1218*33b1fccfSAndroid Build Coastguard Worker 		if (tls->ccfg[i].enable)
1219*33b1fccfSAndroid Build Coastguard Worker 			erofs_compressor_exit(&tls->ccfg[i].handle);
1220*33b1fccfSAndroid Build Coastguard Worker 
1221*33b1fccfSAndroid Build Coastguard Worker 	free(tls->ccfg);
1222*33b1fccfSAndroid Build Coastguard Worker 	free(tls->destbuf);
1223*33b1fccfSAndroid Build Coastguard Worker 	free(tls->queue);
1224*33b1fccfSAndroid Build Coastguard Worker 	free(tls);
1225*33b1fccfSAndroid Build Coastguard Worker 	return NULL;
1226*33b1fccfSAndroid Build Coastguard Worker }
1227*33b1fccfSAndroid Build Coastguard Worker 
z_erofs_mt_workfn(struct erofs_work * work,void * tlsp)1228*33b1fccfSAndroid Build Coastguard Worker void z_erofs_mt_workfn(struct erofs_work *work, void *tlsp)
1229*33b1fccfSAndroid Build Coastguard Worker {
1230*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_compress_work *cwork = (struct erofs_compress_work *)work;
1231*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_compress_wq_tls *tls = tlsp;
1232*33b1fccfSAndroid Build Coastguard Worker 	struct z_erofs_compress_sctx *sctx = &cwork->ctx;
1233*33b1fccfSAndroid Build Coastguard Worker 	struct z_erofs_compress_ictx *ictx = sctx->ictx;
1234*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_inode *inode = ictx->inode;
1235*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_sb_info *sbi = inode->sbi;
1236*33b1fccfSAndroid Build Coastguard Worker 	int ret = 0;
1237*33b1fccfSAndroid Build Coastguard Worker 
1238*33b1fccfSAndroid Build Coastguard Worker 	ret = z_erofs_mt_wq_tls_init_compr(sbi, tls, cwork->alg_id,
1239*33b1fccfSAndroid Build Coastguard Worker 					   cwork->alg_name, cwork->comp_level,
1240*33b1fccfSAndroid Build Coastguard Worker 					   cwork->dict_size);
1241*33b1fccfSAndroid Build Coastguard Worker 	if (ret)
1242*33b1fccfSAndroid Build Coastguard Worker 		goto out;
1243*33b1fccfSAndroid Build Coastguard Worker 
1244*33b1fccfSAndroid Build Coastguard Worker 	sctx->pclustersize = z_erofs_get_max_pclustersize(inode);
1245*33b1fccfSAndroid Build Coastguard Worker 	sctx->queue = tls->queue;
1246*33b1fccfSAndroid Build Coastguard Worker 	sctx->destbuf = tls->destbuf;
1247*33b1fccfSAndroid Build Coastguard Worker 	sctx->chandle = &tls->ccfg[cwork->alg_id].handle;
1248*33b1fccfSAndroid Build Coastguard Worker 	erofs_compressor_reset(sctx->chandle);
1249*33b1fccfSAndroid Build Coastguard Worker 	sctx->membuf = malloc(round_up(sctx->remaining, erofs_blksiz(sbi)));
1250*33b1fccfSAndroid Build Coastguard Worker 	if (!sctx->membuf) {
1251*33b1fccfSAndroid Build Coastguard Worker 		ret = -ENOMEM;
1252*33b1fccfSAndroid Build Coastguard Worker 		goto out;
1253*33b1fccfSAndroid Build Coastguard Worker 	}
1254*33b1fccfSAndroid Build Coastguard Worker 	sctx->memoff = 0;
1255*33b1fccfSAndroid Build Coastguard Worker 
1256*33b1fccfSAndroid Build Coastguard Worker 	ret = z_erofs_compress_segment(sctx, sctx->seg_idx * cfg.c_mkfs_segment_size,
1257*33b1fccfSAndroid Build Coastguard Worker 				       EROFS_NULL_ADDR);
1258*33b1fccfSAndroid Build Coastguard Worker 
1259*33b1fccfSAndroid Build Coastguard Worker out:
1260*33b1fccfSAndroid Build Coastguard Worker 	cwork->errcode = ret;
1261*33b1fccfSAndroid Build Coastguard Worker 	pthread_mutex_lock(&ictx->mutex);
1262*33b1fccfSAndroid Build Coastguard Worker 	if (++ictx->nfini >= ictx->seg_num) {
1263*33b1fccfSAndroid Build Coastguard Worker 		DBG_BUGON(ictx->nfini > ictx->seg_num);
1264*33b1fccfSAndroid Build Coastguard Worker 		pthread_cond_signal(&ictx->cond);
1265*33b1fccfSAndroid Build Coastguard Worker 	}
1266*33b1fccfSAndroid Build Coastguard Worker 	pthread_mutex_unlock(&ictx->mutex);
1267*33b1fccfSAndroid Build Coastguard Worker }
1268*33b1fccfSAndroid Build Coastguard Worker 
z_erofs_merge_segment(struct z_erofs_compress_ictx * ictx,struct z_erofs_compress_sctx * sctx)1269*33b1fccfSAndroid Build Coastguard Worker int z_erofs_merge_segment(struct z_erofs_compress_ictx *ictx,
1270*33b1fccfSAndroid Build Coastguard Worker 			  struct z_erofs_compress_sctx *sctx)
1271*33b1fccfSAndroid Build Coastguard Worker {
1272*33b1fccfSAndroid Build Coastguard Worker 	struct z_erofs_extent_item *ei, *n;
1273*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_sb_info *sbi = ictx->inode->sbi;
1274*33b1fccfSAndroid Build Coastguard Worker 	erofs_blk_t blkoff = 0;
1275*33b1fccfSAndroid Build Coastguard Worker 	int ret = 0, ret2;
1276*33b1fccfSAndroid Build Coastguard Worker 
1277*33b1fccfSAndroid Build Coastguard Worker 	list_for_each_entry_safe(ei, n, &sctx->extents, list) {
1278*33b1fccfSAndroid Build Coastguard Worker 		list_del(&ei->list);
1279*33b1fccfSAndroid Build Coastguard Worker 		list_add_tail(&ei->list, &ictx->extents);
1280*33b1fccfSAndroid Build Coastguard Worker 
1281*33b1fccfSAndroid Build Coastguard Worker 		if (ei->e.blkaddr != EROFS_NULL_ADDR)	/* deduped extents */
1282*33b1fccfSAndroid Build Coastguard Worker 			continue;
1283*33b1fccfSAndroid Build Coastguard Worker 
1284*33b1fccfSAndroid Build Coastguard Worker 		ei->e.blkaddr = sctx->blkaddr;
1285*33b1fccfSAndroid Build Coastguard Worker 		sctx->blkaddr += ei->e.compressedblks;
1286*33b1fccfSAndroid Build Coastguard Worker 
1287*33b1fccfSAndroid Build Coastguard Worker 		/* skip write data but leave blkaddr for inline fallback */
1288*33b1fccfSAndroid Build Coastguard Worker 		if (ei->e.inlined || !ei->e.compressedblks)
1289*33b1fccfSAndroid Build Coastguard Worker 			continue;
1290*33b1fccfSAndroid Build Coastguard Worker 		ret2 = erofs_blk_write(sbi, sctx->membuf + blkoff * erofs_blksiz(sbi),
1291*33b1fccfSAndroid Build Coastguard Worker 				       ei->e.blkaddr, ei->e.compressedblks);
1292*33b1fccfSAndroid Build Coastguard Worker 		blkoff += ei->e.compressedblks;
1293*33b1fccfSAndroid Build Coastguard Worker 		if (ret2) {
1294*33b1fccfSAndroid Build Coastguard Worker 			ret = ret2;
1295*33b1fccfSAndroid Build Coastguard Worker 			continue;
1296*33b1fccfSAndroid Build Coastguard Worker 		}
1297*33b1fccfSAndroid Build Coastguard Worker 	}
1298*33b1fccfSAndroid Build Coastguard Worker 	free(sctx->membuf);
1299*33b1fccfSAndroid Build Coastguard Worker 	return ret;
1300*33b1fccfSAndroid Build Coastguard Worker }
1301*33b1fccfSAndroid Build Coastguard Worker 
z_erofs_mt_compress(struct z_erofs_compress_ictx * ictx)1302*33b1fccfSAndroid Build Coastguard Worker int z_erofs_mt_compress(struct z_erofs_compress_ictx *ictx)
1303*33b1fccfSAndroid Build Coastguard Worker {
1304*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_compress_work *cur, *head = NULL, **last = &head;
1305*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_compress_cfg *ccfg = ictx->ccfg;
1306*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_inode *inode = ictx->inode;
1307*33b1fccfSAndroid Build Coastguard Worker 	int nsegs = DIV_ROUND_UP(inode->i_size, cfg.c_mkfs_segment_size);
1308*33b1fccfSAndroid Build Coastguard Worker 	int i;
1309*33b1fccfSAndroid Build Coastguard Worker 
1310*33b1fccfSAndroid Build Coastguard Worker 	ictx->seg_num = nsegs;
1311*33b1fccfSAndroid Build Coastguard Worker 	ictx->nfini = 0;
1312*33b1fccfSAndroid Build Coastguard Worker 	pthread_mutex_init(&ictx->mutex, NULL);
1313*33b1fccfSAndroid Build Coastguard Worker 	pthread_cond_init(&ictx->cond, NULL);
1314*33b1fccfSAndroid Build Coastguard Worker 
1315*33b1fccfSAndroid Build Coastguard Worker 	for (i = 0; i < nsegs; i++) {
1316*33b1fccfSAndroid Build Coastguard Worker 		pthread_mutex_lock(&z_erofs_mt_ctrl.mutex);
1317*33b1fccfSAndroid Build Coastguard Worker 		cur = z_erofs_mt_ctrl.idle;
1318*33b1fccfSAndroid Build Coastguard Worker 		if (cur) {
1319*33b1fccfSAndroid Build Coastguard Worker 			z_erofs_mt_ctrl.idle = cur->next;
1320*33b1fccfSAndroid Build Coastguard Worker 			cur->next = NULL;
1321*33b1fccfSAndroid Build Coastguard Worker 		}
1322*33b1fccfSAndroid Build Coastguard Worker 		pthread_mutex_unlock(&z_erofs_mt_ctrl.mutex);
1323*33b1fccfSAndroid Build Coastguard Worker 		if (!cur) {
1324*33b1fccfSAndroid Build Coastguard Worker 			cur = calloc(1, sizeof(*cur));
1325*33b1fccfSAndroid Build Coastguard Worker 			if (!cur)
1326*33b1fccfSAndroid Build Coastguard Worker 				return -ENOMEM;
1327*33b1fccfSAndroid Build Coastguard Worker 		}
1328*33b1fccfSAndroid Build Coastguard Worker 		*last = cur;
1329*33b1fccfSAndroid Build Coastguard Worker 		last = &cur->next;
1330*33b1fccfSAndroid Build Coastguard Worker 
1331*33b1fccfSAndroid Build Coastguard Worker 		cur->ctx = (struct z_erofs_compress_sctx) {
1332*33b1fccfSAndroid Build Coastguard Worker 			.ictx = ictx,
1333*33b1fccfSAndroid Build Coastguard Worker 			.seg_idx = i,
1334*33b1fccfSAndroid Build Coastguard Worker 			.pivot = &dummy_pivot,
1335*33b1fccfSAndroid Build Coastguard Worker 		};
1336*33b1fccfSAndroid Build Coastguard Worker 		init_list_head(&cur->ctx.extents);
1337*33b1fccfSAndroid Build Coastguard Worker 
1338*33b1fccfSAndroid Build Coastguard Worker 		if (i == nsegs - 1)
1339*33b1fccfSAndroid Build Coastguard Worker 			cur->ctx.remaining = inode->i_size -
1340*33b1fccfSAndroid Build Coastguard Worker 					      inode->fragment_size -
1341*33b1fccfSAndroid Build Coastguard Worker 					      i * cfg.c_mkfs_segment_size;
1342*33b1fccfSAndroid Build Coastguard Worker 		else
1343*33b1fccfSAndroid Build Coastguard Worker 			cur->ctx.remaining = cfg.c_mkfs_segment_size;
1344*33b1fccfSAndroid Build Coastguard Worker 
1345*33b1fccfSAndroid Build Coastguard Worker 		cur->alg_id = ccfg->handle.alg->id;
1346*33b1fccfSAndroid Build Coastguard Worker 		cur->alg_name = ccfg->handle.alg->name;
1347*33b1fccfSAndroid Build Coastguard Worker 		cur->comp_level = ccfg->handle.compression_level;
1348*33b1fccfSAndroid Build Coastguard Worker 		cur->dict_size = ccfg->handle.dict_size;
1349*33b1fccfSAndroid Build Coastguard Worker 
1350*33b1fccfSAndroid Build Coastguard Worker 		cur->work.fn = z_erofs_mt_workfn;
1351*33b1fccfSAndroid Build Coastguard Worker 		erofs_queue_work(&z_erofs_mt_ctrl.wq, &cur->work);
1352*33b1fccfSAndroid Build Coastguard Worker 	}
1353*33b1fccfSAndroid Build Coastguard Worker 	ictx->mtworks = head;
1354*33b1fccfSAndroid Build Coastguard Worker 	return 0;
1355*33b1fccfSAndroid Build Coastguard Worker }
1356*33b1fccfSAndroid Build Coastguard Worker 
erofs_mt_write_compressed_file(struct z_erofs_compress_ictx * ictx)1357*33b1fccfSAndroid Build Coastguard Worker int erofs_mt_write_compressed_file(struct z_erofs_compress_ictx *ictx)
1358*33b1fccfSAndroid Build Coastguard Worker {
1359*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_sb_info *sbi = ictx->inode->sbi;
1360*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_buffer_head *bh = NULL;
1361*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_compress_work *head = ictx->mtworks, *cur;
1362*33b1fccfSAndroid Build Coastguard Worker 	erofs_blk_t blkaddr, compressed_blocks = 0;
1363*33b1fccfSAndroid Build Coastguard Worker 	int ret;
1364*33b1fccfSAndroid Build Coastguard Worker 
1365*33b1fccfSAndroid Build Coastguard Worker 	pthread_mutex_lock(&ictx->mutex);
1366*33b1fccfSAndroid Build Coastguard Worker 	while (ictx->nfini < ictx->seg_num)
1367*33b1fccfSAndroid Build Coastguard Worker 		pthread_cond_wait(&ictx->cond, &ictx->mutex);
1368*33b1fccfSAndroid Build Coastguard Worker 	pthread_mutex_unlock(&ictx->mutex);
1369*33b1fccfSAndroid Build Coastguard Worker 
1370*33b1fccfSAndroid Build Coastguard Worker 	bh = erofs_balloc(sbi->bmgr, DATA, 0, 0, 0);
1371*33b1fccfSAndroid Build Coastguard Worker 	if (IS_ERR(bh)) {
1372*33b1fccfSAndroid Build Coastguard Worker 		ret = PTR_ERR(bh);
1373*33b1fccfSAndroid Build Coastguard Worker 		goto out;
1374*33b1fccfSAndroid Build Coastguard Worker 	}
1375*33b1fccfSAndroid Build Coastguard Worker 
1376*33b1fccfSAndroid Build Coastguard Worker 	DBG_BUGON(!head);
1377*33b1fccfSAndroid Build Coastguard Worker 	blkaddr = erofs_mapbh(NULL, bh->block);
1378*33b1fccfSAndroid Build Coastguard Worker 
1379*33b1fccfSAndroid Build Coastguard Worker 	ret = 0;
1380*33b1fccfSAndroid Build Coastguard Worker 	do {
1381*33b1fccfSAndroid Build Coastguard Worker 		cur = head;
1382*33b1fccfSAndroid Build Coastguard Worker 		head = cur->next;
1383*33b1fccfSAndroid Build Coastguard Worker 
1384*33b1fccfSAndroid Build Coastguard Worker 		if (cur->errcode) {
1385*33b1fccfSAndroid Build Coastguard Worker 			ret = cur->errcode;
1386*33b1fccfSAndroid Build Coastguard Worker 		} else {
1387*33b1fccfSAndroid Build Coastguard Worker 			int ret2;
1388*33b1fccfSAndroid Build Coastguard Worker 
1389*33b1fccfSAndroid Build Coastguard Worker 			cur->ctx.blkaddr = blkaddr;
1390*33b1fccfSAndroid Build Coastguard Worker 			ret2 = z_erofs_merge_segment(ictx, &cur->ctx);
1391*33b1fccfSAndroid Build Coastguard Worker 			if (ret2)
1392*33b1fccfSAndroid Build Coastguard Worker 				ret = ret2;
1393*33b1fccfSAndroid Build Coastguard Worker 
1394*33b1fccfSAndroid Build Coastguard Worker 			compressed_blocks += cur->ctx.blkaddr - blkaddr;
1395*33b1fccfSAndroid Build Coastguard Worker 			blkaddr = cur->ctx.blkaddr;
1396*33b1fccfSAndroid Build Coastguard Worker 		}
1397*33b1fccfSAndroid Build Coastguard Worker 
1398*33b1fccfSAndroid Build Coastguard Worker 		pthread_mutex_lock(&z_erofs_mt_ctrl.mutex);
1399*33b1fccfSAndroid Build Coastguard Worker 		cur->next = z_erofs_mt_ctrl.idle;
1400*33b1fccfSAndroid Build Coastguard Worker 		z_erofs_mt_ctrl.idle = cur;
1401*33b1fccfSAndroid Build Coastguard Worker 		pthread_mutex_unlock(&z_erofs_mt_ctrl.mutex);
1402*33b1fccfSAndroid Build Coastguard Worker 	} while (head);
1403*33b1fccfSAndroid Build Coastguard Worker 
1404*33b1fccfSAndroid Build Coastguard Worker 	if (ret)
1405*33b1fccfSAndroid Build Coastguard Worker 		goto out;
1406*33b1fccfSAndroid Build Coastguard Worker 	ret = erofs_commit_compressed_file(ictx, bh,
1407*33b1fccfSAndroid Build Coastguard Worker 			blkaddr - compressed_blocks, compressed_blocks);
1408*33b1fccfSAndroid Build Coastguard Worker 
1409*33b1fccfSAndroid Build Coastguard Worker out:
1410*33b1fccfSAndroid Build Coastguard Worker 	close(ictx->fd);
1411*33b1fccfSAndroid Build Coastguard Worker 	free(ictx);
1412*33b1fccfSAndroid Build Coastguard Worker 	return ret;
1413*33b1fccfSAndroid Build Coastguard Worker }
1414*33b1fccfSAndroid Build Coastguard Worker #endif
1415*33b1fccfSAndroid Build Coastguard Worker 
1416*33b1fccfSAndroid Build Coastguard Worker static struct z_erofs_compress_ictx g_ictx;
1417*33b1fccfSAndroid Build Coastguard Worker 
erofs_begin_compressed_file(struct erofs_inode * inode,int fd,u64 fpos)1418*33b1fccfSAndroid Build Coastguard Worker void *erofs_begin_compressed_file(struct erofs_inode *inode, int fd, u64 fpos)
1419*33b1fccfSAndroid Build Coastguard Worker {
1420*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_sb_info *sbi = inode->sbi;
1421*33b1fccfSAndroid Build Coastguard Worker 	struct z_erofs_compress_ictx *ictx;
1422*33b1fccfSAndroid Build Coastguard Worker 	int ret;
1423*33b1fccfSAndroid Build Coastguard Worker 
1424*33b1fccfSAndroid Build Coastguard Worker 	/* initialize per-file compression setting */
1425*33b1fccfSAndroid Build Coastguard Worker 	inode->z_advise = 0;
1426*33b1fccfSAndroid Build Coastguard Worker 	inode->z_logical_clusterbits = sbi->blkszbits;
1427*33b1fccfSAndroid Build Coastguard Worker 	if (!cfg.c_legacy_compress && inode->z_logical_clusterbits <= 14) {
1428*33b1fccfSAndroid Build Coastguard Worker 		if (inode->z_logical_clusterbits <= 12)
1429*33b1fccfSAndroid Build Coastguard Worker 			inode->z_advise |= Z_EROFS_ADVISE_COMPACTED_2B;
1430*33b1fccfSAndroid Build Coastguard Worker 		inode->datalayout = EROFS_INODE_COMPRESSED_COMPACT;
1431*33b1fccfSAndroid Build Coastguard Worker 	} else {
1432*33b1fccfSAndroid Build Coastguard Worker 		inode->datalayout = EROFS_INODE_COMPRESSED_FULL;
1433*33b1fccfSAndroid Build Coastguard Worker 	}
1434*33b1fccfSAndroid Build Coastguard Worker 
1435*33b1fccfSAndroid Build Coastguard Worker 	if (erofs_sb_has_big_pcluster(sbi)) {
1436*33b1fccfSAndroid Build Coastguard Worker 		inode->z_advise |= Z_EROFS_ADVISE_BIG_PCLUSTER_1;
1437*33b1fccfSAndroid Build Coastguard Worker 		if (inode->datalayout == EROFS_INODE_COMPRESSED_COMPACT)
1438*33b1fccfSAndroid Build Coastguard Worker 			inode->z_advise |= Z_EROFS_ADVISE_BIG_PCLUSTER_2;
1439*33b1fccfSAndroid Build Coastguard Worker 	}
1440*33b1fccfSAndroid Build Coastguard Worker 	if (cfg.c_fragments && !cfg.c_dedupe)
1441*33b1fccfSAndroid Build Coastguard Worker 		inode->z_advise |= Z_EROFS_ADVISE_INTERLACED_PCLUSTER;
1442*33b1fccfSAndroid Build Coastguard Worker 
1443*33b1fccfSAndroid Build Coastguard Worker #ifndef NDEBUG
1444*33b1fccfSAndroid Build Coastguard Worker 	if (cfg.c_random_algorithms) {
1445*33b1fccfSAndroid Build Coastguard Worker 		while (1) {
1446*33b1fccfSAndroid Build Coastguard Worker 			inode->z_algorithmtype[0] =
1447*33b1fccfSAndroid Build Coastguard Worker 				rand() % EROFS_MAX_COMPR_CFGS;
1448*33b1fccfSAndroid Build Coastguard Worker 			if (erofs_ccfg[inode->z_algorithmtype[0]].enable)
1449*33b1fccfSAndroid Build Coastguard Worker 				break;
1450*33b1fccfSAndroid Build Coastguard Worker 		}
1451*33b1fccfSAndroid Build Coastguard Worker 	}
1452*33b1fccfSAndroid Build Coastguard Worker #endif
1453*33b1fccfSAndroid Build Coastguard Worker 	inode->idata_size = 0;
1454*33b1fccfSAndroid Build Coastguard Worker 	inode->fragment_size = 0;
1455*33b1fccfSAndroid Build Coastguard Worker 
1456*33b1fccfSAndroid Build Coastguard Worker 	if (z_erofs_mt_enabled) {
1457*33b1fccfSAndroid Build Coastguard Worker 		ictx = malloc(sizeof(*ictx));
1458*33b1fccfSAndroid Build Coastguard Worker 		if (!ictx)
1459*33b1fccfSAndroid Build Coastguard Worker 			return ERR_PTR(-ENOMEM);
1460*33b1fccfSAndroid Build Coastguard Worker 		ictx->fd = dup(fd);
1461*33b1fccfSAndroid Build Coastguard Worker 	} else {
1462*33b1fccfSAndroid Build Coastguard Worker #ifdef EROFS_MT_ENABLED
1463*33b1fccfSAndroid Build Coastguard Worker 		pthread_mutex_lock(&g_ictx.mutex);
1464*33b1fccfSAndroid Build Coastguard Worker 		if (g_ictx.seg_num)
1465*33b1fccfSAndroid Build Coastguard Worker 			pthread_cond_wait(&g_ictx.cond, &g_ictx.mutex);
1466*33b1fccfSAndroid Build Coastguard Worker 		g_ictx.seg_num = 1;
1467*33b1fccfSAndroid Build Coastguard Worker 		pthread_mutex_unlock(&g_ictx.mutex);
1468*33b1fccfSAndroid Build Coastguard Worker #endif
1469*33b1fccfSAndroid Build Coastguard Worker 		ictx = &g_ictx;
1470*33b1fccfSAndroid Build Coastguard Worker 		ictx->fd = fd;
1471*33b1fccfSAndroid Build Coastguard Worker 	}
1472*33b1fccfSAndroid Build Coastguard Worker 
1473*33b1fccfSAndroid Build Coastguard Worker 	ictx->ccfg = &erofs_ccfg[inode->z_algorithmtype[0]];
1474*33b1fccfSAndroid Build Coastguard Worker 	inode->z_algorithmtype[0] = ictx->ccfg->algorithmtype;
1475*33b1fccfSAndroid Build Coastguard Worker 	inode->z_algorithmtype[1] = 0;
1476*33b1fccfSAndroid Build Coastguard Worker 
1477*33b1fccfSAndroid Build Coastguard Worker 	/*
1478*33b1fccfSAndroid Build Coastguard Worker 	 * Handle tails in advance to avoid writing duplicated
1479*33b1fccfSAndroid Build Coastguard Worker 	 * parts into the packed inode.
1480*33b1fccfSAndroid Build Coastguard Worker 	 */
1481*33b1fccfSAndroid Build Coastguard Worker 	if (cfg.c_fragments && !erofs_is_packed_inode(inode)) {
1482*33b1fccfSAndroid Build Coastguard Worker 		ret = z_erofs_fragments_dedupe(inode, fd, &ictx->tof_chksum);
1483*33b1fccfSAndroid Build Coastguard Worker 		if (ret < 0)
1484*33b1fccfSAndroid Build Coastguard Worker 			goto err_free_ictx;
1485*33b1fccfSAndroid Build Coastguard Worker 	}
1486*33b1fccfSAndroid Build Coastguard Worker 
1487*33b1fccfSAndroid Build Coastguard Worker 	ictx->inode = inode;
1488*33b1fccfSAndroid Build Coastguard Worker 	ictx->fpos = fpos;
1489*33b1fccfSAndroid Build Coastguard Worker 	init_list_head(&ictx->extents);
1490*33b1fccfSAndroid Build Coastguard Worker 	ictx->fix_dedupedfrag = false;
1491*33b1fccfSAndroid Build Coastguard Worker 	ictx->fragemitted = false;
1492*33b1fccfSAndroid Build Coastguard Worker 
1493*33b1fccfSAndroid Build Coastguard Worker 	if (cfg.c_all_fragments && !erofs_is_packed_inode(inode) &&
1494*33b1fccfSAndroid Build Coastguard Worker 	    !inode->fragment_size) {
1495*33b1fccfSAndroid Build Coastguard Worker 		ret = z_erofs_pack_file_from_fd(inode, fd, ictx->tof_chksum);
1496*33b1fccfSAndroid Build Coastguard Worker 		if (ret)
1497*33b1fccfSAndroid Build Coastguard Worker 			goto err_free_idata;
1498*33b1fccfSAndroid Build Coastguard Worker 	}
1499*33b1fccfSAndroid Build Coastguard Worker #ifdef EROFS_MT_ENABLED
1500*33b1fccfSAndroid Build Coastguard Worker 	if (ictx != &g_ictx) {
1501*33b1fccfSAndroid Build Coastguard Worker 		ret = z_erofs_mt_compress(ictx);
1502*33b1fccfSAndroid Build Coastguard Worker 		if (ret)
1503*33b1fccfSAndroid Build Coastguard Worker 			goto err_free_idata;
1504*33b1fccfSAndroid Build Coastguard Worker 	}
1505*33b1fccfSAndroid Build Coastguard Worker #endif
1506*33b1fccfSAndroid Build Coastguard Worker 	return ictx;
1507*33b1fccfSAndroid Build Coastguard Worker 
1508*33b1fccfSAndroid Build Coastguard Worker err_free_idata:
1509*33b1fccfSAndroid Build Coastguard Worker 	if (inode->idata) {
1510*33b1fccfSAndroid Build Coastguard Worker 		free(inode->idata);
1511*33b1fccfSAndroid Build Coastguard Worker 		inode->idata = NULL;
1512*33b1fccfSAndroid Build Coastguard Worker 	}
1513*33b1fccfSAndroid Build Coastguard Worker err_free_ictx:
1514*33b1fccfSAndroid Build Coastguard Worker 	if (ictx != &g_ictx)
1515*33b1fccfSAndroid Build Coastguard Worker 		free(ictx);
1516*33b1fccfSAndroid Build Coastguard Worker 	return ERR_PTR(ret);
1517*33b1fccfSAndroid Build Coastguard Worker }
1518*33b1fccfSAndroid Build Coastguard Worker 
erofs_write_compressed_file(struct z_erofs_compress_ictx * ictx)1519*33b1fccfSAndroid Build Coastguard Worker int erofs_write_compressed_file(struct z_erofs_compress_ictx *ictx)
1520*33b1fccfSAndroid Build Coastguard Worker {
1521*33b1fccfSAndroid Build Coastguard Worker 	static u8 g_queue[Z_EROFS_COMPR_QUEUE_SZ];
1522*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_buffer_head *bh;
1523*33b1fccfSAndroid Build Coastguard Worker 	static struct z_erofs_compress_sctx sctx;
1524*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_compress_cfg *ccfg = ictx->ccfg;
1525*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_inode *inode = ictx->inode;
1526*33b1fccfSAndroid Build Coastguard Worker 	erofs_blk_t blkaddr;
1527*33b1fccfSAndroid Build Coastguard Worker 	int ret;
1528*33b1fccfSAndroid Build Coastguard Worker 
1529*33b1fccfSAndroid Build Coastguard Worker #ifdef EROFS_MT_ENABLED
1530*33b1fccfSAndroid Build Coastguard Worker 	if (ictx != &g_ictx)
1531*33b1fccfSAndroid Build Coastguard Worker 		return erofs_mt_write_compressed_file(ictx);
1532*33b1fccfSAndroid Build Coastguard Worker #endif
1533*33b1fccfSAndroid Build Coastguard Worker 
1534*33b1fccfSAndroid Build Coastguard Worker 	/* allocate main data buffer */
1535*33b1fccfSAndroid Build Coastguard Worker 	bh = erofs_balloc(inode->sbi->bmgr, DATA, 0, 0, 0);
1536*33b1fccfSAndroid Build Coastguard Worker 	if (IS_ERR(bh)) {
1537*33b1fccfSAndroid Build Coastguard Worker 		ret = PTR_ERR(bh);
1538*33b1fccfSAndroid Build Coastguard Worker 		goto err_free_idata;
1539*33b1fccfSAndroid Build Coastguard Worker 	}
1540*33b1fccfSAndroid Build Coastguard Worker 	blkaddr = erofs_mapbh(NULL, bh->block); /* start_blkaddr */
1541*33b1fccfSAndroid Build Coastguard Worker 
1542*33b1fccfSAndroid Build Coastguard Worker 	ictx->seg_num = 1;
1543*33b1fccfSAndroid Build Coastguard Worker 	sctx = (struct z_erofs_compress_sctx) {
1544*33b1fccfSAndroid Build Coastguard Worker 		.ictx = ictx,
1545*33b1fccfSAndroid Build Coastguard Worker 		.queue = g_queue,
1546*33b1fccfSAndroid Build Coastguard Worker 		.chandle = &ccfg->handle,
1547*33b1fccfSAndroid Build Coastguard Worker 		.remaining = inode->i_size - inode->fragment_size,
1548*33b1fccfSAndroid Build Coastguard Worker 		.seg_idx = 0,
1549*33b1fccfSAndroid Build Coastguard Worker 		.pivot = &dummy_pivot,
1550*33b1fccfSAndroid Build Coastguard Worker 		.pclustersize = z_erofs_get_max_pclustersize(inode),
1551*33b1fccfSAndroid Build Coastguard Worker 	};
1552*33b1fccfSAndroid Build Coastguard Worker 	init_list_head(&sctx.extents);
1553*33b1fccfSAndroid Build Coastguard Worker 
1554*33b1fccfSAndroid Build Coastguard Worker 	ret = z_erofs_compress_segment(&sctx, -1, blkaddr);
1555*33b1fccfSAndroid Build Coastguard Worker 	if (ret)
1556*33b1fccfSAndroid Build Coastguard Worker 		goto err_free_idata;
1557*33b1fccfSAndroid Build Coastguard Worker 
1558*33b1fccfSAndroid Build Coastguard Worker 	list_splice_tail(&sctx.extents, &ictx->extents);
1559*33b1fccfSAndroid Build Coastguard Worker 	ret = erofs_commit_compressed_file(ictx, bh, blkaddr,
1560*33b1fccfSAndroid Build Coastguard Worker 					   sctx.blkaddr - blkaddr);
1561*33b1fccfSAndroid Build Coastguard Worker 	goto out;
1562*33b1fccfSAndroid Build Coastguard Worker 
1563*33b1fccfSAndroid Build Coastguard Worker err_free_idata:
1564*33b1fccfSAndroid Build Coastguard Worker 	erofs_bdrop(bh, true);	/* revoke buffer */
1565*33b1fccfSAndroid Build Coastguard Worker 	if (inode->idata) {
1566*33b1fccfSAndroid Build Coastguard Worker 		free(inode->idata);
1567*33b1fccfSAndroid Build Coastguard Worker 		inode->idata = NULL;
1568*33b1fccfSAndroid Build Coastguard Worker 	}
1569*33b1fccfSAndroid Build Coastguard Worker out:
1570*33b1fccfSAndroid Build Coastguard Worker #ifdef EROFS_MT_ENABLED
1571*33b1fccfSAndroid Build Coastguard Worker 	pthread_mutex_lock(&ictx->mutex);
1572*33b1fccfSAndroid Build Coastguard Worker 	ictx->seg_num = 0;
1573*33b1fccfSAndroid Build Coastguard Worker 	pthread_cond_signal(&ictx->cond);
1574*33b1fccfSAndroid Build Coastguard Worker 	pthread_mutex_unlock(&ictx->mutex);
1575*33b1fccfSAndroid Build Coastguard Worker #endif
1576*33b1fccfSAndroid Build Coastguard Worker 	return ret;
1577*33b1fccfSAndroid Build Coastguard Worker }
1578*33b1fccfSAndroid Build Coastguard Worker 
z_erofs_build_compr_cfgs(struct erofs_sb_info * sbi,struct erofs_buffer_head * sb_bh,u32 * max_dict_size)1579*33b1fccfSAndroid Build Coastguard Worker static int z_erofs_build_compr_cfgs(struct erofs_sb_info *sbi,
1580*33b1fccfSAndroid Build Coastguard Worker 				    struct erofs_buffer_head *sb_bh,
1581*33b1fccfSAndroid Build Coastguard Worker 				    u32 *max_dict_size)
1582*33b1fccfSAndroid Build Coastguard Worker {
1583*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_buffer_head *bh = sb_bh;
1584*33b1fccfSAndroid Build Coastguard Worker 	int ret = 0;
1585*33b1fccfSAndroid Build Coastguard Worker 
1586*33b1fccfSAndroid Build Coastguard Worker 	if (sbi->available_compr_algs & (1 << Z_EROFS_COMPRESSION_LZ4)) {
1587*33b1fccfSAndroid Build Coastguard Worker 		struct {
1588*33b1fccfSAndroid Build Coastguard Worker 			__le16 size;
1589*33b1fccfSAndroid Build Coastguard Worker 			struct z_erofs_lz4_cfgs lz4;
1590*33b1fccfSAndroid Build Coastguard Worker 		} __packed lz4alg = {
1591*33b1fccfSAndroid Build Coastguard Worker 			.size = cpu_to_le16(sizeof(struct z_erofs_lz4_cfgs)),
1592*33b1fccfSAndroid Build Coastguard Worker 			.lz4 = {
1593*33b1fccfSAndroid Build Coastguard Worker 				.max_distance =
1594*33b1fccfSAndroid Build Coastguard Worker 					cpu_to_le16(sbi->lz4.max_distance),
1595*33b1fccfSAndroid Build Coastguard Worker 				.max_pclusterblks =
1596*33b1fccfSAndroid Build Coastguard Worker 					cfg.c_mkfs_pclustersize_max >> sbi->blkszbits,
1597*33b1fccfSAndroid Build Coastguard Worker 			}
1598*33b1fccfSAndroid Build Coastguard Worker 		};
1599*33b1fccfSAndroid Build Coastguard Worker 
1600*33b1fccfSAndroid Build Coastguard Worker 		bh = erofs_battach(bh, META, sizeof(lz4alg));
1601*33b1fccfSAndroid Build Coastguard Worker 		if (IS_ERR(bh)) {
1602*33b1fccfSAndroid Build Coastguard Worker 			DBG_BUGON(1);
1603*33b1fccfSAndroid Build Coastguard Worker 			return PTR_ERR(bh);
1604*33b1fccfSAndroid Build Coastguard Worker 		}
1605*33b1fccfSAndroid Build Coastguard Worker 		erofs_mapbh(NULL, bh->block);
1606*33b1fccfSAndroid Build Coastguard Worker 		ret = erofs_dev_write(sbi, &lz4alg, erofs_btell(bh, false),
1607*33b1fccfSAndroid Build Coastguard Worker 				      sizeof(lz4alg));
1608*33b1fccfSAndroid Build Coastguard Worker 		bh->op = &erofs_drop_directly_bhops;
1609*33b1fccfSAndroid Build Coastguard Worker 	}
1610*33b1fccfSAndroid Build Coastguard Worker #ifdef HAVE_LIBLZMA
1611*33b1fccfSAndroid Build Coastguard Worker 	if (sbi->available_compr_algs & (1 << Z_EROFS_COMPRESSION_LZMA)) {
1612*33b1fccfSAndroid Build Coastguard Worker 		struct {
1613*33b1fccfSAndroid Build Coastguard Worker 			__le16 size;
1614*33b1fccfSAndroid Build Coastguard Worker 			struct z_erofs_lzma_cfgs lzma;
1615*33b1fccfSAndroid Build Coastguard Worker 		} __packed lzmaalg = {
1616*33b1fccfSAndroid Build Coastguard Worker 			.size = cpu_to_le16(sizeof(struct z_erofs_lzma_cfgs)),
1617*33b1fccfSAndroid Build Coastguard Worker 			.lzma = {
1618*33b1fccfSAndroid Build Coastguard Worker 				.dict_size = cpu_to_le32(
1619*33b1fccfSAndroid Build Coastguard Worker 					max_dict_size
1620*33b1fccfSAndroid Build Coastguard Worker 						[Z_EROFS_COMPRESSION_LZMA]),
1621*33b1fccfSAndroid Build Coastguard Worker 			}
1622*33b1fccfSAndroid Build Coastguard Worker 		};
1623*33b1fccfSAndroid Build Coastguard Worker 
1624*33b1fccfSAndroid Build Coastguard Worker 		bh = erofs_battach(bh, META, sizeof(lzmaalg));
1625*33b1fccfSAndroid Build Coastguard Worker 		if (IS_ERR(bh)) {
1626*33b1fccfSAndroid Build Coastguard Worker 			DBG_BUGON(1);
1627*33b1fccfSAndroid Build Coastguard Worker 			return PTR_ERR(bh);
1628*33b1fccfSAndroid Build Coastguard Worker 		}
1629*33b1fccfSAndroid Build Coastguard Worker 		erofs_mapbh(NULL, bh->block);
1630*33b1fccfSAndroid Build Coastguard Worker 		ret = erofs_dev_write(sbi, &lzmaalg, erofs_btell(bh, false),
1631*33b1fccfSAndroid Build Coastguard Worker 				      sizeof(lzmaalg));
1632*33b1fccfSAndroid Build Coastguard Worker 		bh->op = &erofs_drop_directly_bhops;
1633*33b1fccfSAndroid Build Coastguard Worker 	}
1634*33b1fccfSAndroid Build Coastguard Worker #endif
1635*33b1fccfSAndroid Build Coastguard Worker 	if (sbi->available_compr_algs & (1 << Z_EROFS_COMPRESSION_DEFLATE)) {
1636*33b1fccfSAndroid Build Coastguard Worker 		struct {
1637*33b1fccfSAndroid Build Coastguard Worker 			__le16 size;
1638*33b1fccfSAndroid Build Coastguard Worker 			struct z_erofs_deflate_cfgs z;
1639*33b1fccfSAndroid Build Coastguard Worker 		} __packed zalg = {
1640*33b1fccfSAndroid Build Coastguard Worker 			.size = cpu_to_le16(sizeof(struct z_erofs_deflate_cfgs)),
1641*33b1fccfSAndroid Build Coastguard Worker 			.z = {
1642*33b1fccfSAndroid Build Coastguard Worker 				.windowbits = cpu_to_le32(ilog2(
1643*33b1fccfSAndroid Build Coastguard Worker 					max_dict_size
1644*33b1fccfSAndroid Build Coastguard Worker 						[Z_EROFS_COMPRESSION_DEFLATE])),
1645*33b1fccfSAndroid Build Coastguard Worker 			}
1646*33b1fccfSAndroid Build Coastguard Worker 		};
1647*33b1fccfSAndroid Build Coastguard Worker 
1648*33b1fccfSAndroid Build Coastguard Worker 		bh = erofs_battach(bh, META, sizeof(zalg));
1649*33b1fccfSAndroid Build Coastguard Worker 		if (IS_ERR(bh)) {
1650*33b1fccfSAndroid Build Coastguard Worker 			DBG_BUGON(1);
1651*33b1fccfSAndroid Build Coastguard Worker 			return PTR_ERR(bh);
1652*33b1fccfSAndroid Build Coastguard Worker 		}
1653*33b1fccfSAndroid Build Coastguard Worker 		erofs_mapbh(NULL, bh->block);
1654*33b1fccfSAndroid Build Coastguard Worker 		ret = erofs_dev_write(sbi, &zalg, erofs_btell(bh, false),
1655*33b1fccfSAndroid Build Coastguard Worker 				      sizeof(zalg));
1656*33b1fccfSAndroid Build Coastguard Worker 		bh->op = &erofs_drop_directly_bhops;
1657*33b1fccfSAndroid Build Coastguard Worker 	}
1658*33b1fccfSAndroid Build Coastguard Worker #ifdef HAVE_LIBZSTD
1659*33b1fccfSAndroid Build Coastguard Worker 	if (sbi->available_compr_algs & (1 << Z_EROFS_COMPRESSION_ZSTD)) {
1660*33b1fccfSAndroid Build Coastguard Worker 		struct {
1661*33b1fccfSAndroid Build Coastguard Worker 			__le16 size;
1662*33b1fccfSAndroid Build Coastguard Worker 			struct z_erofs_zstd_cfgs z;
1663*33b1fccfSAndroid Build Coastguard Worker 		} __packed zalg = {
1664*33b1fccfSAndroid Build Coastguard Worker 			.size = cpu_to_le16(sizeof(struct z_erofs_zstd_cfgs)),
1665*33b1fccfSAndroid Build Coastguard Worker 			.z = {
1666*33b1fccfSAndroid Build Coastguard Worker 				.windowlog =
1667*33b1fccfSAndroid Build Coastguard Worker 					ilog2(max_dict_size[Z_EROFS_COMPRESSION_ZSTD]) - 10,
1668*33b1fccfSAndroid Build Coastguard Worker 			}
1669*33b1fccfSAndroid Build Coastguard Worker 		};
1670*33b1fccfSAndroid Build Coastguard Worker 
1671*33b1fccfSAndroid Build Coastguard Worker 		bh = erofs_battach(bh, META, sizeof(zalg));
1672*33b1fccfSAndroid Build Coastguard Worker 		if (IS_ERR(bh)) {
1673*33b1fccfSAndroid Build Coastguard Worker 			DBG_BUGON(1);
1674*33b1fccfSAndroid Build Coastguard Worker 			return PTR_ERR(bh);
1675*33b1fccfSAndroid Build Coastguard Worker 		}
1676*33b1fccfSAndroid Build Coastguard Worker 		erofs_mapbh(NULL, bh->block);
1677*33b1fccfSAndroid Build Coastguard Worker 		ret = erofs_dev_write(sbi, &zalg, erofs_btell(bh, false),
1678*33b1fccfSAndroid Build Coastguard Worker 				      sizeof(zalg));
1679*33b1fccfSAndroid Build Coastguard Worker 		bh->op = &erofs_drop_directly_bhops;
1680*33b1fccfSAndroid Build Coastguard Worker 	}
1681*33b1fccfSAndroid Build Coastguard Worker #endif
1682*33b1fccfSAndroid Build Coastguard Worker 	return ret;
1683*33b1fccfSAndroid Build Coastguard Worker }
1684*33b1fccfSAndroid Build Coastguard Worker 
z_erofs_compress_init(struct erofs_sb_info * sbi,struct erofs_buffer_head * sb_bh)1685*33b1fccfSAndroid Build Coastguard Worker int z_erofs_compress_init(struct erofs_sb_info *sbi, struct erofs_buffer_head *sb_bh)
1686*33b1fccfSAndroid Build Coastguard Worker {
1687*33b1fccfSAndroid Build Coastguard Worker 	int i, ret, id;
1688*33b1fccfSAndroid Build Coastguard Worker 	u32 max_dict_size[Z_EROFS_COMPRESSION_MAX] = {};
1689*33b1fccfSAndroid Build Coastguard Worker 	u32 available_compr_algs = 0;
1690*33b1fccfSAndroid Build Coastguard Worker 
1691*33b1fccfSAndroid Build Coastguard Worker 	for (i = 0; cfg.c_compr_opts[i].alg; ++i) {
1692*33b1fccfSAndroid Build Coastguard Worker 		struct erofs_compress *c = &erofs_ccfg[i].handle;
1693*33b1fccfSAndroid Build Coastguard Worker 
1694*33b1fccfSAndroid Build Coastguard Worker 		ret = erofs_compressor_init(sbi, c, cfg.c_compr_opts[i].alg,
1695*33b1fccfSAndroid Build Coastguard Worker 					    cfg.c_compr_opts[i].level,
1696*33b1fccfSAndroid Build Coastguard Worker 					    cfg.c_compr_opts[i].dict_size);
1697*33b1fccfSAndroid Build Coastguard Worker 		if (ret)
1698*33b1fccfSAndroid Build Coastguard Worker 			return ret;
1699*33b1fccfSAndroid Build Coastguard Worker 
1700*33b1fccfSAndroid Build Coastguard Worker 		id = z_erofs_get_compress_algorithm_id(c);
1701*33b1fccfSAndroid Build Coastguard Worker 		erofs_ccfg[i].algorithmtype = id;
1702*33b1fccfSAndroid Build Coastguard Worker 		erofs_ccfg[i].enable = true;
1703*33b1fccfSAndroid Build Coastguard Worker 		available_compr_algs |= 1 << erofs_ccfg[i].algorithmtype;
1704*33b1fccfSAndroid Build Coastguard Worker 		if (erofs_ccfg[i].algorithmtype != Z_EROFS_COMPRESSION_LZ4)
1705*33b1fccfSAndroid Build Coastguard Worker 			erofs_sb_set_compr_cfgs(sbi);
1706*33b1fccfSAndroid Build Coastguard Worker 		if (c->dict_size > max_dict_size[id])
1707*33b1fccfSAndroid Build Coastguard Worker 			max_dict_size[id] = c->dict_size;
1708*33b1fccfSAndroid Build Coastguard Worker 	}
1709*33b1fccfSAndroid Build Coastguard Worker 
1710*33b1fccfSAndroid Build Coastguard Worker 	/*
1711*33b1fccfSAndroid Build Coastguard Worker 	 * if primary algorithm is empty (e.g. compression off),
1712*33b1fccfSAndroid Build Coastguard Worker 	 * clear 0PADDING feature for old kernel compatibility.
1713*33b1fccfSAndroid Build Coastguard Worker 	 */
1714*33b1fccfSAndroid Build Coastguard Worker 	if (!available_compr_algs ||
1715*33b1fccfSAndroid Build Coastguard Worker 	    (cfg.c_legacy_compress && available_compr_algs == 1))
1716*33b1fccfSAndroid Build Coastguard Worker 		erofs_sb_clear_lz4_0padding(sbi);
1717*33b1fccfSAndroid Build Coastguard Worker 
1718*33b1fccfSAndroid Build Coastguard Worker 	if (!available_compr_algs)
1719*33b1fccfSAndroid Build Coastguard Worker 		return 0;
1720*33b1fccfSAndroid Build Coastguard Worker 
1721*33b1fccfSAndroid Build Coastguard Worker 	if (!sb_bh) {
1722*33b1fccfSAndroid Build Coastguard Worker 		u32 dalg = available_compr_algs & (~sbi->available_compr_algs);
1723*33b1fccfSAndroid Build Coastguard Worker 
1724*33b1fccfSAndroid Build Coastguard Worker 		if (dalg) {
1725*33b1fccfSAndroid Build Coastguard Worker 			erofs_err("unavailable algorithms 0x%x on incremental builds",
1726*33b1fccfSAndroid Build Coastguard Worker 				  dalg);
1727*33b1fccfSAndroid Build Coastguard Worker 			return -EOPNOTSUPP;
1728*33b1fccfSAndroid Build Coastguard Worker 		}
1729*33b1fccfSAndroid Build Coastguard Worker 		if (available_compr_algs & (1 << Z_EROFS_COMPRESSION_LZ4) &&
1730*33b1fccfSAndroid Build Coastguard Worker 		    sbi->lz4.max_pclusterblks << sbi->blkszbits <
1731*33b1fccfSAndroid Build Coastguard Worker 			cfg.c_mkfs_pclustersize_max) {
1732*33b1fccfSAndroid Build Coastguard Worker 			erofs_err("pclustersize %u is too large on incremental builds",
1733*33b1fccfSAndroid Build Coastguard Worker 				  cfg.c_mkfs_pclustersize_max);
1734*33b1fccfSAndroid Build Coastguard Worker 			return -EOPNOTSUPP;
1735*33b1fccfSAndroid Build Coastguard Worker 		}
1736*33b1fccfSAndroid Build Coastguard Worker 	} else {
1737*33b1fccfSAndroid Build Coastguard Worker 		sbi->available_compr_algs = available_compr_algs;
1738*33b1fccfSAndroid Build Coastguard Worker 	}
1739*33b1fccfSAndroid Build Coastguard Worker 
1740*33b1fccfSAndroid Build Coastguard Worker 	/*
1741*33b1fccfSAndroid Build Coastguard Worker 	 * if big pcluster is enabled, an extra CBLKCNT lcluster index needs
1742*33b1fccfSAndroid Build Coastguard Worker 	 * to be loaded in order to get those compressed block counts.
1743*33b1fccfSAndroid Build Coastguard Worker 	 */
1744*33b1fccfSAndroid Build Coastguard Worker 	if (cfg.c_mkfs_pclustersize_max > erofs_blksiz(sbi)) {
1745*33b1fccfSAndroid Build Coastguard Worker 		if (cfg.c_mkfs_pclustersize_max > Z_EROFS_PCLUSTER_MAX_SIZE) {
1746*33b1fccfSAndroid Build Coastguard Worker 			erofs_err("unsupported pclustersize %u (too large)",
1747*33b1fccfSAndroid Build Coastguard Worker 				  cfg.c_mkfs_pclustersize_max);
1748*33b1fccfSAndroid Build Coastguard Worker 			return -EINVAL;
1749*33b1fccfSAndroid Build Coastguard Worker 		}
1750*33b1fccfSAndroid Build Coastguard Worker 		erofs_sb_set_big_pcluster(sbi);
1751*33b1fccfSAndroid Build Coastguard Worker 	}
1752*33b1fccfSAndroid Build Coastguard Worker 	if (cfg.c_mkfs_pclustersize_packed > cfg.c_mkfs_pclustersize_max) {
1753*33b1fccfSAndroid Build Coastguard Worker 		erofs_err("invalid pclustersize for the packed file %u",
1754*33b1fccfSAndroid Build Coastguard Worker 			  cfg.c_mkfs_pclustersize_packed);
1755*33b1fccfSAndroid Build Coastguard Worker 		return -EINVAL;
1756*33b1fccfSAndroid Build Coastguard Worker 	}
1757*33b1fccfSAndroid Build Coastguard Worker 
1758*33b1fccfSAndroid Build Coastguard Worker 	if (sb_bh && erofs_sb_has_compr_cfgs(sbi)) {
1759*33b1fccfSAndroid Build Coastguard Worker 		ret = z_erofs_build_compr_cfgs(sbi, sb_bh, max_dict_size);
1760*33b1fccfSAndroid Build Coastguard Worker 		if (ret)
1761*33b1fccfSAndroid Build Coastguard Worker 			return ret;
1762*33b1fccfSAndroid Build Coastguard Worker 	}
1763*33b1fccfSAndroid Build Coastguard Worker 
1764*33b1fccfSAndroid Build Coastguard Worker 	z_erofs_mt_enabled = false;
1765*33b1fccfSAndroid Build Coastguard Worker #ifdef EROFS_MT_ENABLED
1766*33b1fccfSAndroid Build Coastguard Worker 	if (cfg.c_mt_workers >= 1 && (cfg.c_dedupe ||
1767*33b1fccfSAndroid Build Coastguard Worker 				      (cfg.c_fragments && !cfg.c_all_fragments))) {
1768*33b1fccfSAndroid Build Coastguard Worker 		if (cfg.c_dedupe)
1769*33b1fccfSAndroid Build Coastguard Worker 			erofs_warn("multi-threaded dedupe is NOT implemented for now");
1770*33b1fccfSAndroid Build Coastguard Worker 		if (cfg.c_fragments)
1771*33b1fccfSAndroid Build Coastguard Worker 			erofs_warn("multi-threaded fragments is NOT implemented for now");
1772*33b1fccfSAndroid Build Coastguard Worker 		cfg.c_mt_workers = 0;
1773*33b1fccfSAndroid Build Coastguard Worker 	}
1774*33b1fccfSAndroid Build Coastguard Worker 
1775*33b1fccfSAndroid Build Coastguard Worker 	if (cfg.c_mt_workers >= 1) {
1776*33b1fccfSAndroid Build Coastguard Worker 		ret = erofs_alloc_workqueue(&z_erofs_mt_ctrl.wq,
1777*33b1fccfSAndroid Build Coastguard Worker 					    cfg.c_mt_workers,
1778*33b1fccfSAndroid Build Coastguard Worker 					    cfg.c_mt_workers << 2,
1779*33b1fccfSAndroid Build Coastguard Worker 					    z_erofs_mt_wq_tls_alloc,
1780*33b1fccfSAndroid Build Coastguard Worker 					    z_erofs_mt_wq_tls_free);
1781*33b1fccfSAndroid Build Coastguard Worker 		z_erofs_mt_enabled = !ret;
1782*33b1fccfSAndroid Build Coastguard Worker 	}
1783*33b1fccfSAndroid Build Coastguard Worker 	pthread_mutex_init(&g_ictx.mutex, NULL);
1784*33b1fccfSAndroid Build Coastguard Worker 	pthread_cond_init(&g_ictx.cond, NULL);
1785*33b1fccfSAndroid Build Coastguard Worker #endif
1786*33b1fccfSAndroid Build Coastguard Worker 	return 0;
1787*33b1fccfSAndroid Build Coastguard Worker }
1788*33b1fccfSAndroid Build Coastguard Worker 
z_erofs_compress_exit(void)1789*33b1fccfSAndroid Build Coastguard Worker int z_erofs_compress_exit(void)
1790*33b1fccfSAndroid Build Coastguard Worker {
1791*33b1fccfSAndroid Build Coastguard Worker 	int i, ret;
1792*33b1fccfSAndroid Build Coastguard Worker 
1793*33b1fccfSAndroid Build Coastguard Worker 	for (i = 0; cfg.c_compr_opts[i].alg; ++i) {
1794*33b1fccfSAndroid Build Coastguard Worker 		ret = erofs_compressor_exit(&erofs_ccfg[i].handle);
1795*33b1fccfSAndroid Build Coastguard Worker 		if (ret)
1796*33b1fccfSAndroid Build Coastguard Worker 			return ret;
1797*33b1fccfSAndroid Build Coastguard Worker 	}
1798*33b1fccfSAndroid Build Coastguard Worker 
1799*33b1fccfSAndroid Build Coastguard Worker 	if (z_erofs_mt_enabled) {
1800*33b1fccfSAndroid Build Coastguard Worker #ifdef EROFS_MT_ENABLED
1801*33b1fccfSAndroid Build Coastguard Worker 		ret = erofs_destroy_workqueue(&z_erofs_mt_ctrl.wq);
1802*33b1fccfSAndroid Build Coastguard Worker 		if (ret)
1803*33b1fccfSAndroid Build Coastguard Worker 			return ret;
1804*33b1fccfSAndroid Build Coastguard Worker 		while (z_erofs_mt_ctrl.idle) {
1805*33b1fccfSAndroid Build Coastguard Worker 			struct erofs_compress_work *tmp =
1806*33b1fccfSAndroid Build Coastguard Worker 				z_erofs_mt_ctrl.idle->next;
1807*33b1fccfSAndroid Build Coastguard Worker 			free(z_erofs_mt_ctrl.idle);
1808*33b1fccfSAndroid Build Coastguard Worker 			z_erofs_mt_ctrl.idle = tmp;
1809*33b1fccfSAndroid Build Coastguard Worker 		}
1810*33b1fccfSAndroid Build Coastguard Worker #endif
1811*33b1fccfSAndroid Build Coastguard Worker 	}
1812*33b1fccfSAndroid Build Coastguard Worker 	return 0;
1813*33b1fccfSAndroid Build Coastguard Worker }
1814