Skip to content

Commit 6067047

Browse files
author
Sergey Konev
committed
feature/btrfs: Add multi-device (RAID) boot support
Btrfs multi-device filesystems (RAID1, RAID10, etc.) could not be mounted during boot because the initramfs had no mechanism to wait for all component devices to appear and no way to handle missing devices gracefully. Add an event-driven handler (modeled after the existing mdadm feature) that: - Triggers on each btrfs member device via udev rules - Waits for a configurable timeout (btrfs-member-delay=, default 10s) after the last device appears - Runs a full btrfs device scan after the timeout - Adds the "degraded" mount option to /etc/fstab when devices are missing, allowing the filesystem to mount with available devices - Resets the rootdelay timer after fstab modification New files: data/etc/initrd/cmdline.d/btrfs - boot parameter registration data/lib/uevent/filters/btrfs-member - uevent filter data/lib/uevent/handlers/btrfs-member/100-timeout - main handler Also add integration tests for normal and degraded btrfs RAID1 boot. Signed-off-by: Sergey Konev <darisishe@altlinux.org>
1 parent b2f8221 commit 6067047

10 files changed

Lines changed: 197 additions & 0 deletions

File tree

.github/workflows/testcases.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ jobs:
2020
strategy:
2121
matrix:
2222
testcase:
23+
- btrfs-raid1
24+
- btrfs-raid1-degraded
2325
- btrfs-subvol
2426
- efi-partition
2527
- efi-reqpartition

features/btrfs/README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
11
# Feature: btrfs
22

33
Feature adds btrfs to initramfs.
4+
5+
## Multi-device support
6+
7+
For multi-device btrfs filesystems (RAID), the feature waits for all component
8+
devices to appear before allowing mount. If some devices are missing after the
9+
timeout, the `degraded` mount option is added automatically so the filesystem
10+
can be mounted with available devices.
11+
12+
## Boot parameters
13+
14+
- `btrfs-member-delay=<SECS>` - determines the number of seconds to wait after
15+
the last btrfs member device appears before mounting in degraded mode
16+
(default: 10 seconds). If this value is zero, it means disabling the degraded
17+
mount support.

