Re: move the bdi from the request_queue to the gendisk
flat view
From: Jan Kara <jack@suse.cz>
Date: 2021-08-11 11:25:22
Also in:
cgroups, linux-block, linux-fsdevel
On Tue 10-08-21 22:02:56, Christoph Hellwig wrote:
On Tue, Aug 10, 2021 at 03:36:39PM -0400, Qian Cai wrote:quoted
On 8/9/2021 10:17 AM, Christoph Hellwig wrote:quoted
Hi Jens, this series moves the pointer to the bdi from the request_queue to the bdi, better matching the life time rules of the different objects.Reverting this series fixed an use-after-free in bdev_evict_inode().Please try the patch below as a band-aid. Although the proper fix is that non-default bdi_writeback structures grab a reference to the bdi, as this was a landmine that might have already caused spurious issues before.
Well, non-default bdi_writeback structures do hold bdi reference - see wb_exit() which drops the reference. I think the problem rather was that a block device's inode->i_wb was pointing to the default bdi_writeback structure and that got freed after bdi_put() before block device inode was shutdown through bdput()... So what I think we need is that if the inode references the default writeback structure, it actually holds a reference to the bdi. Honza
quoted hunk ↗ jump to hunk
diff --git a/block/genhd.c b/block/genhd.c index f8def1129501..2e4a9d187196 100644 --- a/block/genhd.c +++ b/block/genhd.c@@ -1086,7 +1086,6 @@ static void disk_release(struct device *dev) might_sleep(); - bdi_put(disk->bdi); if (MAJOR(dev->devt) == BLOCK_EXT_MAJOR) blk_free_ext_minor(MINOR(dev->devt)); disk_release_events(disk);diff --git a/fs/block_dev.c b/fs/block_dev.c index 7c969f81327a..c6087dbae6cf 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c@@ -849,11 +849,15 @@ static void init_once(void *data) static void bdev_evict_inode(struct inode *inode) { + struct block_device *bdev = I_BDEV(inode); + truncate_inode_pages_final(&inode->i_data); invalidate_inode_buffers(inode); /* is it needed here? */ clear_inode(inode); /* Detach inode from wb early as bdi_put() may free bdi->wb */ inode_detach_wb(inode); + if (!bdev_is_partition(bdev)) + bdi_put(bdev->bd_disk->bdi); } static const struct super_operations bdev_sops = {
-- Jan Kara [off-list ref] SUSE Labs, CR