Skip to content

Commit 524bcd1

Browse files
Christoph Hellwigkdave
authored andcommitted
btrfs: simplify the pending I/O counting in struct compressed_bio
Instead of counting the sectors just count the bios, with an extra reference held during submission. This significantly simplifies the submission side error handling. This slightly changes completion and error handling of btrfs_submit_compressed_{read,write} because with the old code the compressed_bio could have been completed in submit_compressed_{read,write} only if there was an error during submission for one of the lower bio, whilst with the new code there is a chance for this to happen even for successful submission if the all the lower bios complete before the end of the function is reached. Reviewed-by: Nikolay Borisov <nborisov@suse.com> Reviewed-by: Boris Burkov <boris@bur.io> Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: David Sterba <dsterba@suse.com>
1 parent c144c63 commit 524bcd1

2 files changed

Lines changed: 32 additions & 97 deletions

File tree

fs/btrfs/compression.c

Lines changed: 30 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -191,44 +191,6 @@ static int check_compressed_csum(struct btrfs_inode *inode, struct bio *bio,
191191
return 0;
192192
}
193193

194-
/*
195-
* Reduce bio and io accounting for a compressed_bio with its corresponding bio.
196-
*
197-
* Return true if there is no pending bio nor io.
198-
* Return false otherwise.
199-
*/
200-
static bool dec_and_test_compressed_bio(struct compressed_bio *cb, struct bio *bio)
201-
{
202-
struct btrfs_fs_info *fs_info = btrfs_sb(cb->inode->i_sb);
203-
unsigned int bi_size = 0;
204-
bool last_io = false;
205-
struct bio_vec *bvec;
206-
struct bvec_iter_all iter_all;
207-
208-
/*
209-
* At endio time, bi_iter.bi_size doesn't represent the real bio size.
210-
* Thus here we have to iterate through all segments to grab correct
211-
* bio size.
212-
*/
213-
bio_for_each_segment_all(bvec, bio, iter_all)
214-
bi_size += bvec->bv_len;
215-
216-
if (bio->bi_status)
217-
cb->status = bio->bi_status;
218-
219-
ASSERT(bi_size && bi_size <= cb->compressed_len);
220-
last_io = refcount_sub_and_test(bi_size >> fs_info->sectorsize_bits,
221-
&cb->pending_sectors);
222-
/*
223-
* Here we must wake up the possible error handler after all other
224-
* operations on @cb finished, or we can race with
225-
* finish_compressed_bio_*() which may free @cb.
226-
*/
227-
wake_up_var(cb);
228-
229-
return last_io;
230-
}
231-
232194
static void finish_compressed_bio_read(struct compressed_bio *cb)
233195
{
234196
unsigned int index;
@@ -288,7 +250,10 @@ static void end_compressed_bio_read(struct bio *bio)
288250
unsigned int mirror = btrfs_bio(bio)->mirror_num;
289251
int ret = 0;
290252

291-
if (!dec_and_test_compressed_bio(cb, bio))
253+
if (bio->bi_status)
254+
cb->status = bio->bi_status;
255+
256+
if (!refcount_dec_and_test(&cb->pending_ios))
292257
goto out;
293258

294259
/*
@@ -417,7 +382,10 @@ static void end_compressed_bio_write(struct bio *bio)
417382
{
418383
struct compressed_bio *cb = bio->bi_private;
419384

420-
if (dec_and_test_compressed_bio(cb, bio)) {
385+
if (bio->bi_status)
386+
cb->status = bio->bi_status;
387+
388+
if (refcount_dec_and_test(&cb->pending_ios)) {
421389
struct btrfs_fs_info *fs_info = btrfs_sb(cb->inode->i_sb);
422390

423391
btrfs_record_physical_zoned(cb->inode, cb->start, bio);
@@ -476,7 +444,7 @@ static struct bio *alloc_compressed_bio(struct compressed_bio *cb, u64 disk_byte
476444
return ERR_PTR(ret);
477445
}
478446
*next_stripe_start = disk_bytenr + geom.len;
479-
447+
refcount_inc(&cb->pending_ios);
480448
return bio;
481449
}
482450

@@ -503,7 +471,7 @@ blk_status_t btrfs_submit_compressed_write(struct btrfs_inode *inode, u64 start,
503471
struct compressed_bio *cb;
504472
u64 cur_disk_bytenr = disk_start;
505473
u64 next_stripe_start;
506-
blk_status_t ret;
474+
blk_status_t ret = BLK_STS_OK;
507475
int skip_sum = inode->flags & BTRFS_INODE_NODATASUM;
508476
const bool use_append = btrfs_use_zone_append(inode, disk_start);
509477
const unsigned int bio_op = use_append ? REQ_OP_ZONE_APPEND : REQ_OP_WRITE;
@@ -513,7 +481,7 @@ blk_status_t btrfs_submit_compressed_write(struct btrfs_inode *inode, u64 start,
513481
cb = kmalloc(compressed_bio_size(fs_info, compressed_len), GFP_NOFS);
514482
if (!cb)
515483
return BLK_STS_RESOURCE;
516-
refcount_set(&cb->pending_sectors, compressed_len >> fs_info->sectorsize_bits);
484+
refcount_set(&cb->pending_ios, 1);
517485
cb->status = BLK_STS_OK;
518486
cb->inode = &inode->vfs_inode;
519487
cb->start = start;
@@ -543,8 +511,7 @@ blk_status_t btrfs_submit_compressed_write(struct btrfs_inode *inode, u64 start,
543511
&next_stripe_start);
544512
if (IS_ERR(bio)) {
545513
ret = errno_to_blk_status(PTR_ERR(bio));
546-
bio = NULL;
547-
goto finish_cb;
514+
break;
548515
}
549516
if (blkcg_css)
550517
bio->bi_opf |= REQ_CGROUP_PUNT;
@@ -588,8 +555,11 @@ blk_status_t btrfs_submit_compressed_write(struct btrfs_inode *inode, u64 start,
588555
if (submit) {
589556
if (!skip_sum) {
590557
ret = btrfs_csum_one_bio(inode, bio, start, true);
591-
if (ret)
592-
goto finish_cb;
558+
if (ret) {
559+
bio->bi_status = ret;
560+
bio_endio(bio);
561+
break;
562+
}
593563
}
594564

595565
ASSERT(bio->bi_iter.bi_size);
@@ -598,33 +568,12 @@ blk_status_t btrfs_submit_compressed_write(struct btrfs_inode *inode, u64 start,
598568
}
599569
cond_resched();
600570
}
601-
if (blkcg_css)
602-
kthread_associate_blkcg(NULL);
603571

604-
return 0;
605-
606-
finish_cb:
607572
if (blkcg_css)
608573
kthread_associate_blkcg(NULL);
609574

610-
if (bio) {
611-
bio->bi_status = ret;
612-
bio_endio(bio);
613-
}
614-
/* Last byte of @cb is submitted, endio will free @cb */
615-
if (cur_disk_bytenr == disk_start + compressed_len)
616-
return ret;
617-
618-
wait_var_event(cb, refcount_read(&cb->pending_sectors) ==
619-
(disk_start + compressed_len - cur_disk_bytenr) >>
620-
fs_info->sectorsize_bits);
621-
/*
622-
* Even with previous bio ended, we should still have io not yet
623-
* submitted, thus need to finish manually.
624-
*/
625-
ASSERT(refcount_read(&cb->pending_sectors));
626-
/* Now we are the only one referring @cb, can finish it safely. */
627-
finish_compressed_bio_write(cb);
575+
if (refcount_dec_and_test(&cb->pending_ios))
576+
finish_compressed_bio_write(cb);
628577
return ret;
629578
}
630579

