btrfs: cloned bios must not be iterated by bio_for_each_segment_all
authorDavid Sterba <dsterba@suse.com>
Thu, 13 Jul 2017 16:10:07 +0000 (18:10 +0200)
committerDavid Sterba <dsterba@suse.com>
Fri, 14 Jul 2017 18:39:31 +0000 (20:39 +0200)
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>
fs/btrfs/compression.c
fs/btrfs/disk-io.c
fs/btrfs/extent_io.c
fs/btrfs/inode.c

index fcd323eceb5bb1dfec946eeab22fb79d44ce943f..8ba1b86c9b725c8ff485bba5f5a20ffbdad3a531 100644 (file)
@@ -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);
 
index b6758892874f3d86f90aa09648b6ba9461579219..075beedb435213d45435bf3e6ea491d43e06fe68 100644 (file)
@@ -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);
index 2e6f69908303311128554c951e573f2596022669..a3122fba54e8d51a5ca30b6f4b6a57955ce8df19 100644 (file)
@@ -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;
 
index 5d3c6ac960fd24c195a102812a9d3332cb8ab53f..529437c337b49cffc441543c857f33fe05085a39 100644 (file)
@@ -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,