diff options
Diffstat (limited to 'target/linux/generic/patches-3.7/441-block2mtd_refresh.patch')
-rw-r--r-- | target/linux/generic/patches-3.7/441-block2mtd_refresh.patch | 268 |
1 files changed, 268 insertions, 0 deletions
diff --git a/target/linux/generic/patches-3.7/441-block2mtd_refresh.patch b/target/linux/generic/patches-3.7/441-block2mtd_refresh.patch new file mode 100644 index 000000000..d54e52900 --- /dev/null +++ b/target/linux/generic/patches-3.7/441-block2mtd_refresh.patch @@ -0,0 +1,268 @@ +--- a/drivers/mtd/devices/block2mtd.c ++++ b/drivers/mtd/devices/block2mtd.c +@@ -29,6 +29,8 @@ struct block2mtd_dev { + struct block_device *blkdev; + struct mtd_info mtd; + struct mutex write_mutex; ++ rwlock_t bdev_mutex; ++ char devname[0]; + }; + + +@@ -79,6 +81,12 @@ static int block2mtd_erase(struct mtd_in + size_t len = instr->len; + int err; + ++ read_lock(&dev->bdev_mutex); ++ if (!dev->blkdev) { ++ err = -EINVAL; ++ goto done; ++ } ++ + instr->state = MTD_ERASING; + mutex_lock(&dev->write_mutex); + err = _block2mtd_erase(dev, from, len); +@@ -90,6 +98,10 @@ static int block2mtd_erase(struct mtd_in + instr->state = MTD_ERASE_DONE; + + mtd_erase_callback(instr); ++ ++done: ++ read_unlock(&dev->bdev_mutex); ++ + return err; + } + +@@ -101,7 +113,13 @@ static int block2mtd_read(struct mtd_inf + struct page *page; + int index = from >> PAGE_SHIFT; + int offset = from & (PAGE_SIZE-1); +- int cpylen; ++ int cpylen, err = 0; ++ ++ read_lock(&dev->bdev_mutex); ++ if (!dev->blkdev || (from > mtd->size)) { ++ err = -EINVAL; ++ goto done; ++ } + + while (len) { + if ((offset + len) > PAGE_SIZE) +@@ -111,8 +129,10 @@ static int block2mtd_read(struct mtd_inf + len = len - cpylen; + + page = page_read(dev->blkdev->bd_inode->i_mapping, index); +- if (IS_ERR(page)) ++ if (IS_ERR(page)) { + return PTR_ERR(page); ++ goto done; ++ } + + memcpy(buf, page_address(page) + offset, cpylen); + page_cache_release(page); +@@ -123,7 +143,10 @@ static int block2mtd_read(struct mtd_inf + offset = 0; + index++; + } +- return 0; ++ ++done: ++ read_unlock(&dev->bdev_mutex); ++ return err; + } + + +@@ -171,13 +194,22 @@ static int block2mtd_write(struct mtd_in + size_t *retlen, const u_char *buf) + { + struct block2mtd_dev *dev = mtd->priv; +- int err; ++ int err = 0; ++ ++ read_lock(&dev->bdev_mutex); ++ if (!dev->blkdev) { ++ err = -EINVAL; ++ goto done; ++ } + + mutex_lock(&dev->write_mutex); + err = _block2mtd_write(dev, buf, to, len, retlen); + mutex_unlock(&dev->write_mutex); + if (err > 0) + err = 0; ++ ++done: ++ read_unlock(&dev->bdev_mutex); + return err; + } + +@@ -186,33 +218,110 @@ static int block2mtd_write(struct mtd_in + static void block2mtd_sync(struct mtd_info *mtd) + { + struct block2mtd_dev *dev = mtd->priv; ++ read_lock(&dev->bdev_mutex); ++ if (dev->blkdev) + sync_blockdev(dev->blkdev); ++ read_unlock(&dev->bdev_mutex); ++ + return; + } + + ++static int _open_bdev(struct block2mtd_dev *dev) ++{ ++ const fmode_t mode = FMODE_READ | FMODE_WRITE | FMODE_EXCL; ++ struct block_device *bdev; ++ ++ /* Get a handle on the device */ ++ bdev = blkdev_get_by_path(dev->devname, mode, dev); ++#ifndef MODULE ++ if (IS_ERR(bdev)) { ++ dev_t devt; ++ ++ /* We might not have rootfs mounted at this point. Try ++ to resolve the device name by other means. */ ++ ++ devt = name_to_dev_t(dev->devname); ++ if (devt) ++ bdev = blkdev_get_by_dev(devt, mode, dev); ++ } ++#endif ++ ++ if (IS_ERR(bdev)) { ++ ERROR("error: cannot open device %s", dev->devname); ++ return 1; ++ } ++ dev->blkdev = bdev; ++ ++ if (MAJOR(bdev->bd_dev) == MTD_BLOCK_MAJOR) { ++ ERROR("attempting to use an MTD device as a block device"); ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static void _close_bdev(struct block2mtd_dev *dev) ++{ ++ struct block_device *bdev; ++ ++ if (!dev->blkdev) ++ return; ++ ++ bdev = dev->blkdev; ++ invalidate_mapping_pages(dev->blkdev->bd_inode->i_mapping, 0, -1); ++ blkdev_put(dev->blkdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL); ++ dev->blkdev = NULL; ++} ++ + static void block2mtd_free_device(struct block2mtd_dev *dev) + { + if (!dev) + return; + + kfree(dev->mtd.name); +- +- if (dev->blkdev) { +- invalidate_mapping_pages(dev->blkdev->bd_inode->i_mapping, +- 0, -1); +- blkdev_put(dev->blkdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL); +- } +- ++ _close_bdev(dev); + kfree(dev); + } + + +-/* FIXME: ensure that mtd->size % erase_size == 0 */ +-static struct block2mtd_dev *add_device(char *devname, int erase_size, const char *mtdname) ++static int block2mtd_refresh(struct mtd_info *mtd) + { +- const fmode_t mode = FMODE_READ | FMODE_WRITE | FMODE_EXCL; ++ struct block2mtd_dev *dev = mtd->priv; + struct block_device *bdev; ++ dev_t devt; ++ int err = 0; ++ ++ /* no other mtd function can run at this point */ ++ write_lock(&dev->bdev_mutex); ++ ++ /* get the device number for the whole disk */ ++ devt = MKDEV(MAJOR(dev->blkdev->bd_dev), 0); ++ ++ /* close the old block device */ ++ _close_bdev(dev); ++ ++ /* open the whole disk, issue a partition rescan, then */ ++ bdev = blkdev_get_by_dev(devt, FMODE_WRITE | FMODE_READ, mtd); ++ if (!bdev || !bdev->bd_disk) ++ err = -EINVAL; ++#ifndef CONFIG_MTD_BLOCK2MTD_MODULE ++ else ++ err = rescan_partitions(bdev->bd_disk, bdev); ++#endif ++ if (bdev) ++ blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL); ++ ++ /* try to open the partition block device again */ ++ _open_bdev(dev); ++ write_unlock(&dev->bdev_mutex); ++ ++ return err; ++} ++ ++/* FIXME: ensure that mtd->size % erase_size == 0 */ ++static struct block2mtd_dev *add_device(char *devname, int erase_size, char *mtdname) ++{ + struct block2mtd_dev *dev; + struct mtd_partition *part; + char *name; +@@ -220,36 +329,17 @@ static struct block2mtd_dev *add_device( + if (!devname) + return NULL; + +- dev = kzalloc(sizeof(struct block2mtd_dev), GFP_KERNEL); ++ dev = kzalloc(sizeof(struct block2mtd_dev) + strlen(devname) + 1, GFP_KERNEL); + if (!dev) + return NULL; + +- /* Get a handle on the device */ +- bdev = blkdev_get_by_path(devname, mode, dev); +-#ifndef MODULE +- if (IS_ERR(bdev)) { ++ strcpy(dev->devname, devname); + +- /* We might not have rootfs mounted at this point. Try +- to resolve the device name by other means. */ +- +- dev_t devt = name_to_dev_t(devname); +- if (devt) +- bdev = blkdev_get_by_dev(devt, mode, dev); +- } +-#endif +- +- if (IS_ERR(bdev)) { +- ERROR("error: cannot open device %s", devname); +- goto devinit_err; +- } +- dev->blkdev = bdev; +- +- if (MAJOR(bdev->bd_dev) == MTD_BLOCK_MAJOR) { +- ERROR("attempting to use an MTD device as a block device"); ++ if (_open_bdev(dev)) + goto devinit_err; +- } + + mutex_init(&dev->write_mutex); ++ rwlock_init(&dev->bdev_mutex); + + /* Setup the MTD structure */ + /* make the name contain the block device in */ +@@ -274,6 +364,7 @@ static struct block2mtd_dev *add_device( + dev->mtd._read = block2mtd_read; + dev->mtd.priv = dev; + dev->mtd.owner = THIS_MODULE; ++ dev->mtd.refresh_device = block2mtd_refresh; + + part = kzalloc(sizeof(struct mtd_partition), GFP_KERNEL); + part->name = name; |