From: Brian Norris <computersforpe...@gmail.com>

3.4.110-rc1 review patch.  If anyone has any objections, please let me know.

------------------


commit 073db4a51ee43ccb827f54a4261c0583b028d5ab upstream.

On A MIPS 32-cores machine a BUG_ON was triggered because some acesses to
mtd->usecount were done without taking mtd_table_mutex.
kernel: Call Trace:
kernel: [<ffffffff80401818>] __put_mtd_device+0x20/0x50
kernel: [<ffffffff804086f4>] blktrans_release+0x8c/0xd8
kernel: [<ffffffff802577e0>] __blkdev_put+0x1a8/0x200
kernel: [<ffffffff802579a4>] blkdev_close+0x1c/0x30
kernel: [<ffffffff8022006c>] __fput+0xac/0x250
kernel: [<ffffffff80171208>] task_work_run+0xd8/0x120
kernel: [<ffffffff8012c23c>] work_notifysig+0x10/0x18
kernel:
kernel:
        Code: 2442ffff  ac8202d8  000217fe <00020336> dc820128  10400003
               00000000  0040f809  00000000
kernel: ---[ end trace 080fbb4579b47a73 ]---

Fixed by taking the mutex in blktrans_open and blktrans_release.

Note that this locking is already suggested in
include/linux/mtd/blktrans.h:

struct mtd_blktrans_ops {
...
        /* Called with mtd_table_mutex held; no race with add/remove */
        int (*open)(struct mtd_blktrans_dev *dev);
        void (*release)(struct mtd_blktrans_dev *dev);
...
};

But we weren't following it.

Originally reported by (and patched by) Zhang and Giuseppe,
independently. Improved and rewritten.

Reported-by: Zhang Xingcai <zhangxing...@huawei.com>
Reported-by: Giuseppe Cantavenera <giuseppe.cantavenera....@nokia.com>
Tested-by: Giuseppe Cantavenera <giuseppe.cantavenera....@nokia.com>
Acked-by: Alexander Sverdlin <alexander.sverd...@nokia.com>
Signed-off-by: Brian Norris <computersforpe...@gmail.com>
Signed-off-by: Zefan Li <lize...@huawei.com>
---
 drivers/mtd/mtd_blkdevs.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c
index f1f0671..1917f7d 100644
--- a/drivers/mtd/mtd_blkdevs.c
+++ b/drivers/mtd/mtd_blkdevs.c
@@ -214,6 +214,7 @@ static int blktrans_open(struct block_device *bdev, fmode_t 
mode)
                return -ERESTARTSYS; /* FIXME: busy loop! -arnd*/
 
        mutex_lock(&dev->lock);
+       mutex_lock(&mtd_table_mutex);
 
        if (dev->open)
                goto unlock;
@@ -237,6 +238,7 @@ static int blktrans_open(struct block_device *bdev, fmode_t 
mode)
 
 unlock:
        dev->open++;
+       mutex_unlock(&mtd_table_mutex);
        mutex_unlock(&dev->lock);
        blktrans_dev_put(dev);
        return ret;
@@ -247,6 +249,7 @@ error_release:
 error_put:
        module_put(dev->tr->owner);
        kref_put(&dev->ref, blktrans_dev_release);
+       mutex_unlock(&mtd_table_mutex);
        mutex_unlock(&dev->lock);
        blktrans_dev_put(dev);
        return ret;
@@ -261,6 +264,7 @@ static int blktrans_release(struct gendisk *disk, fmode_t 
mode)
                return ret;
 
        mutex_lock(&dev->lock);
+       mutex_lock(&mtd_table_mutex);
 
        if (--dev->open)
                goto unlock;
@@ -273,6 +277,7 @@ static int blktrans_release(struct gendisk *disk, fmode_t 
mode)
                __put_mtd_device(dev->mtd);
        }
 unlock:
+       mutex_unlock(&mtd_table_mutex);
        mutex_unlock(&dev->lock);
        blktrans_dev_put(dev);
        return ret;
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to