Commit b6c1f1ec authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull btrfs fixes from David Sterba:
 "A  more fixes for recently reported or discovered problems:

   - fix corner case of send that would generate potentially large
     stream of zeros if there's a hole at the end of the file

   - fix chunk validation in zoned mode on conventional zones, it was
     possible to create chunks that would not be allowed on sequential
     zones

   - fix validation of dev-replace ioctl filenames

   - fix KCSAN warnings about access to block reserve struct members"

* tag 'for-6.8-rc6-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux:
  btrfs: fix data race at btrfs_use_block_rsv() when accessing block reserve
  btrfs: fix data races when accessing the reserved amount of block reserves
  btrfs: send: don't issue unnecessary zero writes for trailing hole
  btrfs: dev-replace: properly validate device names
  btrfs: zoned: don't skip block group profile checks on conventional zones
parents c8e31462 c7bb26b8
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -494,7 +494,7 @@ struct btrfs_block_rsv *btrfs_use_block_rsv(struct btrfs_trans_handle *trans,

	block_rsv = get_block_rsv(trans, root);

	if (unlikely(block_rsv->size == 0))
	if (unlikely(btrfs_block_rsv_size(block_rsv) == 0))
		goto try_reserve;
again:
	ret = btrfs_block_rsv_use_bytes(block_rsv, blocksize);
+32 −0
Original line number Diff line number Diff line
@@ -101,4 +101,36 @@ static inline bool btrfs_block_rsv_full(const struct btrfs_block_rsv *rsv)
	return data_race(rsv->full);
}

/*
 * Get the reserved mount of a block reserve in a context where getting a stale
 * value is acceptable, instead of accessing it directly and trigger data race
 * warning from KCSAN.
 */
static inline u64 btrfs_block_rsv_reserved(struct btrfs_block_rsv *rsv)
{
	u64 ret;

	spin_lock(&rsv->lock);
	ret = rsv->reserved;
	spin_unlock(&rsv->lock);

	return ret;
}

/*
 * Get the size of a block reserve in a context where getting a stale value is
 * acceptable, instead of accessing it directly and trigger data race warning
 * from KCSAN.
 */
static inline u64 btrfs_block_rsv_size(struct btrfs_block_rsv *rsv)
{
	u64 ret;

	spin_lock(&rsv->lock);
	ret = rsv->size;
	spin_unlock(&rsv->lock);

	return ret;
}

#endif /* BTRFS_BLOCK_RSV_H */
+20 −4
Original line number Diff line number Diff line
@@ -725,6 +725,23 @@ static int btrfs_dev_replace_start(struct btrfs_fs_info *fs_info,
	return ret;
}

static int btrfs_check_replace_dev_names(struct btrfs_ioctl_dev_replace_args *args)
{
	if (args->start.srcdevid == 0) {
		if (memchr(args->start.srcdev_name, 0,
			   sizeof(args->start.srcdev_name)) == NULL)
			return -ENAMETOOLONG;
	} else {
		args->start.srcdev_name[0] = 0;
	}

	if (memchr(args->start.tgtdev_name, 0,
		   sizeof(args->start.tgtdev_name)) == NULL)
	    return -ENAMETOOLONG;

	return 0;
}

int btrfs_dev_replace_by_ioctl(struct btrfs_fs_info *fs_info,
			    struct btrfs_ioctl_dev_replace_args *args)
{
@@ -737,10 +754,9 @@ int btrfs_dev_replace_by_ioctl(struct btrfs_fs_info *fs_info,
	default:
		return -EINVAL;
	}

	if ((args->start.srcdevid == 0 && args->start.srcdev_name[0] == '\0') ||
	    args->start.tgtdev_name[0] == '\0')
		return -EINVAL;
	ret = btrfs_check_replace_dev_names(args);
	if (ret < 0)
		return ret;

