diff options
author | Brian Norris <computersforpeace@gmail.com> | 2015-05-07 20:55:16 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2015-07-21 13:10:05 -0400 |
commit | 857814ee65dbc942b18b2dc713124ffff043035e (patch) | |
tree | 0ac915773ff27328da1ff2c649b950346523fb78 /drivers/mtd | |
parent | 2c6f129c8fcf59946e62216792e162b9d9f0dc8e (diff) |
mtd: fix: avoid race condition when accessing mtd->usecount
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>
Diffstat (limited to 'drivers/mtd')
-rw-r--r-- | drivers/mtd/mtd_blkdevs.c | 5 |
1 files changed, 5 insertions, 0 deletions
diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index 2b0c52870999..df7c6c70757a 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c | |||
@@ -197,6 +197,7 @@ static int blktrans_open(struct block_device *bdev, fmode_t mode) | |||
197 | return -ERESTARTSYS; /* FIXME: busy loop! -arnd*/ | 197 | return -ERESTARTSYS; /* FIXME: busy loop! -arnd*/ |
198 | 198 | ||
199 | mutex_lock(&dev->lock); | 199 | mutex_lock(&dev->lock); |
200 | mutex_lock(&mtd_table_mutex); | ||
200 | 201 | ||
201 | if (dev->open) | 202 | if (dev->open) |
202 | goto unlock; | 203 | goto unlock; |
@@ -220,6 +221,7 @@ static int blktrans_open(struct block_device *bdev, fmode_t mode) | |||
220 | 221 | ||
221 | unlock: | 222 | unlock: |
222 | dev->open++; | 223 | dev->open++; |
224 | mutex_unlock(&mtd_table_mutex); | ||
223 | mutex_unlock(&dev->lock); | 225 | mutex_unlock(&dev->lock); |
224 | blktrans_dev_put(dev); | 226 | blktrans_dev_put(dev); |
225 | return ret; | 227 | return ret; |
@@ -230,6 +232,7 @@ error_release: | |||
230 | error_put: | 232 | error_put: |
231 | module_put(dev->tr->owner); | 233 | module_put(dev->tr->owner); |
232 | kref_put(&dev->ref, blktrans_dev_release); | 234 | kref_put(&dev->ref, blktrans_dev_release); |
235 | mutex_unlock(&mtd_table_mutex); | ||
233 | mutex_unlock(&dev->lock); | 236 | mutex_unlock(&dev->lock); |
234 | blktrans_dev_put(dev); | 237 | blktrans_dev_put(dev); |
235 | return ret; | 238 | return ret; |
@@ -243,6 +246,7 @@ static void blktrans_release(struct gendisk *disk, fmode_t mode) | |||
243 | return; | 246 | return; |
244 | 247 | ||
245 | mutex_lock(&dev->lock); | 248 | mutex_lock(&dev->lock); |
249 | mutex_lock(&mtd_table_mutex); | ||
246 | 250 | ||
247 | if (--dev->open) | 251 | if (--dev->open) |
248 | goto unlock; | 252 | goto unlock; |
@@ -256,6 +260,7 @@ static void blktrans_release(struct gendisk *disk, fmode_t mode) | |||
256 | __put_mtd_device(dev->mtd); | 260 | __put_mtd_device(dev->mtd); |
257 | } | 261 | } |
258 | unlock: | 262 | unlock: |
263 | mutex_unlock(&mtd_table_mutex); | ||
259 | mutex_unlock(&dev->lock); | 264 | mutex_unlock(&dev->lock); |
260 | blktrans_dev_put(dev); | 265 | blktrans_dev_put(dev); |
261 | } | 266 | } |