diff mbox series

[11/17] btrfs: make dec_and_test_compressed_bio() to be split bio compatible

Message ID 20211201051756.53742-12-wqu@suse.com (mailing list archive)
State Not Applicable, archived
Delegated to: Mike Snitzer
Headers show
Series btrfs: split bio at btrfs_map_bio() time | expand

Commit Message

Qu Wenruo Dec. 1, 2021, 5:17 a.m. UTC
For compression read write endio functions, they all rely on
dec_and_test_compressed_bio() to determine if they are the last bio.

So here we only need to convert the bio_for_each_segment_all() call into
__bio_for_each_segment() so that compression read/write endio functions
will handle both split and unsplit bios well.

Signed-off-by: Qu Wenruo <wqu@suse.com>
---
 fs/btrfs/compression.c | 14 +++++---------
 1 file changed, 5 insertions(+), 9 deletions(-)

Comments

Josef Bacik March 16, 2022, 7:46 p.m. UTC | #1
On Wed, Dec 01, 2021 at 01:17:50PM +0800, Qu Wenruo wrote:
> For compression read write endio functions, they all rely on
> dec_and_test_compressed_bio() to determine if they are the last bio.
> 
> So here we only need to convert the bio_for_each_segment_all() call into
> __bio_for_each_segment() so that compression read/write endio functions
> will handle both split and unsplit bios well.
> 
> Signed-off-by: Qu Wenruo <wqu@suse.com>
> ---
>  fs/btrfs/compression.c | 14 +++++---------
>  1 file changed, 5 insertions(+), 9 deletions(-)
> 
> diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c
> index 8668c5190805..8b4b84b59b0c 100644
> --- a/fs/btrfs/compression.c
> +++ b/fs/btrfs/compression.c
> @@ -205,18 +205,14 @@ static int check_compressed_csum(struct btrfs_inode *inode, struct bio *bio,
>  static bool dec_and_test_compressed_bio(struct compressed_bio *cb, struct bio *bio)
>  {
>  	struct btrfs_fs_info *fs_info = btrfs_sb(cb->inode->i_sb);
> +	struct bio_vec bvec;
> +	struct bvec_iter iter;
>  	unsigned int bi_size = 0;
>  	bool last_io = false;
> -	struct bio_vec *bvec;
> -	struct bvec_iter_all iter_all;
>  
> -	/*
> -	 * At endio time, bi_iter.bi_size doesn't represent the real bio size.
> -	 * Thus here we have to iterate through all segments to grab correct
> -	 * bio size.
> -	 */
> -	bio_for_each_segment_all(bvec, bio, iter_all)
> -		bi_size += bvec->bv_len;
> +	ASSERT(btrfs_bio(bio)->iter.bi_size);

We're tripping this assert with generic/476 with -o compress, so I assume
there's some error condition that isn't being handled properly.  Thanks,

Josef

--
dm-devel mailing list
dm-devel@redhat.com
https://listman.redhat.com/mailman/listinfo/dm-devel
Qu Wenruo March 16, 2022, 11:30 p.m. UTC | #2
On 2022/3/17 03:46, Josef Bacik wrote:
> On Wed, Dec 01, 2021 at 01:17:50PM +0800, Qu Wenruo wrote:
>> For compression read write endio functions, they all rely on
>> dec_and_test_compressed_bio() to determine if they are the last bio.
>>
>> So here we only need to convert the bio_for_each_segment_all() call into
>> __bio_for_each_segment() so that compression read/write endio functions
>> will handle both split and unsplit bios well.
>>
>> Signed-off-by: Qu Wenruo <wqu@suse.com>
>> ---
>>   fs/btrfs/compression.c | 14 +++++---------
>>   1 file changed, 5 insertions(+), 9 deletions(-)
>>
>> diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c
>> index 8668c5190805..8b4b84b59b0c 100644
>> --- a/fs/btrfs/compression.c
>> +++ b/fs/btrfs/compression.c
>> @@ -205,18 +205,14 @@ static int check_compressed_csum(struct btrfs_inode *inode, struct bio *bio,
>>   static bool dec_and_test_compressed_bio(struct compressed_bio *cb, struct bio *bio)
>>   {
>>   	struct btrfs_fs_info *fs_info = btrfs_sb(cb->inode->i_sb);
>> +	struct bio_vec bvec;
>> +	struct bvec_iter iter;
>>   	unsigned int bi_size = 0;
>>   	bool last_io = false;
>> -	struct bio_vec *bvec;
>> -	struct bvec_iter_all iter_all;
>>
>> -	/*
>> -	 * At endio time, bi_iter.bi_size doesn't represent the real bio size.
>> -	 * Thus here we have to iterate through all segments to grab correct
>> -	 * bio size.
>> -	 */
>> -	bio_for_each_segment_all(bvec, bio, iter_all)
>> -		bi_size += bvec->bv_len;
>> +	ASSERT(btrfs_bio(bio)->iter.bi_size);
>
> We're tripping this assert with generic/476 with -o compress, so I assume
> there's some error condition that isn't being handled properly.  Thanks,

Thank you very much for catching it.

It turns out the ASSERT() is really helpful to detect uninitialized
btrfs_bio::iter.

The problem is related to two call sites:
- btrfs_submit_compressed_read()
- btrfs_submit_compressed_write()

The compressed bio doesn't have its iter properly initialized for error
path, thus it's causing the problem.

Just two new lines and the problem can be fixed.

I'll refresh the patchset.

Thank you again for catching this,
Qu

>
> Josef

--
dm-devel mailing list
dm-devel@redhat.com
https://listman.redhat.com/mailman/listinfo/dm-devel
diff mbox series

Patch

diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c
index 8668c5190805..8b4b84b59b0c 100644
--- a/fs/btrfs/compression.c
+++ b/fs/btrfs/compression.c
@@ -205,18 +205,14 @@  static int check_compressed_csum(struct btrfs_inode *inode, struct bio *bio,
 static bool dec_and_test_compressed_bio(struct compressed_bio *cb, struct bio *bio)
 {
 	struct btrfs_fs_info *fs_info = btrfs_sb(cb->inode->i_sb);
+	struct bio_vec bvec;
+	struct bvec_iter iter;
 	unsigned int bi_size = 0;
 	bool last_io = false;
-	struct bio_vec *bvec;
-	struct bvec_iter_all iter_all;
 
-	/*
-	 * At endio time, bi_iter.bi_size doesn't represent the real bio size.
-	 * Thus here we have to iterate through all segments to grab correct
-	 * bio size.
-	 */
-	bio_for_each_segment_all(bvec, bio, iter_all)
-		bi_size += bvec->bv_len;
+	ASSERT(btrfs_bio(bio)->iter.bi_size);
+	__bio_for_each_segment(bvec, bio, iter, btrfs_bio(bio)->iter)
+		bi_size += bvec.bv_len;
 
 	if (bio->bi_status)
 		cb->errors = 1;