Commit b10c31b7 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull btrfs fixes from David Sterba:

 - fix delayed inode tracking in xarray, eviction can race with
   insertion and leave behind a disconnected inode

 - on systems with large page (64K) and small block size (4K) fix
   compression read that can return partially filled folio

 - slightly relax compression option format for backward compatibility,
   allow to specify level for LZO although there's only one

 - fix simple quota accounting of compressed extents

 - validate minimum device size in 'device add'

 - update maintainers' entry

* tag 'for-6.17-rc5-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux:
  btrfs: don't allow adding block device of less than 1 MB
  MAINTAINERS: update btrfs entry
  btrfs: fix subvolume deletion lockup caused by inodes xarray race
  btrfs: fix corruption reading compressed range when block size is smaller than page size
  btrfs: accept and ignore compression level for lzo
  btrfs: fix squota compressed stats leak
parents 02ffd6f8 3d126747
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -5258,7 +5258,6 @@ F: drivers/gpio/gpio-bt8xx.c
BTRFS FILE SYSTEM
M:	Chris Mason <clm@fb.com>
M:	Josef Bacik <josef@toxicpanda.com>
M:	David Sterba <dsterba@suse.com>
L:	linux-btrfs@vger.kernel.org
S:	Maintained
+30 −10
Original line number Diff line number Diff line
@@ -111,6 +111,24 @@ struct btrfs_bio_ctrl {
	 */
	unsigned long submit_bitmap;
	struct readahead_control *ractl;

	/*
	 * The start offset of the last used extent map by a read operation.
	 *
	 * This is for proper compressed read merge.
	 * U64_MAX means we are starting the read and have made no progress yet.
	 *
	 * The current btrfs_bio_is_contig() only uses disk_bytenr as
	 * the condition to check if the read can be merged with previous
	 * bio, which is not correct. E.g. two file extents pointing to the
	 * same extent but with different offset.
	 *
	 * So here we need to do extra checks to only merge reads that are
	 * covered by the same extent map.
	 * Just extent_map::start will be enough, as they are unique
	 * inside the same inode.
	 */
	u64 last_em_start;
};

static void submit_one_bio(struct btrfs_bio_ctrl *bio_ctrl)
@@ -909,7 +927,7 @@ static void btrfs_readahead_expand(struct readahead_control *ractl,
 * return 0 on success, otherwise return error
 */
static int btrfs_do_readpage(struct folio *folio, struct extent_map **em_cached,
		      struct btrfs_bio_ctrl *bio_ctrl, u64 *prev_em_start)
			     struct btrfs_bio_ctrl *bio_ctrl)
{
	struct inode *inode = folio->mapping->host;
	struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
@@ -1019,12 +1037,11 @@ static int btrfs_do_readpage(struct folio *folio, struct extent_map **em_cached,
		 * non-optimal behavior (submitting 2 bios for the same extent).
		 */
		if (compress_type != BTRFS_COMPRESS_NONE &&
		    prev_em_start && *prev_em_start != (u64)-1 &&
		    *prev_em_start != em->start)
		    bio_ctrl->last_em_start != U64_MAX &&
		    bio_ctrl->last_em_start != em->start)
			force_bio_submit = true;

		if (prev_em_start)
			*prev_em_start = em->start;
		bio_ctrl->last_em_start = em->start;

		btrfs_free_extent_map(em);
		em = NULL;
@@ -1238,12 +1255,15 @@ int btrfs_read_folio(struct file *file, struct folio *folio)
	const u64 start = folio_pos(folio);
	const u64 end = start + folio_size(folio) - 1;
	struct extent_state *cached_state = NULL;
	struct btrfs_bio_ctrl bio_ctrl = { .opf = REQ_OP_READ };
	struct btrfs_bio_ctrl bio_ctrl = {
		.opf = REQ_OP_READ,
		.last_em_start = U64_MAX,
	};
	struct extent_map *em_cached = NULL;
	int ret;

	lock_extents_for_read(inode, start, end, &cached_state);
	ret = btrfs_do_readpage(folio, &em_cached, &bio_ctrl, NULL);
	ret = btrfs_do_readpage(folio, &em_cached, &bio_ctrl);
	btrfs_unlock_extent(&inode->io_tree, start, end, &cached_state);

