• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Created by Li Guifu <blucerlee@gmail.com>
4  */
5 #include <string.h>
6 #include <stdlib.h>
7 #include "erofs/io.h"
8 #include "erofs/print.h"
9 
check_layout_compatibility(struct erofs_sb_info * sbi,struct erofs_super_block * dsb)10 static bool check_layout_compatibility(struct erofs_sb_info *sbi,
11 				       struct erofs_super_block *dsb)
12 {
13 	const unsigned int feature = le32_to_cpu(dsb->feature_incompat);
14 
15 	sbi->feature_incompat = feature;
16 
17 	/* check if current kernel meets all mandatory requirements */
18 	if (feature & (~EROFS_ALL_FEATURE_INCOMPAT)) {
19 		erofs_err("unidentified incompatible feature %x, please upgrade kernel version",
20 			  feature & ~EROFS_ALL_FEATURE_INCOMPAT);
21 		return false;
22 	}
23 	return true;
24 }
25 
erofs_init_devices(struct erofs_sb_info * sbi,struct erofs_super_block * dsb)26 static int erofs_init_devices(struct erofs_sb_info *sbi,
27 			      struct erofs_super_block *dsb)
28 {
29 	unsigned int ondisk_extradevs, i;
30 	erofs_off_t pos;
31 
32 	sbi->total_blocks = sbi->primarydevice_blocks;
33 
34 	if (!erofs_sb_has_device_table())
35 		ondisk_extradevs = 0;
36 	else
37 		ondisk_extradevs = le16_to_cpu(dsb->extra_devices);
38 
39 	if (ondisk_extradevs != sbi->extra_devices) {
40 		erofs_err("extra devices don't match (ondisk %u, given %u)",
41 			  ondisk_extradevs, sbi->extra_devices);
42 		return -EINVAL;
43 	}
44 	if (!ondisk_extradevs)
45 		return 0;
46 
47 	sbi->device_id_mask = roundup_pow_of_two(ondisk_extradevs + 1) - 1;
48 	sbi->devs = calloc(ondisk_extradevs, sizeof(*sbi->devs));
49 	pos = le16_to_cpu(dsb->devt_slotoff) * EROFS_DEVT_SLOT_SIZE;
50 	for (i = 0; i < ondisk_extradevs; ++i) {
51 		struct erofs_deviceslot dis;
52 		int ret;
53 
54 		ret = dev_read(0, &dis, pos, sizeof(dis));
55 		if (ret < 0)
56 			return ret;
57 
58 		sbi->devs[i].mapped_blkaddr = dis.mapped_blkaddr;
59 		sbi->total_blocks += dis.blocks;
60 		pos += EROFS_DEVT_SLOT_SIZE;
61 	}
62 	return 0;
63 }
64 
erofs_read_superblock(void)65 int erofs_read_superblock(void)
66 {
67 	char data[EROFS_BLKSIZ];
68 	struct erofs_super_block *dsb;
69 	unsigned int blkszbits;
70 	int ret;
71 
72 	ret = blk_read(0, data, 0, 1);
73 	if (ret < 0) {
74 		erofs_err("cannot read erofs superblock: %d", ret);
75 		return -EIO;
76 	}
77 	dsb = (struct erofs_super_block *)(data + EROFS_SUPER_OFFSET);
78 
79 	ret = -EINVAL;
80 	if (le32_to_cpu(dsb->magic) != EROFS_SUPER_MAGIC_V1) {
81 		erofs_err("cannot find valid erofs superblock");
82 		return ret;
83 	}
84 
85 	sbi.feature_compat = le32_to_cpu(dsb->feature_compat);
86 
87 	blkszbits = dsb->blkszbits;
88 	/* 9(512 bytes) + LOG_SECTORS_PER_BLOCK == LOG_BLOCK_SIZE */
89 	if (blkszbits != LOG_BLOCK_SIZE) {
90 		erofs_err("blksize %u isn't supported on this platform",
91 			  1 << blkszbits);
92 		return ret;
93 	}
94 
95 	if (!check_layout_compatibility(&sbi, dsb))
96 		return ret;
97 
98 	sbi.primarydevice_blocks = le32_to_cpu(dsb->blocks);
99 	sbi.meta_blkaddr = le32_to_cpu(dsb->meta_blkaddr);
100 	sbi.xattr_blkaddr = le32_to_cpu(dsb->xattr_blkaddr);
101 	sbi.islotbits = EROFS_ISLOTBITS;
102 	sbi.root_nid = le16_to_cpu(dsb->root_nid);
103 	sbi.inos = le64_to_cpu(dsb->inos);
104 	sbi.checksum = le32_to_cpu(dsb->checksum);
105 
106 	sbi.build_time = le64_to_cpu(dsb->build_time);
107 	sbi.build_time_nsec = le32_to_cpu(dsb->build_time_nsec);
108 
109 	memcpy(&sbi.uuid, dsb->uuid, sizeof(dsb->uuid));
110 	return erofs_init_devices(&sbi, dsb);
111 }
112