Re: move the bdi from the request_queue to the gendisk

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue 10-08-21 22:02:56, Christoph Hellwig wrote:
> On Tue, Aug 10, 2021 at 03:36:39PM -0400, Qian Cai wrote:
> > 
> > 
> > On 8/9/2021 10:17 AM, Christoph Hellwig wrote:
> > > 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
> 
> 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 <jack@xxxxxxxx>
SUSE Labs, CR



[Index of Archives]     [Linux RAID]     [Linux SCSI]     [Linux ATA RAID]     [IDE]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Device Mapper]

  Powered by Linux