]>
Commit | Line | Data |
---|---|---|
830613f8 HJ |
1 | /* SPDX-License-Identifier: GPL-2.0+ */ |
2 | #ifndef __EROFS_INTERNAL_H | |
3 | #define __EROFS_INTERNAL_H | |
4 | ||
3a21e92f | 5 | #include "linux/compat.h" |
830613f8 HJ |
6 | #define __packed __attribute__((__packed__)) |
7 | ||
8 | #include <linux/stat.h> | |
9 | #include <linux/bug.h> | |
10 | #include <linux/err.h> | |
11 | #include <linux/printk.h> | |
12 | #include <linux/log2.h> | |
13 | #include <inttypes.h> | |
14 | #include "erofs_fs.h" | |
15 | ||
16 | #define erofs_err(fmt, ...) \ | |
17 | pr_err(fmt "\n", ##__VA_ARGS__) | |
18 | ||
19 | #define erofs_info(fmt, ...) \ | |
20 | pr_info(fmt "\n", ##__VA_ARGS__) | |
21 | ||
22 | #define erofs_dbg(fmt, ...) \ | |
23 | pr_debug(fmt "\n", ##__VA_ARGS__) | |
24 | ||
25 | #define DBG_BUGON(condition) BUG_ON(condition) | |
26 | ||
27 | /* no obvious reason to support explicit PAGE_SIZE != 4096 for now */ | |
28 | #if PAGE_SIZE != 4096 | |
29 | #error incompatible PAGE_SIZE is already defined | |
30 | #endif | |
31 | ||
32 | #define PAGE_MASK (~(PAGE_SIZE - 1)) | |
33 | ||
3a21e92f YZ |
34 | #ifndef EROFS_MAX_BLOCK_SIZE |
35 | #define EROFS_MAX_BLOCK_SIZE PAGE_SIZE | |
36 | #endif | |
830613f8 HJ |
37 | |
38 | #define EROFS_ISLOTBITS 5 | |
39 | #define EROFS_SLOTSIZE (1U << EROFS_ISLOTBITS) | |
40 | ||
41 | typedef u64 erofs_off_t; | |
42 | typedef u64 erofs_nid_t; | |
43 | /* data type for filesystem-wide blocks number */ | |
44 | typedef u32 erofs_blk_t; | |
45 | ||
46 | #define NULL_ADDR ((unsigned int)-1) | |
47 | #define NULL_ADDR_UL ((unsigned long)-1) | |
48 | ||
3a21e92f YZ |
49 | /* global sbi */ |
50 | extern struct erofs_sb_info sbi; | |
51 | ||
52 | #define erofs_blksiz() (1u << sbi.blkszbits) | |
53 | #define erofs_blknr(addr) ((addr) >> sbi.blkszbits) | |
54 | #define erofs_blkoff(addr) ((addr) & (erofs_blksiz() - 1)) | |
55 | #define erofs_pos(nr) ((erofs_off_t)(nr) << sbi.blkszbits) | |
830613f8 | 56 | |
3a21e92f | 57 | #define BLK_ROUND_UP(addr) DIV_ROUND_UP(addr, 1u << sbi.blkszbits) |
830613f8 HJ |
58 | |
59 | struct erofs_buffer_head; | |
60 | ||
61 | struct erofs_device_info { | |
62 | u32 blocks; | |
63 | u32 mapped_blkaddr; | |
64 | }; | |
65 | ||
3a21e92f YZ |
66 | #define EROFS_PACKED_NID_UNALLOCATED -1 |
67 | ||
830613f8 HJ |
68 | struct erofs_sb_info { |
69 | struct erofs_device_info *devs; | |
70 | ||
71 | u64 total_blocks; | |
72 | u64 primarydevice_blocks; | |
73 | ||
74 | erofs_blk_t meta_blkaddr; | |
75 | erofs_blk_t xattr_blkaddr; | |
76 | ||
77 | u32 feature_compat; | |
78 | u32 feature_incompat; | |
79 | u64 build_time; | |
80 | u32 build_time_nsec; | |
81 | ||
82 | unsigned char islotbits; | |
3a21e92f | 83 | unsigned char blkszbits; |
830613f8 HJ |
84 | |
85 | /* what we really care is nid, rather than ino.. */ | |
86 | erofs_nid_t root_nid; | |
87 | /* used for statfs, f_files - f_favail */ | |
88 | u64 inos; | |
89 | ||
90 | u8 uuid[16]; | |
3a21e92f | 91 | char volume_name[16]; |
830613f8 HJ |
92 | |
93 | u16 available_compr_algs; | |
94 | u16 lz4_max_distance; | |
3a21e92f | 95 | |
830613f8 HJ |
96 | u32 checksum; |
97 | u16 extra_devices; | |
98 | union { | |
99 | u16 devt_slotoff; /* used for mkfs */ | |
100 | u16 device_id_mask; /* used for others */ | |
101 | }; | |
3a21e92f YZ |
102 | erofs_nid_t packed_nid; |
103 | ||
104 | u32 xattr_prefix_start; | |
105 | u8 xattr_prefix_count; | |
830613f8 HJ |
106 | }; |
107 | ||
830613f8 HJ |
108 | static inline erofs_off_t iloc(erofs_nid_t nid) |
109 | { | |
3a21e92f | 110 | return erofs_pos(sbi.meta_blkaddr) + (nid << sbi.islotbits); |
830613f8 HJ |
111 | } |
112 | ||
113 | #define EROFS_FEATURE_FUNCS(name, compat, feature) \ | |
114 | static inline bool erofs_sb_has_##name(void) \ | |
115 | { \ | |
116 | return sbi.feature_##compat & EROFS_FEATURE_##feature; \ | |
117 | } \ | |
118 | static inline void erofs_sb_set_##name(void) \ | |
119 | { \ | |
120 | sbi.feature_##compat |= EROFS_FEATURE_##feature; \ | |
121 | } \ | |
122 | static inline void erofs_sb_clear_##name(void) \ | |
123 | { \ | |
124 | sbi.feature_##compat &= ~EROFS_FEATURE_##feature; \ | |
125 | } | |
126 | ||
3a21e92f | 127 | EROFS_FEATURE_FUNCS(lz4_0padding, incompat, INCOMPAT_ZERO_PADDING) |
830613f8 HJ |
128 | EROFS_FEATURE_FUNCS(compr_cfgs, incompat, INCOMPAT_COMPR_CFGS) |
129 | EROFS_FEATURE_FUNCS(big_pcluster, incompat, INCOMPAT_BIG_PCLUSTER) | |
130 | EROFS_FEATURE_FUNCS(chunked_file, incompat, INCOMPAT_CHUNKED_FILE) | |
131 | EROFS_FEATURE_FUNCS(device_table, incompat, INCOMPAT_DEVICE_TABLE) | |
3a21e92f YZ |
132 | EROFS_FEATURE_FUNCS(ztailpacking, incompat, INCOMPAT_ZTAILPACKING) |
133 | EROFS_FEATURE_FUNCS(fragments, incompat, INCOMPAT_FRAGMENTS) | |
134 | EROFS_FEATURE_FUNCS(dedupe, incompat, INCOMPAT_DEDUPE) | |
135 | EROFS_FEATURE_FUNCS(xattr_prefixes, incompat, INCOMPAT_XATTR_PREFIXES) | |
830613f8 HJ |
136 | EROFS_FEATURE_FUNCS(sb_chksum, compat, COMPAT_SB_CHKSUM) |
137 | ||
138 | #define EROFS_I_EA_INITED (1 << 0) | |
139 | #define EROFS_I_Z_INITED (1 << 1) | |
140 | ||
141 | struct erofs_inode { | |
142 | struct list_head i_hash, i_subdirs, i_xattrs; | |
143 | ||
144 | union { | |
145 | /* (erofsfuse) runtime flags */ | |
146 | unsigned int flags; | |
147 | /* (mkfs.erofs) device ID containing source file */ | |
148 | u32 dev; | |
3a21e92f YZ |
149 | /* (mkfs.erofs) queued sub-directories blocking dump */ |
150 | u32 subdirs_queued; | |
830613f8 HJ |
151 | }; |
152 | unsigned int i_count; | |
153 | struct erofs_inode *i_parent; | |
154 | ||
155 | umode_t i_mode; | |
156 | erofs_off_t i_size; | |
157 | ||
158 | u64 i_ino[2]; | |
159 | u32 i_uid; | |
160 | u32 i_gid; | |
3a21e92f YZ |
161 | u64 i_mtime; |
162 | u32 i_mtime_nsec; | |
830613f8 HJ |
163 | u32 i_nlink; |
164 | ||
165 | union { | |
166 | u32 i_blkaddr; | |
167 | u32 i_blocks; | |
168 | u32 i_rdev; | |
169 | struct { | |
170 | unsigned short chunkformat; | |
171 | unsigned char chunkbits; | |
172 | }; | |
173 | } u; | |
174 | ||
3a21e92f YZ |
175 | char *i_srcpath; |
176 | ||
830613f8 HJ |
177 | unsigned char datalayout; |
178 | unsigned char inode_isize; | |
179 | /* inline tail-end packing size */ | |
180 | unsigned short idata_size; | |
3a21e92f YZ |
181 | bool compressed_idata; |
182 | bool lazy_tailblock; | |
830613f8 HJ |
183 | |
184 | unsigned int xattr_isize; | |
185 | unsigned int extent_isize; | |
186 | ||
3a21e92f YZ |
187 | unsigned int xattr_shared_count; |
188 | unsigned int *xattr_shared_xattrs; | |
189 | ||
830613f8 HJ |
190 | erofs_nid_t nid; |
191 | struct erofs_buffer_head *bh; | |
192 | struct erofs_buffer_head *bh_inline, *bh_data; | |
193 | ||
194 | void *idata; | |
195 | ||
3a21e92f YZ |
196 | /* (ztailpacking) in order to recover uncompressed EOF data */ |
197 | void *eof_tailraw; | |
198 | unsigned int eof_tailrawsize; | |
199 | ||
830613f8 HJ |
200 | union { |
201 | void *compressmeta; | |
202 | void *chunkindexes; | |
203 | struct { | |
204 | uint16_t z_advise; | |
205 | uint8_t z_algorithmtype[2]; | |
206 | uint8_t z_logical_clusterbits; | |
207 | uint8_t z_physical_clusterblks; | |
3a21e92f YZ |
208 | uint64_t z_tailextent_headlcn; |
209 | unsigned int z_idataoff; | |
210 | #define z_idata_size idata_size | |
830613f8 HJ |
211 | }; |
212 | }; | |
3a21e92f YZ |
213 | uint64_t capabilities; |
214 | erofs_off_t fragmentoff; | |
215 | unsigned int fragment_size; | |
830613f8 HJ |
216 | }; |
217 | ||
218 | static inline bool is_inode_layout_compression(struct erofs_inode *inode) | |
219 | { | |
220 | return erofs_inode_is_data_compressed(inode->datalayout); | |
221 | } | |
222 | ||
223 | static inline unsigned int erofs_bitrange(unsigned int value, unsigned int bit, | |
224 | unsigned int bits) | |
225 | { | |
226 | return (value >> bit) & ((1 << bits) - 1); | |
227 | } | |
228 | ||
229 | static inline unsigned int erofs_inode_version(unsigned int value) | |
230 | { | |
231 | return erofs_bitrange(value, EROFS_I_VERSION_BIT, | |
232 | EROFS_I_VERSION_BITS); | |
233 | } | |
234 | ||
235 | static inline unsigned int erofs_inode_datalayout(unsigned int value) | |
236 | { | |
237 | return erofs_bitrange(value, EROFS_I_DATALAYOUT_BIT, | |
238 | EROFS_I_DATALAYOUT_BITS); | |
239 | } | |
240 | ||
241 | #define IS_ROOT(x) ((x) == (x)->i_parent) | |
242 | ||
243 | struct erofs_dentry { | |
244 | struct list_head d_child; /* child of parent list */ | |
245 | ||
246 | unsigned int type; | |
247 | char name[EROFS_NAME_LEN]; | |
248 | union { | |
249 | struct erofs_inode *inode; | |
250 | erofs_nid_t nid; | |
251 | }; | |
252 | }; | |
253 | ||
3a21e92f YZ |
254 | static inline bool is_dot_dotdot_len(const char *name, unsigned int len) |
255 | { | |
256 | if (len >= 1 && name[0] != '.') | |
257 | return false; | |
258 | ||
259 | return len == 1 || (len == 2 && name[1] == '.'); | |
260 | } | |
261 | ||
830613f8 HJ |
262 | static inline bool is_dot_dotdot(const char *name) |
263 | { | |
264 | if (name[0] != '.') | |
265 | return false; | |
266 | ||
267 | return name[1] == '\0' || (name[1] == '.' && name[2] == '\0'); | |
268 | } | |
269 | ||
270 | enum { | |
271 | BH_Meta, | |
272 | BH_Mapped, | |
273 | BH_Encoded, | |
274 | BH_FullMapped, | |
3a21e92f YZ |
275 | BH_Fragment, |
276 | BH_Partialref, | |
830613f8 HJ |
277 | }; |
278 | ||
279 | /* Has a disk mapping */ | |
280 | #define EROFS_MAP_MAPPED (1 << BH_Mapped) | |
281 | /* Located in metadata (could be copied from bd_inode) */ | |
282 | #define EROFS_MAP_META (1 << BH_Meta) | |
283 | /* The extent is encoded */ | |
284 | #define EROFS_MAP_ENCODED (1 << BH_Encoded) | |
285 | /* The length of extent is full */ | |
286 | #define EROFS_MAP_FULL_MAPPED (1 << BH_FullMapped) | |
3a21e92f YZ |
287 | /* Located in the special packed inode */ |
288 | #define EROFS_MAP_FRAGMENT (1 << BH_Fragment) | |
289 | /* The extent refers to partial decompressed data */ | |
290 | #define EROFS_MAP_PARTIAL_REF (1 << BH_Partialref) | |
830613f8 HJ |
291 | |
292 | struct erofs_map_blocks { | |
3a21e92f | 293 | char mpage[EROFS_MAX_BLOCK_SIZE]; |
830613f8 HJ |
294 | |
295 | erofs_off_t m_pa, m_la; | |
296 | u64 m_plen, m_llen; | |
297 | ||
298 | unsigned short m_deviceid; | |
299 | char m_algorithmformat; | |
300 | unsigned int m_flags; | |
301 | erofs_blk_t index; | |
302 | }; | |
303 | ||
304 | /* | |
305 | * Used to get the exact decompressed length, e.g. fiemap (consider lookback | |
306 | * approach instead if possible since it's more metadata lightweight.) | |
307 | */ | |
308 | #define EROFS_GET_BLOCKS_FIEMAP 0x0002 | |
3a21e92f YZ |
309 | /* Used to map tail extent for tailpacking inline or fragment pcluster */ |
310 | #define EROFS_GET_BLOCKS_FINDTAIL 0x0008 | |
830613f8 HJ |
311 | |
312 | enum { | |
313 | Z_EROFS_COMPRESSION_SHIFTED = Z_EROFS_COMPRESSION_MAX, | |
3a21e92f | 314 | Z_EROFS_COMPRESSION_INTERLACED, |
830613f8 HJ |
315 | Z_EROFS_COMPRESSION_RUNTIME_MAX |
316 | }; | |
317 | ||
318 | struct erofs_map_dev { | |
319 | erofs_off_t m_pa; | |
320 | unsigned int m_deviceid; | |
321 | }; | |
322 | ||
323 | /* fs.c */ | |
324 | int erofs_blk_read(void *buf, erofs_blk_t start, u32 nblocks); | |
325 | int erofs_dev_read(int device_id, void *buf, u64 offset, size_t len); | |
326 | ||
327 | /* super.c */ | |
328 | int erofs_read_superblock(void); | |
3a21e92f | 329 | void erofs_put_super(void); |
830613f8 HJ |
330 | |
331 | /* namei.c */ | |
332 | int erofs_read_inode_from_disk(struct erofs_inode *vi); | |
333 | int erofs_ilookup(const char *path, struct erofs_inode *vi); | |
334 | int erofs_read_inode_from_disk(struct erofs_inode *vi); | |
335 | ||
336 | /* data.c */ | |
337 | int erofs_pread(struct erofs_inode *inode, char *buf, | |
338 | erofs_off_t count, erofs_off_t offset); | |
3a21e92f YZ |
339 | int erofs_map_blocks(struct erofs_inode *inode, struct erofs_map_blocks *map, |
340 | int flags); | |
341 | int erofs_map_dev(struct erofs_map_dev *map); | |
342 | int erofs_read_one_data(struct erofs_map_blocks *map, char *buffer, u64 offset, | |
343 | size_t len); | |
344 | int z_erofs_read_one_data(struct erofs_inode *inode, | |
345 | struct erofs_map_blocks *map, char *raw, char *buffer, | |
346 | erofs_off_t skip, erofs_off_t length, bool trimmed); | |
347 | ||
348 | static inline int erofs_get_occupied_size(const struct erofs_inode *inode, | |
349 | erofs_off_t *size) | |
350 | { | |
351 | *size = 0; | |
352 | switch (inode->datalayout) { | |
353 | case EROFS_INODE_FLAT_INLINE: | |
354 | case EROFS_INODE_FLAT_PLAIN: | |
355 | case EROFS_INODE_CHUNK_BASED: | |
356 | *size = inode->i_size; | |
357 | break; | |
358 | case EROFS_INODE_COMPRESSED_FULL: | |
359 | case EROFS_INODE_COMPRESSED_COMPACT: | |
360 | *size = inode->u.i_blocks * erofs_blksiz(); | |
361 | break; | |
362 | default: | |
363 | return -EOPNOTSUPP; | |
364 | } | |
365 | return 0; | |
366 | } | |
367 | ||
368 | /* data.c */ | |
369 | int erofs_getxattr(struct erofs_inode *vi, const char *name, char *buffer, | |
370 | size_t buffer_size); | |
371 | int erofs_listxattr(struct erofs_inode *vi, char *buffer, size_t buffer_size); | |
372 | ||
830613f8 HJ |
373 | /* zmap.c */ |
374 | int z_erofs_fill_inode(struct erofs_inode *vi); | |
375 | int z_erofs_map_blocks_iter(struct erofs_inode *vi, | |
376 | struct erofs_map_blocks *map, int flags); | |
377 | ||
378 | #ifdef EUCLEAN | |
379 | #define EFSCORRUPTED EUCLEAN /* Filesystem is corrupted */ | |
380 | #else | |
381 | #define EFSCORRUPTED EIO | |
382 | #endif | |
383 | ||
384 | #define CRC32C_POLY_LE 0x82F63B78 | |
385 | static inline u32 erofs_crc32c(u32 crc, const u8 *in, size_t len) | |
386 | { | |
387 | int i; | |
388 | ||
389 | while (len--) { | |
390 | crc ^= *in++; | |
391 | for (i = 0; i < 8; i++) | |
392 | crc = (crc >> 1) ^ ((crc & 1) ? CRC32C_POLY_LE : 0); | |
393 | } | |
394 | return crc; | |
395 | } | |
396 | ||
397 | #endif |