summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJim Meyering <meyering@redhat.com>2011-04-20 11:21:09 +0200
committerJim Meyering <meyering@redhat.com>2011-04-20 18:48:48 +0200
commit18a474d755aa10d881243d9457d2c420c5e4ea77 (patch)
tree4df68a02135e49569c3287ca0e25b886d9ba9732
parent846d826096fc8fb621d751f8b3db1da68a8bbd06 (diff)
downloadcoreutils-18a474d755aa10d881243d9457d2c420c5e4ea77.tar.xz
copy: use FIEMAP (extent_copy) only for apparently-sparse files,
to avoid the expense of extent_copy's unconditional use of FIEMAP_FLAG_SYNC. * src/copy.c (copy_reg): Do not attempt extent_copy on a file that appears to have no holes. * NEWS (Changes in behavior): Document this. At first I labeled this as a bug fix, but that would be inaccurate, considering there is no documentation of FIEMAP semantics, nor even consensus among kernel FS developers. Here's hoping SEEK_HOLE/SEEK_DATA support will soon make it into the linux kernel.
-rw-r--r--NEWS13
-rw-r--r--src/copy.c37
2 files changed, 34 insertions, 16 deletions
diff --git a/NEWS b/NEWS
index 4873b5a29..7bc2ef39a 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,19 @@ GNU coreutils NEWS -*- outline -*-
* Noteworthy changes in release ?.? (????-??-??) [?]
+** Changes in behavior
+
+ cp's extent-based (FIEMAP) copying code is more reliable in the face
+ of varying and undocumented file system semantics:
+ - it no longer treats unwritten extents specially
+ - a FIEMAP-based extent copy always uses the FIEMAP_FLAG_SYNC flag.
+ Before, it would incur the performance penalty of that sync only
+ for 2.6.38 and older kernels. We thought all problems would be
+ resolved for 2.6.39.
+ - it now attempts a FIEMAP copy only on a file that appears sparse.
+ Sparse files are relatively unusual, and the copying code incurs
+ the performance penalty of the now-mandatory sync only for them.
+
* Noteworthy changes in release 8.11 (2011-04-13) [stable]
diff --git a/src/copy.c b/src/copy.c
index 3db07b5b4..6edf52efc 100644
--- a/src/copy.c
+++ b/src/copy.c
@@ -993,6 +993,7 @@ copy_reg (char const *src_name, char const *dst_name,
/* Deal with sparse files. */
bool make_holes = false;
+ bool sparse_src = false;
if (S_ISREG (sb.st_mode))
{
@@ -1005,8 +1006,8 @@ copy_reg (char const *src_name, char const *dst_name,
blocks. If the file has fewer blocks than would normally be
needed for a file of its size, then at least one of the blocks in
the file is a hole. */
- if (x->sparse_mode == SPARSE_AUTO
- && is_probably_sparse (&src_open_sb))
+ sparse_src = is_probably_sparse (&src_open_sb);
+ if (x->sparse_mode == SPARSE_AUTO && sparse_src)
make_holes = true;
}
@@ -1038,21 +1039,25 @@ copy_reg (char const *src_name, char const *dst_name,
buf_alloc = xmalloc (buf_size + buf_alignment_slop);
buf = ptr_align (buf_alloc, buf_alignment);
- bool normal_copy_required;
- /* Perform an efficient extent-based copy, falling back to the
- standard copy only if the initial extent scan fails. If the
- '--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,
- S_ISREG (sb.st_mode) ? x->sparse_mode : SPARSE_NEVER,
- src_name, dst_name, &normal_copy_required))
- goto preserve_metadata;
-
- if (! normal_copy_required)
+ if (sparse_src)
{
- return_val = false;
- goto close_src_and_dst_desc;
+ bool normal_copy_required;
+
+ /* Perform an efficient extent-based copy, falling back to the
+ standard copy only if the initial extent scan fails. If the
+ '--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,
+ S_ISREG (sb.st_mode) ? x->sparse_mode : SPARSE_NEVER,
+ src_name, dst_name, &normal_copy_required))
+ goto preserve_metadata;
+
+ if (! normal_copy_required)
+ {
+ return_val = false;
+ goto close_src_and_dst_desc;
+ }
}
off_t n_read;