	btrfs_free_extent_map(em_cached);
@@ -2583,7 +2603,8 @@ void btrfs_readahead(struct readahead_control *rac)
{
	struct btrfs_bio_ctrl bio_ctrl = {
		.opf = REQ_OP_READ | REQ_RAHEAD,
		.ractl = rac
		.ractl = rac,
		.last_em_start = U64_MAX,
	};
	struct folio *folio;
	struct btrfs_inode *inode = BTRFS_I(rac->mapping->host);
@@ -2591,12 +2612,11 @@ void btrfs_readahead(struct readahead_control *rac)
	const u64 end = start + readahead_length(rac) - 1;
	struct extent_state *cached_state = NULL;
	struct extent_map *em_cached = NULL;
	u64 prev_em_start = (u64)-1;

	lock_extents_for_read(inode, start, end, &cached_state);

	while ((folio = readahead_folio(rac)) != NULL)
		btrfs_do_readpage(folio, &em_cached, &bio_ctrl, &prev_em_start);
		btrfs_do_readpage(folio, &em_cached, &bio_ctrl);

	btrfs_unlock_extent(&inode->io_tree, start, end, &cached_state);

+11 −1
Original line number Diff line number Diff line
@@ -5696,7 +5696,17 @@ static void btrfs_del_inode_from_root(struct btrfs_inode *inode)
	bool empty = false;

	xa_lock(&root->inodes);
	entry = __xa_erase(&root->inodes, btrfs_ino(inode));
	/*
	 * This btrfs_inode is being freed and has already been unhashed at this
	 * point. It's possible that another btrfs_inode has already been
	 * allocated for the same inode and inserted itself into the root, so
	 * don't delete it in that case.
	 *
	 * Note that this shouldn't need to allocate memory, so the gfp flags
	 * don't really matter.
	 */
	entry = __xa_cmpxchg(&root->inodes, btrfs_ino(inode), inode, NULL,
			     GFP_ATOMIC);
	if (entry == inode)
		empty = xa_empty(&root->inodes);
	xa_unlock(&root->inodes);
+4 −2
Original line number Diff line number Diff line
@@ -1455,6 +1455,7 @@ static int __qgroup_excl_accounting(struct btrfs_fs_info *fs_info, u64 ref_root,
	struct btrfs_qgroup *qgroup;
	LIST_HEAD(qgroup_list);
	u64 num_bytes = src->excl;
	u64 num_bytes_cmpr = src->excl_cmpr;
	int ret = 0;

	qgroup = find_qgroup_rb(fs_info, ref_root);
@@ -1466,11 +1467,12 @@ static int __qgroup_excl_accounting(struct btrfs_fs_info *fs_info, u64 ref_root,
		struct btrfs_qgroup_list *glist;

		qgroup->rfer += sign * num_bytes;
		qgroup->rfer_cmpr += sign * num_bytes;
		qgroup->rfer_cmpr += sign * num_bytes_cmpr;

		WARN_ON(sign < 0 && qgroup->excl < num_bytes);
		WARN_ON(sign < 0 && qgroup->excl_cmpr < num_bytes_cmpr);
		qgroup->excl += sign * num_bytes;
		qgroup->excl_cmpr += sign * num_bytes;
		qgroup->excl_cmpr += sign * num_bytes_cmpr;

		if (sign > 0)
			qgroup_rsv_add_by_qgroup(fs_info, qgroup, src);
+6 −3
Original line number Diff line number Diff line
@@ -299,9 +299,12 @@ static int btrfs_parse_compress(struct btrfs_fs_context *ctx,
		btrfs_set_opt(ctx->mount_opt, COMPRESS);
		btrfs_clear_opt(ctx->mount_opt, NODATACOW);
		btrfs_clear_opt(ctx->mount_opt, NODATASUM);
	} else if (btrfs_match_compress_type(string, "lzo", false)) {
	} else if (btrfs_match_compress_type(string, "lzo", true)) {
		ctx->compress_type = BTRFS_COMPRESS_LZO;
		ctx->compress_level = 0;
		ctx->compress_level = btrfs_compress_str2level(BTRFS_COMPRESS_LZO,
							       string + 3);
		if (string[3] == ':' && string[4])
			btrfs_warn(NULL, "Compression level ignored for LZO");
		btrfs_set_opt(ctx->mount_opt, COMPRESS);
		btrfs_clear_opt(ctx->mount_opt, NODATACOW);
		btrfs_clear_opt(ctx->mount_opt, NODATASUM);
@@ -1079,7 +1082,7 @@ static int btrfs_show_options(struct seq_file *seq, struct dentry *dentry)
			seq_printf(seq, ",compress-force=%s", compress_type);
		else
			seq_printf(seq, ",compress=%s", compress_type);
		if (info->compress_level)
		if (info->compress_level && info->compress_type != BTRFS_COMPRESS_LZO)
			seq_printf(seq, ":%d", info->compress_level);
	}
	if (btrfs_test_opt(info, NOSSD))
Loading