summaryrefslogtreecommitdiff
path: root/tests/cp
diff options
context:
space:
mode:
authorPádraig Brady <P@draigBrady.com>2011-02-11 08:55:22 +0000
committerPádraig Brady <P@draigBrady.com>2011-04-01 15:04:18 +0100
commitbfdb6b585b6842362977b8c10fe7858fb96a1dd0 (patch)
tree0279e6e1674d34072ba8e7bf94ba929f332e54e4 /tests/cp
parentb56b53bd70b1f8fa2b5a95d4569bb72a2419b5cd (diff)
downloadcoreutils-bfdb6b585b6842362977b8c10fe7858fb96a1dd0.tar.xz
copy: process empty extents more efficiently
* src/copy.c (extent_copy): Treat an allocated but empty extent much like a hole. I.E. don't read data we know is going to be NUL. Also we convert the empty extent to a hole only when SPARSE_ALWAYS so that the source and dest have the same allocation. This will be improved soon, when we use fallocate() to do the allocation. * tests/cp/fiemap-empty: A new test for efficiency and correctness of copying empty extents. * tests/Makefile.am: Reference the new test. * NEWS: Mention the change in behavior.
Diffstat (limited to 'tests/cp')
-rwxr-xr-xtests/cp/fiemap-empty89
1 files changed, 89 insertions, 0 deletions
diff --git a/tests/cp/fiemap-empty b/tests/cp/fiemap-empty
new file mode 100755
index 000000000..f1ed71c71
--- /dev/null
+++ b/tests/cp/fiemap-empty
@@ -0,0 +1,89 @@
+#!/bin/sh
+# Test cp reads unwritten extents efficiently
+
+# Copyright (C) 2011 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/init.sh"; path_prepend_ ../src
+print_ver_ cp
+
+touch fiemap_chk
+fiemap_capable_ fiemap_chk ||
+ skip_test_ 'this file system lacks FIEMAP support'
+rm fiemap_chk
+
+# TODO: rather than requiring `fallocate`, possible add
+# this functionality to truncate --alloc
+fallocate --help >/dev/null || skip_test_ 'The fallocate utility is required'
+fallocate -l 1 -n falloc.test ||
+ skip_test_ 'this file system lacks FALLOCATE support'
+rm falloc.test
+
+fallocate -l 600000000 space.test ||
+ skip_test_ 'this test needs at least 600MB free space'
+
+# Disable this test on old BTRFS (e.g. Fedora 14)
+# which reports ordinary extents for unwritten ones.
+filefrag space.test || skip_test_ 'the `filefrag` utility is missing'
+filefrag -v space.test | grep -F 'unwritten' > /dev/null ||
+ skip_test_ 'this file system does not report empty extents as "unwritten"'
+
+rm space.test
+
+# Ensure we read a large empty file quickly
+fallocate -l 300000000 empty.big || framework_failure
+timeout 3 cp --sparse=always empty.big cp.test || fail=1
+test $(stat -c %s empty.big) = $(stat -c %s cp.test) || fail=1
+rm empty.big cp.test
+
+# Ensure we handle extents beyond file size correctly.
+# Note until we support fallocate, we will not maintain
+# the file allocation. Ammend this test when fallocate is supported
+fallocate -l 10000000 -n unwritten.withdata || framework_failure
+dd count=10 if=/dev/urandom conv=notrunc iflag=fullblock of=unwritten.withdata
+cp unwritten.withdata cp.test || fail=1
+test $(stat -c %s unwritten.withdata) = $(stat -c %s cp.test) || fail=1
+cmp unwritten.withdata cp.test || fail=1
+rm unwritten.withdata cp.test
+
+# The following to generate unaccounted extents followed by a hole, is not
+# supported by ext4 at least. The ftruncate discards all extents not
+# accounted for in the size.
+# fallocate -l 10000000 -n unacc.withholes
+# dd count=10 if=/dev/urandom conv=notrunc iflag=fullblock of=unacc.withholes
+# truncate -s20000000 unacc.withholes
+
+# Ensure we handle a hole after empty extents correctly.
+# Since all extents are accounted for in the size,
+# we can maintain the allocation independently from
+# fallocate() support.
+fallocate -l 10000000 empty.withholes
+truncate -s 20000000 empty.withholes
+sectors_per_block=$(expr $(stat -c %o .) / 512)
+cp empty.withholes cp.test || fail=1
+test $(stat -c %s empty.withholes) = $(stat -c %s cp.test) || fail=1
+# These are usually equal but can vary by an IO block due to alignment
+alloc_diff=$(expr $(stat -c %b empty.withholes) - $(stat -c %b cp.test))
+alloc_diff=$(echo $alloc_diff | tr -d -- -) # abs()
+test $alloc_diff -le $sectors_per_block || fail=1
+# Again with SPARSE_ALWAYS
+cp --sparse=always empty.withholes cp.test || fail=1
+test $(stat -c %s empty.withholes) = $(stat -c %s cp.test) || fail=1
+# cp.test should take 0 space, but allowing for some systems
+# that store default extended attributes in data blocks
+test $(stat -c %b cp.test) -le $sectors_per_block || fail=1
+rm empty.withholes cp.test
+
+Exit $fail