Merge tag 'xilinx-for-v2022.07-rc1' of https://source.denx.de/u-boot/custodians/u...
[platform/kernel/u-boot.git] / fs / erofs / super.c
1 // SPDX-License-Identifier: GPL-2.0+
2 #include "internal.h"
3
4 static 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 */
12         if (feature & (~EROFS_ALL_FEATURE_INCOMPAT)) {
13                 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
20 static 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));
43         pos = le16_to_cpu(dsb->devt_slotoff) * EROFS_DEVT_SLOT_SIZE;
44         for (i = 0; i < ondisk_extradevs; ++i) {
45                 struct erofs_deviceslot dis;
46                 int ret;
47
48                 ret = erofs_dev_read(0, &dis, pos, sizeof(dis));
49                 if (ret < 0)
50                         return ret;
51
52                 sbi->devs[i].mapped_blkaddr = dis.mapped_blkaddr;
53                 sbi->total_blocks += dis.blocks;
54                 pos += EROFS_DEVT_SLOT_SIZE;
55         }
56         return 0;
57 }
58
59 int erofs_read_superblock(void)
60 {
61         char data[EROFS_BLKSIZ];
62         struct erofs_super_block *dsb;
63         unsigned int blkszbits;
64         int ret;
65
66         ret = erofs_blk_read(data, 0, 1);
67         if (ret < 0) {
68                 erofs_err("cannot read erofs superblock: %d", ret);
69                 return -EIO;
70         }
71         dsb = (struct erofs_super_block *)(data + EROFS_SUPER_OFFSET);
72
73         ret = -EINVAL;
74         if (le32_to_cpu(dsb->magic) != EROFS_SUPER_MAGIC_V1) {
75                 erofs_err("cannot find valid erofs superblock");
76                 return ret;
77         }
78
79         sbi.feature_compat = le32_to_cpu(dsb->feature_compat);
80
81         blkszbits = dsb->blkszbits;
82         /* 9(512 bytes) + LOG_SECTORS_PER_BLOCK == LOG_BLOCK_SIZE */
83         if (blkszbits != LOG_BLOCK_SIZE) {
84                 erofs_err("blksize %u isn't supported on this platform",
85                           1 << blkszbits);
86                 return ret;
87         }
88
89         if (!check_layout_compatibility(&sbi, dsb))
90                 return ret;
91
92         sbi.primarydevice_blocks = le32_to_cpu(dsb->blocks);
93         sbi.meta_blkaddr = le32_to_cpu(dsb->meta_blkaddr);
94         sbi.xattr_blkaddr = le32_to_cpu(dsb->xattr_blkaddr);
95         sbi.islotbits = EROFS_ISLOTBITS;
96         sbi.root_nid = le16_to_cpu(dsb->root_nid);
97         sbi.inos = le64_to_cpu(dsb->inos);
98         sbi.checksum = le32_to_cpu(dsb->checksum);
99
100         sbi.build_time = le64_to_cpu(dsb->build_time);
101         sbi.build_time_nsec = le32_to_cpu(dsb->build_time_nsec);
102
103         memcpy(&sbi.uuid, dsb->uuid, sizeof(dsb->uuid));
104         return erofs_init_devices(&sbi, dsb);
105 }