|
9 | 9 | . shell-error |
10 | 10 | . shell-quote |
11 | 11 | . shell-args |
| 12 | +. shell-var |
| 13 | + |
| 14 | +. initrd-sh-functions |
12 | 15 |
|
13 | 16 | . "$0-sh-storage" |
14 | 17 | . "$0-sh-installation" |
@@ -145,62 +148,120 @@ KS_ORDERS=( |
145 | 148 | 9200000000:shutdown |
146 | 149 | ) |
147 | 150 |
|
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() |
149 | 154 | { |
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 |
159 | 157 |
|
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 |
164 | 225 | } |
165 | 226 |
|
166 | 227 | ks_block_devices() |
167 | 228 | { |
168 | | - local retval="$1"; shift |
169 | | - local f dev |
170 | | - local maj min |
171 | | - local blocktype |
| 229 | + local retval="$1" |
| 230 | + local majmin dev |
172 | 231 | local exclude=',' |
173 | 232 |
|
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}," |
179 | 239 | done |
180 | 240 |
|
181 | 241 | set -- |
182 | 242 |
|
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" |
186 | 245 |
|
187 | | - maj= |
188 | | - min= |
189 | | - IFS=: read -r maj min < "$f/dev" |
190 | | - blocktype="$(get_device_type "$maj")" |
| 246 | + [ -n "${exclude##*,$majmin,*}" ] || |
| 247 | + continue |
191 | 248 |
|
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:*) |
196 | 257 | continue |
197 | 258 | ;; |
198 | 259 | esac |
199 | 260 |
|
200 | | - [ -n "${exclude##*,${f##*/},*}" ] || |
| 261 | + ks_valid_block_device "$dev" || |
201 | 262 | continue |
202 | 263 |
|
203 | | - set -- "$@" "${f##*/}" |
| 264 | + set -- "$@" "${dev##*/}" |
204 | 265 | done |
205 | 266 |
|
206 | 267 | eval "$retval=\"\$*\"" |
|
0 commit comments