2023-12-06 06:14:41

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [PATCH -next RFC 01/14] block: add some bdev apis

> +void invalidate_bdev_range(struct block_device *bdev, pgoff_t start,
> + pgoff_t end)
> +{
> + invalidate_mapping_pages(bdev->bd_inode->i_mapping, start, end);
> +}
> +EXPORT_SYMBOL_GPL(invalidate_bdev_range);

All these could probably use kerneldoc comments.

For this one I really don't like it existing at all, but we'll have to
discuss that in the btrfs patch.

> +loff_t bdev_size(struct block_device *bdev)
> +{
> + loff_t size;
> +
> + spin_lock(&bdev->bd_size_lock);
> + size = i_size_read(bdev->bd_inode);
> + spin_unlock(&bdev->bd_size_lock);
> +
> + return size;
> +}
> +EXPORT_SYMBOL_GPL(bdev_size);

No need for this one. The callers can simply use bdev_nr_bytes.

> +struct folio *bdev_read_folio(struct block_device *bdev, pgoff_t index)
> +{
> + return read_mapping_folio(bdev->bd_inode->i_mapping, index, NULL);
> +}
> +EXPORT_SYMBOL_GPL(bdev_read_folio);
> +
> +struct folio *bdev_read_folio_gfp(struct block_device *bdev, pgoff_t index,
> + gfp_t gfp)
> +{
> + return mapping_read_folio_gfp(bdev->bd_inode->i_mapping, index, gfp);
> +}
> +EXPORT_SYMBOL_GPL(bdev_read_folio_gfp);

I think we can just drop bdev_read_folio_gfp. Half of the callers simply
pass GPK_KERNEL, and the other half passes GFP_NOFS and could just use
memalloc_nofs_save().

> +void bdev_balance_dirty_pages_ratelimited(struct block_device *bdev)
> +{
> + return balance_dirty_pages_ratelimited(bdev->bd_inode->i_mapping);
> +}
> +EXPORT_SYMBOL_GPL(bdev_balance_dirty_pages_ratelimited);

Hmm, this is just used for block2mtd, and feels a little too low-level
to me, as block2mtd really should be using the normal fileread/write
APIs. I guess we'll have to live with it for now if we want to expedite
killing off bd_inode.

> +void bdev_correlate_mapping(struct block_device *bdev,
> + struct address_space *mapping)
> +{
> + mapping->host = bdev->bd_inode;
> +}
> +EXPORT_SYMBOL_GPL(bdev_correlate_mapping);

