Skip to content

Commit 32cb9ee

Browse files
committed
kickstart: Rewrite block devices detection
Instead of having a whitelist of block device types you can try to guess if it is possible to scan partitions. The same code is used in systemd. Signed-off-by: Alexey Gladkov <[email protected]>
1 parent 13a27fb commit 32cb9ee

File tree

1 file changed

+97
-36
lines changed

1 file changed

+97
-36
lines changed

features/kickstart/data/bin/kickstart

Lines changed: 97 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
. shell-error
1010
. shell-quote
1111
. shell-args
12+
. shell-var
13+
14+
. initrd-sh-functions
1215

1316
. "$0-sh-storage"
1417
. "$0-sh-installation"
@@ -145,62 +148,120 @@ KS_ORDERS=(
145148
9200000000:shutdown
146149
)
147150

148-
get_device_type()
151+
# Based on systemd code.
152+
# https://github.com/systemd/systemd/blob/main/src/shared/blockdev-util.c#L359
153+
ks_valid_block_device()
149154
{
150-
local id="$1"; shift
151-
local block=
152-
local maj type
153-
154-
while read -r maj type; do
155-
if [ -n "$block" ] && [ "$id" = "$maj" ]; then
156-
echo "$type"
157-
return 0
158-
fi
155+
local syspath="$1"
156+
local attr
159157

160-
[ "$maj $type" != 'Block devices:' ] ||
161-
block=1
162-
done </proc/devices
163-
return 1
158+
[ -e "$syspath" ] ||
159+
return 1
160+
161+
# With https://github.com/torvalds/linux/commit/a4217c6740dc64a3eb6815868a9260825e8c68c6 (v6.10,
162+
# backported to v6.6+), the partscan status is directly exposed as
163+
# 'partscan' sysattr.
164+
if [ -r "$syspath/partscan" ]; then
165+
readline attr "$syspath/partscan"
166+
167+
shell_var_is_yes "$attr" ||
168+
return 1
169+
return 0
170+
fi
171+
172+
# For loopback block device, especially for v5.19 or newer. Even if this
173+
# is enabled, we also need to check GENHD_FL_NO_PART flag through
174+
# 'ext_range' and 'capability' sysfs attributes below.
175+
if [ -r "$syspath/loop/partscan" ]; then
176+
readline attr "$syspath/loop/partscan"
177+
178+
shell_var_is_yes "$attr" ||
179+
return 1
180+
fi
181+
182+
# With https://github.com/torvalds/linux/commit/1ebe2e5f9d68e94c524aba876f27b945669a7879 (v5.17),
183+
# we can check the flag from 'ext_range' sysfs attribute directly.
184+
#
185+
# If the ext_range file doesn't exist then we are most likely looking at
186+
# a partition block device, not the whole block device. And that means
187+
# we have no partition scanning on for it (we do for its parent, but not
188+
# for the partition itself).
189+
[ -r "$syspath/ext_range" ] ||
190+
return 1
191+
192+
readline attr "$syspath/ext_range"
193+
194+
# The value should be always positive, but the kernel uses '%d'
195+
# for the attribute.
196+
shell_var_is_number "$attr" ||
197+
return 1
198+
199+
# With https://github.com/torvalds/linux/commit/e81cd5a983bb35dabd38ee472cf3fea1c63e0f23 (v6.3),
200+
# the 'capability' sysfs attribute is deprecated, hence we cannot check
201+
# flags from it.
202+
if [ -r "$syspath/capability" ]; then
203+
# With https://github.com/torvalds/linux/commit/430cc5d3ab4d0ba0bd011cfbb0035e46ba92920c (v5.17),
204+
# the value of GENHD_FL_NO_PART is changed from 0x0200 to 0x0004
205+
local GENHD_FL_NO_PART_v5_17=$(( 0x0200 ))
206+
local GENHD_FL_NO_PART_v6_3=$(( 0x0004 ))
207+
208+
readline attr "$f/capability"
209+
210+
# If one of the NO_PART flags is set, part scanning is
211+
# definitely off.
212+
shell_var_is_number "$attr" &&
213+
[ "$(( $attr & ( $GENHD_FL_NO_PART_v5_17 | $GENHD_FL_NO_PART_v6_3 ) ))" -eq 0 ] ||
214+
return 1
215+
fi
216+
217+
# Otherwise, assume part scanning is on.
218+
return 0
219+
}
220+
221+
ks_list_devices()
222+
{
223+
find /sys/dev/block -mindepth 1 -maxdepth 1 -exec readlink -f '{}' ';' |
224+
sort -d
164225
}
165226

166227
ks_block_devices()
167228
{
168-
local retval="$1"; shift
169-
local f dev
170-
local maj min
171-
local blocktype
229+
local retval="$1"
230+
local majmin dev
172231
local exclude=','
173232

174-
for f in $(findmnt -lno SOURCE | sed -n -e 's,^/dev/,,p'); do
175-
dev="$(readlink -f "/sys/class/block/$f")"
176-
dev="${dev%/$f}"
177-
dev="${dev##*/}"
178-
exclude="$exclude$dev,"
233+
for majmin in $(findmnt -lno MAJ:MIN |sed -e '/^ *0:.*/d' |sort -u); do
234+
dev="$(readlink -f "/sys/dev/block/$majmin")" ||
235+
continue
236+
[ -z "${dev##*/virtual/block/*}" ] ||
237+
dev="${dev%/*}"
238+
exclude="${exclude}${majmin},"
179239
done
180240

181241
set --
182242

183-
for f in $(set +f; printf '%s\n' /sys/block/*); do
184-
[ -e "$f" ] ||
185-
continue
243+
for dev in $(ks_list_devices); do
244+
readline majmin "$dev/dev"
186245

187-
maj=
188-
min=
189-
IFS=: read -r maj min < "$f/dev"
190-
blocktype="$(get_device_type "$maj")"
246+
[ -n "${exclude##*,$majmin,*}" ] ||
247+
continue
191248

192-
case "$blocktype" in
193-
sd|virtblk|mmc|blkext)
194-
;;
195-
*)
249+
case "$majmin" in
250+
# 0 - Unnamed devices (e.g. non-device mounts)
251+
# 1 block - RAM disk
252+
# 4 block - Aliases for dynamically allocated major
253+
# devices to be used when its not possible to
254+
# create the real device nodes because the
255+
# root filesystem is mounted read-only.
256+
0:*|1:*|4:*)
196257
continue
197258
;;
198259
esac
199260

200-
[ -n "${exclude##*,${f##*/},*}" ] ||
261+
ks_valid_block_device "$dev" ||
201262
continue
202263

203-
set -- "$@" "${f##*/}"
264+
set -- "$@" "${dev##*/}"
204265
done
205266

206267
eval "$retval=\"\$*\""

0 commit comments

Comments
 (0)