OpenWrt – Blame information for rev 2
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | --- a/drivers/mtd/Kconfig |
2 | +++ b/drivers/mtd/Kconfig |
||
3 | @@ -52,6 +52,14 @@ config MTD_TESTS |
||
4 | WARNING: some of the tests will ERASE entire MTD device which they |
||
5 | test. Do not use these tests unless you really know what you do. |
||
6 | |||
7 | +config MTD_ROOTFS_ROOT_DEV |
||
8 | + bool "Automatically set 'rootfs' partition to be root filesystem" |
||
9 | + default y |
||
10 | + |
||
11 | +config MTD_ROOTFS_SPLIT |
||
12 | + bool "Automatically split 'rootfs' partition for squashfs" |
||
13 | + default y |
||
14 | + |
||
15 | config MTD_REDBOOT_PARTS |
||
16 | tristate "RedBoot partition table parsing" |
||
17 | ---help--- |
||
18 | --- a/drivers/mtd/mtdpart.c |
||
19 | +++ b/drivers/mtd/mtdpart.c |
||
20 | @@ -30,6 +30,8 @@ |
||
21 | #include <linux/mtd/mtd.h> |
||
22 | #include <linux/mtd/partitions.h> |
||
23 | #include <linux/of.h> |
||
24 | +#include <linux/root_dev.h> |
||
25 | +#include <linux/magic.h> |
||
26 | #include <linux/err.h> |
||
27 | |||
28 | #include "mtdcore.h" |
||
29 | @@ -53,7 +55,7 @@ struct mtd_part { |
||
30 | * the pointer to that structure with this macro. |
||
31 | */ |
||
32 | #define PART(x) ((struct mtd_part *)(x)) |
||
33 | - |
||
34 | +#define IS_PART(mtd) (mtd->_read == part_read) |
||
35 | |||
36 | /* |
||
37 | * MTD methods which simply translate the effective address and pass through |
||
38 | @@ -706,6 +708,144 @@ int mtd_del_partition(struct mtd_info *m |
||
39 | } |
||
40 | EXPORT_SYMBOL_GPL(mtd_del_partition); |
||
41 | |||
42 | +#ifdef CONFIG_MTD_ROOTFS_SPLIT |
||
43 | +#define ROOTFS_SPLIT_NAME "rootfs_data" |
||
44 | +#define ROOTFS_REMOVED_NAME "<removed>" |
||
45 | + |
||
46 | +struct squashfs_super_block { |
||
47 | + __le32 s_magic; |
||
48 | + __le32 pad0[9]; |
||
49 | + __le64 bytes_used; |
||
50 | +}; |
||
51 | + |
||
52 | + |
||
53 | +static int split_squashfs(struct mtd_info *master, int offset, int *split_offset) |
||
54 | +{ |
||
55 | + struct squashfs_super_block sb; |
||
56 | + int len, ret; |
||
57 | + |
||
58 | + ret = mtd_read(master, offset, sizeof(sb), &len, (void *) &sb); |
||
59 | + if (ret || (len != sizeof(sb))) { |
||
60 | + printk(KERN_ALERT "split_squashfs: error occured while reading " |
||
61 | + "from \"%s\"\n", master->name); |
||
62 | + return -EINVAL; |
||
63 | + } |
||
64 | + |
||
65 | + if (SQUASHFS_MAGIC != le32_to_cpu(sb.s_magic) ) { |
||
66 | + printk(KERN_ALERT "split_squashfs: no squashfs found in \"%s\"\n", |
||
67 | + master->name); |
||
68 | + *split_offset = 0; |
||
69 | + return 0; |
||
70 | + } |
||
71 | + |
||
72 | + if (le64_to_cpu((sb.bytes_used)) <= 0) { |
||
73 | + printk(KERN_ALERT "split_squashfs: squashfs is empty in \"%s\"\n", |
||
74 | + master->name); |
||
75 | + *split_offset = 0; |
||
76 | + return 0; |
||
77 | + } |
||
78 | + |
||
79 | + len = (u32) le64_to_cpu(sb.bytes_used); |
||
80 | + len += (offset & 0x000fffff); |
||
81 | + len += (master->erasesize - 1); |
||
82 | + len &= ~(master->erasesize - 1); |
||
83 | + len -= (offset & 0x000fffff); |
||
84 | + *split_offset = offset + len; |
||
85 | + |
||
86 | + return 0; |
||
87 | +} |
||
88 | + |
||
89 | +static int split_rootfs_data(struct mtd_info *master, struct mtd_info *rpart, const struct mtd_partition *part) |
||
90 | +{ |
||
91 | + struct mtd_partition dpart; |
||
92 | + struct mtd_part *slave = NULL; |
||
93 | + struct mtd_part *spart; |
||
94 | + int ret, split_offset = 0; |
||
95 | + |
||
96 | + spart = PART(rpart); |
||
97 | + ret = split_squashfs(master, spart->offset, &split_offset); |
||
98 | + if (ret) |
||
99 | + return ret; |
||
100 | + |
||
101 | + if (split_offset <= 0) |
||
102 | + return 0; |
||
103 | + |
||
104 | + memcpy(&dpart, part, sizeof(dpart)); |
||
105 | + dpart.name = ROOTFS_SPLIT_NAME; |
||
106 | + |
||
107 | + dpart.size = rpart->size - (split_offset - spart->offset); |
||
108 | + dpart.offset = split_offset; |
||
109 | + |
||
110 | + printk(KERN_INFO "mtd: partition \"%s\" created automatically, ofs=%llX, len=%llX \n", |
||
111 | + ROOTFS_SPLIT_NAME, dpart.offset, dpart.size); |
||
112 | + |
||
113 | + slave = allocate_partition(master, &dpart, 0, split_offset); |
||
114 | + if (IS_ERR(slave)) |
||
115 | + return PTR_ERR(slave); |
||
116 | + mutex_lock(&mtd_partitions_mutex); |
||
117 | + list_add(&slave->list, &mtd_partitions); |
||
118 | + mutex_unlock(&mtd_partitions_mutex); |
||
119 | + |
||
120 | + add_mtd_device(&slave->mtd); |
||
121 | + |
||
122 | + rpart->split = &slave->mtd; |
||
123 | + |
||
124 | + return 0; |
||
125 | +} |
||
126 | + |
||
127 | +static int refresh_rootfs_split(struct mtd_info *mtd) |
||
128 | +{ |
||
129 | + struct mtd_partition tpart; |
||
130 | + struct mtd_part *part; |
||
131 | + char *name; |
||
132 | + //int index = 0; |
||
133 | + int offset, size; |
||
134 | + int ret; |
||
135 | + |
||
136 | + part = PART(mtd); |
||
137 | + |
||
138 | + /* check for the new squashfs offset first */ |
||
139 | + ret = split_squashfs(part->master, part->offset, &offset); |
||
140 | + if (ret) |
||
141 | + return ret; |
||
142 | + |
||
143 | + if ((offset > 0) && !mtd->split) { |
||
144 | + printk(KERN_INFO "%s: creating new split partition for \"%s\"\n", __func__, mtd->name); |
||
145 | + /* if we don't have a rootfs split partition, create a new one */ |
||
146 | + tpart.name = (char *) mtd->name; |
||
147 | + tpart.size = mtd->size; |
||
148 | + tpart.offset = part->offset; |
||
149 | + |
||
150 | + return split_rootfs_data(part->master, &part->mtd, &tpart); |
||
151 | + } else if ((offset > 0) && mtd->split) { |
||
152 | + /* update the offsets of the existing partition */ |
||
153 | + size = mtd->size + part->offset - offset; |
||
154 | + |
||
155 | + part = PART(mtd->split); |
||
156 | + part->offset = offset; |
||
157 | + part->mtd.size = size; |
||
158 | + printk(KERN_INFO "%s: %s partition \"" ROOTFS_SPLIT_NAME "\", offset: 0x%06x (0x%06x)\n", |
||
159 | + __func__, (!strcmp(part->mtd.name, ROOTFS_SPLIT_NAME) ? "updating" : "creating"), |
||
160 | + (u32) part->offset, (u32) part->mtd.size); |
||
161 | + name = kmalloc(sizeof(ROOTFS_SPLIT_NAME) + 1, GFP_KERNEL); |
||
162 | + strcpy(name, ROOTFS_SPLIT_NAME); |
||
163 | + part->mtd.name = name; |
||
164 | + } else if ((offset <= 0) && mtd->split) { |
||
165 | + printk(KERN_INFO "%s: removing partition \"%s\"\n", __func__, mtd->split->name); |
||
166 | + |
||
167 | + /* mark existing partition as removed */ |
||
168 | + part = PART(mtd->split); |
||
169 | + name = kmalloc(sizeof(ROOTFS_SPLIT_NAME) + 1, GFP_KERNEL); |
||
170 | + strcpy(name, ROOTFS_REMOVED_NAME); |
||
171 | + part->mtd.name = name; |
||
172 | + part->offset = 0; |
||
173 | + part->mtd.size = 0; |
||
174 | + } |
||
175 | + |
||
176 | + return 0; |
||
177 | +} |
||
178 | +#endif /* CONFIG_MTD_ROOTFS_SPLIT */ |
||
179 | + |
||
180 | /* |
||
181 | * This function, given a master MTD object and a partition table, creates |
||
182 | * and registers slave MTD objects which are bound to the master according to |
||
183 | @@ -722,6 +862,9 @@ int add_mtd_partitions(struct mtd_info * |
||
184 | struct mtd_part *slave; |
||
185 | uint64_t cur_offset = 0; |
||
186 | int i; |
||
187 | +#ifdef CONFIG_MTD_ROOTFS_SPLIT |
||
188 | + int ret; |
||
189 | +#endif |
||
190 | |||
191 | printk(KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nbparts, master->name); |
||
192 | |||
193 | @@ -736,12 +879,53 @@ int add_mtd_partitions(struct mtd_info * |
||
194 | |||
195 | add_mtd_device(&slave->mtd); |
||
196 | |||
197 | + if (!strcmp(parts[i].name, "rootfs")) { |
||
198 | +#ifdef CONFIG_MTD_ROOTFS_ROOT_DEV |
||
199 | + if (ROOT_DEV == 0) { |
||
200 | + printk(KERN_NOTICE "mtd: partition \"rootfs\" " |
||
201 | + "set to be root filesystem\n"); |
||
202 | + ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, slave->mtd.index); |
||
203 | + } |
||
204 | +#endif |
||
205 | +#ifdef CONFIG_MTD_ROOTFS_SPLIT |
||
206 | + ret = split_rootfs_data(master, &slave->mtd, &parts[i]); |
||
207 | + /* if (ret == 0) |
||
208 | + * j++; */ |
||
209 | +#endif |
||
210 | + } |
||
211 | + |
||
212 | cur_offset = slave->offset + slave->mtd.size; |
||
213 | } |
||
214 | |||
215 | return 0; |
||
216 | } |
||
217 | |||
218 | +int mtd_device_refresh(struct mtd_info *mtd) |
||
219 | +{ |
||
220 | + int ret = 0; |
||
221 | + |
||
222 | + if (IS_PART(mtd)) { |
||
223 | + struct mtd_part *part; |
||
224 | + struct mtd_info *master; |
||
225 | + |
||
226 | + part = PART(mtd); |
||
227 | + master = part->master; |
||
228 | + if (master->refresh_device) |
||
229 | + ret = master->refresh_device(master); |
||
230 | + } |
||
231 | + |
||
232 | + if (!ret && mtd->refresh_device) |
||
233 | + ret = mtd->refresh_device(mtd); |
||
234 | + |
||
235 | +#ifdef CONFIG_MTD_ROOTFS_SPLIT |
||
236 | + if (!ret && IS_PART(mtd) && !strcmp(mtd->name, "rootfs")) |
||
237 | + refresh_rootfs_split(mtd); |
||
238 | +#endif |
||
239 | + |
||
240 | + return 0; |
||
241 | +} |
||
242 | +EXPORT_SYMBOL_GPL(mtd_device_refresh); |
||
243 | + |
||
244 | static DEFINE_SPINLOCK(part_parser_lock); |
||
245 | static LIST_HEAD(part_parsers); |
||
246 | |||
247 | --- a/drivers/mtd/mtdchar.c |
||
248 | +++ b/drivers/mtd/mtdchar.c |
||
249 | @@ -1012,6 +1012,12 @@ static int mtdchar_ioctl(struct file *fi |
||
250 | break; |
||
251 | } |
||
252 | |||
253 | + case MTDREFRESH: |
||
254 | + { |
||
255 | + ret = mtd_device_refresh(mtd); |
||
256 | + break; |
||
257 | + } |
||
258 | + |
||
259 | default: |
||
260 | ret = -ENOTTY; |
||
261 | } |
||
262 | --- a/include/linux/mtd/mtd.h |
||
263 | +++ b/include/linux/mtd/mtd.h |
||
264 | @@ -115,6 +115,7 @@ struct nand_ecclayout { |
||
265 | |||
266 | struct module; /* only needed for owner field in mtd_info */ |
||
267 | |||
268 | +struct mtd_info; |
||
269 | struct mtd_info { |
||
270 | u_char type; |
||
271 | uint32_t flags; |
||
272 | @@ -231,6 +232,9 @@ struct mtd_info { |
||
273 | int (*_block_markbad) (struct mtd_info *mtd, loff_t ofs); |
||
274 | int (*_suspend) (struct mtd_info *mtd); |
||
275 | void (*_resume) (struct mtd_info *mtd); |
||
276 | + int (*refresh_device)(struct mtd_info *mtd); |
||
277 | + struct mtd_info *split; |
||
278 | + |
||
279 | /* |
||
280 | * If the driver is something smart, like UBI, it may need to maintain |
||
281 | * its own reference counting. The below functions are only for driver. |
||
282 | @@ -397,6 +401,7 @@ extern int mtd_device_parse_register(str |
||
283 | int defnr_parts); |
||
284 | #define mtd_device_register(master, parts, nr_parts) \ |
||
285 | mtd_device_parse_register(master, NULL, NULL, parts, nr_parts) |
||
286 | +extern int mtd_device_refresh(struct mtd_info *master); |
||
287 | extern int mtd_device_unregister(struct mtd_info *master); |
||
288 | extern struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num); |
||
289 | extern int __get_mtd_device(struct mtd_info *mtd); |
||
290 | --- a/include/linux/mtd/partitions.h |
||
291 | +++ b/include/linux/mtd/partitions.h |
||
292 | @@ -37,12 +37,14 @@ |
||
293 | */ |
||
294 | struct mtd_info; |
||
295 | |||
296 | +struct mtd_partition; |
||
297 | struct mtd_partition { |
||
298 | const char *name; /* identifier string */ |
||
299 | uint64_t size; /* partition size */ |
||
300 | uint64_t offset; /* offset within the master MTD space */ |
||
301 | uint32_t mask_flags; /* master MTD flags to mask out for this partition */ |
||
302 | struct nand_ecclayout *ecclayout; /* out of band layout for this partition (NAND only) */ |
||
303 | + int (*refresh_partition)(struct mtd_info *); |
||
304 | }; |
||
305 | |||
306 | #define MTDPART_OFS_RETAIN (-3) |
||
307 | --- a/include/uapi/mtd/mtd-abi.h |
||
308 | +++ b/include/uapi/mtd/mtd-abi.h |
||
309 | @@ -203,6 +203,7 @@ struct otp_info { |
||
310 | * without OOB, e.g., NOR flash. |
||
311 | */ |
||
312 | #define MEMWRITE _IOWR('M', 24, struct mtd_write_req) |
||
313 | +#define MTDREFRESH _IO('M', 50) |
||
314 | |||
315 | /* |
||
316 | * Obsolete legacy interface. Keep it in order not to break userspace |