diff options
author | David Sterba <dsterba@suse.com> | 2017-07-13 19:10:07 +0300 |
---|---|---|
committer | David Sterba <dsterba@suse.com> | 2017-07-14 21:39:31 +0300 |
commit | c09abff87f90c81d74b6483837a665f97448a475 (patch) | |
tree | 72371fad2cc4dce6180e8399d94ff053a879c607 /fs/btrfs | |
parent | 1014f3d68fc4034966b15234dc12b81147ee83b2 (diff) | |
download | linux-c09abff87f90c81d74b6483837a665f97448a475.tar.xz |
btrfs: cloned bios must not be iterated by bio_for_each_segment_all
We've started using cloned bios more in 4.13, there are some specifics
regarding the iteration. Filipe found [1] that the raid56 iterated a
cloned bio using bio_for_each_segment_all, which is incorrect. The
cloned bios have wrong bi_vcnt and this could lead to silent
corruptions. This patch adds assertions to all remaining
bio_for_each_segment_all cases.
[1] https://patchwork.kernel.org/patch/9838535/
Reviewed-by: Liu Bo <bo.li.liu@oracle.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r-- | fs/btrfs/compression.c | 1 | ||||
-rw-r--r-- | fs/btrfs/disk-io.c | 1 | ||||
-rw-r--r-- | fs/btrfs/extent_io.c | 3 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 2 |
4 files changed, 7 insertions, 0 deletions
diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c index fcd323eceb5b..8ba1b86c9b72 100644 --- a/fs/btrfs/compression.c +++ b/fs/btrfs/compression.c @@ -152,6 +152,7 @@ csum_failed: * we have verified the checksum already, set page * checked so the end_io handlers know about it */ + ASSERT(!bio_flagged(bio, BIO_CLONED)); bio_for_each_segment_all(bvec, cb->orig_bio, i) SetPageChecked(bvec->bv_page); diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index b6758892874f..075beedb4352 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -964,6 +964,7 @@ static int btree_csum_one_bio(struct bio *bio) struct btrfs_root *root; int i, ret = 0; + ASSERT(!bio_flagged(bio, BIO_CLONED)); bio_for_each_segment_all(bvec, bio, i) { root = BTRFS_I(bvec->bv_page->mapping->host)->root; ret = csum_dirty_buffer(root->fs_info, bvec->bv_page); diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 2e6f69908303..a3122fba54e8 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -2452,6 +2452,7 @@ static void end_bio_extent_writepage(struct bio *bio) u64 end; int i; + ASSERT(!bio_flagged(bio, BIO_CLONED)); bio_for_each_segment_all(bvec, bio, i) { struct page *page = bvec->bv_page; struct inode *inode = page->mapping->host; @@ -2522,6 +2523,7 @@ static void end_bio_extent_readpage(struct bio *bio) int ret; int i; + ASSERT(!bio_flagged(bio, BIO_CLONED)); bio_for_each_segment_all(bvec, bio, i) { struct page *page = bvec->bv_page; struct inode *inode = page->mapping->host; @@ -3675,6 +3677,7 @@ static void end_bio_extent_buffer_writepage(struct bio *bio) struct extent_buffer *eb; int i, done; + ASSERT(!bio_flagged(bio, BIO_CLONED)); bio_for_each_segment_all(bvec, bio, i) { struct page *page = bvec->bv_page; diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 5d3c6ac960fd..529437c337b4 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -8060,6 +8060,7 @@ static void btrfs_retry_endio_nocsum(struct bio *bio) ASSERT(bio->bi_io_vec->bv_len == btrfs_inode_sectorsize(inode)); done->uptodate = 1; + ASSERT(!bio_flagged(bio, BIO_CLONED)); bio_for_each_segment_all(bvec, bio, i) clean_io_failure(BTRFS_I(inode)->root->fs_info, failure_tree, io_tree, done->start, bvec->bv_page, @@ -8151,6 +8152,7 @@ static void btrfs_retry_endio(struct bio *bio) io_tree = &BTRFS_I(inode)->io_tree; failure_tree = &BTRFS_I(inode)->io_failure_tree; + ASSERT(!bio_flagged(bio, BIO_CLONED)); bio_for_each_segment_all(bvec, bio, i) { ret = __readpage_endio_check(inode, io_bio, i, bvec->bv_page, bvec->bv_offset, done->start, |