I was looking at adding fallocate() to copy.c,
now that the fiemap code has gone in and
I noticed that if there was allocated space
at the end of a file, not accounted for
in st_size, then any holes would not be detected.
In what other cases does the sparse detection
heuristic fail BTW?

Anwyay, we don't need the heuristic with fiemap,
so I changed accordingly in the attached.

cheers,
Pádraig.
>From a96d650ae634585ef46f96636d47c44297ce513a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?P=C3=A1draig=20Brady?= <[email protected]>
Date: Tue, 8 Feb 2011 19:16:55 +0000
Subject: [PATCH] copy: adjust fiemap handling of sparse files

Don't depend on heuristics to detect sparse files
if fiemap is available.  Also don't introduce new
holes unless --sparse=always has been specified.

* src/copy.c (extent_copy): Pass the user specified
sparse mode, and handle as described above.
Also a redundant lseek has been suppressed when
there is no hole between two extents.
---
 src/copy.c |   25 ++++++++++---------------
 1 files changed, 10 insertions(+), 15 deletions(-)

diff --git a/src/copy.c b/src/copy.c
index 9182c16..63a7b1e 100644
--- a/src/copy.c
+++ b/src/copy.c
@@ -294,7 +294,7 @@ write_zeros (int fd, uint64_t n_bytes)
    return false.  */
 static bool
 extent_copy (int src_fd, int dest_fd, char *buf, size_t buf_size,
-             off_t src_total_size, bool make_holes,
+             off_t src_total_size, enum Sparse_type sparse_mode,
              char const *src_name, char const *dst_name,
              bool *require_normal_copy)
 {
@@ -343,7 +343,8 @@ extent_copy (int src_fd, int dest_fd, char *buf, size_t buf_size,
               return false;
             }
 
-          if (make_holes)
+          uint64_t hole_size = ext_start - last_ext_start - last_ext_len;
+          if (hole_size && sparse_mode != SPARSE_NEVER)
             {
               if (lseek (dest_fd, ext_start, SEEK_SET) < 0)
                 {
@@ -351,21 +352,15 @@ extent_copy (int src_fd, int dest_fd, char *buf, size_t buf_size,
                   goto fail;
                 }
             }
-          else
+          else if (hole_size)
             {
               /* When not inducing holes and when there is a hole between
                  the end of the previous extent and the beginning of the
                  current one, write zeros to the destination file.  */
-              if (last_ext_start + last_ext_len < ext_start)
+              if (! write_zeros (dest_fd, hole_size))
                 {
-                  uint64_t hole_size = (ext_start
-                                        - last_ext_start
-                                        - last_ext_len);
-                  if (! write_zeros (dest_fd, hole_size))
-                    {
-                      error (0, errno, _("%s: write failed"), quote (dst_name));
-                      goto fail;
-                    }
+                  error (0, errno, _("%s: write failed"), quote (dst_name));
+                  goto fail;
                 }
             }
 
@@ -374,7 +369,7 @@ extent_copy (int src_fd, int dest_fd, char *buf, size_t buf_size,
 
           off_t n_read;
           if ( ! sparse_copy (src_fd, dest_fd, buf, buf_size,
-                              make_holes, src_name, dst_name,
+                              sparse_mode == SPARSE_ALWAYS, src_name, dst_name,
                               ext_len, &n_read,
                               &wrote_hole_at_eof))
             return false;
@@ -397,7 +392,7 @@ extent_copy (int src_fd, int dest_fd, char *buf, size_t buf_size,
      just converted them to a hole in the destination, we must call ftruncate
      here in order to record the proper length in the destination.  */
   if ((dest_pos < src_total_size || wrote_hole_at_eof)
-      && (make_holes
+      && (sparse_mode != SPARSE_NEVER
           ? ftruncate (dest_fd, src_total_size)
           : ! write_zeros (dest_fd, src_total_size - dest_pos)))
     {
@@ -968,7 +963,7 @@ copy_reg (char const *src_name, char const *dst_name,
          '--sparse=never' option is specified, write all data but use
          any extents to read more efficiently.  */
       if (extent_copy (source_desc, dest_desc, buf, buf_size,
-                       src_open_sb.st_size, make_holes,
+                       src_open_sb.st_size, x->sparse_mode,
                        src_name, dst_name, &normal_copy_required))
         goto preserve_metadata;
 
-- 
1.7.3.4

Reply via email to