xref: /aosp_15_r20/external/erofs-utils/lib/compress_hints.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), 2008-2021, OPPO Mobile Comm Corp., Ltd.
4*33b1fccfSAndroid Build Coastguard Worker  * Created by Huang Jianan <[email protected]>
5*33b1fccfSAndroid Build Coastguard Worker  */
6*33b1fccfSAndroid Build Coastguard Worker #include <string.h>
7*33b1fccfSAndroid Build Coastguard Worker #include <stdlib.h>
8*33b1fccfSAndroid Build Coastguard Worker #include "erofs/err.h"
9*33b1fccfSAndroid Build Coastguard Worker #include "erofs/list.h"
10*33b1fccfSAndroid Build Coastguard Worker #include "erofs/print.h"
11*33b1fccfSAndroid Build Coastguard Worker #include "erofs/compress_hints.h"
12*33b1fccfSAndroid Build Coastguard Worker 
13*33b1fccfSAndroid Build Coastguard Worker static LIST_HEAD(compress_hints_head);
14*33b1fccfSAndroid Build Coastguard Worker 
dump_regerror(int errcode,const char * s,const regex_t * preg)15*33b1fccfSAndroid Build Coastguard Worker static void dump_regerror(int errcode, const char *s, const regex_t *preg)
16*33b1fccfSAndroid Build Coastguard Worker {
17*33b1fccfSAndroid Build Coastguard Worker 	char str[512];
18*33b1fccfSAndroid Build Coastguard Worker 
19*33b1fccfSAndroid Build Coastguard Worker 	regerror(errcode, preg, str, sizeof(str));
20*33b1fccfSAndroid Build Coastguard Worker 	erofs_err("invalid regex %s (%s)\n", s, str);
21*33b1fccfSAndroid Build Coastguard Worker }
22*33b1fccfSAndroid Build Coastguard Worker 
23*33b1fccfSAndroid Build Coastguard Worker /* algorithmtype is actually ccfg # here */
erofs_insert_compress_hints(const char * s,unsigned int blks,unsigned int algorithmtype)24*33b1fccfSAndroid Build Coastguard Worker static int erofs_insert_compress_hints(const char *s, unsigned int blks,
25*33b1fccfSAndroid Build Coastguard Worker 				       unsigned int algorithmtype)
26*33b1fccfSAndroid Build Coastguard Worker {
27*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_compress_hints *ch;
28*33b1fccfSAndroid Build Coastguard Worker 	int ret;
29*33b1fccfSAndroid Build Coastguard Worker 
30*33b1fccfSAndroid Build Coastguard Worker 	ch = malloc(sizeof(struct erofs_compress_hints));
31*33b1fccfSAndroid Build Coastguard Worker 	if (!ch)
32*33b1fccfSAndroid Build Coastguard Worker 		return -ENOMEM;
33*33b1fccfSAndroid Build Coastguard Worker 
34*33b1fccfSAndroid Build Coastguard Worker 	ret = regcomp(&ch->reg, s, REG_EXTENDED|REG_NOSUB);
35*33b1fccfSAndroid Build Coastguard Worker 	if (ret) {
36*33b1fccfSAndroid Build Coastguard Worker 		dump_regerror(ret, s, &ch->reg);
37*33b1fccfSAndroid Build Coastguard Worker 		free(ch);
38*33b1fccfSAndroid Build Coastguard Worker 		return ret;
39*33b1fccfSAndroid Build Coastguard Worker 	}
40*33b1fccfSAndroid Build Coastguard Worker 	ch->physical_clusterblks = blks;
41*33b1fccfSAndroid Build Coastguard Worker 	ch->algorithmtype = algorithmtype;
42*33b1fccfSAndroid Build Coastguard Worker 
43*33b1fccfSAndroid Build Coastguard Worker 	list_add_tail(&ch->list, &compress_hints_head);
44*33b1fccfSAndroid Build Coastguard Worker 	erofs_info("compress hint %s (%u) is inserted", s, blks);
45*33b1fccfSAndroid Build Coastguard Worker 	return ret;
46*33b1fccfSAndroid Build Coastguard Worker }
47*33b1fccfSAndroid Build Coastguard Worker 
z_erofs_apply_compress_hints(struct erofs_inode * inode)48*33b1fccfSAndroid Build Coastguard Worker bool z_erofs_apply_compress_hints(struct erofs_inode *inode)
49*33b1fccfSAndroid Build Coastguard Worker {
50*33b1fccfSAndroid Build Coastguard Worker 	const char *s;
51*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_compress_hints *r;
52*33b1fccfSAndroid Build Coastguard Worker 	unsigned int pclusterblks, algorithmtype;
53*33b1fccfSAndroid Build Coastguard Worker 
54*33b1fccfSAndroid Build Coastguard Worker 	if (inode->z_physical_clusterblks)
55*33b1fccfSAndroid Build Coastguard Worker 		return true;
56*33b1fccfSAndroid Build Coastguard Worker 
57*33b1fccfSAndroid Build Coastguard Worker 	s = erofs_fspath(inode->i_srcpath);
58*33b1fccfSAndroid Build Coastguard Worker 	pclusterblks = cfg.c_mkfs_pclustersize_def >> inode->sbi->blkszbits;
59*33b1fccfSAndroid Build Coastguard Worker 	algorithmtype = 0;
60*33b1fccfSAndroid Build Coastguard Worker 
61*33b1fccfSAndroid Build Coastguard Worker 	list_for_each_entry(r, &compress_hints_head, list) {
62*33b1fccfSAndroid Build Coastguard Worker 		int ret = regexec(&r->reg, s, (size_t)0, NULL, 0);
63*33b1fccfSAndroid Build Coastguard Worker 
64*33b1fccfSAndroid Build Coastguard Worker 		if (!ret) {
65*33b1fccfSAndroid Build Coastguard Worker 			pclusterblks = r->physical_clusterblks;
66*33b1fccfSAndroid Build Coastguard Worker 			algorithmtype = r->algorithmtype;
67*33b1fccfSAndroid Build Coastguard Worker 			break;
68*33b1fccfSAndroid Build Coastguard Worker 		}
69*33b1fccfSAndroid Build Coastguard Worker 		if (ret != REG_NOMATCH)
70*33b1fccfSAndroid Build Coastguard Worker 			dump_regerror(ret, s, &r->reg);
71*33b1fccfSAndroid Build Coastguard Worker 	}
72*33b1fccfSAndroid Build Coastguard Worker 	inode->z_physical_clusterblks = pclusterblks;
73*33b1fccfSAndroid Build Coastguard Worker 	inode->z_algorithmtype[0] = algorithmtype;
74*33b1fccfSAndroid Build Coastguard Worker 
75*33b1fccfSAndroid Build Coastguard Worker 	/* pclusterblks is 0 means this file shouldn't be compressed */
76*33b1fccfSAndroid Build Coastguard Worker 	return pclusterblks != 0;
77*33b1fccfSAndroid Build Coastguard Worker }
78*33b1fccfSAndroid Build Coastguard Worker 
erofs_cleanup_compress_hints(void)79*33b1fccfSAndroid Build Coastguard Worker void erofs_cleanup_compress_hints(void)
80*33b1fccfSAndroid Build Coastguard Worker {
81*33b1fccfSAndroid Build Coastguard Worker 	struct erofs_compress_hints *r, *n;
82*33b1fccfSAndroid Build Coastguard Worker 
83*33b1fccfSAndroid Build Coastguard Worker 	list_for_each_entry_safe(r, n, &compress_hints_head, list) {
84*33b1fccfSAndroid Build Coastguard Worker 		list_del(&r->list);
85*33b1fccfSAndroid Build Coastguard Worker 		free(r);
86*33b1fccfSAndroid Build Coastguard Worker 	}
87*33b1fccfSAndroid Build Coastguard Worker }
88*33b1fccfSAndroid Build Coastguard Worker 
erofs_load_compress_hints(struct erofs_sb_info * sbi)89*33b1fccfSAndroid Build Coastguard Worker int erofs_load_compress_hints(struct erofs_sb_info *sbi)
90*33b1fccfSAndroid Build Coastguard Worker {
91*33b1fccfSAndroid Build Coastguard Worker 	char buf[PATH_MAX + 100];
92*33b1fccfSAndroid Build Coastguard Worker 	FILE *f;
93*33b1fccfSAndroid Build Coastguard Worker 	unsigned int line, max_pclustersize = 0;
94*33b1fccfSAndroid Build Coastguard Worker 	int ret = 0;
95*33b1fccfSAndroid Build Coastguard Worker 
96*33b1fccfSAndroid Build Coastguard Worker 	if (!cfg.c_compress_hints_file)
97*33b1fccfSAndroid Build Coastguard Worker 		return 0;
98*33b1fccfSAndroid Build Coastguard Worker 
99*33b1fccfSAndroid Build Coastguard Worker 	f = fopen(cfg.c_compress_hints_file, "r");
100*33b1fccfSAndroid Build Coastguard Worker 	if (!f)
101*33b1fccfSAndroid Build Coastguard Worker 		return -errno;
102*33b1fccfSAndroid Build Coastguard Worker 
103*33b1fccfSAndroid Build Coastguard Worker 	for (line = 1; fgets(buf, sizeof(buf), f); ++line) {
104*33b1fccfSAndroid Build Coastguard Worker 		unsigned int pclustersize, ccfg;
105*33b1fccfSAndroid Build Coastguard Worker 		char *alg, *pattern;
106*33b1fccfSAndroid Build Coastguard Worker 
107*33b1fccfSAndroid Build Coastguard Worker 		if (*buf == '#' || *buf == '\n')
108*33b1fccfSAndroid Build Coastguard Worker 			continue;
109*33b1fccfSAndroid Build Coastguard Worker 
110*33b1fccfSAndroid Build Coastguard Worker 		pclustersize = atoi(strtok(buf, "\t "));
111*33b1fccfSAndroid Build Coastguard Worker 		alg = strtok(NULL, "\n\t ");
112*33b1fccfSAndroid Build Coastguard Worker 		pattern = strtok(NULL, "\n");
113*33b1fccfSAndroid Build Coastguard Worker 		if (!pattern) {
114*33b1fccfSAndroid Build Coastguard Worker 			pattern = alg;
115*33b1fccfSAndroid Build Coastguard Worker 			alg = NULL;
116*33b1fccfSAndroid Build Coastguard Worker 		}
117*33b1fccfSAndroid Build Coastguard Worker 		if (!pattern || *pattern == '\0') {
118*33b1fccfSAndroid Build Coastguard Worker 			erofs_err("cannot find a match pattern at line %u",
119*33b1fccfSAndroid Build Coastguard Worker 				  line);
120*33b1fccfSAndroid Build Coastguard Worker 			ret = -EINVAL;
121*33b1fccfSAndroid Build Coastguard Worker 			goto out;
122*33b1fccfSAndroid Build Coastguard Worker 		}
123*33b1fccfSAndroid Build Coastguard Worker 		if (!alg || *alg == '\0') {
124*33b1fccfSAndroid Build Coastguard Worker 			ccfg = 0;
125*33b1fccfSAndroid Build Coastguard Worker 		} else {
126*33b1fccfSAndroid Build Coastguard Worker 			ccfg = atoi(alg);
127*33b1fccfSAndroid Build Coastguard Worker 			if (ccfg >= EROFS_MAX_COMPR_CFGS ||
128*33b1fccfSAndroid Build Coastguard Worker 			    !cfg.c_compr_opts[ccfg].alg) {
129*33b1fccfSAndroid Build Coastguard Worker 				erofs_err("invalid compressing configuration \"%s\" at line %u",
130*33b1fccfSAndroid Build Coastguard Worker 					  alg, line);
131*33b1fccfSAndroid Build Coastguard Worker 				ret = -EINVAL;
132*33b1fccfSAndroid Build Coastguard Worker 				goto out;
133*33b1fccfSAndroid Build Coastguard Worker 			}
134*33b1fccfSAndroid Build Coastguard Worker 		}
135*33b1fccfSAndroid Build Coastguard Worker 
136*33b1fccfSAndroid Build Coastguard Worker 		if (pclustersize % erofs_blksiz(sbi)) {
137*33b1fccfSAndroid Build Coastguard Worker 			erofs_warn("invalid physical clustersize %u, "
138*33b1fccfSAndroid Build Coastguard Worker 				   "use default pclusterblks %u",
139*33b1fccfSAndroid Build Coastguard Worker 				   pclustersize, cfg.c_mkfs_pclustersize_def);
140*33b1fccfSAndroid Build Coastguard Worker 			continue;
141*33b1fccfSAndroid Build Coastguard Worker 		}
142*33b1fccfSAndroid Build Coastguard Worker 		erofs_insert_compress_hints(pattern,
143*33b1fccfSAndroid Build Coastguard Worker 				pclustersize / erofs_blksiz(sbi), ccfg);
144*33b1fccfSAndroid Build Coastguard Worker 
145*33b1fccfSAndroid Build Coastguard Worker 		if (pclustersize > max_pclustersize)
146*33b1fccfSAndroid Build Coastguard Worker 			max_pclustersize = pclustersize;
147*33b1fccfSAndroid Build Coastguard Worker 	}
148*33b1fccfSAndroid Build Coastguard Worker 
149*33b1fccfSAndroid Build Coastguard Worker 	if (cfg.c_mkfs_pclustersize_max < max_pclustersize) {
150*33b1fccfSAndroid Build Coastguard Worker 		cfg.c_mkfs_pclustersize_max = max_pclustersize;
151*33b1fccfSAndroid Build Coastguard Worker 		erofs_warn("update max pclustersize to %u",
152*33b1fccfSAndroid Build Coastguard Worker 			   cfg.c_mkfs_pclustersize_max);
153*33b1fccfSAndroid Build Coastguard Worker 	}
154*33b1fccfSAndroid Build Coastguard Worker out:
155*33b1fccfSAndroid Build Coastguard Worker 	fclose(f);
156*33b1fccfSAndroid Build Coastguard Worker 	return ret;
157*33b1fccfSAndroid Build Coastguard Worker }
158