features/btrfs/config.mk

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,6 @@ BTRFS_UDEV_RULES := $(wildcard $(FEATURESDIR)/btrfs/rules.d/*.rules)
55
BTRFS_PROGS = btrfs
66
BTRFS_PRELOAD = btrfs
77
BTRFS_MODULES = crc32c
8+
9+
BTRFS_DATADIR = \
10+
$(FEATURESDIR)/btrfs/data
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
register_parameter number BTRFS_MEMBER_DELAY 10
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#!/bin/bash -efu
2+
3+
. /.initrd/initenv
4+
. uevent-sh-functions
5+
6+
mkdir -p "$filterdir/btrfs-member/.tmp"
7+
8+
event="$(make_event btrfs-member)"
9+
release_event btrfs-member "$event"
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
#!/bin/bash -eu
2+
3+
. shell-error
4+
. initrd-sh-functions
5+
. uevent-sh-functions
6+
. /.initrd/initenv
7+
8+
PROG="${QUEUE:--}: session=${SESSION:-0}: $PROG"
9+
message_time=1
10+
11+
pidfile="/var/run/$PROG.pid"
12+
tsfile=/.initrd/btrfs-member-timeout
13+
delay="${BTRFS_MEMBER_DELAY-}"
14+
15+
for e in "$1"/btrfs-member.*; do
16+
done_event "$e" ||:
17+
done
18+
19+
[ -n "$delay" ] && [ "$delay" -gt 0 ] ||
20+
exit 0
21+
22+
now="$(timestamp boottime raw)"
23+
now="${now%.*}"
24+
echo "$(($now + $delay))" > "$tsfile"
25+
26+
[ ! -e "$pidfile" ] ||
27+
exit 0
28+
29+
btrfs_fstab_entries()
30+
{
31+
local fsdev fsdir fstype fsopts freq passno uuid
32+
33+
while read -r fsdev fsdir fstype fsopts freq passno; do
34+
[ -n "$fsdev" ] || continue
35+
case "$fstype" in
36+
btrfs|auto) ;;
37+
*) continue ;;
38+
esac
39+
40+
case "$fsdev" in
41+
UUID=*)
42+
uuid="${fsdev#UUID=}"
43+
printf '%s %s\n' "$fsdev" "$uuid"
44+
;;
45+
LABEL=*)
46+
uuid="$(blkid -l -o value -s UUID -t "$fsdev" 2>/dev/null)" ||:
47+
[ -z "$uuid" ] || printf '%s %s\n' "$fsdev" "$uuid"
48+
;;
49+
esac
50+
done < /etc/fstab
51+
}
52+
53+
check_btrfs_arrays()
54+
{
55+
local fsdev uuid show total missing need_wait=
56+
57+
while read -r fsdev uuid; do
58+
show="$(btrfs filesystem show "$uuid" 2>/dev/null)" ||
59+
continue
60+
61+
total="$(printf '%s\n' "$show" |
62+
sed -n 's/.*Total devices \([0-9]\+\).*/\1/p')"
63+
64+
[ -n "$total" ] && [ "$total" -gt 1 ] ||
65+
continue
66+
67+
missing="$(printf '%s\n' "$show" | grep -c 'missing' ||:)"
68+
69+
if [ "${missing:-0}" -gt 0 ]; then
70+
need_wait=1
71+
fi
72+
done < <(btrfs_fstab_entries | sort -u -k2,2)
73+
74+
[ -n "$need_wait" ]
75+
}
76+
77+
# No multi-device btrfs in fstab, or all devices already present.
78+
check_btrfs_arrays ||
79+
exit 0
80+
81+
(
82+
while :; do
83+
now="$(timestamp boottime raw)"
84+
now="${now%.*}"
85+
86+
ts=
87+
readline ts "$tsfile"
88+
89+
[ "$ts" -ge "$now" ] ||
90+
break
91+
sleep 1
92+
done
93+
94+
# Run a full device scan to resolve any per-device scan race conditions.
95+
btrfs device scan ||:
96+
97+
changed=
98+
while read -r fsdev uuid; do
99+
show="$(btrfs filesystem show "$uuid" 2>/dev/null)" ||
100+
continue
101+
102+
total="$(printf '%s\n' "$show" |
103+
sed -n 's/.*Total devices \([0-9]\+\).*/\1/p')"
104+
105+
[ -n "$total" ] && [ "$total" -gt 1 ] ||
106+
continue
107+
108+
missing="$(printf '%s\n' "$show" | grep -c 'missing' ||:)"
109+
110+
if [ "${missing:-0}" -gt 0 ]; then
111+
message "btrfs $uuid: $missing of $total device(s) missing, adding degraded mount option"
112+
113+
# shellcheck disable=SC2016
114+
fsdev_escaped="$(printf '%s\n' "$fsdev" | sed 's/[[\.*^$()+?{|]/\\&/g')"
115+
if ! grep -qE "^${fsdev_escaped}[[:space:]].*degraded" /etc/fstab; then
116+
sed -i "/^${fsdev_escaped}[[:space:]]/s/\(auto\|btrfs\)\([[:space:]]\+\)/btrfs\2degraded,/" /etc/fstab
117+
changed=1
118+
fi
119+
else
120+
message "btrfs $uuid: all $total devices present"
121+
fi
122+
done < <(btrfs_fstab_entries | sort -u -k2,2)
123+
124+
[ -z "$changed" ] ||
125+
rootdelay_reset_timer
126+
) &
127+
128+
echo "$!" > "$pidfile"
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
SUBSYSTEM=="block", ACTION!="remove", ENV{ID_FS_TYPE}=="btrfs", RUN+="/bin/udev-run btrfs device scan $env{DEVNAME}"
2+
SUBSYSTEM=="block", ACTION!="remove", ENV{ID_FS_TYPE}=="btrfs", RUN+="/lib/uevent/filters/btrfs-member"

features/btrfs/rules.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ MODULES_ADD += $(BTRFS_MODULES)
44

55
PUT_UDEV_RULES += $(BTRFS_UDEV_RULES)
66
PUT_FEATURE_PROGS += $(BTRFS_PROGS)
7+
PUT_FEATURE_DIRS += $(BTRFS_DATADIR)
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# param KICKSTART_DISKS=3
2+
# param BOOT_DISKS=2
3+
# param BOOT_CMDLINE="$BOOT_CMDLINE rdacct=1 rdlog=console rd-debug-udev=1 quiet panic=0 root=LABEL=fs rootflags=subvol=root"
4+
5+
ignoredisk --drives=LABEL=SYSIMAGE
6+
clearpart --all --initlabel --disklabel=mbr
7+
8+
part /boot --size=100% --fstype=ext4 --label=BOOT
9+
10+
part btrfs.01 --size=100%
11+
part btrfs.02 --size=100%
12+
13+
btrfs none --data=1 --metadata=1 --label=fs btrfs.0*
14+
15+
btrfs / --subvol --name=root LABEL=fs
16+
17+
liveimg --url=dir:///sysimage/
18+
19+
shutdown

testing/test-root-btrfs-raid1.cfg

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# param KICKSTART_DISKS=3
2+
# param BOOT_DISKS=3
3+
# param BOOT_CMDLINE="$BOOT_CMDLINE rdacct=1 rdlog=console rd-debug-udev=1 quiet panic=0 root=LABEL=fs rootflags=subvol=root"
4+
5+
ignoredisk --drives=LABEL=SYSIMAGE
6+
clearpart --all --initlabel --disklabel=mbr
7+
8+
part /boot --size=100% --fstype=ext4 --label=BOOT
9+
10+
part btrfs.01 --size=100%
11+
part btrfs.02 --size=100%
12+
13+
btrfs none --data=1 --metadata=1 --label=fs btrfs.0*
14+
15+
btrfs / --subvol --name=root LABEL=fs
16+
17+
liveimg --url=dir:///sysimage/
18+
19+
shutdown

0 commit comments

Comments
 (0)