#!/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 . . "${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. FIXME: amend 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