coreutils
[Top][All Lists]
Advanced

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

[coreutils] Feature: add ocfs2 reflink to cp(1)


From: jeff.liu
Subject: [coreutils] Feature: add ocfs2 reflink to cp(1)
Date: Sun, 04 Apr 2010 23:44:48 +0800
User-agent: Thunderbird 2.0.0.14 (X11/20080505)

Hi All,

I'd like to introduce OCFS2 reflink feature to cp(1).

Currently, we could run cp(1) with '--reflink=[WHEN]' to perform Btrfs clone 
operation.
We can share the same trigger option to do OCFS2 reflink operation without any 
conflicts.

Here is the different between Btrfs clone and OCFS2 reflink, refers to Joel's 
comments before.
"ocfs2's reflink (where the term was coined) is an atomic
creation of a new target inode duplicating the attributes of and sharing
cow data extents with the source.  btrfs's ioctl(2) links data extents
from one existing inode to another existing inode.  It is not atomic
regarding the target inode creation, and it doesn't inherently set the
attributes of the target inode."


>From 43cadc7bf905492e38d0c259adf0f00e7b5ab7ac Mon Sep 17 00:00:00 2001
From: Jie Liu <address@hidden>
Date: Sun, 4 Apr 2010 23:29:33 +0800
Subject: [PATCH] Add OCFS2 reflink feature to cp(1).

Currently, cp(1) does Btrfs's ioctl(2) reflinks via "--reflink=[WHEN]".

This patch add OCFS2 reflink which share the same trigger option, it perform 
ocfs2
ioctl(2) reflink only if the source file is resides on OCFS2 filesystem and 
link destination
file system is OCFS2 as well.

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

diff --git a/src/copy.c b/src/copy.c
index 29f37c9..cb515ed 100644
--- a/src/copy.c
+++ b/src/copy.c
@@ -53,6 +53,13 @@
 #include "write-any-file.h"
 #include "areadlink.h"
 #include "yesno.h"
+#include "fs.h"
+
+#if HAVE_SYS_VFS_H
+# include <sys/vfs.h>
+#else
+# include <sys/statfs.h>
+#endif

 #if USE_XATTR
 # include <attr/error_context.h>
@@ -132,6 +139,74 @@ utimens_symlink (char const *file, struct timespec const 
*timespec)
   return err;
 }

+/* This function detects whether the source and destination files
+   are all resides on OCFS2.  If true, then perform the OCFS2 reflink
+   operation.  Otherwise, performing btrfs clone operation.  */
+static inline bool
+is_ocfs2_file (int dst_fd, int src_fd)
+{
+#if HAVE_FSTATFS && HAVE_STRUCT_STATFS_F_TYPE && defined __linux__
+  struct statfs statfsbuf1;
+  struct statfs statfsbuf2;
+
+  return (fstatfs (src_fd, &statfsbuf1) == 0
+          && statfsbuf1.f_type == S_MAGIC_OCFS2
+          && fstatfs (dst_fd, &statfsbuf2) == 0
+          && statfsbuf2.f_type == S_MAGIC_OCFS2);
+#else
+  (void) dst_fd;
+  (void) src_fd;
+  return false;
+#endif
+}
+
+/* Perform the OCFS2 CoW reflink operation if possible.
+   We do not attempt to preserve security attributes for a reference
+   counted link.  Instead, let 'x->preserve_xxxx' to process them if
+   they are the user expected.
+   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 *new_dst)
+{
+#ifdef __linux__
+# ifndef REFLINK_ATTR_NONE
+#  define REFLINK_ATTR_NONE 0
+# 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
+  /* Check if the destination does not exist but created by cp(1) before.
+     In this case, we have to unlink(2) it before performing reflink.
+     Reflink can not create a file that already exists.  */
+  if (*new_dst)
+    {
+      if (unlink (dst_name) != 0)
+        return -1;
+    }
+
+  struct reflink_arguments args = {
+    .old_path = (unsigned long) src_name,
+    .new_path = (unsigned long) dst_name,
+    .preserve = REFLINK_ATTR_NONE,
+  };
+
+  return ioctl (src_fd, OCFS2_IOC_REFLINK, &args);
+#else
+  (void) src_name;
+  (void) dst_name;
+  (void) src_fd;
+  (void) new_dst;
+  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
@@ -634,12 +709,15 @@ copy_reg (char const *src_name, char const *dst_name,

   if (x->reflink_mode)
     {
-      bool clone_ok = clone_file (dest_desc, source_desc) == 0;
-      if (clone_ok || x->reflink_mode == REFLINK_ALWAYS)
+      bool reflink_ok = is_ocfs2_file (dest_desc, source_desc)
+                        ? reflink_file (src_name, dst_name, source_desc, 
new_dst) == 0
+                        : clone_file (dest_desc, source_desc) == 0;
+
+      if (reflink_ok || x->reflink_mode == REFLINK_ALWAYS)
         {
-          if (!clone_ok)
+          if (!reflink_ok)
             {
-              error (0, errno, _("failed to clone %s"), quote (dst_name));
+              error (0, errno, _("failed to reflink %s"), quote (dst_name));
               return_val = false;
               goto close_src_and_dst_desc;
             }
-- 
1.5.4.3


Best Regards,
-Jef





reply via email to

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