blob: d405d488fd27ace2ff6d8ef3be2ea971ccad968f [file] [log] [blame]
Huang Jianan830613f2022-02-26 15:05:47 +08001// SPDX-License-Identifier: GPL-2.0+
2#include "internal.h"
3
4static bool check_layout_compatibility(struct erofs_sb_info *sbi,
5 struct erofs_super_block *dsb)
6{
7 const unsigned int feature = le32_to_cpu(dsb->feature_incompat);
8
9 sbi->feature_incompat = feature;
10
11 /* check if current kernel meets all mandatory requirements */
Yifan Zhao3a21e922023-07-07 23:52:12 +080012 if (feature & ~EROFS_ALL_FEATURE_INCOMPAT) {
Huang Jianan830613f2022-02-26 15:05:47 +080013 erofs_err("unidentified incompatible feature %x, please upgrade kernel version",
14 feature & ~EROFS_ALL_FEATURE_INCOMPAT);
15 return false;
16 }
17 return true;
18}
19
20static int erofs_init_devices(struct erofs_sb_info *sbi,
21 struct erofs_super_block *dsb)
22{
23 unsigned int ondisk_extradevs, i;
24 erofs_off_t pos;
25
26 sbi->total_blocks = sbi->primarydevice_blocks;
27
28 if (!erofs_sb_has_device_table())
29 ondisk_extradevs = 0;
30 else
31 ondisk_extradevs = le16_to_cpu(dsb->extra_devices);
32
33 if (ondisk_extradevs != sbi->extra_devices) {
34 erofs_err("extra devices don't match (ondisk %u, given %u)",
35 ondisk_extradevs, sbi->extra_devices);
36 return -EINVAL;
37 }
38 if (!ondisk_extradevs)
39 return 0;
40
41 sbi->device_id_mask = roundup_pow_of_two(ondisk_extradevs + 1) - 1;
42 sbi->devs = calloc(ondisk_extradevs, sizeof(*sbi->devs));
Yifan Zhao3a21e922023-07-07 23:52:12 +080043 if (!sbi->devs)
44 return -ENOMEM;
Huang Jianan830613f2022-02-26 15:05:47 +080045 pos = le16_to_cpu(dsb->devt_slotoff) * EROFS_DEVT_SLOT_SIZE;
46 for (i = 0; i < ondisk_extradevs; ++i) {
47 struct erofs_deviceslot dis;
48 int ret;
49
50 ret = erofs_dev_read(0, &dis, pos, sizeof(dis));
Yifan Zhao3a21e922023-07-07 23:52:12 +080051 if (ret < 0) {
52 free(sbi->devs);
Huang Jianan830613f2022-02-26 15:05:47 +080053 return ret;
Yifan Zhao3a21e922023-07-07 23:52:12 +080054 }
Huang Jianan830613f2022-02-26 15:05:47 +080055
56 sbi->devs[i].mapped_blkaddr = dis.mapped_blkaddr;
57 sbi->total_blocks += dis.blocks;
58 pos += EROFS_DEVT_SLOT_SIZE;
59 }
60 return 0;
61}
62
63int erofs_read_superblock(void)
64{
Yifan Zhao3a21e922023-07-07 23:52:12 +080065 u8 data[EROFS_MAX_BLOCK_SIZE];
Huang Jianan830613f2022-02-26 15:05:47 +080066 struct erofs_super_block *dsb;
Huang Jianan830613f2022-02-26 15:05:47 +080067 int ret;
68
Yifan Zhao3a21e922023-07-07 23:52:12 +080069 ret = erofs_blk_read(data, 0, erofs_blknr(sizeof(data)));
Huang Jianan830613f2022-02-26 15:05:47 +080070 if (ret < 0) {
Simon Glass97f4bc32023-08-13 08:26:40 -060071 erofs_dbg("cannot read erofs superblock: %d", ret);
Huang Jianan830613f2022-02-26 15:05:47 +080072 return -EIO;
73 }
74 dsb = (struct erofs_super_block *)(data + EROFS_SUPER_OFFSET);
75
76 ret = -EINVAL;
77 if (le32_to_cpu(dsb->magic) != EROFS_SUPER_MAGIC_V1) {
Simon Glass97f4bc32023-08-13 08:26:40 -060078 erofs_dbg("cannot find valid erofs superblock");
Huang Jianan830613f2022-02-26 15:05:47 +080079 return ret;
80 }
81
82 sbi.feature_compat = le32_to_cpu(dsb->feature_compat);
83
Yifan Zhao3a21e922023-07-07 23:52:12 +080084 sbi.blkszbits = dsb->blkszbits;
85 if (sbi.blkszbits < 9 ||
86 sbi.blkszbits > ilog2(EROFS_MAX_BLOCK_SIZE)) {
87 erofs_err("blksize %llu isn't supported on this platform",
88 erofs_blksiz() | 0ULL);
89 return ret;
90 } else if (!check_layout_compatibility(&sbi, dsb)) {
Huang Jianan830613f2022-02-26 15:05:47 +080091 return ret;
92 }
93
Huang Jianan830613f2022-02-26 15:05:47 +080094 sbi.primarydevice_blocks = le32_to_cpu(dsb->blocks);
95 sbi.meta_blkaddr = le32_to_cpu(dsb->meta_blkaddr);
96 sbi.xattr_blkaddr = le32_to_cpu(dsb->xattr_blkaddr);
97 sbi.islotbits = EROFS_ISLOTBITS;
98 sbi.root_nid = le16_to_cpu(dsb->root_nid);
Yifan Zhao3a21e922023-07-07 23:52:12 +080099 sbi.packed_nid = le64_to_cpu(dsb->packed_nid);
Huang Jianan830613f2022-02-26 15:05:47 +0800100 sbi.inos = le64_to_cpu(dsb->inos);
101 sbi.checksum = le32_to_cpu(dsb->checksum);
102
103 sbi.build_time = le64_to_cpu(dsb->build_time);
104 sbi.build_time_nsec = le32_to_cpu(dsb->build_time_nsec);
105
106 memcpy(&sbi.uuid, dsb->uuid, sizeof(dsb->uuid));
107 return erofs_init_devices(&sbi, dsb);
108}