File: btt-errors.sh

package info (click to toggle)
ndctl 81-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 3,436 kB
  • sloc: ansic: 41,432; sh: 3,931; makefile: 28
file content (148 lines) | stat: -rwxr-xr-x 3,988 bytes parent folder | download | duplicates (3)
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
#!/bin/bash -x
# SPDX-License-Identifier: GPL-2.0
# Copyright (C) 2015-2020 Intel Corporation. All rights reserved.

MNT=test_btt_mnt
FILE=image
blockdev=""
rc=77

. $(dirname $0)/common

cleanup()
{
	if grep -q "$MNT" /proc/mounts; then
		umount $MNT
	else
		rc=77
	fi
	rm -rf $MNT
}

force_raw()
{
	raw="$1"
	if grep -q "$MNT" /proc/mounts; then umount $MNT; fi
	$NDCTL disable-namespace "$dev"
	echo "$raw" > "/sys/bus/nd/devices/$dev/force_raw"
	$NDCTL enable-namespace "$dev"
	echo "Set $dev to raw mode: $raw"
	if [[ "$raw" == "1" ]]; then
		raw_bdev=${blockdev%s}
		test -b "/dev/$raw_bdev"
	else
		raw_bdev=""
	fi
}

check_min_kver "4.15" || do_skip "may lack BTT error handling"

set -e
mkdir -p $MNT
trap 'err $LINENO cleanup' ERR

# setup (reset nfit_test dimms)
modprobe nfit_test
resetV

rc=1

# create a btt namespace and clear errors (if any)
dev="x"
json=$($NDCTL create-namespace -b $NFIT_TEST_BUS0 -t pmem -m sector)
eval "$(echo "$json" | json2var)"
[ $dev = "x" ] && echo "fail: $LINENO" && exit 1

force_raw 1
if read -r sector len < "/sys/block/$raw_bdev/badblocks"; then
	dd of=/dev/$raw_bdev if=/dev/zero oflag=direct bs=512 seek="$sector" count="$len"
fi
force_raw 0

mkfs.ext4 "/dev/$blockdev" -b 4096
mount -o nodelalloc "/dev/$blockdev" $MNT

# prepare an image file with random data
dd if=/dev/urandom of=$FILE bs=4096 count=1
test -s $FILE

# copy it to the file system
cp $FILE $MNT/$FILE

# Get the start sector for the file
start_sect=$(filefrag -v -b512 $MNT/$FILE | grep -E "^[ ]+[0-9]+.*" | head -1 | awk '{ print $4 }' | cut -d. -f1)
start_4k=$((start_sect/8))
test -n "$start_sect"
echo "start sector of the file is: $start_sect (512B) or $start_4k (4096B)"

# figure out the btt offset

force_raw 1

# calculate start of the map
map=$(hexdump -s 96 -n 4 "/dev/$raw_bdev" | head -1 | cut -d' ' -f2-)
map=$(tr -d ' ' <<< "0x${map#* }${map%% *}")
printf "btt map starts at: %x\n" "$map"

# calculate map entry byte offset for the file's block
map_idx=$((map + (4 * start_4k)))
printf "btt map entry location for sector %x: %x\n" "$start_4k" "$map_idx"

# read the map entry
map_ent=$(hexdump -s $map_idx -n 4 "/dev/$raw_bdev" | head -1 | cut -d' ' -f2-)
map_ent=$(tr -d ' ' <<< "0x${map_ent#* }${map_ent%% *}")
map_ent=$((map_ent & 0x3fffffff))
printf "btt map entry: 0x%x\n" "$map_ent"

# calculate the data offset
dataoff=$(((map_ent * 4096) + 4096))
printf "dataoff: 0x%x\n" "$dataoff"

bb_inj=$((dataoff/512))

# inject badblocks for one page at the start of the file
$NDCTL inject-error --block="$bb_inj" --count=8 $dev
$NDCTL start-scrub $NFIT_TEST_BUS0 && $NDCTL wait-scrub $NFIT_TEST_BUS0

force_raw 0
mount -o nodelalloc "/dev/$blockdev" $MNT

# make sure reading the first block of the file fails as expected
: The following 'dd' is expected to hit an I/O Error
dd if=$MNT/$FILE of=/dev/null iflag=direct bs=4096 count=1 && err $LINENO || true

# write via btt to clear the error
dd if=/dev/zero of=$MNT/$FILE oflag=direct bs=4096 count=1

# read again and that should succeed
dd if=$MNT/$FILE of=/dev/null iflag=direct bs=4096 count=1


## ensure we get an EIO for errors in namespace metadata

# reset everything to get a clean log
if grep -q "$MNT" /proc/mounts; then umount $MNT; fi
resetV
dev="x"
json=$($NDCTL create-namespace -b $NFIT_TEST_BUS0 -t pmem -m sector)
eval "$(echo "$json" | json2var)"
[ $dev = "x" ] && echo "fail: $LINENO" && exit 1

# insert error at an arbitrary offset in the map (sector 0)
force_raw 1
map=$(hexdump -s 96 -n 4 "/dev/$raw_bdev" | head -1 | cut -d' ' -f2-)
map=$(tr -d ' ' <<< "0x${map#* }${map%% *}")
bb_inj=$((map/512))
$NDCTL inject-error --block="$bb_inj" --count=1 $dev
$NDCTL start-scrub $NFIT_TEST_BUS0 && $NDCTL wait-scrub $NFIT_TEST_BUS0
force_raw 0

# make sure reading the first block of the namespace fails
: The following 'dd' is expected to hit an I/O Error
dd if=/dev/$blockdev of=/dev/null iflag=direct bs=4096 count=1 && err $LINENO || true

# done, exit
reset
cleanup
_cleanup
exit 0