coreutils
[Top][All Lists]
Advanced

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

cp/reflink support for OCFS2


From: jeff.liu
Subject: cp/reflink support for OCFS2
Date: Tue, 03 May 2011 22:47:16 +0800
User-agent: Thunderbird 2.0.0.14 (X11/20080505)

Hello All,

I'd like to introduce the ocfs2 reflink support to cp(1) when it was called with
"--reflink=[WHEN]".
With this patch, `cp' will try OCFS2 reflink first, if it fails with EEXIST, 
IMHO, it definitely
means the user is intended to perform reflink on OCFS2, but the destination 
file is already exists,
so set the retval = false and return, or try Btrfs clone again.

I have done some tests, includes reflink on OCFS2, reflink to an existing file, 
reflink files
cross-filesystems, and reflink attributes only, all works fine.

For the test automation, the existing reflink test are presume the tests 
running on either file
systems with Cow support IMO, maybe we can improve them with real filesystems 
on loop device?

Also, the old bug ticket for this topic will be closed at:
http://lists.gnu.org/archive/html/bug-coreutils/2010-04/msg00185.html

The patch was shown as following,

>From 34556c4e36effc165032724cd37e6a4d2682f880 Mon Sep 17 00:00:00 2001
From: Jie Liu <address@hidden>
Date: Tue, 3 May 2011 22:21:41 +0800
Subject: [PATCH 1/1] copy: add OCFS2 reflink support

* src/copy.c (copy_reg): When cp is invoked with '--reflink=[WHEN]', try
  OCFS2 reflink file first, if it fails, try btrfs clone file later if
  possible.  The reflink will fails with EEXIST if the destination file
  is already exists on OCFS2, in this case, it means the user is intended
  to do OCFS2 reflink rather than btrfs clone, so we need not try the latter.

Signed-off-by: Jie Liu <address@hidden>
---
 src/copy.c |   98 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 90 insertions(+), 8 deletions(-)

diff --git a/src/copy.c b/src/copy.c
index 801a474..2ef0436 100644
--- a/src/copy.c
+++ b/src/copy.c
@@ -234,6 +234,46 @@ sparse_copy (int src_fd, int dest_fd, char *buf, size_t 
buf_size,
   return true;
 }

+/* Perform the OCFS2 CoW reflink ioctl(2) operation if possible.
+   When using '-p' option, the file's default attributes(i.e. mode,timestamp,
+   ownership and security context if possbile) are reflinked to the destination
+   file as well, we will then skip over the standard preserve process for such
+   attributes.  Upon success, return 0, Otherwise, return -1 and set errno.  */
+static inline int
+reflink_file (char const *src_name, char const *dst_name,
+              int src_fd, bool preserve_attrs)
+{
+#ifdef __linux__
+# ifndef REFLINK_ATTR_NONE
+#  define REFLINK_ATTR_NONE 0
+# endif
+# ifndef REFLINK_ATTR_PRESERVE
+#  define REFLINK_ATTR_PRESERVE 1
+# endif
+# ifndef OCFS2_IOC_REFLINK
+   struct reflink_arguments {
+     uint64_t old_path;
+     uint64_t new_path;
+     uint64_t preserve;
+   };
+#  define OCFS2_IOC_REFLINK _IOW ('o', 4, struct reflink_arguments)
+# endif
+  struct reflink_arguments args = {
+    .old_path = (unsigned long) src_name,
+    .new_path = (unsigned long) dst_name,
+    .preserve = preserve_attrs ? REFLINK_ATTR_PRESERVE : REFLINK_ATTR_NONE,
+  };
+  return ioctl (src_fd, OCFS2_IOC_REFLINK, &args);
+#else
+  (void) src_name;
+  (void) dst_name;
+  (void) src_fd;
+  (void) preserve_attrs;
+  errno = ENOTSUP;
+  return -1;
+#endif
+}
+
 /* Perform the O(1) btrfs clone operation, if possible.
    Upon success, return 0.  Otherwise, return -1 and set errno.  */
 static inline int
@@ -838,6 +878,45 @@ copy_reg (char const *src_name, char const *dst_name,
       goto close_src_desc;
     }

+  /* When cp is invoked with '--reflink=[WHEN]', try to do OCFS2 reflink
+     ioctl(2) first, if it fails, try btrfs clone file later if possible.
+     The reason why perform those operations separately is because `cp'
+     will create the destination file if it is a '*new_dst'.  In this case,
+     we have to unlink(2) it firstly, otherwise, OCFS2 reflink will fail with
+     'EEXIST'.  */
+  bool reflink_ok = false;
+  if (data_copy_required && x->reflink_mode)
+    {
+      bool preserve_attributes = (x->preserve_ownership
+                                  && x->preserve_mode
+                                  && x->preserve_timestamps);
+      reflink_ok = reflink_file (src_name, dst_name, source_desc,
+                                 preserve_attributes) == 0;
+      if (reflink_ok)
+        {
+          *new_dst = false;
+
+          /* Skip over the standard attributes preserve process
+             if reflink succeeds and they are already reflinked.  */
+          if (preserve_attributes)
+            goto close_src_desc;
+        }
+      else
+        {
+          /* When the destination file is aready exists on OCFS2, the
+             above reflink should fails with EEXIST.  If that happens,
+             we need not try btrfs clone again since it means the user
+             is definitely want a OCFS2 reflink.  */
+          if (errno == EEXIST)
+            {
+              error (0, errno, _("failed to reflink %s from %s"),
+                     quote_n (0, dst_name), quote_n (1, src_name));
+              return_val = false;
+              goto close_src_desc;
+            }
+        }
+    }
+
   /* The semantics of the following open calls are mandated
      by the specs for both cp and mv.  */
   if (! *new_dst)
@@ -969,17 +1048,20 @@ copy_reg (char const *src_name, char const *dst_name,
   /* --attributes-only overrides --reflink.  */
   if (data_copy_required && x->reflink_mode)
     {
-      bool clone_ok = clone_file (dest_desc, source_desc) == 0;
-      if (clone_ok || x->reflink_mode == REFLINK_ALWAYS)
+      if (! reflink_ok)
         {
-          if (!clone_ok)
+          bool clone_ok = clone_file (dest_desc, source_desc) == 0;
+          if (clone_ok || x->reflink_mode == REFLINK_ALWAYS)
             {
-              error (0, errno, _("failed to clone %s from %s"),
-                     quote_n (0, dst_name), quote_n (1, src_name));
-              return_val = false;
-              goto close_src_and_dst_desc;
+              if (!clone_ok)
+                {
+                  error (0, errno, _("failed to clone %s from %s"),
+                         quote_n (0, dst_name), quote_n (1, src_name));
+                  return_val = false;
+                  goto close_src_and_dst_desc;
+                }
+              data_copy_required = false;
             }
-          data_copy_required = false;
         }
     }

-- 
1.5.4.3



Any comments are welcome!

Thanks,
-Jeff



reply via email to

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