mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-10-31 08:44:41 +00:00 
			
		
		
		
	Merge branch 'for-4.13-part2' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux
Pull btrfs fixes from David Sterba: "We've identified and fixed a silent corruption (introduced by code in the first pull), a fixup after the blk_status_t merge and two fixes to incremental send that Filipe has been hunting for some time" * 'for-4.13-part2' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux: Btrfs: fix unexpected return value of bio_readpage_error btrfs: btrfs_create_repair_bio never fails, skip error handling btrfs: cloned bios must not be iterated by bio_for_each_segment_all Btrfs: fix write corruption due to bio cloning on raid5/6 Btrfs: incremental send, fix invalid memory access Btrfs: incremental send, fix invalid path for link commands
This commit is contained in:
		
						commit
						bc243704fb
					
				
					 7 changed files with 88 additions and 57 deletions
				
			
		|  | @ -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); | ||||
| 
 | ||||
|  |  | |||
|  | @ -964,6 +964,7 @@ static blk_status_t 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); | ||||
|  |  | |||
|  | @ -2258,7 +2258,7 @@ int btrfs_get_io_failure_record(struct inode *inode, u64 start, u64 end, | |||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int btrfs_check_repairable(struct inode *inode, struct bio *failed_bio, | ||||
| bool btrfs_check_repairable(struct inode *inode, struct bio *failed_bio, | ||||
| 			   struct io_failure_record *failrec, int failed_mirror) | ||||
| { | ||||
| 	struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); | ||||
|  | @ -2274,7 +2274,7 @@ int btrfs_check_repairable(struct inode *inode, struct bio *failed_bio, | |||
| 		btrfs_debug(fs_info, | ||||
| 			"Check Repairable: cannot repair, num_copies=%d, next_mirror %d, failed_mirror %d", | ||||
| 			num_copies, failrec->this_mirror, failed_mirror); | ||||
| 		return 0; | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
|  | @ -2315,10 +2315,10 @@ int btrfs_check_repairable(struct inode *inode, struct bio *failed_bio, | |||
| 		btrfs_debug(fs_info, | ||||
| 			"Check Repairable: (fail) num_copies=%d, next_mirror %d, failed_mirror %d", | ||||
| 			num_copies, failrec->this_mirror, failed_mirror); | ||||
| 		return 0; | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	return 1; | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | @ -2382,8 +2382,8 @@ static int bio_readpage_error(struct bio *failed_bio, u64 phy_offset, | |||
| 	if (ret) | ||||
| 		return ret; | ||||
| 
 | ||||
| 	ret = btrfs_check_repairable(inode, failed_bio, failrec, failed_mirror); | ||||
| 	if (!ret) { | ||||
| 	if (!btrfs_check_repairable(inode, failed_bio, failrec, | ||||
| 				    failed_mirror)) { | ||||
| 		free_io_failure(failure_tree, tree, failrec); | ||||
| 		return -EIO; | ||||
| 	} | ||||
|  | @ -2396,10 +2396,6 @@ static int bio_readpage_error(struct bio *failed_bio, u64 phy_offset, | |||
| 				      start - page_offset(page), | ||||
| 				      (int)phy_offset, failed_bio->bi_end_io, | ||||
| 				      NULL); | ||||
| 	if (!bio) { | ||||
| 		free_io_failure(failure_tree, tree, failrec); | ||||
| 		return -EIO; | ||||
| 	} | ||||
| 	bio_set_op_attrs(bio, REQ_OP_READ, read_mode); | ||||
| 
 | ||||
| 	btrfs_debug(btrfs_sb(inode->i_sb), | ||||
|  | @ -2456,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; | ||||
|  | @ -2526,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; | ||||
|  | @ -3680,6 +3678,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; | ||||
| 
 | ||||
|  |  | |||
|  | @ -539,8 +539,8 @@ void btrfs_free_io_failure_record(struct btrfs_inode *inode, u64 start, | |||
| 		u64 end); | ||||
| int btrfs_get_io_failure_record(struct inode *inode, u64 start, u64 end, | ||||
| 				struct io_failure_record **failrec_ret); | ||||
| int btrfs_check_repairable(struct inode *inode, struct bio *failed_bio, | ||||
| 			   struct io_failure_record *failrec, int fail_mirror); | ||||
| bool btrfs_check_repairable(struct inode *inode, struct bio *failed_bio, | ||||
| 			    struct io_failure_record *failrec, int fail_mirror); | ||||
| struct bio *btrfs_create_repair_bio(struct inode *inode, struct bio *failed_bio, | ||||
| 				    struct io_failure_record *failrec, | ||||
| 				    struct page *page, int pg_offset, int icsum, | ||||
|  |  | |||
|  | @ -8016,10 +8016,6 @@ static int dio_read_error(struct inode *inode, struct bio *failed_bio, | |||
| 	isector >>= inode->i_sb->s_blocksize_bits; | ||||
| 	bio = btrfs_create_repair_bio(inode, failed_bio, failrec, page, | ||||
| 				pgoff, isector, repair_endio, repair_arg); | ||||
| 	if (!bio) { | ||||
| 		free_io_failure(failure_tree, io_tree, failrec); | ||||
| 		return -EIO; | ||||
| 	} | ||||
| 	bio_set_op_attrs(bio, REQ_OP_READ, read_mode); | ||||
| 
 | ||||
| 	btrfs_debug(BTRFS_I(inode)->root->fs_info, | ||||
|  | @ -8059,6 +8055,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, | ||||
|  | @ -8150,6 +8147,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, | ||||
|  |  | |||
|  | @ -1136,20 +1136,27 @@ static void validate_rbio_for_rmw(struct btrfs_raid_bio *rbio) | |||
| static void index_rbio_pages(struct btrfs_raid_bio *rbio) | ||||
| { | ||||
| 	struct bio *bio; | ||||
| 	struct bio_vec *bvec; | ||||
| 	u64 start; | ||||
| 	unsigned long stripe_offset; | ||||
| 	unsigned long page_index; | ||||
| 	int i; | ||||
| 
 | ||||
| 	spin_lock_irq(&rbio->bio_list_lock); | ||||
| 	bio_list_for_each(bio, &rbio->bio_list) { | ||||
| 		struct bio_vec bvec; | ||||
| 		struct bvec_iter iter; | ||||
| 		int i = 0; | ||||
| 
 | ||||
| 		start = (u64)bio->bi_iter.bi_sector << 9; | ||||
| 		stripe_offset = start - rbio->bbio->raid_map[0]; | ||||
| 		page_index = stripe_offset >> PAGE_SHIFT; | ||||
| 
 | ||||
| 		bio_for_each_segment_all(bvec, bio, i) | ||||
| 			rbio->bio_pages[page_index + i] = bvec->bv_page; | ||||
| 		if (bio_flagged(bio, BIO_CLONED)) | ||||
| 			bio->bi_iter = btrfs_io_bio(bio)->iter; | ||||
| 
 | ||||
| 		bio_for_each_segment(bvec, bio, iter) { | ||||
| 			rbio->bio_pages[page_index + i] = bvec.bv_page; | ||||
| 			i++; | ||||
| 		} | ||||
| 	} | ||||
| 	spin_unlock_irq(&rbio->bio_list_lock); | ||||
| } | ||||
|  | @ -1423,11 +1430,14 @@ static int fail_bio_stripe(struct btrfs_raid_bio *rbio, | |||
|  */ | ||||
| static void set_bio_pages_uptodate(struct bio *bio) | ||||
| { | ||||
| 	struct bio_vec *bvec; | ||||
| 	int i; | ||||
| 	struct bio_vec bvec; | ||||
| 	struct bvec_iter iter; | ||||
| 
 | ||||
| 	bio_for_each_segment_all(bvec, bio, i) | ||||
| 		SetPageUptodate(bvec->bv_page); | ||||
| 	if (bio_flagged(bio, BIO_CLONED)) | ||||
| 		bio->bi_iter = btrfs_io_bio(bio)->iter; | ||||
| 
 | ||||
| 	bio_for_each_segment(bvec, bio, iter) | ||||
| 		SetPageUptodate(bvec.bv_page); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  |  | |||
|  | @ -1856,7 +1856,7 @@ out: | |||
|  */ | ||||
| static int will_overwrite_ref(struct send_ctx *sctx, u64 dir, u64 dir_gen, | ||||
| 			      const char *name, int name_len, | ||||
| 			      u64 *who_ino, u64 *who_gen) | ||||
| 			      u64 *who_ino, u64 *who_gen, u64 *who_mode) | ||||
| { | ||||
| 	int ret = 0; | ||||
| 	u64 gen; | ||||
|  | @ -1905,7 +1905,7 @@ static int will_overwrite_ref(struct send_ctx *sctx, u64 dir, u64 dir_gen, | |||
| 	if (other_inode > sctx->send_progress || | ||||
| 	    is_waiting_for_move(sctx, other_inode)) { | ||||
| 		ret = get_inode_info(sctx->parent_root, other_inode, NULL, | ||||
| 				who_gen, NULL, NULL, NULL, NULL); | ||||
| 				who_gen, who_mode, NULL, NULL, NULL); | ||||
| 		if (ret < 0) | ||||
| 			goto out; | ||||
| 
 | ||||
|  | @ -3683,6 +3683,36 @@ out: | |||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static int update_ref_path(struct send_ctx *sctx, struct recorded_ref *ref) | ||||
| { | ||||
| 	int ret; | ||||
| 	struct fs_path *new_path; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Our reference's name member points to its full_path member string, so | ||||
| 	 * we use here a new path. | ||||
| 	 */ | ||||
| 	new_path = fs_path_alloc(); | ||||
| 	if (!new_path) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	ret = get_cur_path(sctx, ref->dir, ref->dir_gen, new_path); | ||||
| 	if (ret < 0) { | ||||
| 		fs_path_free(new_path); | ||||
| 		return ret; | ||||
| 	} | ||||
| 	ret = fs_path_add(new_path, ref->name, ref->name_len); | ||||
| 	if (ret < 0) { | ||||
| 		fs_path_free(new_path); | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	fs_path_free(ref->full_path); | ||||
| 	set_ref_path(ref, new_path); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * This does all the move/link/unlink/rmdir magic. | ||||
|  */ | ||||
|  | @ -3696,10 +3726,12 @@ static int process_recorded_refs(struct send_ctx *sctx, int *pending_move) | |||
| 	struct fs_path *valid_path = NULL; | ||||
| 	u64 ow_inode = 0; | ||||
| 	u64 ow_gen; | ||||
| 	u64 ow_mode; | ||||
| 	int did_overwrite = 0; | ||||
| 	int is_orphan = 0; | ||||
| 	u64 last_dir_ino_rm = 0; | ||||
| 	bool can_rename = true; | ||||
| 	bool orphanized_dir = false; | ||||
| 	bool orphanized_ancestor = false; | ||||
| 
 | ||||
| 	btrfs_debug(fs_info, "process_recorded_refs %llu", sctx->cur_ino); | ||||
|  | @ -3798,7 +3830,7 @@ static int process_recorded_refs(struct send_ctx *sctx, int *pending_move) | |||
| 		 */ | ||||
| 		ret = will_overwrite_ref(sctx, cur->dir, cur->dir_gen, | ||||
| 				cur->name, cur->name_len, | ||||
| 				&ow_inode, &ow_gen); | ||||
| 				&ow_inode, &ow_gen, &ow_mode); | ||||
| 		if (ret < 0) | ||||
| 			goto out; | ||||
| 		if (ret) { | ||||
|  | @ -3815,6 +3847,8 @@ static int process_recorded_refs(struct send_ctx *sctx, int *pending_move) | |||
| 						cur->full_path); | ||||
| 				if (ret < 0) | ||||
| 					goto out; | ||||
| 				if (S_ISDIR(ow_mode)) | ||||
| 					orphanized_dir = true; | ||||
| 
 | ||||
| 				/*
 | ||||
| 				 * If ow_inode has its rename operation delayed | ||||
|  | @ -3920,6 +3954,18 @@ static int process_recorded_refs(struct send_ctx *sctx, int *pending_move) | |||
| 				if (ret < 0) | ||||
| 					goto out; | ||||
| 			} else { | ||||
| 				/*
 | ||||
| 				 * We might have previously orphanized an inode | ||||
| 				 * which is an ancestor of our current inode, | ||||
| 				 * so our reference's full path, which was | ||||
| 				 * computed before any such orphanizations, must | ||||
| 				 * be updated. | ||||
| 				 */ | ||||
| 				if (orphanized_dir) { | ||||
| 					ret = update_ref_path(sctx, cur); | ||||
| 					if (ret < 0) | ||||
| 						goto out; | ||||
| 				} | ||||
| 				ret = send_link(sctx, cur->full_path, | ||||
| 						valid_path); | ||||
| 				if (ret < 0) | ||||
|  | @ -3990,34 +4036,9 @@ static int process_recorded_refs(struct send_ctx *sctx, int *pending_move) | |||
| 				 * ancestor inode. | ||||
| 				 */ | ||||
| 				if (orphanized_ancestor) { | ||||
| 					struct fs_path *new_path; | ||||
| 
 | ||||
| 					/*
 | ||||
| 					 * Our reference's name member points to | ||||
| 					 * its full_path member string, so we | ||||
| 					 * use here a new path. | ||||
| 					 */ | ||||
| 					new_path = fs_path_alloc(); | ||||
| 					if (!new_path) { | ||||
| 						ret = -ENOMEM; | ||||
| 					ret = update_ref_path(sctx, cur); | ||||
| 					if (ret < 0) | ||||
| 						goto out; | ||||
| 					} | ||||
| 					ret = get_cur_path(sctx, cur->dir, | ||||
| 							   cur->dir_gen, | ||||
| 							   new_path); | ||||
| 					if (ret < 0) { | ||||
| 						fs_path_free(new_path); | ||||
| 						goto out; | ||||
| 					} | ||||
| 					ret = fs_path_add(new_path, | ||||
| 							  cur->name, | ||||
| 							  cur->name_len); | ||||
| 					if (ret < 0) { | ||||
| 						fs_path_free(new_path); | ||||
| 						goto out; | ||||
| 					} | ||||
| 					fs_path_free(cur->full_path); | ||||
| 					set_ref_path(cur, new_path); | ||||
| 				} | ||||
| 				ret = send_unlink(sctx, cur->full_path); | ||||
| 				if (ret < 0) | ||||
|  | @ -5249,15 +5270,12 @@ static int is_extent_unchanged(struct send_ctx *sctx, | |||
| 			goto out; | ||||
| 		} | ||||
| 
 | ||||
| 		right_disknr = btrfs_file_extent_disk_bytenr(eb, ei); | ||||
| 		if (right_type == BTRFS_FILE_EXTENT_INLINE) { | ||||
| 			right_len = btrfs_file_extent_inline_len(eb, slot, ei); | ||||
| 			right_len = PAGE_ALIGN(right_len); | ||||
| 		} else { | ||||
| 			right_len = btrfs_file_extent_num_bytes(eb, ei); | ||||
| 		} | ||||
| 		right_offset = btrfs_file_extent_offset(eb, ei); | ||||
| 		right_gen = btrfs_file_extent_generation(eb, ei); | ||||
| 
 | ||||
| 		/*
 | ||||
| 		 * Are we at extent 8? If yes, we know the extent is changed. | ||||
|  | @ -5282,6 +5300,10 @@ static int is_extent_unchanged(struct send_ctx *sctx, | |||
| 			goto out; | ||||
| 		} | ||||
| 
 | ||||
| 		right_disknr = btrfs_file_extent_disk_bytenr(eb, ei); | ||||
| 		right_offset = btrfs_file_extent_offset(eb, ei); | ||||
| 		right_gen = btrfs_file_extent_generation(eb, ei); | ||||
| 
 | ||||
| 		left_offset_fixed = left_offset; | ||||
| 		if (key.offset < ekey->offset) { | ||||
| 			/* Fix the right offset for 2a and 7. */ | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Linus Torvalds
						Linus Torvalds