diff options
author | Jim Meyering <meyering@redhat.com> | 2011-04-20 11:21:09 +0200 |
---|---|---|
committer | Jim Meyering <meyering@redhat.com> | 2011-04-20 18:48:48 +0200 |
commit | 18a474d755aa10d881243d9457d2c420c5e4ea77 (patch) | |
tree | 4df68a02135e49569c3287ca0e25b886d9ba9732 | |
parent | 846d826096fc8fb621d751f8b3db1da68a8bbd06 (diff) | |
download | coreutils-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-- | NEWS | 13 | ||||
-rw-r--r-- | src/copy.c | 37 |
2 files changed, 34 insertions, 16 deletions
@@ -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; |