[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[RFC][PATCH][cp] btrfs, nocow and cp --reflink

From: Goffredo Baroncelli
Subject: [RFC][PATCH][cp] btrfs, nocow and cp --reflink
Date: Wed, 25 May 2022 19:05:19 +0200
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Thunderbird/91.8.1

Hi All,

recently I discovered that BTRFS allow to reflink a file only if the flag 
FS_NOCOW_FL is the same on both source and destination.
In the end of this email I added a patch to "cp" to set the FS_NOCOW_FL flag 
according to the source.

Even tough this works, I am wondering if this is the expected/the least 
surprise behavior by/for any user. This is the reason why this email is tagged 
as RFC.

Without reflink, the default behavior is that the new file has the FS_NOCOW_FL 
flag set according to the parent directory; with this patch the flag would be 
the same as the source.

I am not sure that this is the correct behviour without warning the user of 
this change.

Another possibility, is to flip the NOCOW flag only if --reflink=always is 

Thoughts ?



diff --git a/src/copy.c b/src/copy.c
index b15d91990..41df45cd5 100644
--- a/src/copy.c
+++ b/src/copy.c
@@ -22,6 +22,8 @@
 #include <sys/ioctl.h>
 #include <sys/types.h>
 #include <selinux/selinux.h>
+#include <sys/vfs.h>
+#include <linux/magic.h>
 # include <hurd.h>
@@ -399,6 +401,32 @@ static inline int
 clone_file (int dest_fd, int src_fd)
 #ifdef FICLONE
+# ifdef __linux__
+  /* BTRFS requires that both source and dest have the same setting
+     about FS_NOCOW_FL */
+  int src_flags, dst_flags, r;
+  struct statfs sbuf;
+  r = fstatfs(dest_fd, &sbuf);
+  if (r < 0)
+    return r;
+  if (sbuf.f_type == BTRFS_SUPER_MAGIC || sbuf.f_type == BTRFS_TEST_MAGIC)
+    {
+      r = ioctl(src_fd, FS_IOC_GETFLAGS, &src_flags);
+      if (r < 0)
+        return r;
+      r = ioctl(dest_fd, FS_IOC_GETFLAGS, &dst_flags);
+      if (r < 0)
+        return r;
+      if ((src_flags ^ dst_flags) & FS_NOCOW_FL)
+        {
+          dst_flags ^= FS_NOCOW_FL;
+          r = ioctl(dest_fd, FS_IOC_SETFLAGS, &dst_flags);
+          if (r < 0)
+            return r;
+        }
+    }
+# endif
   return ioctl (dest_fd, FICLONE, src_fd);
   (void) dest_fd;

gpg Goffredo Baroncelli <>
Key fingerprint BBF5 1610 0B64 DAC6 5F7D  17B2 0EDA 9B37 8B82 E0B5

reply via email to

[Prev in Thread] Current Thread [Next in Thread]