From 5329381354e422f907f95f6d74e97d9cb266094f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20Ferr=C3=A3o?= <2031761+viniciusferrao@users.noreply.github.com> Date: Fri, 21 Aug 2026 00:22:41 -0300 Subject: [PATCH 1/5] fix(getinstdisk): let Xen virtual disks reach the disk scan The device filter accepted sd, hd, vd and nvme names, so the xvd names that a Xen guest presents never entered the scan. On such a guest the whole detection ran on an empty list and the script fell through to the xvda fallback, which takes the first Xen disk without looking at any of them. Accept the xvd names in the filter. A Xen disk now goes through the same classification, kernel search and driver sort as any other disk, so a guest with more than one disk gets a chosen disk rather than the first one. The fallback stays for the case where the scan still finds nothing. The nvme branch of the filter is anchored at the same time, so a name only matches when it starts with nvme. --- xCAT-server/share/xcat/install/scripts/getinstdisk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xCAT-server/share/xcat/install/scripts/getinstdisk b/xCAT-server/share/xcat/install/scripts/getinstdisk index bb345a632..50142519b 100644 --- a/xCAT-server/share/xcat/install/scripts/getinstdisk +++ b/xCAT-server/share/xcat/install/scripts/getinstdisk @@ -38,9 +38,9 @@ if [ -z "$install_disk" ]; then # Get all partitions and disks from /proc/partitions file if [ -z "$has_awk" ]; then - entries=$(cat /proc/partitions | sed 's/ */ /g' | cut -d " " -f5 | grep -v "name" | grep -E '^[s|h|v]d|nvme') + entries=$(cat /proc/partitions | sed 's/ */ /g' | cut -d " " -f5 | grep -v "name" | grep -E '^(x?v|s|h)d|^nvme') else - entries=$(awk -F ' ' '{print $4}' /proc/partitions | grep -v "name" | grep -E '^[s|h|v]d|nvme') + entries=$(awk -F ' ' '{print $4}' /proc/partitions | grep -v "name" | grep -E '^(x?v|s|h)d|^nvme') fi # Classify entries by DEVTYPE From bbd1a7e9d3b044687a18d7f174568e7dbb34d3ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20Ferr=C3=A3o?= <2031761+viniciusferrao@users.noreply.github.com> Date: Fri, 21 Aug 2026 00:23:19 -0300 Subject: [PATCH 2/5] test(getinstdisk): cover the Xen disk scan Cover a guest whose only disk is a Xen disk, which the scan has to select rather than leave to the fallback, and a guest with two Xen disks, where the driver group decides. Against the previous filter both cases fail. --- xCAT-test/unit/getinstdisk_selection.t | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/xCAT-test/unit/getinstdisk_selection.t b/xCAT-test/unit/getinstdisk_selection.t index cb4dfa55d..b207e4931 100644 --- a/xCAT-test/unit/getinstdisk_selection.t +++ b/xCAT-test/unit/getinstdisk_selection.t @@ -130,6 +130,15 @@ selects( '/dev/nvme0n1', 'an NVMe device is selected from the last group', # No usable disk falls back to the documented default. selects( '/dev/sda', 'no disks fall back to the default' ); +# A Xen guest presents xvd names. The scan has to see them, because the +# fallback below it would take the first one without looking. +selects( '/dev/xvda', 'a Xen disk is scanned rather than assumed', + xvda => { driver => 'vbd' } ); + +selects( '/dev/xvdb', 'the better driver group wins among Xen disks', + xvda => { driver => 'vbd' }, + xvdb => { driver => 'ahci' } ); + # Every installer includes the one script, which carries the fallbacks and the # logging that the separate RHEL 10 copy used to hold on its own. my $common = slurp( $scripts[0] ); From 27aaa960fa7bef002d30b949b0f7695e48ca3b22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20Ferr=C3=A3o?= <2031761+viniciusferrao@users.noreply.github.com> Date: Fri, 21 Aug 2026 00:24:35 -0300 Subject: [PATCH 3/5] fix(getinstdisk): choose the driver group before the identifier The scan wrote each disk into a file named after the identifier it reported, wwn, path or neither, and read back the groups of one such file only. Two disks that reported different identifiers therefore never competed on their driver group: a disk without a WWN was dropped as soon as another disk reported one, and when the last disk scanned reported a WWN the readback opened the WWN files alone. A direct attached boot disk that reports no WWN thus lost to a RAID volume that reports one, which is the case the driver groups exist to decide. Write every disk into the file of its driver group and keep the identifier as the sort key inside that group, ranked so that a WWN sorts ahead of a path and a path ahead of no identifier. The driver group now decides first for every disk, the identifier still decides between disks of one group, and no disk is dropped from the scan. --- .../share/xcat/install/scripts/getinstdisk | 48 ++++++++----------- 1 file changed, 19 insertions(+), 29 deletions(-) diff --git a/xCAT-server/share/xcat/install/scripts/getinstdisk b/xCAT-server/share/xcat/install/scripts/getinstdisk index 50142519b..64236b2fc 100644 --- a/xCAT-server/share/xcat/install/scripts/getinstdisk +++ b/xCAT-server/share/xcat/install/scripts/getinstdisk @@ -156,10 +156,8 @@ if [ -z "$install_disk" ]; then rm $file; done - has_wwn=0 - has_path=0 - file_pre="" disk_data="" + disk_rank="" # Check disks which had installed OS, or check all disks in /proc/partitions for disk in $disks; do @@ -177,59 +175,51 @@ if [ -z "$install_disk" ]; then echo "[get_install_disk] disk_path=$disk_path" echo "[get_install_disk] disk_driver=$disk_driver" - # Check whether there is WWN, PATH information + # Rank the identifier. A disk that reports a WWN sorts ahead of one + # that reports only a path, and that one ahead of a disk with neither, + # but the rank decides only among disks of the same driver group. if [ "$disk_wwn" ]; then - has_wwn=1 - file_pre="wwn" + disk_rank="0" disk_data=$disk_wwn - elif [ $has_wwn -eq 1 ]; then - echo "[get_install_disk] The disk $disk has no wwn info." - echo "[get_install_disk] There is another disk with wwn info, so don't record this disk." - continue; elif [ "$disk_path" ]; then - has_path=1 - file_pre="path" + disk_rank="1" disk_data=$disk_path - elif [ $has_path -eq 1 ]; then - echo "[get_install_disk] The disk $disk has no wwn or path info." - echo "[get_install_disk] There is another disk with path info, so don't record this disk." - continue; else - file_pre="other" - disk_data="" + disk_rank="2" + disk_data="" fi # Sort disks by DRIVER type case "$disk_driver" in "ata_piix"*|"ahci") - echo "$disk $disk_data" >> "$tmpfile""$file_pre""firstchoicedisks" - echo "[get_install_disk] Add disk: $disk $disk_data into $file_pre firstchoicedisks" + echo "$disk $disk_rank$disk_data" >> "$tmpfile""firstchoicedisks" + echo "[get_install_disk] Add disk: $disk $disk_data into firstchoicedisks" ;; "PMC MaxRAID"|"megaraid_sas") - echo "$disk $disk_data" >> "$tmpfile""$file_pre""secondchoicedisks" - echo "[get_install_disk] Add disk: $disk $disk_data into $file_pre secondchoicedisks" + echo "$disk $disk_rank$disk_data" >> "$tmpfile""secondchoicedisks" + echo "[get_install_disk] Add disk: $disk $disk_data into secondchoicedisks" ;; "mptsas"|"mpt2sas"|"mpt3sas") - echo "$disk $disk_data" >> "$tmpfile""$file_pre""thirdchoicedisks" - echo "[get_install_disk] Add disk: $disk $disk_data into $file_pre thirdchoicedisks" + echo "$disk $disk_rank$disk_data" >> "$tmpfile""thirdchoicedisks" + echo "[get_install_disk] Add disk: $disk $disk_data into thirdchoicedisks" ;; *) - echo "$disk $disk_data" >> "$tmpfile""$file_pre""fourthchoicedisks" - echo "[get_install_disk] Add disk: $disk $disk_data into $file_pre fourthchoicedisks" + echo "$disk $disk_rank$disk_data" >> "$tmpfile""fourthchoicedisks" + echo "[get_install_disk] Add disk: $disk $disk_data into fourthchoicedisks" ;; esac done for seq in first second third fourth; do - if [ -s $tmpfile$file_pre${seq}choicedisks ]; then - install_file="$tmpfile$file_pre${seq}choicedisks" + if [ -s $tmpfile${seq}choicedisks ]; then + install_file="$tmpfile${seq}choicedisks" break fi done if [ "$install_file" ] && [ -s $install_file ]; then install_disk=/dev/$(cat $install_file | grep -v "^$" | sort -k 2 -b | cut -d " " -f1 | head -n 1) - echo "[get_install_disk]The install_disk is $install_disk by sorting $file_pre and DRIVER." + echo "[get_install_disk]The install_disk is $install_disk by DRIVER, then by identifier." fi for file in $tmpfile*; do From 492f9171a2c33f11c9ab78e22eb9ef43fdaf4506 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20Ferr=C3=A3o?= <2031761+viniciusferrao@users.noreply.github.com> Date: Fri, 21 Aug 2026 00:24:42 -0300 Subject: [PATCH 4/5] test(getinstdisk): cover the driver group against the identifier Cover a RAID volume that reports a WWN against a direct attached disk that reports none, in both scan orders, which the previous readback decided by identifier. Keep the identifier rules of one group under test as well: the disk that reports a WWN wins, the lower WWN wins between two, and a path wins over no identifier at all. --- xCAT-test/unit/getinstdisk_selection.t | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/xCAT-test/unit/getinstdisk_selection.t b/xCAT-test/unit/getinstdisk_selection.t index b207e4931..00f040548 100644 --- a/xCAT-test/unit/getinstdisk_selection.t +++ b/xCAT-test/unit/getinstdisk_selection.t @@ -55,6 +55,7 @@ sub run_scenario { my %attr = %{ $disk{$name} }; open( my $props, '>', "$fixdir/$name.props" ) or die $!; print $props "ID_WWN=$attr{wwn}\n" if $attr{wwn}; + print $props "DEVPATH=$attr{path}\n" if $attr{path}; print $props "DEVTYPE=disk\n"; close($props); open( my $attrs, '>', "$fixdir/$name.attrs" ) or die $!; @@ -130,6 +131,31 @@ selects( '/dev/nvme0n1', 'an NVMe device is selected from the last group', # No usable disk falls back to the documented default. selects( '/dev/sda', 'no disks fall back to the default' ); +# The driver group decides before the identifier. A disk that reports no WWN +# used to be dropped when another disk reported one, or to be ignored because +# the readback only opened the files of the last identifier class seen. +selects( '/dev/sdb', 'the direct attached disk wins when only the RAID volume reports a WWN', + sda => { driver => 'megaraid_sas', wwn => '0x5000cca0aaaa0001' }, + sdb => { driver => 'ahci' } ); + +selects( '/dev/sda', 'the direct attached disk wins when it is scanned first without a WWN', + sda => { driver => 'ahci' }, + sdb => { driver => 'megaraid_sas', wwn => '0x5000cca0aaaa0002' } ); + +# Within one driver group the identifier decides, and a disk that reports one +# is preferred, because that name is stable across reboots. +selects( '/dev/sdb', 'the disk with a WWN wins inside the group', + sda => { driver => 'ahci' }, + sdb => { driver => 'ahci', wwn => '0x5000cca0bbbb0001' } ); + +selects( '/dev/sdb', 'the lower WWN wins inside the group', + sda => { driver => 'ahci', wwn => '0x5000cca0bbbb0002' }, + sdb => { driver => 'ahci', wwn => '0x5000cca0bbbb0001' } ); + +selects( '/dev/sda', 'a path is preferred over no identifier at all', + sda => { driver => 'ahci', path => '/devices/pci0000:00/0000:00:1f.2/ata1/host0/target0:0:0/0:0:0:0/block/sda' }, + sdb => { driver => 'ahci' } ); + # A Xen guest presents xvd names. The scan has to see them, because the # fallback below it would take the first one without looking. selects( '/dev/xvda', 'a Xen disk is scanned rather than assumed', From 9fc3d52b8186031f89402fd3104abd852cd70c0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20Ferr=C3=A3o?= <2031761+viniciusferrao@users.noreply.github.com> Date: Fri, 21 Aug 2026 01:13:50 -0300 Subject: [PATCH 5/5] test(getinstdisk): follow the log lines of the new selection The install disk autotests read the log of a provisioned node. The choice files no longer carry the identifier in their name, and the selection message names the driver group and the identifier instead of the previous wording, so read the new lines. The reinstall case reads the record of its disk without naming a group, as it did before. --- .../autotest/testcase/get_install_disk/fresh_install_disk | 4 ++-- .../autotest/testcase/get_install_disk/reinstall_disk | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/xCAT-test/autotest/testcase/get_install_disk/fresh_install_disk b/xCAT-test/autotest/testcase/get_install_disk/fresh_install_disk index c75af50c8..8d7756a5e 100644 --- a/xCAT-test/autotest/testcase/get_install_disk/fresh_install_disk +++ b/xCAT-test/autotest/testcase/get_install_disk/fresh_install_disk @@ -56,11 +56,11 @@ check:output=~0x500a0751036d9e61 check:output=~0x500a0751036d9e83 check:output=~0x500a0751036d9e7a check:output=~0x500a0751036d9c24 -cmd:cat /tmp/__GETNODEATTR($$CN,os)__-__GETNODEATTR($$CN,arch)__fr_$$NO | grep "into wwn thirdchoicedisks" +cmd:cat /tmp/__GETNODEATTR($$CN,os)__-__GETNODEATTR($$CN,arch)__fr_$$NO | grep "into thirdchoicedisks" check:output=~sda 0x500a0751036d9e61 check:output=~sdb 0x500a0751036d9c24 check:output=~sdc 0x500a0751036d9e7a check:output=~sdd 0x500a0751036d9e83 -cmd:cat /tmp/__GETNODEATTR($$CN,os)__-__GETNODEATTR($$CN,arch)__fr_$$NO | grep "by sorting wwn and DRIVER" +cmd:cat /tmp/__GETNODEATTR($$CN,os)__-__GETNODEATTR($$CN,arch)__fr_$$NO | grep "by DRIVER, then by identifier" check:output=~sdb end diff --git a/xCAT-test/autotest/testcase/get_install_disk/reinstall_disk b/xCAT-test/autotest/testcase/get_install_disk/reinstall_disk index 8e096114f..dc3b3b396 100644 --- a/xCAT-test/autotest/testcase/get_install_disk/reinstall_disk +++ b/xCAT-test/autotest/testcase/get_install_disk/reinstall_disk @@ -35,7 +35,7 @@ check:rc==0 check:output=~booted cmd:xdsh $$CN "scp /var/log/xcat/xcat.log root@$$MN:/tmp/__GETNODEATTR($$CN,os)__-__GETNODEATTR($$CN,arch)__fr_before_re_$$NO" -cmd:cat /tmp/__GETNODEATTR($$CN,os)__-__GETNODEATTR($$CN,arch)__fr_$$NO | grep "by sorting wwn and DRIVER" +cmd:cat /tmp/__GETNODEATTR($$CN,os)__-__GETNODEATTR($$CN,arch)__fr_$$NO | grep "by DRIVER, then by identifier" check:output=~sdb cmd:chdef $$CN status= @@ -72,9 +72,9 @@ cmd:cat /tmp/__GETNODEATTR($$CN,os)__-__GETNODEATTR($$CN,arch)__fr_$$NO | grep " check:output=~The disk sdb information cmd:cat /tmp/__GETNODEATTR($$CN,os)__-__GETNODEATTR($$CN,arch)__fr_$$NO | grep "disk_wwn=" check:output=~0x500a0751036d9c24 -cmd:cat /tmp/__GETNODEATTR($$CN,os)__-__GETNODEATTR($$CN,arch)__fr_$$NO | grep "into wwn" -check:output=~sdb 0x500a0751036d9c24 into wwn -cmd:cat /tmp/__GETNODEATTR($$CN,os)__-__GETNODEATTR($$CN,arch)__fr_$$NO | grep "by sorting wwn and DRIVER" +cmd:cat /tmp/__GETNODEATTR($$CN,os)__-__GETNODEATTR($$CN,arch)__fr_$$NO | grep "0x500a0751036d9c24 into" +check:output=~sdb 0x500a0751036d9c24 into +cmd:cat /tmp/__GETNODEATTR($$CN,os)__-__GETNODEATTR($$CN,arch)__fr_$$NO | grep "by DRIVER, then by identifier" check:output=~sdb end