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