065-rootfs_split.patch 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951
  1. --- a/drivers/mtd/Kconfig
  2. +++ b/drivers/mtd/Kconfig
  3. @@ -47,6 +47,16 @@ config MTD_PARTITIONS
  4. devices. Partitioning on NFTL 'devices' is a different - that's the
  5. 'normal' form of partitioning used on a block device.
  6. +config MTD_ROOTFS_ROOT_DEV
  7. + bool "Automatically set 'rootfs' partition to be root filesystem"
  8. + depends on MTD_PARTITIONS
  9. + default y
  10. +
  11. +config MTD_ROOTFS_SPLIT
  12. + bool "Automatically split 'rootfs' partition for squashfs"
  13. + depends on MTD_PARTITIONS
  14. + default y
  15. +
  16. config MTD_REDBOOT_PARTS
  17. tristate "RedBoot partition table parsing"
  18. depends on MTD_PARTITIONS
  19. --- a/drivers/mtd/mtdpart.c
  20. +++ b/drivers/mtd/mtdpart.c
  21. @@ -20,6 +20,8 @@
  22. #include <linux/mtd/mtd.h>
  23. #include <linux/mtd/partitions.h>
  24. #include <linux/mtd/compatmac.h>
  25. +#include <linux/squashfs_fs.h>
  26. +#include <linux/root_dev.h>
  27. /* Our partition linked list */
  28. static LIST_HEAD(mtd_partitions);
  29. @@ -39,7 +41,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. * MTD methods which simply translate the effective address and pass through
  37. @@ -322,6 +324,316 @@ int del_mtd_partitions(struct mtd_info *
  38. return 0;
  39. }
  40. +static u_int32_t cur_offset = 0;
  41. +static int add_one_partition(struct mtd_info *master, const struct mtd_partition *part,
  42. + int i, struct mtd_part **slp)
  43. +{
  44. + struct mtd_part *slave;
  45. +
  46. + /* allocate the partition structure */
  47. + slave = kzalloc (sizeof(*slave), GFP_KERNEL);
  48. + if (!slave) {
  49. + printk ("memory allocation error while creating partitions for \"%s\"\n",
  50. + master->name);
  51. + del_mtd_partitions(master);
  52. + return -ENOMEM;
  53. + }
  54. + list_add(&slave->list, &mtd_partitions);
  55. +
  56. + /* set up the MTD object for this partition */
  57. + slave->mtd.type = master->type;
  58. + slave->mtd.flags = master->flags & ~part->mask_flags;
  59. + slave->mtd.size = part->size;
  60. + slave->mtd.writesize = master->writesize;
  61. + slave->mtd.oobsize = master->oobsize;
  62. + slave->mtd.oobavail = master->oobavail;
  63. + slave->mtd.subpage_sft = master->subpage_sft;
  64. +
  65. + slave->mtd.name = part->name;
  66. + slave->mtd.owner = master->owner;
  67. +
  68. + slave->mtd.read = part_read;
  69. + slave->mtd.write = part_write;
  70. +
  71. + if (master->panic_write)
  72. + slave->mtd.panic_write = part_panic_write;
  73. +
  74. + slave->mtd.refresh_device = part->refresh_partition;
  75. +
  76. + if(master->point && master->unpoint){
  77. + slave->mtd.point = part_point;
  78. + slave->mtd.unpoint = part_unpoint;
  79. + }
  80. +
  81. + if (master->read_oob)
  82. + slave->mtd.read_oob = part_read_oob;
  83. + if (master->write_oob)
  84. + slave->mtd.write_oob = part_write_oob;
  85. + if(master->read_user_prot_reg)
  86. + slave->mtd.read_user_prot_reg = part_read_user_prot_reg;
  87. + if(master->read_fact_prot_reg)
  88. + slave->mtd.read_fact_prot_reg = part_read_fact_prot_reg;
  89. + if(master->write_user_prot_reg)
  90. + slave->mtd.write_user_prot_reg = part_write_user_prot_reg;
  91. + if(master->lock_user_prot_reg)
  92. + slave->mtd.lock_user_prot_reg = part_lock_user_prot_reg;
  93. + if(master->get_user_prot_info)
  94. + slave->mtd.get_user_prot_info = part_get_user_prot_info;
  95. + if(master->get_fact_prot_info)
  96. + slave->mtd.get_fact_prot_info = part_get_fact_prot_info;
  97. + if (master->sync)
  98. + slave->mtd.sync = part_sync;
  99. + if (!i && master->suspend && master->resume) {
  100. + slave->mtd.suspend = part_suspend;
  101. + slave->mtd.resume = part_resume;
  102. + }
  103. + if (master->writev)
  104. + slave->mtd.writev = part_writev;
  105. + if (master->lock)
  106. + slave->mtd.lock = part_lock;
  107. + if (master->unlock)
  108. + slave->mtd.unlock = part_unlock;
  109. + if (master->block_isbad)
  110. + slave->mtd.block_isbad = part_block_isbad;
  111. + if (master->block_markbad)
  112. + slave->mtd.block_markbad = part_block_markbad;
  113. + slave->mtd.erase = part_erase;
  114. + slave->master = master;
  115. + slave->offset = part->offset;
  116. + slave->index = i;
  117. +
  118. + if (slave->offset == MTDPART_OFS_APPEND)
  119. + slave->offset = cur_offset;
  120. + if (slave->offset == MTDPART_OFS_NXTBLK) {
  121. + slave->offset = cur_offset;
  122. + if ((cur_offset % master->erasesize) != 0) {
  123. + /* Round up to next erasesize */
  124. + slave->offset = ((cur_offset / master->erasesize) + 1) * master->erasesize;
  125. + printk(KERN_NOTICE "Moving partition %d: "
  126. + "0x%08x -> 0x%08x\n", i,
  127. + cur_offset, slave->offset);
  128. + }
  129. + }
  130. + if (slave->mtd.size == MTDPART_SIZ_FULL)
  131. + slave->mtd.size = master->size - slave->offset;
  132. + cur_offset = slave->offset + slave->mtd.size;
  133. +
  134. + printk (KERN_NOTICE "0x%08x-0x%08x : \"%s\"\n", slave->offset,
  135. + slave->offset + slave->mtd.size, slave->mtd.name);
  136. +
  137. + /* let's do some sanity checks */
  138. + if (slave->offset >= master->size) {
  139. + /* let's register it anyway to preserve ordering */
  140. + slave->offset = 0;
  141. + slave->mtd.size = 0;
  142. + printk ("mtd: partition \"%s\" is out of reach -- disabled\n",
  143. + part->name);
  144. + }
  145. + if (slave->offset + slave->mtd.size > master->size) {
  146. + slave->mtd.size = master->size - slave->offset;
  147. + printk ("mtd: partition \"%s\" extends beyond the end of device \"%s\" -- size truncated to %#x\n",
  148. + part->name, master->name, slave->mtd.size);
  149. + }
  150. + if (master->numeraseregions>1) {
  151. + /* Deal with variable erase size stuff */
  152. + int i;
  153. + struct mtd_erase_region_info *regions = master->eraseregions;
  154. +
  155. + /* Find the first erase regions which is part of this partition. */
  156. + for (i=0; i < master->numeraseregions && slave->offset >= regions[i].offset; i++)
  157. + ;
  158. +
  159. + for (i--; i < master->numeraseregions && slave->offset + slave->mtd.size > regions[i].offset; i++) {
  160. + if (slave->mtd.erasesize < regions[i].erasesize) {
  161. + slave->mtd.erasesize = regions[i].erasesize;
  162. + }
  163. + }
  164. + } else {
  165. + /* Single erase size */
  166. + slave->mtd.erasesize = master->erasesize;
  167. + }
  168. +
  169. + if ((slave->mtd.flags & MTD_WRITEABLE) &&
  170. + (slave->offset % slave->mtd.erasesize)) {
  171. + /* Doesn't start on a boundary of major erase size */
  172. + /* FIXME: Let it be writable if it is on a boundary of _minor_ erase size though */
  173. + slave->mtd.flags &= ~MTD_WRITEABLE;
  174. + printk ("mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n",
  175. + part->name);
  176. + }
  177. + if ((slave->mtd.flags & MTD_WRITEABLE) &&
  178. + (slave->mtd.size % slave->mtd.erasesize)) {
  179. + slave->mtd.flags &= ~MTD_WRITEABLE;
  180. + printk ("mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n",
  181. + part->name);
  182. + }
  183. +
  184. + slave->mtd.ecclayout = master->ecclayout;
  185. + if (master->block_isbad) {
  186. + uint32_t offs = 0;
  187. +
  188. + while(offs < slave->mtd.size) {
  189. + if (master->block_isbad(master,
  190. + offs + slave->offset))
  191. + slave->mtd.ecc_stats.badblocks++;
  192. + offs += slave->mtd.erasesize;
  193. + }
  194. + }
  195. +
  196. + if(part->mtdp)
  197. + { /* store the object pointer (caller may or may not register it */
  198. + *part->mtdp = &slave->mtd;
  199. + slave->registered = 0;
  200. + }
  201. + else
  202. + {
  203. + /* register our partition */
  204. + add_mtd_device(&slave->mtd);
  205. + slave->registered = 1;
  206. + }
  207. +
  208. + if (slp)
  209. + *slp = slave;
  210. +
  211. + return 0;
  212. +}
  213. +
  214. +#ifdef CONFIG_MTD_ROOTFS_SPLIT
  215. +#define ROOTFS_SPLIT_NAME "rootfs_data"
  216. +#define ROOTFS_REMOVED_NAME "<removed>"
  217. +static int split_squashfs(struct mtd_info *master, int offset, int *split_offset)
  218. +{
  219. + char buf[512];
  220. + struct squashfs_super_block *sb = (struct squashfs_super_block *) buf;
  221. + int len, ret;
  222. +
  223. + ret = master->read(master, offset, sizeof(*sb), &len, buf);
  224. + if (ret || (len != sizeof(*sb))) {
  225. + printk(KERN_ALERT "split_squashfs: error occured while reading "
  226. + "from \"%s\"\n", master->name);
  227. + return -EINVAL;
  228. + }
  229. +
  230. + if (*((u32 *) buf) != SQUASHFS_MAGIC) {
  231. + printk(KERN_ALERT "split_squashfs: no squashfs found in \"%s\"\n",
  232. + master->name);
  233. + *split_offset = 0;
  234. + return 0;
  235. + }
  236. +
  237. + if (sb->bytes_used <= 0) {
  238. + printk(KERN_ALERT "split_squashfs: squashfs is empty in \"%s\"\n",
  239. + master->name);
  240. + *split_offset = 0;
  241. + return 0;
  242. + }
  243. +
  244. + len = (u32) sb->bytes_used;
  245. + len += (offset & 0x000fffff);
  246. + len += (master->erasesize - 1);
  247. + len &= ~(master->erasesize - 1);
  248. + len -= (offset & 0x000fffff);
  249. + *split_offset = offset + len;
  250. +
  251. + return 0;
  252. +}
  253. +
  254. +static int split_rootfs_data(struct mtd_info *master, struct mtd_info *rpart, struct mtd_partition *part,
  255. + int index)
  256. +{
  257. + struct mtd_partition *dpart;
  258. + struct mtd_part *slave = NULL;
  259. + int split_offset = 0;
  260. + int ret;
  261. +
  262. + ret = split_squashfs(master, part->offset, &split_offset);
  263. + if (ret)
  264. + return ret;
  265. +
  266. + if (split_offset <= 0)
  267. + return 0;
  268. +
  269. + dpart = kmalloc(sizeof(*part)+sizeof(ROOTFS_SPLIT_NAME)+1, GFP_KERNEL);
  270. + if (dpart == NULL) {
  271. + printk(KERN_INFO "split_squashfs: no memory for partition \"%s\"\n",
  272. + ROOTFS_SPLIT_NAME);
  273. + return -ENOMEM;
  274. + }
  275. +
  276. + memcpy(dpart, part, sizeof(*part));
  277. + dpart->name = (unsigned char *)&dpart[1];
  278. + strcpy(dpart->name, ROOTFS_SPLIT_NAME);
  279. +
  280. + dpart->size -= split_offset - dpart->offset;
  281. + dpart->offset = split_offset;
  282. +
  283. + if (dpart == NULL)
  284. + return 1;
  285. +
  286. + printk(KERN_INFO "mtd: partition \"%s\" created automatically, ofs=%X, len=%X \n",
  287. + ROOTFS_SPLIT_NAME, dpart->offset, dpart->size);
  288. +
  289. + ret = add_one_partition(master, dpart, index, &slave);
  290. + if (ret)
  291. + kfree(dpart);
  292. + else if (slave)
  293. + rpart->split = &slave->mtd;
  294. +
  295. + return ret;
  296. +}
  297. +
  298. +static int refresh_rootfs_split(struct mtd_info *mtd)
  299. +{
  300. + struct mtd_partition tpart;
  301. + struct mtd_part *part;
  302. + int index = 0;
  303. + int offset, size;
  304. + int ret;
  305. +
  306. + part = PART(mtd);
  307. +
  308. + /* check for the new squashfs offset first */
  309. + ret = split_squashfs(part->master, part->offset, &offset);
  310. + if (ret)
  311. + return ret;
  312. +
  313. + if ((offset > 0) && !mtd->split) {
  314. + printk(KERN_INFO "%s: creating new split partition for \"%s\"\n", __func__, mtd->name);
  315. + /* if we don't have a rootfs split partition, create a new one */
  316. + tpart.name = mtd->name;
  317. + tpart.size = mtd->size;
  318. + tpart.offset = part->offset;
  319. +
  320. + /* find the index of the last partition */
  321. + if (!list_empty(&mtd_partitions))
  322. + index = list_first_entry(&mtd_partitions, struct mtd_part, list)->index + 1;
  323. +
  324. + return split_rootfs_data(part->master, &part->mtd, &tpart, index);
  325. + } else if ((offset > 0) && mtd->split) {
  326. + /* update the offsets of the existing partition */
  327. + size = mtd->size + part->offset - offset;
  328. +
  329. + part = PART(mtd->split);
  330. + part->offset = offset;
  331. + part->mtd.size = size;
  332. + printk(KERN_INFO "%s: %s partition \"" ROOTFS_SPLIT_NAME "\", offset: 0x%06x (0x%06x)\n",
  333. + __func__, (!strcmp(part->mtd.name, ROOTFS_SPLIT_NAME) ? "updating" : "creating"),
  334. + part->offset, part->mtd.size);
  335. + strcpy(part->mtd.name, ROOTFS_SPLIT_NAME);
  336. + } else if ((offset <= 0) && mtd->split) {
  337. + printk(KERN_INFO "%s: removing partition \"%s\"\n", __func__, mtd->split->name);
  338. +
  339. + /* mark existing partition as removed */
  340. + part = PART(mtd->split);
  341. + strcpy(part->mtd.name, ROOTFS_REMOVED_NAME);
  342. + part->offset = 0;
  343. + part->mtd.size = 0;
  344. + }
  345. +
  346. + return 0;
  347. +}
  348. +#endif /* CONFIG_MTD_ROOTFS_SPLIT */
  349. +
  350. /*
  351. * This function, given a master MTD object and a partition table, creates
  352. * and registers slave MTD objects which are bound to the master according to
  353. @@ -334,171 +646,31 @@ int add_mtd_partitions(struct mtd_info *
  354. int nbparts)
  355. {
  356. struct mtd_part *slave;
  357. - u_int32_t cur_offset = 0;
  358. - int i;
  359. + struct mtd_partition *part;
  360. + int i, j, ret = 0;
  361. printk (KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nbparts, master->name);
  362. - for (i = 0; i < nbparts; i++) {
  363. -
  364. - /* allocate the partition structure */
  365. - slave = kzalloc (sizeof(*slave), GFP_KERNEL);
  366. - if (!slave) {
  367. - printk ("memory allocation error while creating partitions for \"%s\"\n",
  368. - master->name);
  369. - del_mtd_partitions(master);
  370. - return -ENOMEM;
  371. - }
  372. - list_add(&slave->list, &mtd_partitions);
  373. -
  374. - /* set up the MTD object for this partition */
  375. - slave->mtd.type = master->type;
  376. - slave->mtd.flags = master->flags & ~parts[i].mask_flags;
  377. - slave->mtd.size = parts[i].size;
  378. - slave->mtd.writesize = master->writesize;
  379. - slave->mtd.oobsize = master->oobsize;
  380. - slave->mtd.oobavail = master->oobavail;
  381. - slave->mtd.subpage_sft = master->subpage_sft;
  382. -
  383. - slave->mtd.name = parts[i].name;
  384. - slave->mtd.owner = master->owner;
  385. -
  386. - slave->mtd.read = part_read;
  387. - slave->mtd.write = part_write;
  388. -
  389. - if (master->panic_write)
  390. - slave->mtd.panic_write = part_panic_write;
  391. -
  392. - if(master->point && master->unpoint){
  393. - slave->mtd.point = part_point;
  394. - slave->mtd.unpoint = part_unpoint;
  395. - }
  396. -
  397. - if (master->read_oob)
  398. - slave->mtd.read_oob = part_read_oob;
  399. - if (master->write_oob)
  400. - slave->mtd.write_oob = part_write_oob;
  401. - if(master->read_user_prot_reg)
  402. - slave->mtd.read_user_prot_reg = part_read_user_prot_reg;
  403. - if(master->read_fact_prot_reg)
  404. - slave->mtd.read_fact_prot_reg = part_read_fact_prot_reg;
  405. - if(master->write_user_prot_reg)
  406. - slave->mtd.write_user_prot_reg = part_write_user_prot_reg;
  407. - if(master->lock_user_prot_reg)
  408. - slave->mtd.lock_user_prot_reg = part_lock_user_prot_reg;
  409. - if(master->get_user_prot_info)
  410. - slave->mtd.get_user_prot_info = part_get_user_prot_info;
  411. - if(master->get_fact_prot_info)
  412. - slave->mtd.get_fact_prot_info = part_get_fact_prot_info;
  413. - if (master->sync)
  414. - slave->mtd.sync = part_sync;
  415. - if (!i && master->suspend && master->resume) {
  416. - slave->mtd.suspend = part_suspend;
  417. - slave->mtd.resume = part_resume;
  418. - }
  419. - if (master->writev)
  420. - slave->mtd.writev = part_writev;
  421. - if (master->lock)
  422. - slave->mtd.lock = part_lock;
  423. - if (master->unlock)
  424. - slave->mtd.unlock = part_unlock;
  425. - if (master->block_isbad)
  426. - slave->mtd.block_isbad = part_block_isbad;
  427. - if (master->block_markbad)
  428. - slave->mtd.block_markbad = part_block_markbad;
  429. - slave->mtd.erase = part_erase;
  430. - slave->master = master;
  431. - slave->offset = parts[i].offset;
  432. - slave->index = i;
  433. -
  434. - if (slave->offset == MTDPART_OFS_APPEND)
  435. - slave->offset = cur_offset;
  436. - if (slave->offset == MTDPART_OFS_NXTBLK) {
  437. - slave->offset = cur_offset;
  438. - if ((cur_offset % master->erasesize) != 0) {
  439. - /* Round up to next erasesize */
  440. - slave->offset = ((cur_offset / master->erasesize) + 1) * master->erasesize;
  441. - printk(KERN_NOTICE "Moving partition %d: "
  442. - "0x%08x -> 0x%08x\n", i,
  443. - cur_offset, slave->offset);
  444. - }
  445. - }
  446. - if (slave->mtd.size == MTDPART_SIZ_FULL)
  447. - slave->mtd.size = master->size - slave->offset;
  448. - cur_offset = slave->offset + slave->mtd.size;
  449. -
  450. - printk (KERN_NOTICE "0x%08x-0x%08x : \"%s\"\n", slave->offset,
  451. - slave->offset + slave->mtd.size, slave->mtd.name);
  452. -
  453. - /* let's do some sanity checks */
  454. - if (slave->offset >= master->size) {
  455. - /* let's register it anyway to preserve ordering */
  456. - slave->offset = 0;
  457. - slave->mtd.size = 0;
  458. - printk ("mtd: partition \"%s\" is out of reach -- disabled\n",
  459. - parts[i].name);
  460. - }
  461. - if (slave->offset + slave->mtd.size > master->size) {
  462. - slave->mtd.size = master->size - slave->offset;
  463. - printk ("mtd: partition \"%s\" extends beyond the end of device \"%s\" -- size truncated to %#x\n",
  464. - parts[i].name, master->name, slave->mtd.size);
  465. - }
  466. - if (master->numeraseregions>1) {
  467. - /* Deal with variable erase size stuff */
  468. - int i;
  469. - struct mtd_erase_region_info *regions = master->eraseregions;
  470. -
  471. - /* Find the first erase regions which is part of this partition. */
  472. - for (i=0; i < master->numeraseregions && slave->offset >= regions[i].offset; i++)
  473. - ;
  474. -
  475. - for (i--; i < master->numeraseregions && slave->offset + slave->mtd.size > regions[i].offset; i++) {
  476. - if (slave->mtd.erasesize < regions[i].erasesize) {
  477. - slave->mtd.erasesize = regions[i].erasesize;
  478. - }
  479. + for (i = 0, j = 0; i < nbparts; i++) {
  480. + part = (struct mtd_partition *) &parts[i];
  481. + ret = add_one_partition(master, part, j, &slave);
  482. + if (ret)
  483. + return ret;
  484. + j++;
  485. +
  486. + if (strcmp(part->name, "rootfs") == 0 && slave->registered) {
  487. +#ifdef CONFIG_MTD_ROOTFS_ROOT_DEV
  488. + if (ROOT_DEV == 0) {
  489. + printk(KERN_NOTICE "mtd: partition \"rootfs\" "
  490. + "set to be root filesystem\n");
  491. + ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, slave->mtd.index);
  492. }
  493. - } else {
  494. - /* Single erase size */
  495. - slave->mtd.erasesize = master->erasesize;
  496. - }
  497. -
  498. - if ((slave->mtd.flags & MTD_WRITEABLE) &&
  499. - (slave->offset % slave->mtd.erasesize)) {
  500. - /* Doesn't start on a boundary of major erase size */
  501. - /* FIXME: Let it be writable if it is on a boundary of _minor_ erase size though */
  502. - slave->mtd.flags &= ~MTD_WRITEABLE;
  503. - printk ("mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n",
  504. - parts[i].name);
  505. - }
  506. - if ((slave->mtd.flags & MTD_WRITEABLE) &&
  507. - (slave->mtd.size % slave->mtd.erasesize)) {
  508. - slave->mtd.flags &= ~MTD_WRITEABLE;
  509. - printk ("mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n",
  510. - parts[i].name);
  511. - }
  512. -
  513. - slave->mtd.ecclayout = master->ecclayout;
  514. - if (master->block_isbad) {
  515. - uint32_t offs = 0;
  516. -
  517. - while(offs < slave->mtd.size) {
  518. - if (master->block_isbad(master,
  519. - offs + slave->offset))
  520. - slave->mtd.ecc_stats.badblocks++;
  521. - offs += slave->mtd.erasesize;
  522. - }
  523. - }
  524. -
  525. - if(parts[i].mtdp)
  526. - { /* store the object pointer (caller may or may not register it */
  527. - *parts[i].mtdp = &slave->mtd;
  528. - slave->registered = 0;
  529. - }
  530. - else
  531. - {
  532. - /* register our partition */
  533. - add_mtd_device(&slave->mtd);
  534. - slave->registered = 1;
  535. +#endif
  536. +#ifdef CONFIG_MTD_ROOTFS_SPLIT
  537. + ret = split_rootfs_data(master, &slave->mtd, part, j);
  538. + if (ret == 0)
  539. + j++;
  540. +#endif
  541. }
  542. }
  543. @@ -574,6 +746,32 @@ int parse_mtd_partitions(struct mtd_info
  544. return ret;
  545. }
  546. +int refresh_mtd_partitions(struct mtd_info *mtd)
  547. +{
  548. + int ret = 0;
  549. +
  550. + if (IS_PART(mtd)) {
  551. + struct mtd_part *part;
  552. + struct mtd_info *master;
  553. +
  554. + part = PART(mtd);
  555. + master = part->master;
  556. + if (master->refresh_device)
  557. + ret = master->refresh_device(master);
  558. + }
  559. +
  560. + if (!ret && mtd->refresh_device)
  561. + ret = mtd->refresh_device(mtd);
  562. +
  563. +#ifdef CONFIG_MTD_ROOTFS_SPLIT
  564. + if (!ret && IS_PART(mtd) && !strcmp(mtd->name, "rootfs"))
  565. + refresh_rootfs_split(mtd);
  566. +#endif
  567. +
  568. + return 0;
  569. +}
  570. +
  571. EXPORT_SYMBOL_GPL(parse_mtd_partitions);
  572. +EXPORT_SYMBOL_GPL(refresh_mtd_partitions);
  573. EXPORT_SYMBOL_GPL(register_mtd_parser);
  574. EXPORT_SYMBOL_GPL(deregister_mtd_parser);
  575. --- a/drivers/mtd/devices/block2mtd.c
  576. +++ b/drivers/mtd/devices/block2mtd.c
  577. @@ -34,6 +34,8 @@ struct block2mtd_dev {
  578. struct block_device *blkdev;
  579. struct mtd_info mtd;
  580. struct mutex write_mutex;
  581. + rwlock_t bdev_mutex;
  582. + char devname[0];
  583. };
  584. @@ -86,6 +88,12 @@ static int block2mtd_erase(struct mtd_in
  585. size_t len = instr->len;
  586. int err;
  587. + read_lock(&dev->bdev_mutex);
  588. + if (!dev->blkdev) {
  589. + err = -EINVAL;
  590. + goto done;
  591. + }
  592. +
  593. instr->state = MTD_ERASING;
  594. mutex_lock(&dev->write_mutex);
  595. err = _block2mtd_erase(dev, from, len);
  596. @@ -98,6 +106,10 @@ static int block2mtd_erase(struct mtd_in
  597. instr->state = MTD_ERASE_DONE;
  598. mtd_erase_callback(instr);
  599. +
  600. +done:
  601. + read_unlock(&dev->bdev_mutex);
  602. +
  603. return err;
  604. }
  605. @@ -109,10 +121,14 @@ static int block2mtd_read(struct mtd_inf
  606. struct page *page;
  607. int index = from >> PAGE_SHIFT;
  608. int offset = from & (PAGE_SIZE-1);
  609. - int cpylen;
  610. + int cpylen, err = 0;
  611. +
  612. + read_lock(&dev->bdev_mutex);
  613. + if (!dev->blkdev || (from > mtd->size)) {
  614. + err = -EINVAL;
  615. + goto done;
  616. + }
  617. - if (from > mtd->size)
  618. - return -EINVAL;
  619. if (from + len > mtd->size)
  620. len = mtd->size - from;
  621. @@ -127,10 +143,14 @@ static int block2mtd_read(struct mtd_inf
  622. len = len - cpylen;
  623. page = page_read(dev->blkdev->bd_inode->i_mapping, index);
  624. - if (!page)
  625. - return -ENOMEM;
  626. - if (IS_ERR(page))
  627. - return PTR_ERR(page);
  628. + if (!page) {
  629. + err = -ENOMEM;
  630. + goto done;
  631. + }
  632. + if (IS_ERR(page)) {
  633. + err = PTR_ERR(page);
  634. + goto done;
  635. + }
  636. memcpy(buf, page_address(page) + offset, cpylen);
  637. page_cache_release(page);
  638. @@ -141,7 +161,10 @@ static int block2mtd_read(struct mtd_inf
  639. offset = 0;
  640. index++;
  641. }
  642. - return 0;
  643. +
  644. +done:
  645. + read_unlock(&dev->bdev_mutex);
  646. + return err;
  647. }
  648. @@ -193,12 +216,22 @@ static int block2mtd_write(struct mtd_in
  649. size_t *retlen, const u_char *buf)
  650. {
  651. struct block2mtd_dev *dev = mtd->priv;
  652. - int err;
  653. + int err = 0;
  654. +
  655. + read_lock(&dev->bdev_mutex);
  656. + if (!dev->blkdev) {
  657. + err = -EINVAL;
  658. + goto done;
  659. + }
  660. if (!len)
  661. - return 0;
  662. - if (to >= mtd->size)
  663. - return -ENOSPC;
  664. + goto done;
  665. +
  666. + if (to >= mtd->size) {
  667. + err = -ENOSPC;
  668. + goto done;
  669. + }
  670. +
  671. if (to + len > mtd->size)
  672. len = mtd->size - to;
  673. @@ -207,6 +240,9 @@ static int block2mtd_write(struct mtd_in
  674. mutex_unlock(&dev->write_mutex);
  675. if (err > 0)
  676. err = 0;
  677. +
  678. +done:
  679. + read_unlock(&dev->bdev_mutex);
  680. return err;
  681. }
  682. @@ -215,51 +251,29 @@ static int block2mtd_write(struct mtd_in
  683. static void block2mtd_sync(struct mtd_info *mtd)
  684. {
  685. struct block2mtd_dev *dev = mtd->priv;
  686. - sync_blockdev(dev->blkdev);
  687. - return;
  688. -}
  689. -
  690. -
  691. -static void block2mtd_free_device(struct block2mtd_dev *dev)
  692. -{
  693. - if (!dev)
  694. - return;
  695. -
  696. - kfree(dev->mtd.name);
  697. - if (dev->blkdev) {
  698. - invalidate_mapping_pages(dev->blkdev->bd_inode->i_mapping,
  699. - 0, -1);
  700. - close_bdev_excl(dev->blkdev);
  701. - }
  702. + read_lock(&dev->bdev_mutex);
  703. + if (dev->blkdev)
  704. + sync_blockdev(dev->blkdev);
  705. + read_unlock(&dev->bdev_mutex);
  706. - kfree(dev);
  707. + return;
  708. }
  709. -/* FIXME: ensure that mtd->size % erase_size == 0 */
  710. -static struct block2mtd_dev *add_device(char *devname, int erase_size, char *mtdname)
  711. +static int _open_bdev(struct block2mtd_dev *dev)
  712. {
  713. struct block_device *bdev;
  714. - struct block2mtd_dev *dev;
  715. - struct mtd_partition *part;
  716. -
  717. - if (!devname)
  718. - return NULL;
  719. -
  720. - dev = kzalloc(sizeof(struct block2mtd_dev), GFP_KERNEL);
  721. - if (!dev)
  722. - return NULL;
  723. /* Get a handle on the device */
  724. - bdev = open_bdev_excl(devname, O_RDWR, NULL);
  725. + bdev = open_bdev_excl(dev->devname, O_RDWR, NULL);
  726. #ifndef MODULE
  727. if (IS_ERR(bdev)) {
  728. /* We might not have rootfs mounted at this point. Try
  729. to resolve the device name by other means. */
  730. - dev_t devt = name_to_dev_t(devname);
  731. + dev_t devt = name_to_dev_t(dev->devname);
  732. if (devt) {
  733. bdev = open_by_devnum(devt, FMODE_WRITE | FMODE_READ);
  734. }
  735. @@ -267,17 +281,96 @@ static struct block2mtd_dev *add_device(
  736. #endif
  737. if (IS_ERR(bdev)) {
  738. - ERROR("error: cannot open device %s", devname);
  739. - goto devinit_err;
  740. + ERROR("error: cannot open device %s", dev->devname);
  741. + return 1;
  742. }
  743. dev->blkdev = bdev;
  744. if (MAJOR(bdev->bd_dev) == MTD_BLOCK_MAJOR) {
  745. ERROR("attempting to use an MTD device as a block device");
  746. - goto devinit_err;
  747. + return 1;
  748. }
  749. + return 0;
  750. +}
  751. +
  752. +static void _close_bdev(struct block2mtd_dev *dev)
  753. +{
  754. + struct block_device *bdev;
  755. +
  756. + if (!dev->blkdev)
  757. + return;
  758. +
  759. + bdev = dev->blkdev;
  760. + invalidate_mapping_pages(dev->blkdev->bd_inode->i_mapping, 0, -1);
  761. + close_bdev_excl(dev->blkdev);
  762. + dev->blkdev = NULL;
  763. +}
  764. +
  765. +static void block2mtd_free_device(struct block2mtd_dev *dev)
  766. +{
  767. + if (!dev)
  768. + return;
  769. +
  770. + kfree(dev->mtd.name);
  771. + _close_bdev(dev);
  772. + kfree(dev);
  773. +}
  774. +
  775. +
  776. +static int block2mtd_refresh(struct mtd_info *mtd)
  777. +{
  778. + struct block2mtd_dev *dev = mtd->priv;
  779. + struct block_device *bdev;
  780. + dev_t devt;
  781. + int err = 0;
  782. +
  783. + /* no other mtd function can run at this point */
  784. + write_lock(&dev->bdev_mutex);
  785. +
  786. + /* get the device number for the whole disk */
  787. + devt = MKDEV(MAJOR(dev->blkdev->bd_dev), 0);
  788. +
  789. + /* close the old block device */
  790. + _close_bdev(dev);
  791. +
  792. + /* open the whole disk, issue a partition rescan, then */
  793. + bdev = open_by_devnum(devt, FMODE_WRITE | FMODE_READ);
  794. + if (!bdev || !bdev->bd_disk)
  795. + err = -EINVAL;
  796. + else {
  797. + err = rescan_partitions(bdev->bd_disk, bdev);
  798. + }
  799. + if (bdev)
  800. + close_bdev_excl(bdev);
  801. +
  802. + /* try to open the partition block device again */
  803. + _open_bdev(dev);
  804. + write_unlock(&dev->bdev_mutex);
  805. +
  806. + return err;
  807. +}
  808. +
  809. +/* FIXME: ensure that mtd->size % erase_size == 0 */
  810. +static struct block2mtd_dev *add_device(char *devname, int erase_size, char *mtdname)
  811. +{
  812. + struct block2mtd_dev *dev;
  813. + struct mtd_partition *part;
  814. +
  815. + if (!devname)
  816. + return NULL;
  817. +
  818. + dev = kzalloc(sizeof(struct block2mtd_dev) + strlen(devname) + 1, GFP_KERNEL);
  819. + if (!dev)
  820. + return NULL;
  821. +
  822. + strcpy(dev->devname, devname);
  823. +
  824. + if (_open_bdev(dev))
  825. + goto devinit_err;
  826. +
  827. mutex_init(&dev->write_mutex);
  828. + rwlock_init(&dev->bdev_mutex);
  829. /* Setup the MTD structure */
  830. /* make the name contain the block device in */
  831. @@ -304,6 +397,7 @@ static struct block2mtd_dev *add_device(
  832. dev->mtd.read = block2mtd_read;
  833. dev->mtd.priv = dev;
  834. dev->mtd.owner = THIS_MODULE;
  835. + dev->mtd.refresh_device = block2mtd_refresh;
  836. part = kzalloc(sizeof(struct mtd_partition), GFP_KERNEL);
  837. part->name = dev->mtd.name;
  838. --- a/drivers/mtd/mtdchar.c
  839. +++ b/drivers/mtd/mtdchar.c
  840. @@ -17,6 +17,7 @@
  841. #include <linux/mtd/mtd.h>
  842. #include <linux/mtd/compatmac.h>
  843. +#include <linux/mtd/partitions.h>
  844. #include <asm/uaccess.h>
  845. @@ -756,6 +757,13 @@ static int mtd_ioctl(struct inode *inode
  846. file->f_pos = 0;
  847. break;
  848. }
  849. +#ifdef CONFIG_MTD_PARTITIONS
  850. + case MTDREFRESH:
  851. + {
  852. + ret = refresh_mtd_partitions(mtd);
  853. + break;
  854. + }
  855. +#endif
  856. default:
  857. ret = -ENOTTY;
  858. --- a/include/linux/mtd/mtd.h
  859. +++ b/include/linux/mtd/mtd.h
  860. @@ -98,6 +98,7 @@ struct mtd_oob_ops {
  861. uint8_t *oobbuf;
  862. };
  863. +struct mtd_info;
  864. struct mtd_info {
  865. u_char type;
  866. u_int32_t flags;
  867. @@ -211,6 +212,9 @@ struct mtd_info {
  868. struct module *owner;
  869. int usecount;
  870. + int (*refresh_device)(struct mtd_info *mtd);
  871. + struct mtd_info *split;
  872. +
  873. /* If the driver is something smart, like UBI, it may need to maintain
  874. * its own reference counting. The below functions are only for driver.
  875. * The driver may register its callbacks. These callbacks are not
  876. --- a/include/linux/mtd/partitions.h
  877. +++ b/include/linux/mtd/partitions.h
  878. @@ -36,6 +36,7 @@
  879. * erasesize aligned (e.g. use MTDPART_OFS_NEXTBLK).
  880. */
  881. +struct mtd_partition;
  882. struct mtd_partition {
  883. char *name; /* identifier string */
  884. u_int32_t size; /* partition size */
  885. @@ -43,6 +44,7 @@ struct mtd_partition {
  886. u_int32_t mask_flags; /* master MTD flags to mask out for this partition */
  887. struct nand_ecclayout *ecclayout; /* out of band layout for this partition (NAND only)*/
  888. struct mtd_info **mtdp; /* pointer to store the MTD object */
  889. + int (*refresh_partition)(struct mtd_info *);
  890. };
  891. #define MTDPART_OFS_NXTBLK (-2)
  892. @@ -52,6 +54,7 @@ struct mtd_partition {
  893. int add_mtd_partitions(struct mtd_info *, const struct mtd_partition *, int);
  894. int del_mtd_partitions(struct mtd_info *);
  895. +int refresh_mtd_partitions(struct mtd_info *);
  896. /*
  897. * Functions dealing with the various ways of partitioning the space
  898. --- a/include/mtd/mtd-abi.h
  899. +++ b/include/mtd/mtd-abi.h
  900. @@ -95,6 +95,7 @@ struct otp_info {
  901. #define ECCGETLAYOUT _IOR('M', 17, struct nand_ecclayout)
  902. #define ECCGETSTATS _IOR('M', 18, struct mtd_ecc_stats)
  903. #define MTDFILEMODE _IO('M', 19)
  904. +#define MTDREFRESH _IO('M', 23)
  905. /*
  906. * Obsolete legacy interface. Keep it in order not to break userspace