	ret = btrfs_dev_replace_start(fs_info, args->start.tgtdev_name,
					args->start.srcdevid,
+13 −4
Original line number Diff line number Diff line
@@ -6705,11 +6705,20 @@ static int finish_inode_if_needed(struct send_ctx *sctx, int at_end)
				if (ret)
					goto out;
			}
			if (sctx->cur_inode_last_extent <
			    sctx->cur_inode_size) {
			if (sctx->cur_inode_last_extent < sctx->cur_inode_size) {
				ret = range_is_hole_in_parent(sctx,
						      sctx->cur_inode_last_extent,
						      sctx->cur_inode_size);
				if (ret < 0) {
					goto out;
				} else if (ret == 0) {
					ret = send_hole(sctx, sctx->cur_inode_size);
				if (ret)
					if (ret < 0)
						goto out;
				} else {
					/* Range is already a hole, skip. */
					ret = 0;
				}
			}
		}
		if (need_truncate) {
+13 −13
Original line number Diff line number Diff line
@@ -856,7 +856,7 @@ btrfs_calc_reclaim_metadata_size(struct btrfs_fs_info *fs_info,
static bool need_preemptive_reclaim(struct btrfs_fs_info *fs_info,
				    struct btrfs_space_info *space_info)
{
	u64 global_rsv_size = fs_info->global_block_rsv.reserved;
	const u64 global_rsv_size = btrfs_block_rsv_reserved(&fs_info->global_block_rsv);
	u64 ordered, delalloc;
	u64 thresh;
	u64 used;
@@ -956,8 +956,8 @@ static bool need_preemptive_reclaim(struct btrfs_fs_info *fs_info,
	ordered = percpu_counter_read_positive(&fs_info->ordered_bytes) >> 1;
	delalloc = percpu_counter_read_positive(&fs_info->delalloc_bytes);
	if (ordered >= delalloc)
		used += fs_info->delayed_refs_rsv.reserved +
			fs_info->delayed_block_rsv.reserved;
		used += btrfs_block_rsv_reserved(&fs_info->delayed_refs_rsv) +
			btrfs_block_rsv_reserved(&fs_info->delayed_block_rsv);
	else
		used += space_info->bytes_may_use - global_rsv_size;

@@ -1173,7 +1173,7 @@ static void btrfs_preempt_reclaim_metadata_space(struct work_struct *work)
		enum btrfs_flush_state flush;
		u64 delalloc_size = 0;
		u64 to_reclaim, block_rsv_size;
		u64 global_rsv_size = global_rsv->reserved;
		const u64 global_rsv_size = btrfs_block_rsv_reserved(global_rsv);

		loops++;

@@ -1185,9 +1185,9 @@ static void btrfs_preempt_reclaim_metadata_space(struct work_struct *work)
		 * assume it's tied up in delalloc reservations.
		 */
		block_rsv_size = global_rsv_size +
			delayed_block_rsv->reserved +
			delayed_refs_rsv->reserved +
			trans_rsv->reserved;
			btrfs_block_rsv_reserved(delayed_block_rsv) +
			btrfs_block_rsv_reserved(delayed_refs_rsv) +
			btrfs_block_rsv_reserved(trans_rsv);
		if (block_rsv_size < space_info->bytes_may_use)
			delalloc_size = space_info->bytes_may_use - block_rsv_size;

@@ -1207,16 +1207,16 @@ static void btrfs_preempt_reclaim_metadata_space(struct work_struct *work)
			to_reclaim = delalloc_size;
			flush = FLUSH_DELALLOC;
		} else if (space_info->bytes_pinned >
			   (delayed_block_rsv->reserved +
			    delayed_refs_rsv->reserved)) {
			   (btrfs_block_rsv_reserved(delayed_block_rsv) +
			    btrfs_block_rsv_reserved(delayed_refs_rsv))) {
			to_reclaim = space_info->bytes_pinned;
			flush = COMMIT_TRANS;
		} else if (delayed_block_rsv->reserved >
			   delayed_refs_rsv->reserved) {
			to_reclaim = delayed_block_rsv->reserved;
		} else if (btrfs_block_rsv_reserved(delayed_block_rsv) >
			   btrfs_block_rsv_reserved(delayed_refs_rsv)) {
			to_reclaim = btrfs_block_rsv_reserved(delayed_block_rsv);
			flush = FLUSH_DELAYED_ITEMS_NR;
		} else {
			to_reclaim = delayed_refs_rsv->reserved;
			to_reclaim = btrfs_block_rsv_reserved(delayed_refs_rsv);
			flush = FLUSH_DELAYED_REFS_NR;
		}

Loading