Maybe associated insted of correlate? Either way this basically
fully exposes the bdev inode again :(

> +gfp_t bdev_gfp_constraint(struct block_device *bdev, gfp_t gfp)
> +{
> + return mapping_gfp_constraint(bdev->bd_inode->i_mapping, gfp);
> +}
> +EXPORT_SYMBOL_GPL(bdev_gfp_constraint);

The right fix here is to:

- use memalloc_nofs_save in extet instead of using
mapping_gfp_constraint to clear it from the mapping flags
- remove __ext4_sb_bread_gfp and just have buffer.c helper that does
the right thing (either by changing the calling conventions of an
existing one, or adding a new one).

> +/*
> + * The del_gendisk() function uninitializes the disk-specific data
> + * structures, including the bdi structure, without telling anyone
> + * else. Once this happens, any attempt to call mark_buffer_dirty()
> + * (for example, by ext4_commit_super), will cause a kernel OOPS.
> + * This is a kludge to prevent these oops until we can put in a proper
> + * hook in del_gendisk() to inform the VFS and file system layers.
> + */
> +int bdev_ejected(struct block_device *bdev)
> +{
> + struct backing_dev_info *bdi = inode_to_bdi(bdev->bd_inode);
> +
> + return bdi->dev == NULL;
> +}
> +EXPORT_SYMBOL_GPL(bdev_ejected);

And this code in ext4 should just go away entirely. The bdi should
always be valid for a live bdev for years.

> --- a/block/bio.c
> +++ b/block/bio.c
> @@ -1119,6 +1119,7 @@ void bio_add_folio_nofail(struct bio *bio, struct folio *folio, size_t len,
> WARN_ON_ONCE(off > UINT_MAX);
> __bio_add_page(bio, &folio->page, len, off);
> }
> +EXPORT_SYMBOL_GPL(bio_add_folio_nofail);

How is this realted? The export is fine, but really should be a
separate, well-documented commit.

>
> +static inline u8 block_bits(struct block_device *bdev)
> +{
> + return bdev->bd_inode->i_blkbits;
> +}

Not sure we should need this. i_blkbits comes from the blocksize
the fs set, so it should have other ways to get at it.


2023-12-06 06:51:22

by Yu Kuai

[permalink] [raw]
Subject: Re: [PATCH -next RFC 01/14] block: add some bdev apis

Hi,

?? 2023/12/06 14:14, Christoph Hellwig ะด??:
>> +void invalidate_bdev_range(struct block_device *bdev, pgoff_t start,
>> + pgoff_t end)
>> +{
>> + invalidate_mapping_pages(bdev->bd_inode->i_mapping, start, end);
>> +}
>> +EXPORT_SYMBOL_GPL(invalidate_bdev_range);
>
> All these could probably use kerneldoc comments.

Ok, and thanks for reviewing the patchset!
>
> For this one I really don't like it existing at all, but we'll have to
> discuss that in the btrfs patch.
>
>> +loff_t bdev_size(struct block_device *bdev)
>> +{
>> + loff_t size;
>> +
>> + spin_lock(&bdev->bd_size_lock);
>> + size = i_size_read(bdev->bd_inode);
>> + spin_unlock(&bdev->bd_size_lock);
>> +
>> + return size;
>> +}
>> +EXPORT_SYMBOL_GPL(bdev_size);
>
> No need for this one. The callers can simply use bdev_nr_bytes.

Ok, I'll replace it with bdev_nr_bytes.
>
>> +struct folio *bdev_read_folio(struct block_device *bdev, pgoff_t index)
>> +{
>> + return read_mapping_folio(bdev->bd_inode->i_mapping, index, NULL);
>> +}
>> +EXPORT_SYMBOL_GPL(bdev_read_folio);
>> +
>> +struct folio *bdev_read_folio_gfp(struct block_device *bdev, pgoff_t index,
>> + gfp_t gfp)
>> +{
>> + return mapping_read_folio_gfp(bdev->bd_inode->i_mapping, index, gfp);
>> +}
>> +EXPORT_SYMBOL_GPL(bdev_read_folio_gfp);
>
> I think we can just drop bdev_read_folio_gfp. Half of the callers simply
> pass GPK_KERNEL, and the other half passes GFP_NOFS and could just use
> memalloc_nofs_save().

I'm a litter confused, so there are 3 use cases:
1) use GFP_USER, default gfp from bdev_alloc.
2) use GFP_KERNEL
3) use GFP_NOFS

I understand that you're suggesting memalloc_nofs_save() to distinguish
2 and 3, but how can I distinguish 1?
>
>> +void bdev_balance_dirty_pages_ratelimited(struct block_device *bdev)
>> +{
>> + return balance_dirty_pages_ratelimited(bdev->bd_inode->i_mapping);
>> +}
>> +EXPORT_SYMBOL_GPL(bdev_balance_dirty_pages_ratelimited);
>
> Hmm, this is just used for block2mtd, and feels a little too low-level
> to me, as block2mtd really should be using the normal fileread/write
> APIs. I guess we'll have to live with it for now if we want to expedite
> killing off bd_inode.
>
>> +void bdev_correlate_mapping(struct block_device *bdev,
>> + struct address_space *mapping)
>> +{
>> + mapping->host = bdev->bd_inode;
>> +}
>> +EXPORT_SYMBOL_GPL(bdev_correlate_mapping);
>
> Maybe associated insted of correlate? Either way this basically
> fully exposes the bdev inode again :(
>
>> +gfp_t bdev_gfp_constraint(struct block_device *bdev, gfp_t gfp)
>> +{
>> + return mapping_gfp_constraint(bdev->bd_inode->i_mapping, gfp);
>> +}
>> +EXPORT_SYMBOL_GPL(bdev_gfp_constraint);
>
> The right fix here is to:
>
> - use memalloc_nofs_save in extet instead of using
> mapping_gfp_constraint to clear it from the mapping flags
> - remove __ext4_sb_bread_gfp and just have buffer.c helper that does
> the right thing (either by changing the calling conventions of an
> existing one, or adding a new one).

Thanks for the suggestions, but I'm not sure how to do this yet, I must
read more ext4 code.
>
>> +/*
>> + * The del_gendisk() function uninitializes the disk-specific data
>> + * structures, including the bdi structure, without telling anyone
>> + * else. Once this happens, any attempt to call mark_buffer_dirty()
>> + * (for example, by ext4_commit_super), will cause a kernel OOPS.
>> + * This is a kludge to prevent these oops until we can put in a proper
>> + * hook in del_gendisk() to inform the VFS and file system layers.
>> + */
>> +int bdev_ejected(struct block_device *bdev)
>> +{
>> + struct backing_dev_info *bdi = inode_to_bdi(bdev->bd_inode);
>> +
>> + return bdi->dev == NULL;
>> +}
>> +EXPORT_SYMBOL_GPL(bdev_ejected);
>
> And this code in ext4 should just go away entirely. The bdi should
> always be valid for a live bdev for years.
Sounds good, I was confused about this code as well.

>
>> --- a/block/bio.c
>> +++ b/block/bio.c
>> @@ -1119,6 +1119,7 @@ void bio_add_folio_nofail(struct bio *bio, struct folio *folio, size_t len,
>> WARN_ON_ONCE(off > UINT_MAX);
>> __bio_add_page(bio, &folio->page, len, off);
>> }
>> +EXPORT_SYMBOL_GPL(bio_add_folio_nofail);
>
> How is this realted? The export is fine, but really should be a
> separate, well-documented commit.

This is used to replace __bio_add_page() in btrfs while converting page
to folio, please let me know if I should keep this, if so, I'll split
this into a new commit.
>
>>
>> +static inline u8 block_bits(struct block_device *bdev)
>> +{
>> + return bdev->bd_inode->i_blkbits;
>> +}
>
> Not sure we should need this. i_blkbits comes from the blocksize
> the fs set, so it should have other ways to get at it.

Yes, this is now only used for erofs, and erofs do call
sb_set_blocksize() while initializing, hence it's right there is other
way to get blkbits and this helper is not needed.

Thanks,
Kuai

> .
>


2023-12-06 07:21:23

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [PATCH -next RFC 01/14] block: add some bdev apis

On Wed, Dec 06, 2023 at 02:50:56PM +0800, Yu Kuai wrote:
> I'm a litter confused, so there are 3 use cases:
> 1) use GFP_USER, default gfp from bdev_alloc.
> 2) use GFP_KERNEL
> 3) use GFP_NOFS
>
> I understand that you're suggesting memalloc_nofs_save() to distinguish
> 2 and 3, but how can I distinguish 1?

You shouldn't. Diverging from the default flags except for clearing
the FS or IO flags is simply a bug. Note that things like block2mtd
should probably also ensure a noio allocation if they aren't doing that
yet.

> > - use memalloc_nofs_save in extet instead of using
> > mapping_gfp_constraint to clear it from the mapping flags
> > - remove __ext4_sb_bread_gfp and just have buffer.c helper that does
> > the right thing (either by changing the calling conventions of an
> > existing one, or adding a new one).
>
> Thanks for the suggestions, but I'm not sure how to do this yet, I must
> read more ext4 code.

the nofs save part should be trivial. You can just skip the rest for
now as it's not needed for this patch series.


2023-12-06 17:53:29

by Theodore Ts'o

[permalink] [raw]
Subject: Re: [PATCH -next RFC 01/14] block: add some bdev apis

On Tue, Dec 05, 2023 at 10:14:00PM -0800, Christoph Hellwig wrote:
> > +/*
> > + * The del_gendisk() function uninitializes the disk-specific data
> > + * structures, including the bdi structure, without telling anyone
> > + * else. Once this happens, any attempt to call mark_buffer_dirty()
> > + * (for example, by ext4_commit_super), will cause a kernel OOPS.
> > + * This is a kludge to prevent these oops until we can put in a proper
> > + * hook in del_gendisk() to inform the VFS and file system layers.
> > + */
> > +int bdev_ejected(struct block_device *bdev)
> > +{
> > + struct backing_dev_info *bdi = inode_to_bdi(bdev->bd_inode);
> > +
> > + return bdi->dev == NULL;
> > +}
> > +EXPORT_SYMBOL_GPL(bdev_ejected);
>
> And this code in ext4 should just go away entirely. The bdi should
> always be valid for a live bdev for years.

This was added because pulling a mounted a USB thumb drive (or a HDD
drops off the SATA bus) while the file system is mounted and actively
in use, would result in a kernel OOPS. If that's no longer true,
that's great, but it would be good to test to make sure this is the
case....

If we really want to remove it, I'd suggest doing this as a separate
commit, so that after we see syzbot reports, or users complaining
about kernel crashes, we can revert the removal if necessary.

Cheers,

- Ted