summaryrefslogtreecommitdiff
path: root/tests/btrfs/260
blob: b16e8378e8eebb1142f1ffd396090da7dba7aa83 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#! /bin/bash
# SPDX-License-Identifier: GPL-2.0
# Copyright (C) 2022 SUSE Linux Products GmbH. All Rights Reserved.
#
# FS QA Test 260
#
# Make sure "btrfs filesystem defragment" can still convert the compression
# algorithm of all regular extents.
#
. ./common/preamble
_begin_fstest auto quick defrag compress prealloc fiemap

# Override the default cleanup function.
# _cleanup()
# {
# 	cd /
# 	rm -r -f $tmp.*
# }

. ./common/filter

_supported_fs btrfs
_require_scratch
_require_xfs_io_command "fiemap" "ranged"
_require_xfs_io_command "falloc"
_require_btrfs_command inspect-internal dump-tree

get_inode_number()
{
	local file="$1"

	stat -c "%i" "$file"
}

get_file_extent()
{
	local file="$1"
	local offset="$2"
	local ino=$(get_inode_number "$file")
	local file_extent_key="($ino EXTENT_DATA $offset)"

	$BTRFS_UTIL_PROG inspect-internal dump-tree -t 5 $SCRATCH_DEV |\
		grep -A4 "$file_extent_key"
}

check_file_extent()
{
	local file="$1"
	local offset="$2"
	local expected="$3"

	echo "=== file extent at file '$file' offset $offset ===" >> $seqres.full
	get_file_extent "$file" "$offset" > $tmp.output
	cat $tmp.output >> $seqres.full
	grep -q "$expected" $tmp.output ||\
		echo "file \"$file\" offset $offset doesn't have expected string \"$expected\""
}

# Unlike file extents whose btrfs specific attributes need to be grabbed from
# dump-tree, we can check holes by fiemap. And mkfs enables no-holes feature by
# default in recent versions of btrfs-progs, preventing us from grabbing holes
# from dump-tree.
check_hole()
{
	local file="$1"
	local offset="$2"
	local len="$3"

	output=$($XFS_IO_PROG -c "fiemap $offset $len" "$file" |\
		 _filter_xfs_io_fiemap | head -n1)
	if [ -z $output ]; then
		echo "=== file extent at file '$file' offset $offset is a hole ===" \
			>> $seqres.full
	else
		echo "=== file extent at file '$file' offset $offset is not a hole ==="
	fi
}

# Needs 4K sectorsize as the test is crafted using that sectorsize
_require_btrfs_support_sectorsize 4096

_scratch_mkfs -s 4k >> $seqres.full 2>&1

# Initial data is compressed using lzo
_scratch_mount -o compress=lzo

# file 'large' has all of its compressed extents at their maximum size
$XFS_IO_PROG -f -c "pwrite 0 1m" "$SCRATCH_MNT/large" >> $seqres.full

# file 'fragment' has all of its compressed extents adjacent to
# preallocated/hole ranges, which should not be defragged with regular
# defrag ioctl, but should still be defragged by
# "btrfs filesystem defragment -c"
$XFS_IO_PROG -f -c "pwrite 0 16k" \
		-c "pwrite 32k 16k" -c "pwrite 64k 16k" \
		"$SCRATCH_MNT/fragment" >> $seqres.full
sync
# We only do the falloc after the compressed data reached disk.
# Or the inode could have PREALLOC flag, and prevent the
# data from being compressed.
$XFS_IO_PROG -c "falloc 16k 16k" "$SCRATCH_MNT/fragment"
sync

echo "====== Before the defrag ======" >> $seqres.full

# Should be lzo compressed
check_file_extent "$SCRATCH_MNT/large" 0 "compression 2"

# Should be lzo compressed
check_file_extent "$SCRATCH_MNT/fragment" 0 "compression 2"

# Should be preallocated
check_file_extent "$SCRATCH_MNT/fragment" 16384 "type 2"

# Should be lzo compressed
check_file_extent "$SCRATCH_MNT/fragment" 32768 "compression 2"

# Should be hole
check_hole "$SCRATCH_MNT/fragment" 49152 16384

# Should be lzo compressed
check_file_extent "$SCRATCH_MNT/fragment" 65536 "compression 2"

$BTRFS_UTIL_PROG filesystem defragment "$SCRATCH_MNT/large" -czstd \
	"$SCRATCH_MNT/fragment" >> $seqres.full
# Need to commit the transaction or dump-tree won't grab the new
# metadata on-disk.
sync

echo "====== After the defrag ======" >> $seqres.full

# Should be zstd compressed
check_file_extent "$SCRATCH_MNT/large" 0 "compression 3"

# Should be zstd compressed
check_file_extent "$SCRATCH_MNT/fragment" 0 "compression 3"

# Should be preallocated
check_file_extent "$SCRATCH_MNT/fragment" 16384 "type 2"

# Should be zstd compressed
check_file_extent "$SCRATCH_MNT/fragment" 32768 "compression 3"

# Should be hole
check_hole "$SCRATCH_MNT/fragment" 49152 16384

# Should be zstd compressed
check_file_extent "$SCRATCH_MNT/fragment" 65536 "compression 3"

echo "Silence is golden"

# success, all done
status=0
exit