| From 073db4a51ee43ccb827f54a4261c0583b028d5ab Mon Sep 17 00:00:00 2001 |
| From: Brian Norris <computersforpeace@gmail.com> |
| Date: Thu, 7 May 2015 17:55:16 -0700 |
| Subject: mtd: fix: avoid race condition when accessing mtd->usecount |
| |
| From: Brian Norris <computersforpeace@gmail.com> |
| |
| 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 <zhangxingcai@huawei.com> |
| Reported-by: Giuseppe Cantavenera <giuseppe.cantavenera.ext@nokia.com> |
| Tested-by: Giuseppe Cantavenera <giuseppe.cantavenera.ext@nokia.com> |
| Acked-by: Alexander Sverdlin <alexander.sverdlin@nokia.com> |
| Signed-off-by: Brian Norris <computersforpeace@gmail.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/mtd/mtd_blkdevs.c | 5 +++++ |
| 1 file changed, 5 insertions(+) |
| |
| --- a/drivers/mtd/mtd_blkdevs.c |
| +++ b/drivers/mtd/mtd_blkdevs.c |
| @@ -200,6 +200,7 @@ static int blktrans_open(struct block_de |
| return -ERESTARTSYS; /* FIXME: busy loop! -arnd*/ |
| |
| mutex_lock(&dev->lock); |
| + mutex_lock(&mtd_table_mutex); |
| |
| if (dev->open) |
| goto unlock; |
| @@ -223,6 +224,7 @@ static int blktrans_open(struct block_de |
| |
| unlock: |
| dev->open++; |
| + mutex_unlock(&mtd_table_mutex); |
| mutex_unlock(&dev->lock); |
| blktrans_dev_put(dev); |
| return ret; |
| @@ -233,6 +235,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; |
| @@ -246,6 +249,7 @@ static void blktrans_release(struct gend |
| return; |
| |
| mutex_lock(&dev->lock); |
| + mutex_lock(&mtd_table_mutex); |
| |
| if (--dev->open) |
| goto unlock; |
| @@ -259,6 +263,7 @@ static void blktrans_release(struct gend |
| __put_mtd_device(dev->mtd); |
| } |
| unlock: |
| + mutex_unlock(&mtd_table_mutex); |
| mutex_unlock(&dev->lock); |
| blktrans_dev_put(dev); |
| } |