From: Qu Wenruo <quwenruo.btrfs@gmx.com>
To: Sam Ho <samho@synology.com>, clm@fb.com, dsterba@suse.com
Cc: linux-btrfs@vger.kernel.org
Subject: Re: [PATCH] btrfs: preserve the compression property when other inode flags change
Date: Fri, 14 Aug 2026 18:28:25 +0930 [thread overview]
Message-ID: <f13ee8ae-aae1-4877-b4e9-5ff82ec075d5@gmx.com> (raw)
In-Reply-To: <20260814051406.1244006-1-samho@synology.com>
在 2026/8/14 14:44, Sam Ho 写道:
> Setting the compression property on an inode also sets BTRFS_INODE_COMPRESS
> on it, and btrfs_inode_flags_to_fsflags() reports that back as FS_COMPR_FL
> to FS_IOC_GETFLAGS. chattr(1), like any other FS_IOC_SETFLAGS caller, reads
> the current flags, flips only the bit the user asked for and writes the
> whole set back, so a request as unrelated as "chattr +i" reaches
> btrfs_fileattr_set() with FS_COMPR_FL set.
>
> btrfs_fileattr_set() takes that as a request to enable compression and
> overwrites the compression property with the algorithm from the mount
> options, falling back to zlib when the filesystem was not mounted with
> -o compress. The algorithm the user selected is silently replaced:
>
> # btrfs property set /mnt/foo compression zstd
> # btrfs property get /mnt/foo compression
> compression=zstd
> # chattr +i /mnt/foo
> # btrfs property get /mnt/foo compression
> compression=zlib
>
> Every chattr operation triggers this, not just +i, and directories are
> affected as well, so files created afterwards inherit the wrong algorithm
> too. On a filesystem mounted with -o compress=lzo the property is replaced
> with lzo instead. Recovering needs a chattr -i first, because the immutable
> flag rejects the setxattr that "btrfs property set" issues.
>
> Only pick the default algorithm when compression is actually being enabled
> by this call, that is when FS_COMPR_FL was not set before, and otherwise
> keep the algorithm recorded in the property. Inodes that have the compress
> flag set but no property still get the default, so they behave as before.
>
> Signed-off-by: Sam Ho <samho@synology.com>
The analyze looks good to me.
Although a minor nitpick related to the compression checks.
> ---
> fs/btrfs/ioctl.c | 22 +++++++++++++++++++---
> 1 file changed, 19 insertions(+), 3 deletions(-)
>
> diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
> index baa645e98812..2e54694f06f7 100644
> --- a/fs/btrfs/ioctl.c
> +++ b/fs/btrfs/ioctl.c
> @@ -384,9 +384,25 @@ int btrfs_fileattr_set(struct mnt_idmap *idmap,
> inode_flags |= BTRFS_INODE_COMPRESS;
> inode_flags &= ~BTRFS_INODE_NOCOMPRESS;
>
> - comp = btrfs_compress_type2str(fs_info->compress_type);
> - if (!comp || comp[0] == 0)
> - comp = btrfs_compress_type2str(BTRFS_COMPRESS_ZLIB);
> + /*
> + * If compression was already enabled, keep the algorithm that
> + * is recorded in the compression property. Otherwise changing
> + * an unrelated attribute would reset it to the mount default,
> + * since FS_IOC_SETFLAGS callers pass back the whole flag set
> + * they got from FS_IOC_GETFLAGS.
> + *
> + * Fall back to the default when compression is being enabled
> + * by this call, or when the inode has the compress flag set
> + * but no property, which is possible on filesystems touched by
> + * kernels that did not keep the two in sync.
> + */
> + if (old_fsflags & FS_COMPR_FL)
> + comp = btrfs_compress_type2str(inode->prop_compress);
I do not think we need to always use the string.
We can directly use the compression type and convert it to string at the
last second.
And we can skip the old_fsflags check and directly check
inode->prop_compress.
E.g. something like the following will be a little easier to read:
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index ebfb258161c8..befc0df0d5ab 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -384,6 +384,7 @@ int btrfs_fileattr_set(struct mnt_idmap *idmap,
inode_flags &= ~BTRFS_INODE_COMPRESS;
inode_flags |= BTRFS_INODE_NOCOMPRESS;
} else if (fsflags & FS_COMPR_FL) {
+ enum btrfs_compression_type comp_type;
if (IS_SWAPFILE(&inode->vfs_inode))
return -ETXTBSY;
@@ -391,9 +392,13 @@ int btrfs_fileattr_set(struct mnt_idmap *idmap,
inode_flags |= BTRFS_INODE_COMPRESS;
inode_flags &= ~BTRFS_INODE_NOCOMPRESS;
- comp = btrfs_compress_type2str(fs_info->compress_type);
- if (!comp || comp[0] == 0)
- comp = btrfs_compress_type2str(BTRFS_COMPRESS_ZLIB);
+ if (inode->prop_compress)
+ comp_type = inode->prop_compress;
+ else if (fs_info->compress_type)
+ comp_type = fs_info->compress_type;
+ else
+ comp_type = BTRFS_COMPRESS_ZLIB;
+ comp = btrfs_compress_type2str(comp_type);
} else {
inode_flags &= ~(BTRFS_INODE_COMPRESS |
BTRFS_INODE_NOCOMPRESS);
}
Thanks,
Qu
> + if (!comp || comp[0] == 0) {
> + comp = btrfs_compress_type2str(fs_info->compress_type);
> + if (!comp || comp[0] == 0)
> + comp = btrfs_compress_type2str(BTRFS_COMPRESS_ZLIB);
> + }
> } else {
> inode_flags &= ~(BTRFS_INODE_COMPRESS | BTRFS_INODE_NOCOMPRESS);
> }
next prev parent reply other threads:[~2026-08-14 8:58 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-14 5:14 [PATCH] btrfs: preserve the compression property when other inode flags change Sam Ho
2026-08-14 8:58 ` Qu Wenruo [this message]
2026-08-14 13:01 ` [PATCH v2] " Sam Ho
2026-08-14 22:08 ` Qu Wenruo
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=f13ee8ae-aae1-4877-b4e9-5ff82ec075d5@gmx.com \
--to=quwenruo.btrfs@gmx.com \
--cc=clm@fb.com \
--cc=dsterba@suse.com \
--cc=linux-btrfs@vger.kernel.org \
--cc=samho@synology.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox