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