065-rootfs_split.patch 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633
  1. --- a/drivers/mtd/Kconfig
  2. +++ b/drivers/mtd/Kconfig
  3. @@ -53,6 +53,16 @@ config MTD_TESTS
  4. should normally be compiled as kernel modules. The modules perform
  5. various checks and verifications when loaded.
  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. @@ -18,6 +18,8 @@
  22. #include <linux/mtd/mtd.h>
  23. #include <linux/mtd/partitions.h>
  24. #include <linux/mtd/compatmac.h>
  25. +#include <linux/root_dev.h>
  26. +#include <linux/magic.h>
  27. /* Our partition linked list */
  28. static LIST_HEAD(mtd_partitions);
  29. @@ -37,7 +39,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. @@ -489,6 +491,156 @@ out_register:
  38. return slave;
  39. }
  40. +#ifdef CONFIG_MTD_ROOTFS_SPLIT
  41. +#define ROOTFS_SPLIT_NAME "rootfs_data"
  42. +#define ROOTFS_REMOVED_NAME "<removed>"
  43. +
  44. +struct squashfs_super_block {
  45. + __le32 s_magic;
  46. + __le32 pad0[9];
  47. + __le64 bytes_used;
  48. +};
  49. +
  50. +
  51. +static int split_squashfs(struct mtd_info *master, int offset, int *split_offset)
  52. +{
  53. + char buf[512];
  54. + struct squashfs_super_block *sb = (struct squashfs_super_block *) buf;
  55. + int len, ret;
  56. +
  57. + ret = master->read(master, offset, sizeof(*sb), &len, buf);
  58. + if (ret || (len != sizeof(*sb))) {
  59. + printk(KERN_ALERT "split_squashfs: error occured while reading "
  60. + "from \"%s\"\n", master->name);
  61. + return -EINVAL;
  62. + }
  63. +
  64. + if (*((u32 *) buf) != SQUASHFS_MAGIC) {
  65. + printk(KERN_ALERT "split_squashfs: no squashfs found in \"%s\"\n",
  66. + master->name);
  67. + *split_offset = 0;
  68. + return 0;
  69. + }
  70. +
  71. + if (sb->bytes_used <= 0) {
  72. + printk(KERN_ALERT "split_squashfs: squashfs is empty in \"%s\"\n",
  73. + master->name);
  74. + *split_offset = 0;
  75. + return 0;
  76. + }
  77. +
  78. + len = (u32) sb->bytes_used;
  79. + len += (offset & 0x000fffff);
  80. + len += (master->erasesize - 1);
  81. + len &= ~(master->erasesize - 1);
  82. + len -= (offset & 0x000fffff);
  83. + *split_offset = offset + len;
  84. +
  85. + return 0;
  86. +}
  87. +
  88. +static int split_rootfs_data(struct mtd_info *master, struct mtd_info *rpart, const struct mtd_partition *part,
  89. + int index)
  90. +{
  91. + struct mtd_partition *dpart;
  92. + struct mtd_part *slave = NULL;
  93. + int split_offset = 0;
  94. + int ret;
  95. +
  96. + ret = split_squashfs(master, part->offset, &split_offset);
  97. + if (ret)
  98. + return ret;
  99. +
  100. + if (split_offset <= 0)
  101. + return 0;
  102. +
  103. + dpart = kmalloc(sizeof(*part)+sizeof(ROOTFS_SPLIT_NAME)+1, GFP_KERNEL);
  104. + if (dpart == NULL) {
  105. + printk(KERN_INFO "split_squashfs: no memory for partition \"%s\"\n",
  106. + ROOTFS_SPLIT_NAME);
  107. + return -ENOMEM;
  108. + }
  109. +
  110. + memcpy(dpart, part, sizeof(*part));
  111. + dpart->name = (unsigned char *)&dpart[1];
  112. + strcpy(dpart->name, ROOTFS_SPLIT_NAME);
  113. +
  114. + dpart->size -= split_offset - dpart->offset;
  115. + dpart->offset = split_offset;
  116. +
  117. + if (dpart == NULL)
  118. + return 1;
  119. +
  120. + printk(KERN_INFO "mtd: partition \"%s\" created automatically, ofs=%llX, len=%llX \n",
  121. + ROOTFS_SPLIT_NAME, dpart->offset, dpart->size);
  122. +
  123. + slave = add_one_partition(master, dpart, index, split_offset);
  124. + if (!slave) {
  125. + kfree(dpart);
  126. + return -ENOMEM;
  127. + }
  128. + rpart->split = &slave->mtd;
  129. +
  130. + return 0;
  131. +}
  132. +
  133. +static int refresh_rootfs_split(struct mtd_info *mtd)
  134. +{
  135. + struct mtd_partition tpart;
  136. + struct mtd_part *part;
  137. + char *name;
  138. + int index = 0;
  139. + int offset, size;
  140. + int ret;
  141. +
  142. + part = PART(mtd);
  143. +
  144. + /* check for the new squashfs offset first */
  145. + ret = split_squashfs(part->master, part->offset, &offset);
  146. + if (ret)
  147. + return ret;
  148. +
  149. + if ((offset > 0) && !mtd->split) {
  150. + printk(KERN_INFO "%s: creating new split partition for \"%s\"\n", __func__, mtd->name);
  151. + /* if we don't have a rootfs split partition, create a new one */
  152. + tpart.name = (char *) mtd->name;
  153. + tpart.size = mtd->size;
  154. + tpart.offset = part->offset;
  155. +
  156. + /* find the index of the last partition */
  157. + if (!list_empty(&mtd_partitions))
  158. + index = list_first_entry(&mtd_partitions, struct mtd_part, list)->index + 1;
  159. +
  160. + return split_rootfs_data(part->master, &part->mtd, &tpart, index);
  161. + } else if ((offset > 0) && mtd->split) {
  162. + /* update the offsets of the existing partition */
  163. + size = mtd->size + part->offset - offset;
  164. +
  165. + part = PART(mtd->split);
  166. + part->offset = offset;
  167. + part->mtd.size = size;
  168. + printk(KERN_INFO "%s: %s partition \"" ROOTFS_SPLIT_NAME "\", offset: 0x%06x (0x%06x)\n",
  169. + __func__, (!strcmp(part->mtd.name, ROOTFS_SPLIT_NAME) ? "updating" : "creating"),
  170. + (u32) part->offset, (u32) part->mtd.size);
  171. + name = kmalloc(sizeof(ROOTFS_SPLIT_NAME) + 1, GFP_KERNEL);
  172. + strcpy(name, ROOTFS_SPLIT_NAME);
  173. + part->mtd.name = name;
  174. + } else if ((offset <= 0) && mtd->split) {
  175. + printk(KERN_INFO "%s: removing partition \"%s\"\n", __func__, mtd->split->name);
  176. +
  177. + /* mark existing partition as removed */
  178. + part = PART(mtd->split);
  179. + name = kmalloc(sizeof(ROOTFS_SPLIT_NAME) + 1, GFP_KERNEL);
  180. + strcpy(name, ROOTFS_REMOVED_NAME);
  181. + part->mtd.name = name;
  182. + part->offset = 0;
  183. + part->mtd.size = 0;
  184. + }
  185. +
  186. + return 0;
  187. +}
  188. +#endif /* CONFIG_MTD_ROOTFS_SPLIT */
  189. +
  190. /*
  191. * This function, given a master MTD object and a partition table, creates
  192. * and registers slave MTD objects which are bound to the master according to
  193. @@ -502,14 +654,29 @@ int add_mtd_partitions(struct mtd_info *
  194. {
  195. struct mtd_part *slave;
  196. uint64_t cur_offset = 0;
  197. - int i;
  198. + int i, j, ret;
  199. printk(KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nbparts, master->name);
  200. - for (i = 0; i < nbparts; i++) {
  201. - slave = add_one_partition(master, parts + i, i, cur_offset);
  202. + for (i = 0, j = 0; i < nbparts; i++) {
  203. + slave = add_one_partition(master, parts + i, j++, cur_offset);
  204. if (!slave)
  205. return -ENOMEM;
  206. +
  207. + if (!strcmp(parts[i].name, "rootfs") && slave->registered) {
  208. +#ifdef CONFIG_MTD_ROOTFS_ROOT_DEV
  209. + if (ROOT_DEV == 0) {
  210. + printk(KERN_NOTICE "mtd: partition \"rootfs\" "
  211. + "set to be root filesystem\n");
  212. + ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, slave->mtd.index);
  213. + }
  214. +#endif
  215. +#ifdef CONFIG_MTD_ROOTFS_SPLIT
  216. + ret = split_rootfs_data(master, &slave->mtd, &parts[i], j);
  217. + if (ret == 0)
  218. + j++;
  219. +#endif
  220. + }
  221. cur_offset = slave->offset + slave->mtd.size;
  222. }
  223. @@ -517,6 +684,32 @@ int add_mtd_partitions(struct mtd_info *
  224. }
  225. EXPORT_SYMBOL(add_mtd_partitions);
  226. +int refresh_mtd_partitions(struct mtd_info *mtd)
  227. +{
  228. + int ret = 0;
  229. +
  230. + if (IS_PART(mtd)) {
  231. + struct mtd_part *part;
  232. + struct mtd_info *master;
  233. +
  234. + part = PART(mtd);
  235. + master = part->master;
  236. + if (master->refresh_device)
  237. + ret = master->refresh_device(master);
  238. + }
  239. +
  240. + if (!ret && mtd->refresh_device)
  241. + ret = mtd->refresh_device(mtd);
  242. +
  243. +#ifdef CONFIG_MTD_ROOTFS_SPLIT
  244. + if (!ret && IS_PART(mtd) && !strcmp(mtd->name, "rootfs"))
  245. + refresh_rootfs_split(mtd);
  246. +#endif
  247. +
  248. + return 0;
  249. +}
  250. +EXPORT_SYMBOL_GPL(refresh_mtd_partitions);
  251. +
  252. static DEFINE_SPINLOCK(part_parser_lock);
  253. static LIST_HEAD(part_parsers);
  254. --- a/drivers/mtd/devices/block2mtd.c
  255. +++ b/drivers/mtd/devices/block2mtd.c
  256. @@ -29,6 +29,8 @@ struct block2mtd_dev {
  257. struct block_device *blkdev;
  258. struct mtd_info mtd;
  259. struct mutex write_mutex;
  260. + rwlock_t bdev_mutex;
  261. + char devname[0];
  262. };
  263. @@ -81,6 +83,12 @@ static int block2mtd_erase(struct mtd_in
  264. size_t len = instr->len;
  265. int err;
  266. + read_lock(&dev->bdev_mutex);
  267. + if (!dev->blkdev) {
  268. + err = -EINVAL;
  269. + goto done;
  270. + }
  271. +
  272. instr->state = MTD_ERASING;
  273. mutex_lock(&dev->write_mutex);
  274. err = _block2mtd_erase(dev, from, len);
  275. @@ -93,6 +101,10 @@ static int block2mtd_erase(struct mtd_in
  276. instr->state = MTD_ERASE_DONE;
  277. mtd_erase_callback(instr);
  278. +
  279. +done:
  280. + read_unlock(&dev->bdev_mutex);
  281. +
  282. return err;
  283. }
  284. @@ -104,10 +116,14 @@ static int block2mtd_read(struct mtd_inf
  285. struct page *page;
  286. int index = from >> PAGE_SHIFT;
  287. int offset = from & (PAGE_SIZE-1);
  288. - int cpylen;
  289. + int cpylen, err = 0;
  290. +
  291. + read_lock(&dev->bdev_mutex);
  292. + if (!dev->blkdev || (from > mtd->size)) {
  293. + err = -EINVAL;
  294. + goto done;
  295. + }
  296. - if (from > mtd->size)
  297. - return -EINVAL;
  298. if (from + len > mtd->size)
  299. len = mtd->size - from;
  300. @@ -122,10 +138,14 @@ static int block2mtd_read(struct mtd_inf
  301. len = len - cpylen;
  302. page = page_read(dev->blkdev->bd_inode->i_mapping, index);
  303. - if (!page)
  304. - return -ENOMEM;
  305. - if (IS_ERR(page))
  306. - return PTR_ERR(page);
  307. + if (!page) {
  308. + err = -ENOMEM;
  309. + goto done;
  310. + }
  311. + if (IS_ERR(page)) {
  312. + err = PTR_ERR(page);
  313. + goto done;
  314. + }
  315. memcpy(buf, page_address(page) + offset, cpylen);
  316. page_cache_release(page);
  317. @@ -136,7 +156,10 @@ static int block2mtd_read(struct mtd_inf
  318. offset = 0;
  319. index++;
  320. }
  321. - return 0;
  322. +
  323. +done:
  324. + read_unlock(&dev->bdev_mutex);
  325. + return err;
  326. }
  327. @@ -188,12 +211,22 @@ static int block2mtd_write(struct mtd_in
  328. size_t *retlen, const u_char *buf)
  329. {
  330. struct block2mtd_dev *dev = mtd->priv;
  331. - int err;
  332. + int err = 0;
  333. +
  334. + read_lock(&dev->bdev_mutex);
  335. + if (!dev->blkdev) {
  336. + err = -EINVAL;
  337. + goto done;
  338. + }
  339. if (!len)
  340. - return 0;
  341. - if (to >= mtd->size)
  342. - return -ENOSPC;
  343. + goto done;
  344. +
  345. + if (to >= mtd->size) {
  346. + err = -ENOSPC;
  347. + goto done;
  348. + }
  349. +
  350. if (to + len > mtd->size)
  351. len = mtd->size - to;
  352. @@ -202,6 +235,9 @@ static int block2mtd_write(struct mtd_in
  353. mutex_unlock(&dev->write_mutex);
  354. if (err > 0)
  355. err = 0;
  356. +
  357. +done:
  358. + read_unlock(&dev->bdev_mutex);
  359. return err;
  360. }
  361. @@ -210,52 +246,29 @@ static int block2mtd_write(struct mtd_in
  362. static void block2mtd_sync(struct mtd_info *mtd)
  363. {
  364. struct block2mtd_dev *dev = mtd->priv;
  365. - sync_blockdev(dev->blkdev);
  366. - return;
  367. -}
  368. -
  369. -
  370. -static void block2mtd_free_device(struct block2mtd_dev *dev)
  371. -{
  372. - if (!dev)
  373. - return;
  374. -
  375. - kfree(dev->mtd.name);
  376. - if (dev->blkdev) {
  377. - invalidate_mapping_pages(dev->blkdev->bd_inode->i_mapping,
  378. - 0, -1);
  379. - close_bdev_exclusive(dev->blkdev, FMODE_READ|FMODE_WRITE);
  380. - }
  381. + read_lock(&dev->bdev_mutex);
  382. + if (dev->blkdev)
  383. + sync_blockdev(dev->blkdev);
  384. + read_unlock(&dev->bdev_mutex);
  385. - kfree(dev);
  386. + return;
  387. }
  388. -/* FIXME: ensure that mtd->size % erase_size == 0 */
  389. -static struct block2mtd_dev *add_device(char *devname, int erase_size, const char *mtdname)
  390. +static int _open_bdev(struct block2mtd_dev *dev)
  391. {
  392. struct block_device *bdev;
  393. - struct block2mtd_dev *dev;
  394. - struct mtd_partition *part;
  395. - char *name;
  396. -
  397. - if (!devname)
  398. - return NULL;
  399. -
  400. - dev = kzalloc(sizeof(struct block2mtd_dev), GFP_KERNEL);
  401. - if (!dev)
  402. - return NULL;
  403. /* Get a handle on the device */
  404. - bdev = open_bdev_exclusive(devname, FMODE_READ|FMODE_WRITE, NULL);
  405. + bdev = open_bdev_exclusive(dev->devname, FMODE_READ|FMODE_WRITE, NULL);
  406. #ifndef MODULE
  407. if (IS_ERR(bdev)) {
  408. /* We might not have rootfs mounted at this point. Try
  409. to resolve the device name by other means. */
  410. - dev_t devt = name_to_dev_t(devname);
  411. + dev_t devt = name_to_dev_t(dev->devname);
  412. if (devt) {
  413. bdev = open_by_devnum(devt, FMODE_WRITE | FMODE_READ);
  414. }
  415. @@ -263,17 +276,97 @@ static struct block2mtd_dev *add_device(
  416. #endif
  417. if (IS_ERR(bdev)) {
  418. - ERROR("error: cannot open device %s", devname);
  419. - goto devinit_err;
  420. + ERROR("error: cannot open device %s", dev->devname);
  421. + return 1;
  422. }
  423. dev->blkdev = bdev;
  424. if (MAJOR(bdev->bd_dev) == MTD_BLOCK_MAJOR) {
  425. ERROR("attempting to use an MTD device as a block device");
  426. - goto devinit_err;
  427. + return 1;
  428. }
  429. + return 0;
  430. +}
  431. +
  432. +static void _close_bdev(struct block2mtd_dev *dev)
  433. +{
  434. + struct block_device *bdev;
  435. +
  436. + if (!dev->blkdev)
  437. + return;
  438. +
  439. + bdev = dev->blkdev;
  440. + invalidate_mapping_pages(dev->blkdev->bd_inode->i_mapping, 0, -1);
  441. + close_bdev_exclusive(dev->blkdev, FMODE_READ|FMODE_WRITE);
  442. + dev->blkdev = NULL;
  443. +}
  444. +
  445. +static void block2mtd_free_device(struct block2mtd_dev *dev)
  446. +{
  447. + if (!dev)
  448. + return;
  449. +
  450. + kfree(dev->mtd.name);
  451. + _close_bdev(dev);
  452. + kfree(dev);
  453. +}
  454. +
  455. +
  456. +static int block2mtd_refresh(struct mtd_info *mtd)
  457. +{
  458. + struct block2mtd_dev *dev = mtd->priv;
  459. + struct block_device *bdev;
  460. + dev_t devt;
  461. + int err = 0;
  462. +
  463. + /* no other mtd function can run at this point */
  464. + write_lock(&dev->bdev_mutex);
  465. +
  466. + /* get the device number for the whole disk */
  467. + devt = MKDEV(MAJOR(dev->blkdev->bd_dev), 0);
  468. +
  469. + /* close the old block device */
  470. + _close_bdev(dev);
  471. +
  472. + /* open the whole disk, issue a partition rescan, then */
  473. + bdev = open_by_devnum(devt, FMODE_WRITE | FMODE_READ);
  474. + if (!bdev || !bdev->bd_disk)
  475. + err = -EINVAL;
  476. + else {
  477. + err = rescan_partitions(bdev->bd_disk, bdev);
  478. + }
  479. + if (bdev)
  480. + close_bdev_exclusive(bdev, FMODE_READ|FMODE_WRITE);
  481. +
  482. + /* try to open the partition block device again */
  483. + _open_bdev(dev);
  484. + write_unlock(&dev->bdev_mutex);
  485. +
  486. + return err;
  487. +}
  488. +
  489. +/* FIXME: ensure that mtd->size % erase_size == 0 */
  490. +static struct block2mtd_dev *add_device(char *devname, int erase_size, char *mtdname)
  491. +{
  492. + struct block2mtd_dev *dev;
  493. + struct mtd_partition *part;
  494. + char *name;
  495. +
  496. + if (!devname)
  497. + return NULL;
  498. +
  499. + dev = kzalloc(sizeof(struct block2mtd_dev) + strlen(devname) + 1, GFP_KERNEL);
  500. + if (!dev)
  501. + return NULL;
  502. +
  503. + strcpy(dev->devname, devname);
  504. +
  505. + if (_open_bdev(dev))
  506. + goto devinit_err;
  507. +
  508. mutex_init(&dev->write_mutex);
  509. + rwlock_init(&dev->bdev_mutex);
  510. if (!mtdname)
  511. mtdname = devname;
  512. @@ -297,6 +390,7 @@ static struct block2mtd_dev *add_device(
  513. dev->mtd.read = block2mtd_read;
  514. dev->mtd.priv = dev;
  515. dev->mtd.owner = THIS_MODULE;
  516. + dev->mtd.refresh_device = block2mtd_refresh;
  517. part = kzalloc(sizeof(struct mtd_partition), GFP_KERNEL);
  518. part->name = dev->mtd.name;
  519. --- a/drivers/mtd/mtdchar.c
  520. +++ b/drivers/mtd/mtdchar.c
  521. @@ -16,6 +16,7 @@
  522. #include <linux/mtd/mtd.h>
  523. #include <linux/mtd/compatmac.h>
  524. +#include <linux/mtd/partitions.h>
  525. #include <asm/uaccess.h>
  526. @@ -773,6 +774,13 @@ static int mtd_ioctl(struct inode *inode
  527. file->f_pos = 0;
  528. break;
  529. }
  530. +#ifdef CONFIG_MTD_PARTITIONS
  531. + case MTDREFRESH:
  532. + {
  533. + ret = refresh_mtd_partitions(mtd);
  534. + break;
  535. + }
  536. +#endif
  537. default:
  538. ret = -ENOTTY;
  539. --- a/include/linux/mtd/mtd.h
  540. +++ b/include/linux/mtd/mtd.h
  541. @@ -100,6 +100,7 @@ struct mtd_oob_ops {
  542. uint8_t *oobbuf;
  543. };
  544. +struct mtd_info;
  545. struct mtd_info {
  546. u_char type;
  547. uint32_t flags;
  548. @@ -225,6 +226,9 @@ struct mtd_info {
  549. struct module *owner;
  550. int usecount;
  551. + int (*refresh_device)(struct mtd_info *mtd);
  552. + struct mtd_info *split;
  553. +
  554. /* If the driver is something smart, like UBI, it may need to maintain
  555. * its own reference counting. The below functions are only for driver.
  556. * The driver may register its callbacks. These callbacks are not
  557. --- a/include/linux/mtd/partitions.h
  558. +++ b/include/linux/mtd/partitions.h
  559. @@ -34,6 +34,7 @@
  560. * erasesize aligned (e.g. use MTDPART_OFS_NEXTBLK).
  561. */
  562. +struct mtd_partition;
  563. struct mtd_partition {
  564. char *name; /* identifier string */
  565. uint64_t size; /* partition size */
  566. @@ -41,6 +42,7 @@ struct mtd_partition {
  567. uint32_t mask_flags; /* master MTD flags to mask out for this partition */
  568. struct nand_ecclayout *ecclayout; /* out of band layout for this partition (NAND only)*/
  569. struct mtd_info **mtdp; /* pointer to store the MTD object */
  570. + int (*refresh_partition)(struct mtd_info *);
  571. };
  572. #define MTDPART_OFS_NXTBLK (-2)
  573. @@ -50,6 +52,7 @@ struct mtd_partition {
  574. int add_mtd_partitions(struct mtd_info *, const struct mtd_partition *, int);
  575. int del_mtd_partitions(struct mtd_info *);
  576. +int refresh_mtd_partitions(struct mtd_info *);
  577. /*
  578. * Functions dealing with the various ways of partitioning the space
  579. --- a/include/mtd/mtd-abi.h
  580. +++ b/include/mtd/mtd-abi.h
  581. @@ -93,6 +93,7 @@ struct otp_info {
  582. #define ECCGETLAYOUT _IOR('M', 17, struct nand_ecclayout)
  583. #define ECCGETSTATS _IOR('M', 18, struct mtd_ecc_stats)
  584. #define MTDFILEMODE _IO('M', 19)
  585. +#define MTDREFRESH _IO('M', 23)
  586. /*
  587. * Obsolete legacy interface. Keep it in order not to break userspace