mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	mtd: fix: avoid race condition when accessing mtd->usecount
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.
Cc: stable@vger.kernel.org
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>
			
			
This commit is contained in:
		
							parent
							
								
									5844feeaa4
								
							
						
					
					
						commit
						073db4a51e
					
				
					 1 changed files with 5 additions and 0 deletions
				
			
		| 
						 | 
				
			
			@ -197,6 +197,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;
 | 
			
		||||
| 
						 | 
				
			
			@ -220,6 +221,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;
 | 
			
		||||
| 
						 | 
				
			
			@ -230,6 +232,7 @@ static int blktrans_open(struct block_device *bdev, fmode_t mode)
 | 
			
		|||
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;
 | 
			
		||||
| 
						 | 
				
			
			@ -243,6 +246,7 @@ static void blktrans_release(struct gendisk *disk, fmode_t mode)
 | 
			
		|||
		return;
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&dev->lock);
 | 
			
		||||
	mutex_lock(&mtd_table_mutex);
 | 
			
		||||
 | 
			
		||||
	if (--dev->open)
 | 
			
		||||
		goto unlock;
 | 
			
		||||
| 
						 | 
				
			
			@ -256,6 +260,7 @@ static void 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);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue