67f4764b7b7902409d1c51d225565c347a86dcfa
[openwrt.git] / target / linux / generic-2.6 / patches-2.6.22 / 060-rootfs_split.patch
1 Index: linux/drivers/mtd/Kconfig
2 ===================================================================
3 --- linux.orig/drivers/mtd/Kconfig
4 +++ linux/drivers/mtd/Kconfig
5 @@ -47,6 +47,16 @@ config MTD_PARTITIONS
6           devices. Partitioning on NFTL 'devices' is a different - that's the
7           'normal' form of partitioning used on a block device.
8  
9 +config MTD_ROOTFS_ROOT_DEV
10 +       bool "Automatically set 'rootfs' partition to be root filesystem"
11 +       depends on MTD_PARTITIONS
12 +       default y
13 +
14 +config MTD_ROOTFS_SPLIT
15 +       bool "Automatically split 'rootfs' partition for squashfs"
16 +       depends on MTD_PARTITIONS
17 +       default y
18 +
19  config MTD_REDBOOT_PARTS
20         tristate "RedBoot partition table parsing"
21         depends on MTD_PARTITIONS
22 Index: linux/drivers/mtd/mtdpart.c
23 ===================================================================
24 --- linux.orig/drivers/mtd/mtdpart.c
25 +++ linux/drivers/mtd/mtdpart.c
26 @@ -20,6 +20,8 @@
27  #include <linux/mtd/mtd.h>
28  #include <linux/mtd/partitions.h>
29  #include <linux/mtd/compatmac.h>
30 +#include <linux/squashfs_fs.h>
31 +#include <linux/root_dev.h>
32  
33  /* Our partition linked list */
34  static LIST_HEAD(mtd_partitions);
35 @@ -308,6 +310,265 @@ int del_mtd_partitions(struct mtd_info *
36         return 0;
37  }
38  
39 +static u_int32_t cur_offset = 0;
40 +static int add_one_partition(struct mtd_info *master, const struct mtd_partition *part,
41 +               int i, struct mtd_part **slp)
42 +{
43 +       struct mtd_part *slave;
44 +
45 +       /* allocate the partition structure */
46 +       slave = kzalloc (sizeof(*slave), GFP_KERNEL);
47 +       if (!slave) {
48 +               printk ("memory allocation error while creating partitions for \"%s\"\n",
49 +                       master->name);
50 +               del_mtd_partitions(master);
51 +               return -ENOMEM;
52 +       }
53 +       list_add(&slave->list, &mtd_partitions);
54 +
55 +       /* set up the MTD object for this partition */
56 +       slave->mtd.type = master->type;
57 +       slave->mtd.flags = master->flags & ~part->mask_flags;
58 +       slave->mtd.size = part->size;
59 +       slave->mtd.writesize = master->writesize;
60 +       slave->mtd.oobsize = master->oobsize;
61 +       slave->mtd.oobavail = master->oobavail;
62 +       slave->mtd.subpage_sft = master->subpage_sft;
63 +
64 +       slave->mtd.name = part->name;
65 +       slave->mtd.owner = master->owner;
66 +
67 +       slave->mtd.read = part_read;
68 +       slave->mtd.write = part_write;
69 +
70 +       if(master->point && master->unpoint){
71 +               slave->mtd.point = part_point;
72 +               slave->mtd.unpoint = part_unpoint;
73 +       }
74 +
75 +       if (master->read_oob)
76 +               slave->mtd.read_oob = part_read_oob;
77 +       if (master->write_oob)
78 +               slave->mtd.write_oob = part_write_oob;
79 +       if(master->read_user_prot_reg)
80 +               slave->mtd.read_user_prot_reg = part_read_user_prot_reg;
81 +       if(master->read_fact_prot_reg)
82 +               slave->mtd.read_fact_prot_reg = part_read_fact_prot_reg;
83 +       if(master->write_user_prot_reg)
84 +               slave->mtd.write_user_prot_reg = part_write_user_prot_reg;
85 +       if(master->lock_user_prot_reg)
86 +               slave->mtd.lock_user_prot_reg = part_lock_user_prot_reg;
87 +       if(master->get_user_prot_info)
88 +               slave->mtd.get_user_prot_info = part_get_user_prot_info;
89 +       if(master->get_fact_prot_info)
90 +               slave->mtd.get_fact_prot_info = part_get_fact_prot_info;
91 +       if (master->sync)
92 +               slave->mtd.sync = part_sync;
93 +       if (!i && master->suspend && master->resume) {
94 +                       slave->mtd.suspend = part_suspend;
95 +                       slave->mtd.resume = part_resume;
96 +       }
97 +       if (master->writev)
98 +               slave->mtd.writev = part_writev;
99 +       if (master->lock)
100 +               slave->mtd.lock = part_lock;
101 +       if (master->unlock)
102 +               slave->mtd.unlock = part_unlock;
103 +       if (master->block_isbad)
104 +               slave->mtd.block_isbad = part_block_isbad;
105 +       if (master->block_markbad)
106 +               slave->mtd.block_markbad = part_block_markbad;
107 +       slave->mtd.erase = part_erase;
108 +       slave->master = master;
109 +       slave->offset = part->offset;
110 +       slave->index = i;
111 +
112 +       if (slave->offset == MTDPART_OFS_APPEND)
113 +               slave->offset = cur_offset;
114 +       if (slave->offset == MTDPART_OFS_NXTBLK) {
115 +               slave->offset = cur_offset;
116 +               if ((cur_offset % master->erasesize) != 0) {
117 +                       /* Round up to next erasesize */
118 +                       slave->offset = ((cur_offset / master->erasesize) + 1) * master->erasesize;
119 +                       printk(KERN_NOTICE "Moving partition %d: "
120 +                              "0x%08x -> 0x%08x\n", i,
121 +                              cur_offset, slave->offset);
122 +               }
123 +       }
124 +       if (slave->mtd.size == MTDPART_SIZ_FULL)
125 +               slave->mtd.size = master->size - slave->offset;
126 +       cur_offset = slave->offset + slave->mtd.size;
127 +
128 +       printk (KERN_NOTICE "0x%08x-0x%08x : \"%s\"\n", slave->offset,
129 +               slave->offset + slave->mtd.size, slave->mtd.name);
130 +
131 +       /* let's do some sanity checks */
132 +       if (slave->offset >= master->size) {
133 +                       /* let's register it anyway to preserve ordering */
134 +               slave->offset = 0;
135 +               slave->mtd.size = 0;
136 +               printk ("mtd: partition \"%s\" is out of reach -- disabled\n",
137 +                       part->name);
138 +       }
139 +       if (slave->offset + slave->mtd.size > master->size) {
140 +               slave->mtd.size = master->size - slave->offset;
141 +               printk ("mtd: partition \"%s\" extends beyond the end of device \"%s\" -- size truncated to %#x\n",
142 +                       part->name, master->name, slave->mtd.size);
143 +       }
144 +       if (master->numeraseregions>1) {
145 +               /* Deal with variable erase size stuff */
146 +               int i;
147 +               struct mtd_erase_region_info *regions = master->eraseregions;
148 +
149 +               /* Find the first erase regions which is part of this partition. */
150 +               for (i=0; i < master->numeraseregions && slave->offset >= regions[i].offset; i++)
151 +                       ;
152 +
153 +               for (i--; i < master->numeraseregions && slave->offset + slave->mtd.size > regions[i].offset; i++) {
154 +                       if (slave->mtd.erasesize < regions[i].erasesize) {
155 +                               slave->mtd.erasesize = regions[i].erasesize;
156 +                       }
157 +               }
158 +       } else {
159 +               /* Single erase size */
160 +               slave->mtd.erasesize = master->erasesize;
161 +       }
162 +
163 +       if ((slave->mtd.flags & MTD_WRITEABLE) &&
164 +           (slave->offset % slave->mtd.erasesize)) {
165 +               /* Doesn't start on a boundary of major erase size */
166 +               /* FIXME: Let it be writable if it is on a boundary of _minor_ erase size though */
167 +               slave->mtd.flags &= ~MTD_WRITEABLE;
168 +               printk ("mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n",
169 +                       part->name);
170 +       }
171 +       if ((slave->mtd.flags & MTD_WRITEABLE) &&
172 +           (slave->mtd.size % slave->mtd.erasesize)) {
173 +               slave->mtd.flags &= ~MTD_WRITEABLE;
174 +               printk ("mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n",
175 +                       part->name);
176 +       }
177 +
178 +       slave->mtd.ecclayout = master->ecclayout;
179 +       if (master->block_isbad) {
180 +               uint32_t offs = 0;
181 +
182 +               while(offs < slave->mtd.size) {
183 +                       if (master->block_isbad(master,
184 +                                               offs + slave->offset))
185 +                               slave->mtd.ecc_stats.badblocks++;
186 +                       offs += slave->mtd.erasesize;
187 +               }
188 +       }
189 +
190 +       if(part->mtdp)
191 +       {       /* store the object pointer (caller may or may not register it */
192 +               *part->mtdp = &slave->mtd;
193 +               slave->registered = 0;
194 +       }
195 +       else
196 +       {
197 +               /* register our partition */
198 +               add_mtd_device(&slave->mtd);
199 +               slave->registered = 1;
200 +       }
201 +
202 +       if (slp)
203 +               *slp = slave;
204 +
205 +       return 0;
206 +}
207 +
208 +#ifdef CONFIG_MTD_ROOTFS_SPLIT
209 +#define ROOTFS_SPLIT_NAME "rootfs_data"
210 +static int split_squashfs(struct mtd_info *master, struct mtd_partition *old,
211 +               struct mtd_partition **new)
212 +{
213 +       struct mtd_partition *part = NULL;
214 +       int len;
215 +       char buf[512];
216 +       struct squashfs_super_block *sb = (struct squashfs_super_block *) buf;
217 +       int ret;
218 +
219 +       ret = master->read(master, old->offset, sizeof(*sb), &len, buf);
220 +       if (ret) {
221 +               printk(KERN_ALERT "split_squashfs: error occured while reading "
222 +                       "from \"%s\"\n", master->name);
223 +               goto out;
224 +       }
225 +
226 +       if (len != sizeof(*sb)) {
227 +               printk(KERN_ALERT "split_squashfs: unable to read superblock "
228 +                       "from \"%s\"\n", master->name);
229 +               ret=-1;
230 +               goto out;
231 +       }
232 +
233 +       if (*((u32 *) buf) != SQUASHFS_MAGIC) {
234 +               printk(KERN_ALERT "split_squasfs: no squashfs found in \"%s\"\n",
235 +                       master->name);
236 +               ret=0;
237 +               goto out;
238 +       }
239 +
240 +       if (sb->bytes_used <= 0) {
241 +               printk(KERN_ALERT "split_squashfs: squashfs is empty in \"%s\"\n",
242 +                       master->name);
243 +               ret=0;
244 +               goto out;
245 +       }
246 +
247 +       part = kmalloc(sizeof(*part)+sizeof(ROOTFS_SPLIT_NAME)+1, GFP_KERNEL);
248 +       if (part == NULL) {
249 +               printk(KERN_INFO "split_squashfs: no memory for partition \"%s\"\n",
250 +                       ROOTFS_SPLIT_NAME);
251 +               ret = -ENOMEM;
252 +               goto out;
253 +       }
254 +
255 +       memcpy(part, old, sizeof(*part));
256 +       part->name = (unsigned char *)&part[1];
257 +       strcpy(part->name, ROOTFS_SPLIT_NAME);
258 +
259 +       len = (u32) sb->bytes_used;
260 +       len += (part->offset & 0x000fffff);
261 +       len +=  (master->erasesize - 1);
262 +       len &= ~(master->erasesize - 1);
263 +       len -= (part->offset & 0x000fffff);
264 +       part->offset += len;
265 +       part->size -= len;
266 +
267 +       ret = 0;
268 +
269 +out:
270 +       *new = part;
271 +       return ret;
272 +}
273 +
274 +static int split_rootfs_data(struct mtd_info *master, struct mtd_partition *part,
275 +               int index)
276 +{
277 +       struct mtd_partition *dpart;
278 +       int ret;
279 +
280 +       ret = split_squashfs(master, part, &dpart);
281 +       if (ret)
282 +               return ret;
283 +
284 +       if (dpart == NULL)
285 +               return 1;
286 +
287 +       printk(KERN_INFO "mtd: partition \"%s\" created automatically, ofs=%lX, len=%lX \n",
288 +               ROOTFS_SPLIT_NAME, dpart->offset, dpart->size);
289 +
290 +       ret = add_one_partition(master, dpart, index, NULL);
291 +       if (ret)
292 +               kfree(dpart);
293 +
294 +       return ret;
295 +}
296 +#endif /* CONFIG_MTD_ROOTFS_SPLIT */
297 +
298  /*
299   * This function, given a master MTD object and a partition table, creates
300   * and registers slave MTD objects which are bound to the master according to
301 @@ -320,168 +581,31 @@ int add_mtd_partitions(struct mtd_info *
302                        int nbparts)
303  {
304         struct mtd_part *slave;
305 -       u_int32_t cur_offset = 0;
306 -       int i;
307 +       struct mtd_partition *part;
308 +       int i, j, ret = 0;
309  
310         printk (KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nbparts, master->name);
311  
312 -       for (i = 0; i < nbparts; i++) {
313 -
314 -               /* allocate the partition structure */
315 -               slave = kzalloc (sizeof(*slave), GFP_KERNEL);
316 -               if (!slave) {
317 -                       printk ("memory allocation error while creating partitions for \"%s\"\n",
318 -                               master->name);
319 -                       del_mtd_partitions(master);
320 -                       return -ENOMEM;
321 -               }
322 -               list_add(&slave->list, &mtd_partitions);
323 -
324 -               /* set up the MTD object for this partition */
325 -               slave->mtd.type = master->type;
326 -               slave->mtd.flags = master->flags & ~parts[i].mask_flags;
327 -               slave->mtd.size = parts[i].size;
328 -               slave->mtd.writesize = master->writesize;
329 -               slave->mtd.oobsize = master->oobsize;
330 -               slave->mtd.oobavail = master->oobavail;
331 -               slave->mtd.subpage_sft = master->subpage_sft;
332 -
333 -               slave->mtd.name = parts[i].name;
334 -               slave->mtd.owner = master->owner;
335 -
336 -               slave->mtd.read = part_read;
337 -               slave->mtd.write = part_write;
338 -
339 -               if(master->point && master->unpoint){
340 -                       slave->mtd.point = part_point;
341 -                       slave->mtd.unpoint = part_unpoint;
342 -               }
343 -
344 -               if (master->read_oob)
345 -                       slave->mtd.read_oob = part_read_oob;
346 -               if (master->write_oob)
347 -                       slave->mtd.write_oob = part_write_oob;
348 -               if(master->read_user_prot_reg)
349 -                       slave->mtd.read_user_prot_reg = part_read_user_prot_reg;
350 -               if(master->read_fact_prot_reg)
351 -                       slave->mtd.read_fact_prot_reg = part_read_fact_prot_reg;
352 -               if(master->write_user_prot_reg)
353 -                       slave->mtd.write_user_prot_reg = part_write_user_prot_reg;
354 -               if(master->lock_user_prot_reg)
355 -                       slave->mtd.lock_user_prot_reg = part_lock_user_prot_reg;
356 -               if(master->get_user_prot_info)
357 -                       slave->mtd.get_user_prot_info = part_get_user_prot_info;
358 -               if(master->get_fact_prot_info)
359 -                       slave->mtd.get_fact_prot_info = part_get_fact_prot_info;
360 -               if (master->sync)
361 -                       slave->mtd.sync = part_sync;
362 -               if (!i && master->suspend && master->resume) {
363 -                               slave->mtd.suspend = part_suspend;
364 -                               slave->mtd.resume = part_resume;
365 -               }
366 -               if (master->writev)
367 -                       slave->mtd.writev = part_writev;
368 -               if (master->lock)
369 -                       slave->mtd.lock = part_lock;
370 -               if (master->unlock)
371 -                       slave->mtd.unlock = part_unlock;
372 -               if (master->block_isbad)
373 -                       slave->mtd.block_isbad = part_block_isbad;
374 -               if (master->block_markbad)
375 -                       slave->mtd.block_markbad = part_block_markbad;
376 -               slave->mtd.erase = part_erase;
377 -               slave->master = master;
378 -               slave->offset = parts[i].offset;
379 -               slave->index = i;
380 -
381 -               if (slave->offset == MTDPART_OFS_APPEND)
382 -                       slave->offset = cur_offset;
383 -               if (slave->offset == MTDPART_OFS_NXTBLK) {
384 -                       slave->offset = cur_offset;
385 -                       if ((cur_offset % master->erasesize) != 0) {
386 -                               /* Round up to next erasesize */
387 -                               slave->offset = ((cur_offset / master->erasesize) + 1) * master->erasesize;
388 -                               printk(KERN_NOTICE "Moving partition %d: "
389 -                                      "0x%08x -> 0x%08x\n", i,
390 -                                      cur_offset, slave->offset);
391 -                       }
392 -               }
393 -               if (slave->mtd.size == MTDPART_SIZ_FULL)
394 -                       slave->mtd.size = master->size - slave->offset;
395 -               cur_offset = slave->offset + slave->mtd.size;
396 -
397 -               printk (KERN_NOTICE "0x%08x-0x%08x : \"%s\"\n", slave->offset,
398 -                       slave->offset + slave->mtd.size, slave->mtd.name);
399 -
400 -               /* let's do some sanity checks */
401 -               if (slave->offset >= master->size) {
402 -                               /* let's register it anyway to preserve ordering */
403 -                       slave->offset = 0;
404 -                       slave->mtd.size = 0;
405 -                       printk ("mtd: partition \"%s\" is out of reach -- disabled\n",
406 -                               parts[i].name);
407 -               }
408 -               if (slave->offset + slave->mtd.size > master->size) {
409 -                       slave->mtd.size = master->size - slave->offset;
410 -                       printk ("mtd: partition \"%s\" extends beyond the end of device \"%s\" -- size truncated to %#x\n",
411 -                               parts[i].name, master->name, slave->mtd.size);
412 -               }
413 -               if (master->numeraseregions>1) {
414 -                       /* Deal with variable erase size stuff */
415 -                       int i;
416 -                       struct mtd_erase_region_info *regions = master->eraseregions;
417 -
418 -                       /* Find the first erase regions which is part of this partition. */
419 -                       for (i=0; i < master->numeraseregions && slave->offset >= regions[i].offset; i++)
420 -                               ;
421 -
422 -                       for (i--; i < master->numeraseregions && slave->offset + slave->mtd.size > regions[i].offset; i++) {
423 -                               if (slave->mtd.erasesize < regions[i].erasesize) {
424 -                                       slave->mtd.erasesize = regions[i].erasesize;
425 -                               }
426 -                       }
427 -               } else {
428 -                       /* Single erase size */
429 -                       slave->mtd.erasesize = master->erasesize;
430 -               }
431 -
432 -               if ((slave->mtd.flags & MTD_WRITEABLE) &&
433 -                   (slave->offset % slave->mtd.erasesize)) {
434 -                       /* Doesn't start on a boundary of major erase size */
435 -                       /* FIXME: Let it be writable if it is on a boundary of _minor_ erase size though */
436 -                       slave->mtd.flags &= ~MTD_WRITEABLE;
437 -                       printk ("mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n",
438 -                               parts[i].name);
439 -               }
440 -               if ((slave->mtd.flags & MTD_WRITEABLE) &&
441 -                   (slave->mtd.size % slave->mtd.erasesize)) {
442 -                       slave->mtd.flags &= ~MTD_WRITEABLE;
443 -                       printk ("mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n",
444 -                               parts[i].name);
445 -               }
446 -
447 -               slave->mtd.ecclayout = master->ecclayout;
448 -               if (master->block_isbad) {
449 -                       uint32_t offs = 0;
450 -
451 -                       while(offs < slave->mtd.size) {
452 -                               if (master->block_isbad(master,
453 -                                                       offs + slave->offset))
454 -                                       slave->mtd.ecc_stats.badblocks++;
455 -                               offs += slave->mtd.erasesize;
456 +       for (i = 0, j = 0; i < nbparts; i++) {
457 +               part = (struct mtd_partition *) &parts[i];
458 +               ret = add_one_partition(master, part, j, &slave);
459 +               if (ret)
460 +                       return ret;
461 +               j++;
462 +
463 +               if (strcmp(part->name, "rootfs") == 0 && slave->registered) {
464 +#ifdef CONFIG_MTD_ROOTFS_ROOT_DEV
465 +                       if (ROOT_DEV == 0) {
466 +                               printk(KERN_NOTICE "mtd: partition \"rootfs\" "
467 +                                       "set to be root filesystem\n");
468 +                               ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, slave->mtd.index);
469                         }
470 -               }
471 -
472 -               if(parts[i].mtdp)
473 -               {       /* store the object pointer (caller may or may not register it */
474 -                       *parts[i].mtdp = &slave->mtd;
475 -                       slave->registered = 0;
476 -               }
477 -               else
478 -               {
479 -                       /* register our partition */
480 -                       add_mtd_device(&slave->mtd);
481 -                       slave->registered = 1;
482 +#endif
483 +#ifdef CONFIG_MTD_ROOTFS_SPLIT
484 +                       ret = split_rootfs_data(master, part, j);
485 +                       if (ret == 0)
486 +                               j++;
487 +#endif
488                 }
489         }
490