Skip to content

Commit

Permalink
btrfs: cloned bios must not be iterated by bio_for_each_segment_all
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: David Sterba <[email protected]>
  • Loading branch information
kdave committed Jul 14, 2017
1 parent 1014f3d commit c09abff
Show file tree
Hide file tree
Showing 4 changed files with 7 additions and 0 deletions.
1 change: 1 addition & 0 deletions fs/btrfs/compression.c
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ static void end_compressed_bio_read(struct bio *bio)
* 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);

Expand Down
1 change: 1 addition & 0 deletions fs/btrfs/disk-io.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
3 changes: 3 additions & 0 deletions fs/btrfs/extent_io.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;

Expand Down
2 changes: 2 additions & 0 deletions fs/btrfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down

0 comments on commit c09abff

Please sign in to comment.