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
