summaryrefslogtreecommitdiff
path: root/tests/btrfs/299
blob: fe80771a8adb70f47a3d688632491aa5ec78713f (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
#! /bin/bash
# SPDX-License-Identifier: GPL-2.0
# Copyright (c) 2022 Meta Platforms, Inc.  All Rights Reserved.
#
# FS QA Test 299
#
# Given a file with extents:
# [0 : 4096) (inline)
# [4096 : N] (prealloc)
# if a user uses the ioctl BTRFS_IOC_LOGICAL_INO[_V2] asking for the file of the
# non-inline extent, it results in reading the offset field of the inline
# extent, which is meaningless (it is full of user data..). If we are
# particularly lucky, it can be past the end of the extent buffer, resulting in
# a crash. This test creates that circumstance and asserts that logical inode
# resolution is still successful.
#
. ./common/preamble
_begin_fstest auto quick preallocrw logical_resolve

_supported_fs btrfs
_require_scratch
_require_xfs_io_command "falloc" "-k"
_require_btrfs_command inspect-internal logical-resolve
# Can't run with nodatacow because we need to be able to create an inline extent
# in a range with a prealloc extent, which can only happen with COW enabled.
_require_btrfs_no_nodatacow
_fixed_by_kernel_commit 560840afc3e6 \
	"btrfs: fix resolving backrefs for inline extent followed by prealloc"

# This test needs to create conditions s.t. the special inode's inline extent
# is the first item in a leaf. Therefore, fix a leaf size and add
# items that are otherwise not necessary to reproduce the inline-prealloc
# condition to get to such a state.
#
# Roughly, the idea for getting the right item fill is to:
# 1. create extra inline items to cause leaf splitting.
# 2. put the target item in the middle so it is likely to catch the split
# 3. add an extra variable inline item to tweak any final adjustments
#
# It took a bit of trial and error to hit working counts of inline items, since
# it also had to account for dir and index items all going to the front.

# use a 64k nodesize so that an fs with 64k pages and no subpage sector size
# support will correctly reproduce the problem.
_scratch_mkfs "--nodesize 64k" >> $seqres.full || _fail "mkfs failed"
_scratch_mount

f=$SCRATCH_MNT/f
# write extra files before the evil file to use up the leaf and
# help trick leaf balancing
for i in {1..41}; do
	$XFS_IO_PROG -fc "pwrite -q 0 1024" $f.inl.$i
done

# write a variable inline file to help pad the preceeding leaf
$XFS_IO_PROG -fc "pwrite -q 0 1" $f.inl-var.$i

# falloc the evil file whose inline extent will start a leaf
$XFS_IO_PROG -fc "falloc -k 0 1m" $f.evil
$XFS_IO_PROG -fc fsync $f.evil

# write extra files after the evil file to use up the leaf and
# help trick leaf balancing
for i in {1..42}; do
	$XFS_IO_PROG -fc "pwrite -q 0 1024" $f.inl.2.$i
done

# grab the prealloc offset from dump tree while it's still the only
# extent data item for the inode
logical=$(_btrfs_get_file_extent_item_bytenr $f.evil 0)

# do the "small write; fsync; small write" pattern which reproduces the desired
# item pattern of an inline extent followed by a preallocated extent. The 23
# size is somewhat arbitrary, but ensures that the offset field is past the eb
# when we are item 0 (borrowed from the actual crash this reproduces).
$XFS_IO_PROG -fc "pwrite -q 0 23" $f.evil
$XFS_IO_PROG -fc fsync $f.evil
$XFS_IO_PROG -fc "pwrite -q 0 23" $f.evil

# ensure we have all the extent_data items for when we do logical to inode
# resolution
sync

# trigger the backref walk which accesses the bad inline extent
btrfs inspect-internal logical-resolve $logical $SCRATCH_MNT

echo "Silence is golden"
status=0
exit