瀏覽代碼

Merge tag 'for-4.20-rc4-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux

Pull btrfs fixes from David Sterba:
 "Some of these bugs are being hit during testing so we'd like to get
  them merged, otherwise there are usual stability fixes for stable
  trees"

* tag 'for-4.20-rc4-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux:
  btrfs: relocation: set trans to be NULL after ending transaction
  Btrfs: fix race between enabling quotas and subvolume creation
  Btrfs: send, fix infinite loop due to directory rename dependencies
  Btrfs: ensure path name is null terminated at btrfs_control_ioctl
  Btrfs: fix rare chances for data loss when doing a fast fsync
  btrfs: Always try all copies when reading extent buffers
Linus Torvalds 6 年之前
父節點
當前提交
121b018f8c
共有 6 個文件被更改,包括 37 次插入14 次删除
  1. 1 10
      fs/btrfs/disk-io.c
  2. 24 0
      fs/btrfs/file.c
  3. 2 1
      fs/btrfs/qgroup.c
  4. 1 0
      fs/btrfs/relocation.c
  5. 8 3
      fs/btrfs/send.c
  6. 1 0
      fs/btrfs/super.c

+ 1 - 10
fs/btrfs/disk-io.c

@@ -477,9 +477,9 @@ static int btree_read_extent_buffer_pages(struct btrfs_fs_info *fs_info,
 	int mirror_num = 0;
 	int mirror_num = 0;
 	int failed_mirror = 0;
 	int failed_mirror = 0;
 
 
-	clear_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags);
 	io_tree = &BTRFS_I(fs_info->btree_inode)->io_tree;
 	io_tree = &BTRFS_I(fs_info->btree_inode)->io_tree;
 	while (1) {
 	while (1) {
+		clear_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags);
 		ret = read_extent_buffer_pages(io_tree, eb, WAIT_COMPLETE,
 		ret = read_extent_buffer_pages(io_tree, eb, WAIT_COMPLETE,
 					       mirror_num);
 					       mirror_num);
 		if (!ret) {
 		if (!ret) {
@@ -493,15 +493,6 @@ static int btree_read_extent_buffer_pages(struct btrfs_fs_info *fs_info,
 				break;
 				break;
 		}
 		}
 
 
-		/*
-		 * This buffer's crc is fine, but its contents are corrupted, so
-		 * there is no reason to read the other copies, they won't be
-		 * any less wrong.
-		 */
-		if (test_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags) ||
-		    ret == -EUCLEAN)
-			break;
-
 		num_copies = btrfs_num_copies(fs_info,
 		num_copies = btrfs_num_copies(fs_info,
 					      eb->start, eb->len);
 					      eb->start, eb->len);
 		if (num_copies == 1)
 		if (num_copies == 1)

+ 24 - 0
fs/btrfs/file.c

@@ -2088,6 +2088,30 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
 
 
 	atomic_inc(&root->log_batch);
 	atomic_inc(&root->log_batch);
 
 
+	/*
+	 * Before we acquired the inode's lock, someone may have dirtied more
+	 * pages in the target range. We need to make sure that writeback for
+	 * any such pages does not start while we are logging the inode, because
+	 * if it does, any of the following might happen when we are not doing a
+	 * full inode sync:
+	 *
+	 * 1) We log an extent after its writeback finishes but before its
+	 *    checksums are added to the csum tree, leading to -EIO errors
+	 *    when attempting to read the extent after a log replay.
+	 *
+	 * 2) We can end up logging an extent before its writeback finishes.
+	 *    Therefore after the log replay we will have a file extent item
+	 *    pointing to an unwritten extent (and no data checksums as well).
+	 *
+	 * So trigger writeback for any eventual new dirty pages and then we
+	 * wait for all ordered extents to complete below.
+	 */
+	ret = start_ordered_ops(inode, start, end);
+	if (ret) {
+		inode_unlock(inode);
+		goto out;
+	}
+
 	/*
 	/*
 	 * We have to do this here to avoid the priority inversion of waiting on
 	 * We have to do this here to avoid the priority inversion of waiting on
 	 * IO of a lower priority task while holding a transaciton open.
 	 * IO of a lower priority task while holding a transaciton open.

+ 2 - 1
fs/btrfs/qgroup.c

@@ -2659,7 +2659,7 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, u64 srcid,
 	int i;
 	int i;
 	u64 *i_qgroups;
 	u64 *i_qgroups;
 	struct btrfs_fs_info *fs_info = trans->fs_info;
 	struct btrfs_fs_info *fs_info = trans->fs_info;
-	struct btrfs_root *quota_root = fs_info->quota_root;
+	struct btrfs_root *quota_root;
 	struct btrfs_qgroup *srcgroup;
 	struct btrfs_qgroup *srcgroup;
 	struct btrfs_qgroup *dstgroup;
 	struct btrfs_qgroup *dstgroup;
 	u32 level_size = 0;
 	u32 level_size = 0;
@@ -2669,6 +2669,7 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, u64 srcid,
 	if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags))
 	if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags))
 		goto out;
 		goto out;
 
 
+	quota_root = fs_info->quota_root;
 	if (!quota_root) {
 	if (!quota_root) {
 		ret = -EINVAL;
 		ret = -EINVAL;
 		goto out;
 		goto out;

+ 1 - 0
fs/btrfs/relocation.c

@@ -3959,6 +3959,7 @@ static noinline_for_stack int relocate_block_group(struct reloc_control *rc)
 restart:
 restart:
 		if (update_backref_cache(trans, &rc->backref_cache)) {
 		if (update_backref_cache(trans, &rc->backref_cache)) {
 			btrfs_end_transaction(trans);
 			btrfs_end_transaction(trans);
+			trans = NULL;
 			continue;
 			continue;
 		}
 		}
 
 

+ 8 - 3
fs/btrfs/send.c

@@ -3340,7 +3340,8 @@ static void free_pending_move(struct send_ctx *sctx, struct pending_dir_move *m)
 	kfree(m);
 	kfree(m);
 }
 }
 
 
-static void tail_append_pending_moves(struct pending_dir_move *moves,
+static void tail_append_pending_moves(struct send_ctx *sctx,
+				      struct pending_dir_move *moves,
 				      struct list_head *stack)
 				      struct list_head *stack)
 {
 {
 	if (list_empty(&moves->list)) {
 	if (list_empty(&moves->list)) {
@@ -3351,6 +3352,10 @@ static void tail_append_pending_moves(struct pending_dir_move *moves,
 		list_add_tail(&moves->list, stack);
 		list_add_tail(&moves->list, stack);
 		list_splice_tail(&list, stack);
 		list_splice_tail(&list, stack);
 	}
 	}
+	if (!RB_EMPTY_NODE(&moves->node)) {
+		rb_erase(&moves->node, &sctx->pending_dir_moves);
+		RB_CLEAR_NODE(&moves->node);
+	}
 }
 }
 
 
 static int apply_children_dir_moves(struct send_ctx *sctx)
 static int apply_children_dir_moves(struct send_ctx *sctx)
@@ -3365,7 +3370,7 @@ static int apply_children_dir_moves(struct send_ctx *sctx)
 		return 0;
 		return 0;
 
 
 	INIT_LIST_HEAD(&stack);
 	INIT_LIST_HEAD(&stack);
-	tail_append_pending_moves(pm, &stack);
+	tail_append_pending_moves(sctx, pm, &stack);
 
 
 	while (!list_empty(&stack)) {
 	while (!list_empty(&stack)) {
 		pm = list_first_entry(&stack, struct pending_dir_move, list);
 		pm = list_first_entry(&stack, struct pending_dir_move, list);
@@ -3376,7 +3381,7 @@ static int apply_children_dir_moves(struct send_ctx *sctx)
 			goto out;
 			goto out;
 		pm = get_pending_dir_moves(sctx, parent_ino);
 		pm = get_pending_dir_moves(sctx, parent_ino);
 		if (pm)
 		if (pm)
-			tail_append_pending_moves(pm, &stack);
+			tail_append_pending_moves(sctx, pm, &stack);
 	}
 	}
 	return 0;
 	return 0;
 
 

+ 1 - 0
fs/btrfs/super.c

@@ -2237,6 +2237,7 @@ static long btrfs_control_ioctl(struct file *file, unsigned int cmd,
 	vol = memdup_user((void __user *)arg, sizeof(*vol));
 	vol = memdup_user((void __user *)arg, sizeof(*vol));
 	if (IS_ERR(vol))
 	if (IS_ERR(vol))
 		return PTR_ERR(vol);
 		return PTR_ERR(vol);
+	vol->name[BTRFS_PATH_NAME_MAX] = '\0';
 
 
 	switch (cmd) {
 	switch (cmd) {
 	case BTRFS_IOC_SCAN_DEV:
 	case BTRFS_IOC_SCAN_DEV: