forked from mirrors/linux
		
	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>
This commit is contained in:
		
							parent
							
								
									1014f3d68f
								
							
						
					
					
						commit
						c09abff87f
					
				
					 4 changed files with 7 additions and 0 deletions
				
			
		| 
						 | 
				
			
			@ -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);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue