btrfs_repair_one_sector just wants to free the bio if submit_bio_hook fails, but btrfs_submit_data_bio will call bio_endio which will call into the submitter of the original bio and free the bio there as well. Move the bio_endio calls from btrfs_submit_data_bio and btrfs_submit_metadata_bio into submit_one_bio to fix this double free. Signed-off-by: Christoph Hellwig <hch@xxxxxx> --- fs/btrfs/disk-io.c | 2 -- fs/btrfs/extent_io.c | 4 ++++ fs/btrfs/inode.c | 4 ---- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index b3e9cf3fd1dd1..c245e1b131964 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -941,8 +941,6 @@ blk_status_t btrfs_submit_metadata_bio(struct inode *inode, struct bio *bio, return 0; out_w_error: - bio->bi_status = ret; - bio_endio(bio); return ret; } diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 3b386bbb85a7f..e9fa0f6d605ee 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -181,6 +181,10 @@ int __must_check submit_one_bio(struct bio *bio, int mirror_num, ret = btrfs_submit_metadata_bio(tree->private_data, bio, mirror_num, bio_flags); + if (ret) { + bio->bi_status = ret; + bio_endio(bio); + } return blk_status_to_errno(ret); } diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 5bbea5ec31fc5..3ef8b63bb1b5c 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -2571,10 +2571,6 @@ blk_status_t btrfs_submit_data_bio(struct inode *inode, struct bio *bio, ret = btrfs_map_bio(fs_info, bio, mirror_num); out: - if (ret) { - bio->bi_status = ret; - bio_endio(bio); - } return ret; } -- 2.30.2