]> git.hungrycats.org Git - linux/commitdiff
btrfs: allow NODATACOW | NOCOMPRESS
authorZygo Blaxell <ce3g8jdj@umail.furryterror.org>
Sun, 17 Aug 2025 20:57:07 +0000 (16:57 -0400)
committerZygo Blaxell <ce3g8jdj@umail.furryterror.org>
Wed, 16 Sep 2026 21:39:58 +0000 (17:39 -0400)
Commit f37c563bab42 ("btrfs: add missing check for nocow and compression
inode flags") added conflict checks for certain inode flag combinations,
and commit 0e852ab8974c ("btrfs: do not allow compression on nodatacow
files") extended the same logic to xattrs.

Both commits also forbade the combination of FS_NOCOW_FL (NODATACOW)
and FS_NOCOMP_FL (NOCOMPRESS).  This restriction is undocumented, has
no technical basis, and provides no benefit.  NODATACOW files cannot be
compressed in any case, so the NOCOMPRESS bit is a no-op:  behavior is
the same whether the flag is present or not.

Forcing an unnecessary conflict makes inode flags harder to use.
Portable applications may inherit COMPRESS, NOCOMPRESS, or NODATACOW bits
from parent directories and combine them with unrelated flags such as
IMMUTABLE or NOATIME.  Rejecting otherwise valid flag sets with EINVAL
creates surprises for applications that do not know about btrfs-specific
interactions and only touch the flags they care about.

Fix by permitting the combination of NODATACOW and NOCOMPRESS, both via
FS_IOC_SETFLAGS and by setting btrfs.compression to "no"/"none" through
xattrs.

Fixes: f37c563bab42 ("btrfs: add missing check for nocow and compression inode flags")
Fixes: 0e852ab8974c ("btrfs: do not allow compression on nodatacow files")
Signed-off-by: Zygo Blaxell <ce3g8jdj@umail.furryterror.org>
fs/btrfs/ioctl.c
fs/btrfs/props.c

index 9e99236d3989a2bb15aa8251e4d4e6f3c4274246..2cd89e88332c164531495c043db6b3f8ee5129ef 100644 (file)
@@ -340,10 +340,10 @@ int btrfs_fileattr_set(struct mnt_idmap *idmap,
                 * are not changed.
                 */
                if ((inode_flags & BTRFS_INODE_NODATACOW) &&
-                   (fsflags & (FS_COMPR_FL | FS_NOCOMP_FL))) {
+                   (fsflags & FS_COMPR_FL)) {
                        old_fsflags = btrfs_inode_flags_to_fsflags(inode);
-                       if ((old_fsflags & (FS_NOCOW_FL | FS_COMPR_FL | FS_NOCOMP_FL)) !=
-                           (fsflags & (FS_NOCOW_FL | FS_COMPR_FL | FS_NOCOMP_FL)))
+                       if ((old_fsflags & (FS_NOCOW_FL | FS_COMPR_FL)) !=
+                           (fsflags & (FS_NOCOW_FL | FS_COMPR_FL)))
                                return -EINVAL;
                }
        } else {
index adc956432d2f1501d27ebeed3e7c437715361bf7..8d25e517fa76a503a9f7d89b30ae4fc70dcdb345 100644 (file)
@@ -285,14 +285,14 @@ int btrfs_load_inode_props(struct btrfs_inode *inode, struct btrfs_path *path)
 static int prop_compression_validate(const struct btrfs_inode *inode,
                                     const char *value, size_t len)
 {
-       if (!btrfs_inode_can_compress(inode))
-               return -EINVAL;
-
        if (!value)
                return 0;
 
-       if (btrfs_compress_is_valid_type(value, len))
+       if (btrfs_compress_is_valid_type(value, len)) {
+               if (!btrfs_inode_can_compress(inode))
+                       return -EINVAL;
                return 0;
+       }
 
        if ((len == 2 && strncmp("no", value, 2) == 0) ||
            (len == 4 && strncmp("none", value, 4) == 0))