]> 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>
Fri, 18 Sep 2026 21:36:15 +0000 (17:36 -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 d22ae2dcbe054c6f436d777d09d7d1f95eaf97e3..b206b42bc7ee665fdb0dfbf1663129007fa9ec58 100644 (file)
@@ -365,10 +365,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 bb77d46376d4bb2c1033f478f1a5ee422375e253..f22641241ce5efe5dffeef64e1ae8a39ba290bfc 100644 (file)
@@ -295,14 +295,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))