From: koraynilay <koray.fra@gmail.com>
To: Chris Mason <clm@fb.com>, David Sterba <dsterba@suse.com>
Cc: Qu Wenruo <wqu@suse.com>,
Zygo Blaxell <ce3g8jdj@umail.furryterror.org>,
linux-btrfs@vger.kernel.org, koraynilay <koray.fra@gmail.com>
Subject: [PATCH v4 6/6] btrfs: preserve btrfs.compression when setting inode flags
Date: Tue, 25 Aug 2026 15:07:45 +0200 [thread overview]
Message-ID: <20260825130745.229008-7-koray.fra@gmail.com> (raw)
In-Reply-To: <20260825130745.229008-1-koray.fra@gmail.com>
Any call to FS_IOC_SETFLAGS (e.g. via chattr), even when no flag bits
change, and even for flags unrelated to compression, overwrites the
btrfs.compression property with the mount default compression type.
Example:
# mount ... -o compress=zstd ...
$ touch zero
$ setfattr -n btrfs.compression -v zlib zero
$ getfattr -n btrfs.compression zero | grep =
btrfs.compression="zlib"
$ lsattr zero
--------c------------- zero
$ chattr +A zero
$ lsattr zero
-------Ac------------- zero
$ getfattr -n btrfs.compression zero | grep =
btrfs.compression="zstd"
Here, `+A` modifies only the atime flag, but the compression property
was silently replaced. The same happens even if the ioctl writes back
the same flags value that was already set.
The problem is that btrfs_fileattr_set unconditionally regenerates the
compression string from fs_info->compress_type (or falls back to "zlib")
and overwrites any existing property.
Fix this by first checking for an existing per-inode compression
property and using it if present. Only fall back to fs_info->compress_type
or zlib when no property has been set. This ensures that inode-flag
updates no longer clobber user-configured compression settings.
Also move BTRFS_COMPRESS_PROP_MAX_LEN from props.c to props.h so it can
be used by ioctl.c, since it now requires a temporary buffer to write the
property string to.
[ Commit message and code slightly adapted from Zygo's patch for this same
issue ]
Reported-by: Zygo Blaxell <ce3g8jdj@umail.furryterror.org>
Suggested-by: Zygo Blaxell <ce3g8jdj@umail.furryterror.org>
Assisted-by: Gemini:3.1-pro antigravity-cli-1.1.7
Signed-off-by: koraynilay <koray.fra@gmail.com>
---
fs/btrfs/ioctl.c | 13 ++++++++++++-
fs/btrfs/props.c | 9 ---------
fs/btrfs/props.h | 9 +++++++++
3 files changed, 21 insertions(+), 10 deletions(-)
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 72bc9d4f7708..17c8c164cefc 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -288,6 +288,7 @@ int btrfs_fileattr_set(struct mnt_idmap *idmap,
unsigned int fsflags, old_fsflags;
int ret;
const char *comp = NULL;
+ char comp_buf[BTRFS_COMPRESS_PROP_MAX_LEN];
u32 inode_flags;
bool prop_set = false;
@@ -391,7 +392,17 @@ 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 compression is already enabled, we must reconstruct the
+ * full "algo:level" property string and write it back,
+ * otherwise any chattr + operation would reset the compression
+ * algorithm to the fs_info one, also removing the level.
+ */
+ comp = btrfs_compress_typelevel2str(inode->prop_compress,
+ inode->prop_compress_level,
+ comp_buf, sizeof(comp_buf));
+ 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 {
diff --git a/fs/btrfs/props.c b/fs/btrfs/props.c
index d8830f63984a..b95a1e7a96d2 100644
--- a/fs/btrfs/props.c
+++ b/fs/btrfs/props.c
@@ -18,15 +18,6 @@
#include "super.h"
#include "dir-item.h"
-/*
- * Max length of compression algorithm:level string.
- *
- * For now the longest possible string is "zstd:-15", which is
- * 8 characters + 1 terminating null byte.
- * Rounding it up to the closest power of 2 gives 16.
- */
-#define BTRFS_COMPRESS_PROP_MAX_LEN 16
-
#define BTRFS_PROP_HANDLERS_HT_BITS 8
static DEFINE_HASHTABLE(prop_handlers_ht, BTRFS_PROP_HANDLERS_HT_BITS);
diff --git a/fs/btrfs/props.h b/fs/btrfs/props.h
index 15d9a025c923..93b55a85a728 100644
--- a/fs/btrfs/props.h
+++ b/fs/btrfs/props.h
@@ -9,6 +9,15 @@
#include <linux/types.h>
#include <linux/compiler_types.h>
+/*
+ * Max length of compression algorithm:level string.
+ *
+ * For now the longest possible string is "zstd:-15", which is
+ * 8 characters + 1 terminating null byte.
+ * Rounding it up to the closest power of 2 gives 16.
+ */
+#define BTRFS_COMPRESS_PROP_MAX_LEN 16
+
struct btrfs_inode;
struct btrfs_path;
struct btrfs_trans_handle;
--
2.55.0
prev parent reply other threads:[~2026-08-25 13:08 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-25 13:07 [PATCH v4 0/6] btrfs: add per-inode compression levels in xattrs koraynilay
2026-08-25 13:07 ` [PATCH v4 1/6] btrfs: export btrfs_match_compress_type(), move it to compression.h koraynilay
2026-08-25 13:07 ` [PATCH v4 2/6] btrfs: also validate compression levels in btrfs_compress_is_valid_type() koraynilay
2026-08-25 13:07 ` [PATCH v4 3/6] btrfs: add per-inode compression levels in xattrs koraynilay
2026-08-25 13:07 ` [PATCH v4 4/6] btrfs: support inheritance for per-inode compression levels koraynilay
2026-08-25 13:07 ` [PATCH v4 5/6] btrfs: add btrfs_compress_typelevel2str() helper koraynilay
2026-08-25 13:07 ` koraynilay [this message]
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=20260825130745.229008-7-koray.fra@gmail.com \
--to=koray.fra@gmail.com \
--cc=ce3g8jdj@umail.furryterror.org \
--cc=clm@fb.com \
--cc=dsterba@suse.com \
--cc=linux-btrfs@vger.kernel.org \
--cc=wqu@suse.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