• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0+ OR Apache-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 #include "erofs/xattr.h"
10 
check_layout_compatibility(struct erofs_sb_info * sbi,struct erofs_super_block * dsb)11 static bool check_layout_compatibility(struct erofs_sb_info *sbi,
12 				       struct erofs_super_block *dsb)
13 {
14 	const unsigned int feature = le32_to_cpu(dsb->feature_incompat);
15 
16 	sbi->feature_incompat = feature;
17 
18 	/* check if current kernel meets all mandatory requirements */
19 	if (feature & ~EROFS_ALL_FEATURE_INCOMPAT) {
20 		erofs_err("unidentified incompatible feature %x, please upgrade kernel version",
21 			  feature & ~EROFS_ALL_FEATURE_INCOMPAT);
22 		return false;
23 	}
24 	return true;
25 }
26 
erofs_init_devices(struct erofs_sb_info * sbi,struct erofs_super_block * dsb)27 static int erofs_init_devices(struct erofs_sb_info *sbi,
28 			      struct erofs_super_block *dsb)
29 {
30 	unsigned int ondisk_extradevs, i;
31 	erofs_off_t pos;
32 
33 	sbi->total_blocks = sbi->primarydevice_blocks;
34 
35 	if (!erofs_sb_has_device_table(sbi))
36 		ondisk_extradevs = 0;
37 	else
38 		ondisk_extradevs = le16_to_cpu(dsb->extra_devices);
39 
40 	if (sbi->extra_devices &&
41 	    ondisk_extradevs != sbi->extra_devices) {
42 		erofs_err("extra devices don't match (ondisk %u, given %u)",
43 			  ondisk_extradevs, sbi->extra_devices);
44 		return -EINVAL;
45 	}
46 	if (!ondisk_extradevs)
47 		return 0;
48 
49 	sbi->extra_devices = ondisk_extradevs;
50 	sbi->device_id_mask = roundup_pow_of_two(ondisk_extradevs + 1) - 1;
51 	sbi->devs = calloc(ondisk_extradevs, sizeof(*sbi->devs));
52 	if (!sbi->devs)
53 		return -ENOMEM;
54 	pos = le16_to_cpu(dsb->devt_slotoff) * EROFS_DEVT_SLOT_SIZE;
55 	for (i = 0; i < ondisk_extradevs; ++i) {
56 		struct erofs_deviceslot dis;
57 		int ret;
58 
59 		ret = dev_read(sbi, 0, &dis, pos, sizeof(dis));
60 		if (ret < 0) {
61 			free(sbi->devs);
62 			sbi->devs = NULL;
63 			return ret;
64 		}
65 
66 		sbi->devs[i].mapped_blkaddr = le32_to_cpu(dis.mapped_blkaddr);
67 		sbi->devs[i].blocks = le32_to_cpu(dis.blocks);
68 		memcpy(sbi->devs[i].tag, dis.tag, sizeof(dis.tag));
69 		sbi->total_blocks += sbi->devs[i].blocks;
70 		pos += EROFS_DEVT_SLOT_SIZE;
71 	}
72 	return 0;
73 }
74 
erofs_read_superblock(struct erofs_sb_info * sbi)75 int erofs_read_superblock(struct erofs_sb_info *sbi)
76 {
77 	u8 data[EROFS_MAX_BLOCK_SIZE];
78 	struct erofs_super_block *dsb;
79 	int ret;
80 
81 	sbi->blkszbits = ilog2(EROFS_MAX_BLOCK_SIZE);
82 	ret = blk_read(sbi, 0, data, 0, erofs_blknr(sbi, sizeof(data)));
83 	if (ret < 0) {
84 		erofs_err("cannot read erofs superblock: %d", ret);
85 		return -EIO;
86 	}
87 	dsb = (struct erofs_super_block *)(data + EROFS_SUPER_OFFSET);
88 
89 	ret = -EINVAL;
90 	if (le32_to_cpu(dsb->magic) != EROFS_SUPER_MAGIC_V1) {
91 		erofs_err("cannot find valid erofs superblock");
92 		return ret;
93 	}
94 
95 	sbi->feature_compat = le32_to_cpu(dsb->feature_compat);
96 
97 	sbi->blkszbits = dsb->blkszbits;
98 	if (sbi->blkszbits < 9 ||
99 	    sbi->blkszbits > ilog2(EROFS_MAX_BLOCK_SIZE)) {
100 		erofs_err("blksize %llu isn't supported on this platform",
101 			  erofs_blksiz(sbi) | 0ULL);
102 		return ret;
103 	} else if (!check_layout_compatibility(sbi, dsb)) {
104 		return ret;
105 	}
106 
107 	sbi->primarydevice_blocks = le32_to_cpu(dsb->blocks);
108 	sbi->meta_blkaddr = le32_to_cpu(dsb->meta_blkaddr);
109 	sbi->xattr_blkaddr = le32_to_cpu(dsb->xattr_blkaddr);
110 	sbi->xattr_prefix_start = le32_to_cpu(dsb->xattr_prefix_start);
111 	sbi->xattr_prefix_count = dsb->xattr_prefix_count;
112 	sbi->islotbits = EROFS_ISLOTBITS;
113 	sbi->root_nid = le16_to_cpu(dsb->root_nid);
114 	sbi->packed_nid = le64_to_cpu(dsb->packed_nid);
115 	sbi->inos = le64_to_cpu(dsb->inos);
116 	sbi->checksum = le32_to_cpu(dsb->checksum);
117 	sbi->extslots = dsb->sb_extslots;
118 
119 	sbi->build_time = le64_to_cpu(dsb->build_time);
120 	sbi->build_time_nsec = le32_to_cpu(dsb->build_time_nsec);
121 
122 	memcpy(&sbi->uuid, dsb->uuid, sizeof(dsb->uuid));
123 
124 	if (erofs_sb_has_compr_cfgs(sbi))
125 		sbi->available_compr_algs = le16_to_cpu(dsb->u1.available_compr_algs);
126 	else
127 		sbi->lz4_max_distance = le16_to_cpu(dsb->u1.lz4_max_distance);
128 
129 	ret = erofs_init_devices(sbi, dsb);
130 	if (ret)
131 		return ret;
132 
133 	ret = erofs_xattr_prefixes_init(sbi);
134 	if (ret && sbi->devs) {
135 		free(sbi->devs);
136 		sbi->devs = NULL;
137 	}
138 	return ret;
139 }
140 
erofs_put_super(struct erofs_sb_info * sbi)141 void erofs_put_super(struct erofs_sb_info *sbi)
142 {
143 	if (sbi->devs) {
144 		free(sbi->devs);
145 		sbi->devs = NULL;
146 	}
147 	erofs_xattr_prefixes_cleanup(sbi);
148 }
149