Subject: Re: bug#23904: Btrfs clone support in copy operations
From: Paul Eggert <[email-masked]>
To: Eli Zaretskii <[email-masked]>
Cc: [email-masked], [email-masked], [email-masked], [email-masked]
Date: Sat, 10 Sep 2016 19:16:39 -0700
List-Id: <debbugs-submit.debbugs.gnu.org>

I looked into this a bit more, and it appears that there's little point to 
giving the user an option to clone or not clone when copying files, as the 
cloning (or not cloning) can occur anyway.

We plan to release a coreutils version soon and to change the default to clone 
after the release. For Emacs master the next release is far away, so there is 
plenty of time to try out the FICLONE performance improvement. I installed the 
attached two patches and am marking this bug report as done.

The second patch merely updates the documentation to discuss the issue; it is 
logically independent of the first patch, since the issue can occur both with 
and without the first patch.
From f9527cb5a5cdd05b2c98be089023b64ee9ee318b Mon Sep 17 00:00:00 2001
From: Paul Eggert <[email-masked]>
Date: Sat, 10 Sep 2016 12:51:27 -0700
Subject: [PATCH 1/2] copy-file now uses GNU/Linux file cloning

From a suggestion by Kieran Colford (see Bug#23904).
* configure.ac: Check for linux/fs.h.
* src/fileio.c [HAVE_LINUX_FS_H]: Include sys/ioctl.h and linux/fs.h.
(clone_file): New function.
(Fcopy_file): Use it.
---
 configure.ac |  1 +
 src/fileio.c | 33 +++++++++++++++++++++++++--------
 2 files changed, 26 insertions(+), 8 deletions(-)

diff --git a/configure.ac b/configure.ac
index 9856228..82a672b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1638,6 +1638,7 @@ AC_DEFUN
 
 dnl checks for header files
 AC_CHECK_HEADERS_ONCE(
+  linux/fs.h
   malloc.h
   sys/systeminfo.h
   sys/sysinfo.h
diff --git a/src/fileio.c b/src/fileio.c
index bf6bf62..b4316b3 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -52,6 +52,11 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "region-cache.h"
 #include "frame.h"
 
+#ifdef HAVE_LINUX_FS_H
+# include <sys/ioctl.h>
+# include <linux/fs.h>
+#endif
+
 #ifdef WINDOWSNT
 #define NOMINMAX 1
 #include <windows.h>
@@ -1829,6 +1834,16 @@ barf_or_query_if_file_exists (Lisp_Object absname, bool known_to_exist,
     }
 }
 
+/* Copy data to DEST from SOURCE if possible.  Return true if OK.  */
+static bool
+clone_file (int dest, int source)
+{
+#ifdef FICLONE
+  return ioctl (dest, FICLONE, source) == 0;
+#endif
+  return false;
+}
+
 DEFUN ("copy-file", Fcopy_file, Scopy_file, 2, 6,
        "fCopy file: \nGCopy %s to file: \np\nP",
        doc: /* Copy FILE to NEWNAME.  Both args must be strings.
@@ -1975,7 +1990,7 @@ permissions.  */)
 
   record_unwind_protect_int (close_file_unwind, ofd);
 
-  off_t oldsize = 0, newsize = 0;
+  off_t oldsize = 0, newsize;
 
   if (already_exists)
     {
@@ -1991,17 +2006,19 @@ permissions.  */)
 
   immediate_quit = 1;
   QUIT;
-  while (true)
+
+  if (clone_file (ofd, ifd))
+    newsize = st.st_size;
+  else
     {
       char buf[MAX_ALLOCA];
-      ptrdiff_t n = emacs_read (ifd, buf, sizeof buf);
+      ptrdiff_t n;
+      for (newsize = 0; 0 < (n = emacs_read (ifd, buf, sizeof buf));
+	   newsize += n)
+	if (emacs_write_sig (ofd, buf, n) != n)
+	  report_file_error ("Write error", newname);
       if (n < 0)
 	report_file_error ("Read error", file);
-      if (n == 0)
-	break;
-      if (emacs_write_sig (ofd, buf, n) != n)
-	report_file_error ("Write error", newname);
-      newsize += n;
     }
 
   /* Truncate any existing output file after writing the data.  This
-- 
2.7.4

From 62f0eb5f8ce6a05288c0b7b7cf8ec3dc373583e4 Mon Sep 17 00:00:00 2001
From: Paul Eggert <[email-masked]>
Date: Sat, 10 Sep 2016 19:12:21 -0700
Subject: [PATCH 2/2] Document file synchronization issues

* doc/lispref/files.texi (Files and Storage): New section.
---
 doc/emacs/files.texi     |  4 ++--
 doc/lispref/backups.texi |  5 +++++
 doc/lispref/files.texi   | 25 +++++++++++++++++++++++++
 3 files changed, 32 insertions(+), 2 deletions(-)

diff --git a/doc/emacs/files.texi b/doc/emacs/files.texi
index f195a41..7bf4690 100644
--- a/doc/emacs/files.texi
+++ b/doc/emacs/files.texi
@@ -1554,8 +1554,8 @@ Misc File Ops
 
 @findex copy-file
 @cindex copying files
-  @kbd{M-x copy-file} reads the file @var{old} and writes a new file
-named @var{new} with the same contents.
+  @kbd{M-x copy-file} copies the contents of the file @var{old} to the
+file @var{new}.
 
 @findex copy-directory
   @kbd{M-x copy-directory} copies directories, similar to the
diff --git a/doc/lispref/backups.texi b/doc/lispref/backups.texi
index b9e6466..35a1865 100644
--- a/doc/lispref/backups.texi
+++ b/doc/lispref/backups.texi
@@ -41,6 +41,11 @@ Backup Files
 file gets a new name.  You can delete old numbered backups when you
 don't want them any more, or Emacs can delete them automatically.
 
+  For performance, the operating system may not write the backup
+file's contents to secondary storage immediately, or may alias the
+backup data with the original until one or the other is later
+modified.  @xref{Files and Storage}.
+
 @menu
 * Making Backups::     How Emacs makes backup files, and when.
 * Rename or Copy::     Two alternatives: renaming the old file or copying it.
diff --git a/doc/lispref/files.texi b/doc/lispref/files.texi
index 0aea1df..b912d7b 100644
--- a/doc/lispref/files.texi
+++ b/doc/lispref/files.texi
@@ -41,6 +41,7 @@ Files
                                simultaneous editing by two people.
 * Information about Files::  Testing existence, accessibility, size of files.
 * Changing Files::           Renaming files, changing permissions, etc.
+* Files and Storage::        Surviving power and media failures
 * File Names::               Decomposing and expanding file names.
 * Contents of Directories::  Getting a list of the files in a directory.
 * Create/Delete Dirs::       Creating and Deleting Directories.
@@ -1496,6 +1497,10 @@ Changing Files
 system-dependent error message that describes the reason for the
 failure.
 
+  For performance, the operating system may cache or alias changes
+made by these functions instead of writing them immediately to
+secondary storage.  @xref{Files and Storage}.
+
   In the functions that have an argument @var{newname}, if a file by the
 name of @var{newname} already exists, the actions taken depend on the
 value of the argument @var{ok-if-already-exists}:
@@ -1794,6 +1799,26 @@ Changing Files
 @var{filename}, @code{nil} otherwise.
 @end defun
 
+@node Files and Storage
+@section Files and Secondary Storage
+@cindex secondary storage
+
+After Emacs changes a file, there are two reasons the changes might
+not survive later failures of power or media, both having to do with
+efficiency.  First, the operating system might alias written data with
+data already stored elsewhere on secondary storage until one file or
+the other is later modified; this will lose both files if the only
+copy on secondary storage is lost due to media failure.  Second, the
+operating system might not write data to secondary storage
+immediately, which will lose the data if power is lost.
+
+Although both sorts of failures can largely be avoided by a suitably
+configured file system, such systems are typically more expensive or
+less efficient.  In more-typical systems, to survive media failure you
+can copy the file to a different device, and to survive a power
+failure you can invoke the @command{sync} utility (@pxref{sync
+invocation,,, coreutils, The @sc{gnu} @code{Coreutils} Manual}).
+
 @node File Names
 @section File Names
 @cindex file names
-- 
2.7.4