@@ -830,7 +779,7 @@ void btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
830779
goto out;
831780
}
832781

833-
refcount_set(&cb->pending_sectors, compressed_len >> fs_info->sectorsize_bits);
782+
refcount_set(&cb->pending_ios, 1);
834783
cb->status = BLK_STS_OK;
835784
cb->inode = inode;
836785
cb->mirror_num = mirror_num;
@@ -880,9 +829,8 @@ void btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
880829
REQ_OP_READ, end_compressed_bio_read,
881830
&next_stripe_start);
882831
if (IS_ERR(comp_bio)) {
883-
ret = errno_to_blk_status(PTR_ERR(comp_bio));
884-
comp_bio = NULL;
885-
goto finish_cb;
832+
cb->status = errno_to_blk_status(PTR_ERR(comp_bio));
833+
break;
886834
}
887835
}
888836
/*
@@ -921,8 +869,11 @@ void btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
921869
unsigned int nr_sectors;
922870

923871
ret = btrfs_lookup_bio_sums(inode, comp_bio, sums);
924-
if (ret)
925-
goto finish_cb;
872+
if (ret) {
873+
comp_bio->bi_status = ret;
874+
bio_endio(comp_bio);
875+
break;
876+
}
926877

927878
nr_sectors = DIV_ROUND_UP(comp_bio->bi_iter.bi_size,
928879
fs_info->sectorsize);
@@ -933,6 +884,9 @@ void btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
933884
comp_bio = NULL;
934885
}
935886
}
887+
888+
if (refcount_dec_and_test(&cb->pending_ios))
889+
finish_compressed_bio_read(cb);
936890
return;
937891

938892
fail:
@@ -950,25 +904,6 @@ void btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
950904
bio->bi_status = ret;
951905
bio_endio(bio);
952906
return;
953-
finish_cb:
954-
if (comp_bio) {
955-
comp_bio->bi_status = ret;
956-
bio_endio(comp_bio);
957-
}
958-
/* All bytes of @cb is submitted, endio will free @cb */
959-
if (cur_disk_byte == disk_bytenr + compressed_len)
960-
return;
961-
962-
wait_var_event(cb, refcount_read(&cb->pending_sectors) ==
963-
(disk_bytenr + compressed_len - cur_disk_byte) >>
964-
fs_info->sectorsize_bits);
965-
/*
966-
* Even with previous bio ended, we should still have io not yet
967-
* submitted, thus need to finish @cb manually.
968-
*/
969-
ASSERT(refcount_read(&cb->pending_sectors));
970-
/* Now we are the only one referring @cb, can finish it safely. */
971-
finish_compressed_bio_read(cb);
972907
}
973908

974909
/*

fs/btrfs/compression.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ static_assert((BTRFS_MAX_COMPRESSED % PAGE_SIZE) == 0);
3030
#define BTRFS_ZLIB_DEFAULT_LEVEL 3
3131

3232
struct compressed_bio {
33-
/* Number of sectors with unfinished IO (unsubmitted or unfinished) */
34-
refcount_t pending_sectors;
33+
/* Number of outstanding bios */
34+
refcount_t pending_ios;
3535

3636
/* Number of compressed pages in the array */
3737
unsigned int nr_pages;

0 commit comments

Comments
 (0)