1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (C) 2017-2018 HUAWEI, Inc. |
4 | * https://www.huawei.com/ |
5 | * Copyright (C) 2021, Alibaba Cloud |
6 | */ |
7 | #include <linux/statfs.h> |
8 | #include <linux/seq_file.h> |
9 | #include <linux/crc32c.h> |
10 | #include <linux/fs_context.h> |
11 | #include <linux/fs_parser.h> |
12 | #include <linux/exportfs.h> |
13 | #include "xattr.h" |
14 | |
15 | #define CREATE_TRACE_POINTS |
16 | #include <trace/events/erofs.h> |
17 | |
18 | static struct kmem_cache *erofs_inode_cachep __read_mostly; |
19 | |
20 | void _erofs_err(struct super_block *sb, const char *func, const char *fmt, ...) |
21 | { |
22 | struct va_format vaf; |
23 | va_list args; |
24 | |
25 | va_start(args, fmt); |
26 | |
27 | vaf.fmt = fmt; |
28 | vaf.va = &args; |
29 | |
30 | if (sb) |
31 | pr_err("(device %s): %s: %pV" , sb->s_id, func, &vaf); |
32 | else |
33 | pr_err("%s: %pV" , func, &vaf); |
34 | va_end(args); |
35 | } |
36 | |
37 | void _erofs_info(struct super_block *sb, const char *func, const char *fmt, ...) |
38 | { |
39 | struct va_format vaf; |
40 | va_list args; |
41 | |
42 | va_start(args, fmt); |
43 | |
44 | vaf.fmt = fmt; |
45 | vaf.va = &args; |
46 | |
47 | if (sb) |
48 | pr_info("(device %s): %pV" , sb->s_id, &vaf); |
49 | else |
50 | pr_info("%pV" , &vaf); |
51 | va_end(args); |
52 | } |
53 | |
54 | static int erofs_superblock_csum_verify(struct super_block *sb, void *sbdata) |
55 | { |
56 | size_t len = 1 << EROFS_SB(sb)->blkszbits; |
57 | struct erofs_super_block *dsb; |
58 | u32 expected_crc, crc; |
59 | |
60 | if (len > EROFS_SUPER_OFFSET) |
61 | len -= EROFS_SUPER_OFFSET; |
62 | |
63 | dsb = kmemdup(p: sbdata + EROFS_SUPER_OFFSET, size: len, GFP_KERNEL); |
64 | if (!dsb) |
65 | return -ENOMEM; |
66 | |
67 | expected_crc = le32_to_cpu(dsb->checksum); |
68 | dsb->checksum = 0; |
69 | /* to allow for x86 boot sectors and other oddities. */ |
70 | crc = crc32c(crc: ~0, address: dsb, length: len); |
71 | kfree(objp: dsb); |
72 | |
73 | if (crc != expected_crc) { |
74 | erofs_err(sb, "invalid checksum 0x%08x, 0x%08x expected" , |
75 | crc, expected_crc); |
76 | return -EBADMSG; |
77 | } |
78 | return 0; |
79 | } |
80 | |
81 | static void erofs_inode_init_once(void *ptr) |
82 | { |
83 | struct erofs_inode *vi = ptr; |
84 | |
85 | inode_init_once(&vi->vfs_inode); |
86 | } |
87 | |
88 | static struct inode *erofs_alloc_inode(struct super_block *sb) |
89 | { |
90 | struct erofs_inode *vi = |
91 | alloc_inode_sb(sb, cache: erofs_inode_cachep, GFP_KERNEL); |
92 | |
93 | if (!vi) |
94 | return NULL; |
95 | |
96 | /* zero out everything except vfs_inode */ |
97 | memset(vi, 0, offsetof(struct erofs_inode, vfs_inode)); |
98 | return &vi->vfs_inode; |
99 | } |
100 | |
101 | static void erofs_free_inode(struct inode *inode) |
102 | { |
103 | struct erofs_inode *vi = EROFS_I(inode); |
104 | |
105 | if (inode->i_op == &erofs_fast_symlink_iops) |
106 | kfree(objp: inode->i_link); |
107 | kfree(objp: vi->xattr_shared_xattrs); |
108 | kmem_cache_free(s: erofs_inode_cachep, objp: vi); |
109 | } |
110 | |
111 | static bool check_layout_compatibility(struct super_block *sb, |
112 | struct erofs_super_block *dsb) |
113 | { |
114 | const unsigned int feature = le32_to_cpu(dsb->feature_incompat); |
115 | |
116 | EROFS_SB(sb)->feature_incompat = feature; |
117 | |
118 | /* check if current kernel meets all mandatory requirements */ |
119 | if (feature & (~EROFS_ALL_FEATURE_INCOMPAT)) { |
120 | erofs_err(sb, "unidentified incompatible feature %x, please upgrade kernel" , |
121 | feature & ~EROFS_ALL_FEATURE_INCOMPAT); |
122 | return false; |
123 | } |
124 | return true; |
125 | } |
126 | |
127 | /* read variable-sized metadata, offset will be aligned by 4-byte */ |
128 | void *erofs_read_metadata(struct super_block *sb, struct erofs_buf *buf, |
129 | erofs_off_t *offset, int *lengthp) |
130 | { |
131 | u8 *buffer, *ptr; |
132 | int len, i, cnt; |
133 | |
134 | *offset = round_up(*offset, 4); |
135 | ptr = erofs_bread(buf, erofs_blknr(sb, *offset), type: EROFS_KMAP); |
136 | if (IS_ERR(ptr)) |
137 | return ptr; |
138 | |
139 | len = le16_to_cpu(*(__le16 *)&ptr[erofs_blkoff(sb, *offset)]); |
140 | if (!len) |
141 | len = U16_MAX + 1; |
142 | buffer = kmalloc(size: len, GFP_KERNEL); |
143 | if (!buffer) |
144 | return ERR_PTR(error: -ENOMEM); |
145 | *offset += sizeof(__le16); |
146 | *lengthp = len; |
147 | |
148 | for (i = 0; i < len; i += cnt) { |
149 | cnt = min_t(int, sb->s_blocksize - erofs_blkoff(sb, *offset), |
150 | len - i); |
151 | ptr = erofs_bread(buf, erofs_blknr(sb, *offset), type: EROFS_KMAP); |
152 | if (IS_ERR(ptr)) { |
153 | kfree(objp: buffer); |
154 | return ptr; |
155 | } |
156 | memcpy(buffer + i, ptr + erofs_blkoff(sb, *offset), cnt); |
157 | *offset += cnt; |
158 | } |
159 | return buffer; |
160 | } |
161 | |
162 | #ifndef CONFIG_EROFS_FS_ZIP |
163 | static int z_erofs_parse_cfgs(struct super_block *sb, |
164 | struct erofs_super_block *dsb) |
165 | { |
166 | if (!dsb->u1.available_compr_algs) |
167 | return 0; |
168 | |
169 | erofs_err(sb, "compression disabled, unable to mount compressed EROFS" ); |
170 | return -EOPNOTSUPP; |
171 | } |
172 | #endif |
173 | |
174 | static int erofs_init_device(struct erofs_buf *buf, struct super_block *sb, |
175 | struct erofs_device_info *dif, erofs_off_t *pos) |
176 | { |
177 | struct erofs_sb_info *sbi = EROFS_SB(sb); |
178 | struct erofs_fscache *fscache; |
179 | struct erofs_deviceslot *dis; |
180 | struct file *bdev_file; |
181 | void *ptr; |
182 | |
183 | ptr = erofs_read_metabuf(buf, sb, erofs_blknr(sb, *pos), type: EROFS_KMAP); |
184 | if (IS_ERR(ptr)) |
185 | return PTR_ERR(ptr); |
186 | dis = ptr + erofs_blkoff(sb, *pos); |
187 | |
188 | if (!sbi->devs->flatdev && !dif->path) { |
189 | if (!dis->tag[0]) { |
190 | erofs_err(sb, "empty device tag @ pos %llu" , *pos); |
191 | return -EINVAL; |
192 | } |
193 | dif->path = kmemdup_nul(s: dis->tag, len: sizeof(dis->tag), GFP_KERNEL); |
194 | if (!dif->path) |
195 | return -ENOMEM; |
196 | } |
197 | |
198 | if (erofs_is_fscache_mode(sb)) { |
199 | fscache = erofs_fscache_register_cookie(sb, name: dif->path, flags: 0); |
200 | if (IS_ERR(ptr: fscache)) |
201 | return PTR_ERR(ptr: fscache); |
202 | dif->fscache = fscache; |
203 | } else if (!sbi->devs->flatdev) { |
204 | bdev_file = bdev_file_open_by_path(path: dif->path, BLK_OPEN_READ, |
205 | holder: sb->s_type, NULL); |
206 | if (IS_ERR(ptr: bdev_file)) |
207 | return PTR_ERR(ptr: bdev_file); |
208 | dif->bdev_file = bdev_file; |
209 | dif->dax_dev = fs_dax_get_by_bdev(bdev: file_bdev(bdev_file), |
210 | start_off: &dif->dax_part_off, NULL, NULL); |
211 | } |
212 | |
213 | dif->blocks = le32_to_cpu(dis->blocks); |
214 | dif->mapped_blkaddr = le32_to_cpu(dis->mapped_blkaddr); |
215 | sbi->total_blocks += dif->blocks; |
216 | *pos += EROFS_DEVT_SLOT_SIZE; |
217 | return 0; |
218 | } |
219 | |
220 | static int erofs_scan_devices(struct super_block *sb, |
221 | struct erofs_super_block *dsb) |
222 | { |
223 | struct erofs_sb_info *sbi = EROFS_SB(sb); |
224 | unsigned int ; |
225 | erofs_off_t pos; |
226 | struct erofs_buf buf = __EROFS_BUF_INITIALIZER; |
227 | struct erofs_device_info *dif; |
228 | int id, err = 0; |
229 | |
230 | sbi->total_blocks = sbi->primarydevice_blocks; |
231 | if (!erofs_sb_has_device_table(sbi)) |
232 | ondisk_extradevs = 0; |
233 | else |
234 | ondisk_extradevs = le16_to_cpu(dsb->extra_devices); |
235 | |
236 | if (sbi->devs->extra_devices && |
237 | ondisk_extradevs != sbi->devs->extra_devices) { |
238 | erofs_err(sb, "extra devices don't match (ondisk %u, given %u)" , |
239 | ondisk_extradevs, sbi->devs->extra_devices); |
240 | return -EINVAL; |
241 | } |
242 | if (!ondisk_extradevs) |
243 | return 0; |
244 | |
245 | if (!sbi->devs->extra_devices && !erofs_is_fscache_mode(sb)) |
246 | sbi->devs->flatdev = true; |
247 | |
248 | sbi->device_id_mask = roundup_pow_of_two(ondisk_extradevs + 1) - 1; |
249 | pos = le16_to_cpu(dsb->devt_slotoff) * EROFS_DEVT_SLOT_SIZE; |
250 | down_read(sem: &sbi->devs->rwsem); |
251 | if (sbi->devs->extra_devices) { |
252 | idr_for_each_entry(&sbi->devs->tree, dif, id) { |
253 | err = erofs_init_device(buf: &buf, sb, dif, pos: &pos); |
254 | if (err) |
255 | break; |
256 | } |
257 | } else { |
258 | for (id = 0; id < ondisk_extradevs; id++) { |
259 | dif = kzalloc(size: sizeof(*dif), GFP_KERNEL); |
260 | if (!dif) { |
261 | err = -ENOMEM; |
262 | break; |
263 | } |
264 | |
265 | err = idr_alloc(&sbi->devs->tree, ptr: dif, start: 0, end: 0, GFP_KERNEL); |
266 | if (err < 0) { |
267 | kfree(objp: dif); |
268 | break; |
269 | } |
270 | ++sbi->devs->extra_devices; |
271 | |
272 | err = erofs_init_device(buf: &buf, sb, dif, pos: &pos); |
273 | if (err) |
274 | break; |
275 | } |
276 | } |
277 | up_read(sem: &sbi->devs->rwsem); |
278 | erofs_put_metabuf(buf: &buf); |
279 | return err; |
280 | } |
281 | |
282 | static int erofs_read_superblock(struct super_block *sb) |
283 | { |
284 | struct erofs_sb_info *sbi; |
285 | struct erofs_buf buf = __EROFS_BUF_INITIALIZER; |
286 | struct erofs_super_block *dsb; |
287 | void *data; |
288 | int ret; |
289 | |
290 | data = erofs_read_metabuf(buf: &buf, sb, blkaddr: 0, type: EROFS_KMAP); |
291 | if (IS_ERR(ptr: data)) { |
292 | erofs_err(sb, "cannot read erofs superblock" ); |
293 | return PTR_ERR(ptr: data); |
294 | } |
295 | |
296 | sbi = EROFS_SB(sb); |
297 | dsb = (struct erofs_super_block *)(data + EROFS_SUPER_OFFSET); |
298 | |
299 | ret = -EINVAL; |
300 | if (le32_to_cpu(dsb->magic) != EROFS_SUPER_MAGIC_V1) { |
301 | erofs_err(sb, "cannot find valid erofs superblock" ); |
302 | goto out; |
303 | } |
304 | |
305 | sbi->blkszbits = dsb->blkszbits; |
306 | if (sbi->blkszbits < 9 || sbi->blkszbits > PAGE_SHIFT) { |
307 | erofs_err(sb, "blkszbits %u isn't supported" , sbi->blkszbits); |
308 | goto out; |
309 | } |
310 | if (dsb->dirblkbits) { |
311 | erofs_err(sb, "dirblkbits %u isn't supported" , dsb->dirblkbits); |
312 | goto out; |
313 | } |
314 | |
315 | sbi->feature_compat = le32_to_cpu(dsb->feature_compat); |
316 | if (erofs_sb_has_sb_chksum(sbi)) { |
317 | ret = erofs_superblock_csum_verify(sb, sbdata: data); |
318 | if (ret) |
319 | goto out; |
320 | } |
321 | |
322 | ret = -EINVAL; |
323 | if (!check_layout_compatibility(sb, dsb)) |
324 | goto out; |
325 | |
326 | sbi->sb_size = 128 + dsb->sb_extslots * EROFS_SB_EXTSLOT_SIZE; |
327 | if (sbi->sb_size > PAGE_SIZE - EROFS_SUPER_OFFSET) { |
328 | erofs_err(sb, "invalid sb_extslots %u (more than a fs block)" , |
329 | sbi->sb_size); |
330 | goto out; |
331 | } |
332 | sbi->primarydevice_blocks = le32_to_cpu(dsb->blocks); |
333 | sbi->meta_blkaddr = le32_to_cpu(dsb->meta_blkaddr); |
334 | #ifdef CONFIG_EROFS_FS_XATTR |
335 | sbi->xattr_blkaddr = le32_to_cpu(dsb->xattr_blkaddr); |
336 | sbi->xattr_prefix_start = le32_to_cpu(dsb->xattr_prefix_start); |
337 | sbi->xattr_prefix_count = dsb->xattr_prefix_count; |
338 | sbi->xattr_filter_reserved = dsb->xattr_filter_reserved; |
339 | #endif |
340 | sbi->islotbits = ilog2(sizeof(struct erofs_inode_compact)); |
341 | sbi->root_nid = le16_to_cpu(dsb->root_nid); |
342 | sbi->packed_nid = le64_to_cpu(dsb->packed_nid); |
343 | sbi->inos = le64_to_cpu(dsb->inos); |
344 | |
345 | sbi->build_time = le64_to_cpu(dsb->build_time); |
346 | sbi->build_time_nsec = le32_to_cpu(dsb->build_time_nsec); |
347 | |
348 | memcpy(&sb->s_uuid, dsb->uuid, sizeof(dsb->uuid)); |
349 | |
350 | ret = strscpy(sbi->volume_name, dsb->volume_name, |
351 | sizeof(dsb->volume_name)); |
352 | if (ret < 0) { /* -E2BIG */ |
353 | erofs_err(sb, "bad volume name without NIL terminator" ); |
354 | ret = -EFSCORRUPTED; |
355 | goto out; |
356 | } |
357 | |
358 | /* parse on-disk compression configurations */ |
359 | ret = z_erofs_parse_cfgs(sb, dsb); |
360 | if (ret < 0) |
361 | goto out; |
362 | |
363 | /* handle multiple devices */ |
364 | ret = erofs_scan_devices(sb, dsb); |
365 | |
366 | if (erofs_is_fscache_mode(sb)) |
367 | erofs_info(sb, "EXPERIMENTAL fscache-based on-demand read feature in use. Use at your own risk!" ); |
368 | out: |
369 | erofs_put_metabuf(buf: &buf); |
370 | return ret; |
371 | } |
372 | |
373 | static void erofs_default_options(struct erofs_fs_context *ctx) |
374 | { |
375 | #ifdef CONFIG_EROFS_FS_ZIP |
376 | ctx->opt.cache_strategy = EROFS_ZIP_CACHE_READAROUND; |
377 | ctx->opt.max_sync_decompress_pages = 3; |
378 | ctx->opt.sync_decompress = EROFS_SYNC_DECOMPRESS_AUTO; |
379 | #endif |
380 | #ifdef CONFIG_EROFS_FS_XATTR |
381 | set_opt(&ctx->opt, XATTR_USER); |
382 | #endif |
383 | #ifdef CONFIG_EROFS_FS_POSIX_ACL |
384 | set_opt(&ctx->opt, POSIX_ACL); |
385 | #endif |
386 | } |
387 | |
388 | enum { |
389 | Opt_user_xattr, |
390 | Opt_acl, |
391 | Opt_cache_strategy, |
392 | Opt_dax, |
393 | Opt_dax_enum, |
394 | Opt_device, |
395 | Opt_fsid, |
396 | Opt_domain_id, |
397 | Opt_err |
398 | }; |
399 | |
400 | static const struct constant_table erofs_param_cache_strategy[] = { |
401 | {"disabled" , EROFS_ZIP_CACHE_DISABLED}, |
402 | {"readahead" , EROFS_ZIP_CACHE_READAHEAD}, |
403 | {"readaround" , EROFS_ZIP_CACHE_READAROUND}, |
404 | {} |
405 | }; |
406 | |
407 | static const struct constant_table erofs_dax_param_enums[] = { |
408 | {"always" , EROFS_MOUNT_DAX_ALWAYS}, |
409 | {"never" , EROFS_MOUNT_DAX_NEVER}, |
410 | {} |
411 | }; |
412 | |
413 | static const struct fs_parameter_spec erofs_fs_parameters[] = { |
414 | fsparam_flag_no("user_xattr" , Opt_user_xattr), |
415 | fsparam_flag_no("acl" , Opt_acl), |
416 | fsparam_enum("cache_strategy" , Opt_cache_strategy, |
417 | erofs_param_cache_strategy), |
418 | fsparam_flag("dax" , Opt_dax), |
419 | fsparam_enum("dax" , Opt_dax_enum, erofs_dax_param_enums), |
420 | fsparam_string("device" , Opt_device), |
421 | fsparam_string("fsid" , Opt_fsid), |
422 | fsparam_string("domain_id" , Opt_domain_id), |
423 | {} |
424 | }; |
425 | |
426 | static bool erofs_fc_set_dax_mode(struct fs_context *fc, unsigned int mode) |
427 | { |
428 | #ifdef CONFIG_FS_DAX |
429 | struct erofs_fs_context *ctx = fc->fs_private; |
430 | |
431 | switch (mode) { |
432 | case EROFS_MOUNT_DAX_ALWAYS: |
433 | set_opt(&ctx->opt, DAX_ALWAYS); |
434 | clear_opt(&ctx->opt, DAX_NEVER); |
435 | return true; |
436 | case EROFS_MOUNT_DAX_NEVER: |
437 | set_opt(&ctx->opt, DAX_NEVER); |
438 | clear_opt(&ctx->opt, DAX_ALWAYS); |
439 | return true; |
440 | default: |
441 | DBG_BUGON(1); |
442 | return false; |
443 | } |
444 | #else |
445 | errorfc(fc, "dax options not supported" ); |
446 | return false; |
447 | #endif |
448 | } |
449 | |
450 | static int erofs_fc_parse_param(struct fs_context *fc, |
451 | struct fs_parameter *param) |
452 | { |
453 | struct erofs_fs_context *ctx = fc->fs_private; |
454 | struct fs_parse_result result; |
455 | struct erofs_device_info *dif; |
456 | int opt, ret; |
457 | |
458 | opt = fs_parse(fc, desc: erofs_fs_parameters, param, result: &result); |
459 | if (opt < 0) |
460 | return opt; |
461 | |
462 | switch (opt) { |
463 | case Opt_user_xattr: |
464 | #ifdef CONFIG_EROFS_FS_XATTR |
465 | if (result.boolean) |
466 | set_opt(&ctx->opt, XATTR_USER); |
467 | else |
468 | clear_opt(&ctx->opt, XATTR_USER); |
469 | #else |
470 | errorfc(fc, "{,no}user_xattr options not supported" ); |
471 | #endif |
472 | break; |
473 | case Opt_acl: |
474 | #ifdef CONFIG_EROFS_FS_POSIX_ACL |
475 | if (result.boolean) |
476 | set_opt(&ctx->opt, POSIX_ACL); |
477 | else |
478 | clear_opt(&ctx->opt, POSIX_ACL); |
479 | #else |
480 | errorfc(fc, "{,no}acl options not supported" ); |
481 | #endif |
482 | break; |
483 | case Opt_cache_strategy: |
484 | #ifdef CONFIG_EROFS_FS_ZIP |
485 | ctx->opt.cache_strategy = result.uint_32; |
486 | #else |
487 | errorfc(fc, "compression not supported, cache_strategy ignored" ); |
488 | #endif |
489 | break; |
490 | case Opt_dax: |
491 | if (!erofs_fc_set_dax_mode(fc, EROFS_MOUNT_DAX_ALWAYS)) |
492 | return -EINVAL; |
493 | break; |
494 | case Opt_dax_enum: |
495 | if (!erofs_fc_set_dax_mode(fc, mode: result.uint_32)) |
496 | return -EINVAL; |
497 | break; |
498 | case Opt_device: |
499 | dif = kzalloc(size: sizeof(*dif), GFP_KERNEL); |
500 | if (!dif) |
501 | return -ENOMEM; |
502 | dif->path = kstrdup(s: param->string, GFP_KERNEL); |
503 | if (!dif->path) { |
504 | kfree(objp: dif); |
505 | return -ENOMEM; |
506 | } |
507 | down_write(sem: &ctx->devs->rwsem); |
508 | ret = idr_alloc(&ctx->devs->tree, ptr: dif, start: 0, end: 0, GFP_KERNEL); |
509 | up_write(sem: &ctx->devs->rwsem); |
510 | if (ret < 0) { |
511 | kfree(objp: dif->path); |
512 | kfree(objp: dif); |
513 | return ret; |
514 | } |
515 | ++ctx->devs->extra_devices; |
516 | break; |
517 | #ifdef CONFIG_EROFS_FS_ONDEMAND |
518 | case Opt_fsid: |
519 | kfree(objp: ctx->fsid); |
520 | ctx->fsid = kstrdup(s: param->string, GFP_KERNEL); |
521 | if (!ctx->fsid) |
522 | return -ENOMEM; |
523 | break; |
524 | case Opt_domain_id: |
525 | kfree(objp: ctx->domain_id); |
526 | ctx->domain_id = kstrdup(s: param->string, GFP_KERNEL); |
527 | if (!ctx->domain_id) |
528 | return -ENOMEM; |
529 | break; |
530 | #else |
531 | case Opt_fsid: |
532 | case Opt_domain_id: |
533 | errorfc(fc, "%s option not supported" , erofs_fs_parameters[opt].name); |
534 | break; |
535 | #endif |
536 | default: |
537 | return -ENOPARAM; |
538 | } |
539 | return 0; |
540 | } |
541 | |
542 | static struct inode *erofs_nfs_get_inode(struct super_block *sb, |
543 | u64 ino, u32 generation) |
544 | { |
545 | return erofs_iget(sb, nid: ino); |
546 | } |
547 | |
548 | static struct dentry *erofs_fh_to_dentry(struct super_block *sb, |
549 | struct fid *fid, int fh_len, int fh_type) |
550 | { |
551 | return generic_fh_to_dentry(sb, fid, fh_len, fh_type, |
552 | get_inode: erofs_nfs_get_inode); |
553 | } |
554 | |
555 | static struct dentry *erofs_fh_to_parent(struct super_block *sb, |
556 | struct fid *fid, int fh_len, int fh_type) |
557 | { |
558 | return generic_fh_to_parent(sb, fid, fh_len, fh_type, |
559 | get_inode: erofs_nfs_get_inode); |
560 | } |
561 | |
562 | static struct dentry *erofs_get_parent(struct dentry *child) |
563 | { |
564 | erofs_nid_t nid; |
565 | unsigned int d_type; |
566 | int err; |
567 | |
568 | err = erofs_namei(dir: d_inode(dentry: child), name: &dotdot_name, nid: &nid, d_type: &d_type); |
569 | if (err) |
570 | return ERR_PTR(error: err); |
571 | return d_obtain_alias(erofs_iget(sb: child->d_sb, nid)); |
572 | } |
573 | |
574 | static const struct export_operations erofs_export_ops = { |
575 | .encode_fh = generic_encode_ino32_fh, |
576 | .fh_to_dentry = erofs_fh_to_dentry, |
577 | .fh_to_parent = erofs_fh_to_parent, |
578 | .get_parent = erofs_get_parent, |
579 | }; |
580 | |
581 | static int erofs_fc_fill_super(struct super_block *sb, struct fs_context *fc) |
582 | { |
583 | struct inode *inode; |
584 | struct erofs_sb_info *sbi; |
585 | struct erofs_fs_context *ctx = fc->fs_private; |
586 | int err; |
587 | |
588 | sb->s_magic = EROFS_SUPER_MAGIC; |
589 | sb->s_flags |= SB_RDONLY | SB_NOATIME; |
590 | sb->s_maxbytes = MAX_LFS_FILESIZE; |
591 | sb->s_op = &erofs_sops; |
592 | |
593 | sbi = kzalloc(size: sizeof(*sbi), GFP_KERNEL); |
594 | if (!sbi) |
595 | return -ENOMEM; |
596 | |
597 | sb->s_fs_info = sbi; |
598 | sbi->opt = ctx->opt; |
599 | sbi->devs = ctx->devs; |
600 | ctx->devs = NULL; |
601 | sbi->fsid = ctx->fsid; |
602 | ctx->fsid = NULL; |
603 | sbi->domain_id = ctx->domain_id; |
604 | ctx->domain_id = NULL; |
605 | |
606 | sbi->blkszbits = PAGE_SHIFT; |
607 | if (erofs_is_fscache_mode(sb)) { |
608 | sb->s_blocksize = PAGE_SIZE; |
609 | sb->s_blocksize_bits = PAGE_SHIFT; |
610 | |
611 | err = erofs_fscache_register_fs(sb); |
612 | if (err) |
613 | return err; |
614 | |
615 | err = super_setup_bdi(sb); |
616 | if (err) |
617 | return err; |
618 | } else { |
619 | if (!sb_set_blocksize(sb, PAGE_SIZE)) { |
620 | errorfc(fc, "failed to set initial blksize" ); |
621 | return -EINVAL; |
622 | } |
623 | |
624 | sbi->dax_dev = fs_dax_get_by_bdev(bdev: sb->s_bdev, |
625 | start_off: &sbi->dax_part_off, |
626 | NULL, NULL); |
627 | } |
628 | |
629 | err = erofs_read_superblock(sb); |
630 | if (err) |
631 | return err; |
632 | |
633 | if (sb->s_blocksize_bits != sbi->blkszbits) { |
634 | if (erofs_is_fscache_mode(sb)) { |
635 | errorfc(fc, "unsupported blksize for fscache mode" ); |
636 | return -EINVAL; |
637 | } |
638 | if (!sb_set_blocksize(sb, 1 << sbi->blkszbits)) { |
639 | errorfc(fc, "failed to set erofs blksize" ); |
640 | return -EINVAL; |
641 | } |
642 | } |
643 | |
644 | if (test_opt(&sbi->opt, DAX_ALWAYS)) { |
645 | if (!sbi->dax_dev) { |
646 | errorfc(fc, "DAX unsupported by block device. Turning off DAX." ); |
647 | clear_opt(&sbi->opt, DAX_ALWAYS); |
648 | } else if (sbi->blkszbits != PAGE_SHIFT) { |
649 | errorfc(fc, "unsupported blocksize for DAX" ); |
650 | clear_opt(&sbi->opt, DAX_ALWAYS); |
651 | } |
652 | } |
653 | |
654 | sb->s_time_gran = 1; |
655 | sb->s_xattr = erofs_xattr_handlers; |
656 | sb->s_export_op = &erofs_export_ops; |
657 | |
658 | if (test_opt(&sbi->opt, POSIX_ACL)) |
659 | sb->s_flags |= SB_POSIXACL; |
660 | else |
661 | sb->s_flags &= ~SB_POSIXACL; |
662 | |
663 | #ifdef CONFIG_EROFS_FS_ZIP |
664 | xa_init(xa: &sbi->managed_pslots); |
665 | #endif |
666 | |
667 | inode = erofs_iget(sb, nid: sbi->root_nid); |
668 | if (IS_ERR(ptr: inode)) |
669 | return PTR_ERR(ptr: inode); |
670 | |
671 | if (!S_ISDIR(inode->i_mode)) { |
672 | erofs_err(sb, "rootino(nid %llu) is not a directory(i_mode %o)" , |
673 | sbi->root_nid, inode->i_mode); |
674 | iput(inode); |
675 | return -EINVAL; |
676 | } |
677 | |
678 | sb->s_root = d_make_root(inode); |
679 | if (!sb->s_root) |
680 | return -ENOMEM; |
681 | |
682 | erofs_shrinker_register(sb); |
683 | if (erofs_sb_has_fragments(sbi) && sbi->packed_nid) { |
684 | sbi->packed_inode = erofs_iget(sb, nid: sbi->packed_nid); |
685 | if (IS_ERR(ptr: sbi->packed_inode)) { |
686 | err = PTR_ERR(ptr: sbi->packed_inode); |
687 | sbi->packed_inode = NULL; |
688 | return err; |
689 | } |
690 | } |
691 | err = erofs_init_managed_cache(sb); |
692 | if (err) |
693 | return err; |
694 | |
695 | err = erofs_xattr_prefixes_init(sb); |
696 | if (err) |
697 | return err; |
698 | |
699 | err = erofs_register_sysfs(sb); |
700 | if (err) |
701 | return err; |
702 | |
703 | erofs_info(sb, "mounted with root inode @ nid %llu." , sbi->root_nid); |
704 | return 0; |
705 | } |
706 | |
707 | static int erofs_fc_get_tree(struct fs_context *fc) |
708 | { |
709 | struct erofs_fs_context *ctx = fc->fs_private; |
710 | |
711 | if (IS_ENABLED(CONFIG_EROFS_FS_ONDEMAND) && ctx->fsid) |
712 | return get_tree_nodev(fc, fill_super: erofs_fc_fill_super); |
713 | |
714 | return get_tree_bdev(fc, fill_super: erofs_fc_fill_super); |
715 | } |
716 | |
717 | static int erofs_fc_reconfigure(struct fs_context *fc) |
718 | { |
719 | struct super_block *sb = fc->root->d_sb; |
720 | struct erofs_sb_info *sbi = EROFS_SB(sb); |
721 | struct erofs_fs_context *ctx = fc->fs_private; |
722 | |
723 | DBG_BUGON(!sb_rdonly(sb)); |
724 | |
725 | if (ctx->fsid || ctx->domain_id) |
726 | erofs_info(sb, "ignoring reconfiguration for fsid|domain_id." ); |
727 | |
728 | if (test_opt(&ctx->opt, POSIX_ACL)) |
729 | fc->sb_flags |= SB_POSIXACL; |
730 | else |
731 | fc->sb_flags &= ~SB_POSIXACL; |
732 | |
733 | sbi->opt = ctx->opt; |
734 | |
735 | fc->sb_flags |= SB_RDONLY; |
736 | return 0; |
737 | } |
738 | |
739 | static int erofs_release_device_info(int id, void *ptr, void *data) |
740 | { |
741 | struct erofs_device_info *dif = ptr; |
742 | |
743 | fs_put_dax(dax_dev: dif->dax_dev, NULL); |
744 | if (dif->bdev_file) |
745 | fput(dif->bdev_file); |
746 | erofs_fscache_unregister_cookie(fscache: dif->fscache); |
747 | dif->fscache = NULL; |
748 | kfree(objp: dif->path); |
749 | kfree(objp: dif); |
750 | return 0; |
751 | } |
752 | |
753 | static void erofs_free_dev_context(struct erofs_dev_context *devs) |
754 | { |
755 | if (!devs) |
756 | return; |
757 | idr_for_each(&devs->tree, fn: &erofs_release_device_info, NULL); |
758 | idr_destroy(&devs->tree); |
759 | kfree(objp: devs); |
760 | } |
761 | |
762 | static void erofs_fc_free(struct fs_context *fc) |
763 | { |
764 | struct erofs_fs_context *ctx = fc->fs_private; |
765 | |
766 | erofs_free_dev_context(devs: ctx->devs); |
767 | kfree(objp: ctx->fsid); |
768 | kfree(objp: ctx->domain_id); |
769 | kfree(objp: ctx); |
770 | } |
771 | |
772 | static const struct fs_context_operations erofs_context_ops = { |
773 | .parse_param = erofs_fc_parse_param, |
774 | .get_tree = erofs_fc_get_tree, |
775 | .reconfigure = erofs_fc_reconfigure, |
776 | .free = erofs_fc_free, |
777 | }; |
778 | |
779 | static int erofs_init_fs_context(struct fs_context *fc) |
780 | { |
781 | struct erofs_fs_context *ctx; |
782 | |
783 | ctx = kzalloc(size: sizeof(*ctx), GFP_KERNEL); |
784 | if (!ctx) |
785 | return -ENOMEM; |
786 | ctx->devs = kzalloc(size: sizeof(struct erofs_dev_context), GFP_KERNEL); |
787 | if (!ctx->devs) { |
788 | kfree(objp: ctx); |
789 | return -ENOMEM; |
790 | } |
791 | fc->fs_private = ctx; |
792 | |
793 | idr_init(idr: &ctx->devs->tree); |
794 | init_rwsem(&ctx->devs->rwsem); |
795 | erofs_default_options(ctx); |
796 | fc->ops = &erofs_context_ops; |
797 | return 0; |
798 | } |
799 | |
800 | static void erofs_kill_sb(struct super_block *sb) |
801 | { |
802 | struct erofs_sb_info *sbi; |
803 | |
804 | if (erofs_is_fscache_mode(sb)) |
805 | kill_anon_super(sb); |
806 | else |
807 | kill_block_super(sb); |
808 | |
809 | sbi = EROFS_SB(sb); |
810 | if (!sbi) |
811 | return; |
812 | |
813 | erofs_free_dev_context(devs: sbi->devs); |
814 | fs_put_dax(dax_dev: sbi->dax_dev, NULL); |
815 | erofs_fscache_unregister_fs(sb); |
816 | kfree(objp: sbi->fsid); |
817 | kfree(objp: sbi->domain_id); |
818 | kfree(objp: sbi); |
819 | sb->s_fs_info = NULL; |
820 | } |
821 | |
822 | static void erofs_put_super(struct super_block *sb) |
823 | { |
824 | struct erofs_sb_info *const sbi = EROFS_SB(sb); |
825 | |
826 | DBG_BUGON(!sbi); |
827 | |
828 | erofs_unregister_sysfs(sb); |
829 | erofs_shrinker_unregister(sb); |
830 | erofs_xattr_prefixes_cleanup(sb); |
831 | #ifdef CONFIG_EROFS_FS_ZIP |
832 | iput(sbi->managed_cache); |
833 | sbi->managed_cache = NULL; |
834 | #endif |
835 | iput(sbi->packed_inode); |
836 | sbi->packed_inode = NULL; |
837 | erofs_free_dev_context(devs: sbi->devs); |
838 | sbi->devs = NULL; |
839 | erofs_fscache_unregister_fs(sb); |
840 | } |
841 | |
842 | static struct file_system_type erofs_fs_type = { |
843 | .owner = THIS_MODULE, |
844 | .name = "erofs" , |
845 | .init_fs_context = erofs_init_fs_context, |
846 | .kill_sb = erofs_kill_sb, |
847 | .fs_flags = FS_REQUIRES_DEV | FS_ALLOW_IDMAP, |
848 | }; |
849 | MODULE_ALIAS_FS("erofs" ); |
850 | |
851 | static int __init erofs_module_init(void) |
852 | { |
853 | int err; |
854 | |
855 | erofs_check_ondisk_layout_definitions(); |
856 | |
857 | erofs_inode_cachep = kmem_cache_create(name: "erofs_inode" , |
858 | size: sizeof(struct erofs_inode), align: 0, |
859 | SLAB_RECLAIM_ACCOUNT | SLAB_ACCOUNT, |
860 | ctor: erofs_inode_init_once); |
861 | if (!erofs_inode_cachep) |
862 | return -ENOMEM; |
863 | |
864 | err = erofs_init_shrinker(); |
865 | if (err) |
866 | goto shrinker_err; |
867 | |
868 | err = z_erofs_lzma_init(); |
869 | if (err) |
870 | goto lzma_err; |
871 | |
872 | err = z_erofs_deflate_init(); |
873 | if (err) |
874 | goto deflate_err; |
875 | |
876 | erofs_pcpubuf_init(); |
877 | err = z_erofs_init_zip_subsystem(); |
878 | if (err) |
879 | goto zip_err; |
880 | |
881 | err = erofs_init_sysfs(); |
882 | if (err) |
883 | goto sysfs_err; |
884 | |
885 | err = register_filesystem(&erofs_fs_type); |
886 | if (err) |
887 | goto fs_err; |
888 | |
889 | return 0; |
890 | |
891 | fs_err: |
892 | erofs_exit_sysfs(); |
893 | sysfs_err: |
894 | z_erofs_exit_zip_subsystem(); |
895 | zip_err: |
896 | z_erofs_deflate_exit(); |
897 | deflate_err: |
898 | z_erofs_lzma_exit(); |
899 | lzma_err: |
900 | erofs_exit_shrinker(); |
901 | shrinker_err: |
902 | kmem_cache_destroy(s: erofs_inode_cachep); |
903 | return err; |
904 | } |
905 | |
906 | static void __exit erofs_module_exit(void) |
907 | { |
908 | unregister_filesystem(&erofs_fs_type); |
909 | |
910 | /* Ensure all RCU free inodes / pclusters are safe to be destroyed. */ |
911 | rcu_barrier(); |
912 | |
913 | erofs_exit_sysfs(); |
914 | z_erofs_exit_zip_subsystem(); |
915 | z_erofs_deflate_exit(); |
916 | z_erofs_lzma_exit(); |
917 | erofs_exit_shrinker(); |
918 | kmem_cache_destroy(s: erofs_inode_cachep); |
919 | erofs_pcpubuf_exit(); |
920 | } |
921 | |
922 | static int erofs_statfs(struct dentry *dentry, struct kstatfs *buf) |
923 | { |
924 | struct super_block *sb = dentry->d_sb; |
925 | struct erofs_sb_info *sbi = EROFS_SB(sb); |
926 | u64 id = 0; |
927 | |
928 | if (!erofs_is_fscache_mode(sb)) |
929 | id = huge_encode_dev(dev: sb->s_bdev->bd_dev); |
930 | |
931 | buf->f_type = sb->s_magic; |
932 | buf->f_bsize = sb->s_blocksize; |
933 | buf->f_blocks = sbi->total_blocks; |
934 | buf->f_bfree = buf->f_bavail = 0; |
935 | |
936 | buf->f_files = ULLONG_MAX; |
937 | buf->f_ffree = ULLONG_MAX - sbi->inos; |
938 | |
939 | buf->f_namelen = EROFS_NAME_LEN; |
940 | |
941 | buf->f_fsid = u64_to_fsid(v: id); |
942 | return 0; |
943 | } |
944 | |
945 | static int erofs_show_options(struct seq_file *seq, struct dentry *root) |
946 | { |
947 | struct erofs_sb_info *sbi = EROFS_SB(root->d_sb); |
948 | struct erofs_mount_opts *opt = &sbi->opt; |
949 | |
950 | #ifdef CONFIG_EROFS_FS_XATTR |
951 | if (test_opt(opt, XATTR_USER)) |
952 | seq_puts(m: seq, s: ",user_xattr" ); |
953 | else |
954 | seq_puts(m: seq, s: ",nouser_xattr" ); |
955 | #endif |
956 | #ifdef CONFIG_EROFS_FS_POSIX_ACL |
957 | if (test_opt(opt, POSIX_ACL)) |
958 | seq_puts(m: seq, s: ",acl" ); |
959 | else |
960 | seq_puts(m: seq, s: ",noacl" ); |
961 | #endif |
962 | #ifdef CONFIG_EROFS_FS_ZIP |
963 | if (opt->cache_strategy == EROFS_ZIP_CACHE_DISABLED) |
964 | seq_puts(m: seq, s: ",cache_strategy=disabled" ); |
965 | else if (opt->cache_strategy == EROFS_ZIP_CACHE_READAHEAD) |
966 | seq_puts(m: seq, s: ",cache_strategy=readahead" ); |
967 | else if (opt->cache_strategy == EROFS_ZIP_CACHE_READAROUND) |
968 | seq_puts(m: seq, s: ",cache_strategy=readaround" ); |
969 | #endif |
970 | if (test_opt(opt, DAX_ALWAYS)) |
971 | seq_puts(m: seq, s: ",dax=always" ); |
972 | if (test_opt(opt, DAX_NEVER)) |
973 | seq_puts(m: seq, s: ",dax=never" ); |
974 | #ifdef CONFIG_EROFS_FS_ONDEMAND |
975 | if (sbi->fsid) |
976 | seq_printf(m: seq, fmt: ",fsid=%s" , sbi->fsid); |
977 | if (sbi->domain_id) |
978 | seq_printf(m: seq, fmt: ",domain_id=%s" , sbi->domain_id); |
979 | #endif |
980 | return 0; |
981 | } |
982 | |
983 | const struct super_operations erofs_sops = { |
984 | .put_super = erofs_put_super, |
985 | .alloc_inode = erofs_alloc_inode, |
986 | .free_inode = erofs_free_inode, |
987 | .statfs = erofs_statfs, |
988 | .show_options = erofs_show_options, |
989 | }; |
990 | |
991 | module_init(erofs_module_init); |
992 | module_exit(erofs_module_exit); |
993 | |
994 | MODULE_DESCRIPTION("Enhanced ROM File System" ); |
995 | MODULE_AUTHOR("Gao Xiang, Chao Yu, Miao Xie, CONSUMER BG, HUAWEI Inc." ); |
996 | MODULE_LICENSE("GPL" ); |
997 | |