block: Make blk_get_backing_dev_info() safe without open bdev
Currenly blk_get_backing_dev_info() is not safe to be called when the block device is not open as bdev->bd_disk is NULL in that case. However inode_to_bdi() uses this function and may be call called from flusher worker or other writeback related functions without bdev being open which leads to crashes such as: [113031.075540] Unable to handle kernel paging request for data at address 0x00000000 [113031.075614] Faulting instruction address: 0xc0000000003692e0 0:mon> t [c0000000fb65f900] c00000000036cb6c writeback_sb_inodes+0x30c/0x590 [c0000000fb65fa10] c00000000036ced4 __writeback_inodes_wb+0xe4/0x150 [c0000000fb65fa70] c00000000036d33c wb_writeback+0x30c/0x450 [c0000000fb65fb40] c00000000036e198 wb_workfn+0x268/0x580 [c0000000fb65fc50] c0000000000f3470 process_one_work+0x1e0/0x590 [c0000000fb65fce0] c0000000000f38c8 worker_thread+0xa8/0x660 [c0000000fb65fd80] c0000000000fc4b0 kthread+0x110/0x130 [c0000000fb65fe30] c0000000000098f0 ret_from_kernel_thread+0x5c/0x6c Signed-off-by: Jens Axboe <axboe@fb.com>
This commit is contained in:
parent
d03f6cdc1f
commit
b1d2dc5659
|
@ -110,14 +110,12 @@ void blk_queue_congestion_threshold(struct request_queue *q)
|
||||||
* @bdev: device
|
* @bdev: device
|
||||||
*
|
*
|
||||||
* Locates the passed device's request queue and returns the address of its
|
* Locates the passed device's request queue and returns the address of its
|
||||||
* backing_dev_info. This function can only be called if @bdev is opened
|
* backing_dev_info. The return value is never NULL however we may return
|
||||||
* and the return value is never NULL.
|
* &noop_backing_dev_info if the bdev is not currently open.
|
||||||
*/
|
*/
|
||||||
struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev)
|
struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev)
|
||||||
{
|
{
|
||||||
struct request_queue *q = bdev_get_queue(bdev);
|
return bdev->bd_bdi;
|
||||||
|
|
||||||
return q->backing_dev_info;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(blk_get_backing_dev_info);
|
EXPORT_SYMBOL(blk_get_backing_dev_info);
|
||||||
|
|
||||||
|
|
|
@ -884,6 +884,8 @@ static void bdev_evict_inode(struct inode *inode)
|
||||||
spin_lock(&bdev_lock);
|
spin_lock(&bdev_lock);
|
||||||
list_del_init(&bdev->bd_list);
|
list_del_init(&bdev->bd_list);
|
||||||
spin_unlock(&bdev_lock);
|
spin_unlock(&bdev_lock);
|
||||||
|
if (bdev->bd_bdi != &noop_backing_dev_info)
|
||||||
|
bdi_put(bdev->bd_bdi);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct super_operations bdev_sops = {
|
static const struct super_operations bdev_sops = {
|
||||||
|
@ -986,6 +988,7 @@ struct block_device *bdget(dev_t dev)
|
||||||
bdev->bd_contains = NULL;
|
bdev->bd_contains = NULL;
|
||||||
bdev->bd_super = NULL;
|
bdev->bd_super = NULL;
|
||||||
bdev->bd_inode = inode;
|
bdev->bd_inode = inode;
|
||||||
|
bdev->bd_bdi = &noop_backing_dev_info;
|
||||||
bdev->bd_block_size = (1 << inode->i_blkbits);
|
bdev->bd_block_size = (1 << inode->i_blkbits);
|
||||||
bdev->bd_part_count = 0;
|
bdev->bd_part_count = 0;
|
||||||
bdev->bd_invalidated = 0;
|
bdev->bd_invalidated = 0;
|
||||||
|
@ -1542,6 +1545,8 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
|
||||||
bdev->bd_disk = disk;
|
bdev->bd_disk = disk;
|
||||||
bdev->bd_queue = disk->queue;
|
bdev->bd_queue = disk->queue;
|
||||||
bdev->bd_contains = bdev;
|
bdev->bd_contains = bdev;
|
||||||
|
if (bdev->bd_bdi == &noop_backing_dev_info)
|
||||||
|
bdev->bd_bdi = bdi_get(disk->queue->backing_dev_info);
|
||||||
|
|
||||||
if (!partno) {
|
if (!partno) {
|
||||||
ret = -ENXIO;
|
ret = -ENXIO;
|
||||||
|
@ -1637,6 +1642,8 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
|
||||||
bdev->bd_disk = NULL;
|
bdev->bd_disk = NULL;
|
||||||
bdev->bd_part = NULL;
|
bdev->bd_part = NULL;
|
||||||
bdev->bd_queue = NULL;
|
bdev->bd_queue = NULL;
|
||||||
|
bdi_put(bdev->bd_bdi);
|
||||||
|
bdev->bd_bdi = &noop_backing_dev_info;
|
||||||
if (bdev != bdev->bd_contains)
|
if (bdev != bdev->bd_contains)
|
||||||
__blkdev_put(bdev->bd_contains, mode, 1);
|
__blkdev_put(bdev->bd_contains, mode, 1);
|
||||||
bdev->bd_contains = NULL;
|
bdev->bd_contains = NULL;
|
||||||
|
|
|
@ -423,6 +423,7 @@ struct block_device {
|
||||||
int bd_invalidated;
|
int bd_invalidated;
|
||||||
struct gendisk * bd_disk;
|
struct gendisk * bd_disk;
|
||||||
struct request_queue * bd_queue;
|
struct request_queue * bd_queue;
|
||||||
|
struct backing_dev_info *bd_bdi;
|
||||||
struct list_head bd_list;
|
struct list_head bd_list;
|
||||||
/*
|
/*
|
||||||
* Private data. You must have bd_claim'ed the block_device
|
* Private data. You must have bd_claim'ed the block_device
|
||||||
|
|
Loading…
Reference in New Issue