Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions distro/kernel/ovmx-x86_64.config
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,22 @@ CONFIG_VIRTIO_PCI=y
CONFIG_VIRTIO_BLK=y
CONFIG_VIRTIO_NET=y

# --- virtio-scsi (non-virtio-blk disks: bare-metal SATA/SCSI, vms-ddc / --
# vms-47d) -------------------------------------------------------------
# OVMX targets bare metal, where the system disk is SATA/SCSI/NVMe, not
# virtio-blk. A prior attempt (reverted) tried NVMe here, but this minimal
# from-source config lacks the MSI-X plumbing NVMe needs to bring up
# /dev/nvme0n1 in the guest. virtio-scsi instead reuses the already-enabled
# virtio transport above and presents disks as /dev/sd*, exercising the
# SAME non-virtio probe path (vms_devtab_probe_disks()'s SATA/SCSI loop)
# reliably in a minimal kernel. Built-in (=y, never =m -- the initramfs
# loads no modules). test_kmod_disk.c attaches one real virtio-scsi disk
# and proves the executive enters SDA0: for it.
CONFIG_SCSI=y
CONFIG_BLK_DEV_SD=y
CONFIG_SCSI_LOWLEVEL=y
CONFIG_SCSI_VIRTIO=y

# --- Block layer (the virtio-blk system disk) -----------------------------
CONFIG_BLOCK=y

Expand Down
57 changes: 57 additions & 0 deletions src/kernel-core/vms_devtab.c
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,63 @@ static void vms_devtab_probe_disks(void)
pr_info("vms: disk unit %s -> %s (%u:%u)\n",
devnam, backing, exec_blockdev_major(dev), exec_blockdev_minor(dev));
}

/*
* Beyond virtio-blk: real and bare-metal boots (the operator's Rule-9
* target) rarely have /dev/vd* -- their system disk is SATA/SCSI (/dev/sd*)
* or NVMe (/dev/nvmeNn1). Probing ONLY virtio left the device table with no
* disk row on those substrates, so `SHOW DEVICE <disk>:` returned NOSUCHDEV
* and a bare `SHOW DEVICE` showed only the console -- the "hollow" surface a
* user hits on non-virtio hardware (vms-ddc / vms-47d). These two families
* complete the documented device-native naming scheme. INV-6 is preserved
* exactly as the virtio loop above: exec_blockdev_lookup() must actually
* resolve the node before a unit is entered -- never a speculative row.
*/
for (i = 0; i < VMS_DISK_UNITS; i++) {
char path[16];
char devnam[VMS_DEVNAM_SIZE];
char backing[VMS_BACKING_SIZE];
exec_dev_t dev;
int n;

n = snprintf(path, sizeof(path), "/dev/sd%c", 'a' + i);
if (n < 0 || n >= (int)sizeof(path))
continue;
if (exec_blockdev_lookup(path, &dev) != 0)
continue;

snprintf(devnam, sizeof(devnam), "SDA%u:", (unsigned)i * 100u);
snprintf(backing, sizeof(backing), "sd%c", 'a' + i);
vms_devtab_add_disk(devnam, backing,
exec_blockdev_major(dev), exec_blockdev_minor(dev));
}

/*
* NVMe names a block device <controller>n<namespace> (nvme0n1, nvme1n1...).
* We probe namespace 1 of each controller -- the boot/system-disk case that
* covers essentially every single-namespace machine. Additional namespaces
* (nvme0n2...) are a documented, deliberate not-yet: they are entered by
* whatever probe actually resolves them, never by a speculative branch here
* (same rule the SATA/SCSI comment above states).
*/
for (i = 0; i < VMS_DISK_UNITS; i++) {
char path[16];
char devnam[VMS_DEVNAM_SIZE];
char backing[VMS_BACKING_SIZE];
exec_dev_t dev;
int n;

n = snprintf(path, sizeof(path), "/dev/nvme%dn1", i);
if (n < 0 || n >= (int)sizeof(path))
continue;
if (exec_blockdev_lookup(path, &dev) != 0)
continue;

snprintf(devnam, sizeof(devnam), "NVME%u:", (unsigned)i * 100u);
snprintf(backing, sizeof(backing), "nvme%dn1", i);
vms_devtab_add_disk(devnam, backing,
exec_blockdev_major(dev), exec_blockdev_minor(dev));
}
}

/*
Expand Down
8 changes: 5 additions & 3 deletions src/kernel/vms_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -1526,9 +1526,11 @@ int vms_devtab_init(void);
void vms_devtab_cleanup(void);
/*
* Enter ONE disk unit the SUBSTRATE enumerated, for a substrate whose disks the
* shared /dev/vd* probe cannot name (rd vms-618 -- NetBSD/vax MSCP units). Not
* called on Linux, where vms_devtab_probe_disks() does the enumeration; declared
* here so the shared facility source keeps one prototype on every substrate.
* shared /dev/vd* probe cannot name (rd vms-618 -- NetBSD/vax MSCP units). On
* Linux, vms_devtab_probe_disks() calls this too for the non-virtio-blk
* families it enumerates itself (SATA/SCSI /dev/sd*, NVMe /dev/nvmeNn1 --
* vms-ddc / vms-47d, bare-metal device-native naming); declared here so the
* shared facility source keeps one prototype on every substrate.
*/
int vms_devtab_add_disk(const char *devnam, const char *backing,
uint32_t backing_major, uint32_t backing_minor);
Expand Down
15 changes: 13 additions & 2 deletions tests/qemu/run_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,15 @@ else
echo " the IMGACT-over-ACP test (vms-3e8e) needs an ODS-2 image volume on VDA400: (vde)" >&2
exit 2
fi
trap 'rm -f "$ASSERT_TRANSCRIPT" "$OVMX_DISK0" "$OVMX_DISK1" "$OVMX_DISK2" "$OVMX_DISK3" "$OVMX_DISK4"' EXIT
# A scratch SCSI disk (blank), attached as a REAL virtio-scsi disk below. Its
# only purpose is to prove the executive's non-virtio disk probe: with a real
# /dev/sda present in the guest, vms_devtab_probe_disks() must enter SDA0:
# resolving to that node's real major:minor (test_kmod_disk.c asserts it against
# an independent stat()). Blank is fine -- the probe resolves the node, it does
# not read the contents. vms-ddc / vms-47d (device-native naming beyond virtio).
OVMX_SCSI0=$(mktemp) || { echo "run_tests.sh: mktemp failed" >&2; exit 2; }
truncate -s 16M "$OVMX_SCSI0"
trap 'rm -f "$ASSERT_TRANSCRIPT" "$OVMX_DISK0" "$OVMX_DISK1" "$OVMX_DISK2" "$OVMX_DISK3" "$OVMX_DISK4" "$OVMX_SCSI0"' EXIT

# One virtio-net NIC (vms-9d2). Exactly as the two virtio disks above give the
# executive real block devices to enumerate into DK units, this gives it a real
Expand Down Expand Up @@ -273,6 +281,9 @@ OUTPUT=$(timeout "$TIMEOUT" $QEMU \
-device virtio-blk-pci,drive=ovmxdisk3 \
-drive if=none,id=ovmxdisk4,file="$OVMX_DISK4",format=raw \
-device virtio-blk-pci,drive=ovmxdisk4 \
-device virtio-scsi-pci,id=scsi0 \
-drive if=none,id=ovmxscsi0,file="$OVMX_SCSI0",format=raw \
-device scsi-hd,drive=ovmxscsi0,bus=scsi0.0 \
2>&1) || QEMU_RC=$?

# Splice the assertion transcript (ttyS1, if this arch has one) back into
Expand Down Expand Up @@ -316,7 +327,7 @@ OUTPUT_FILE=$(mktemp) || { echo "run_tests.sh: mktemp failed" >&2; exit 2; }
# ONE trap, both temp files: a second `trap ... EXIT` REPLACES the first
# rather than stacking with it, so registering ASSERT_TRANSCRIPT's cleanup
# separately above would have silently dropped it the moment this line ran.
trap 'rm -f "$OUTPUT_FILE" "$ASSERT_TRANSCRIPT" "$OVMX_DISK0" "$OVMX_DISK1" "$OVMX_DISK2" "$OVMX_DISK3" "$OVMX_DISK4"' EXIT
trap 'rm -f "$OUTPUT_FILE" "$ASSERT_TRANSCRIPT" "$OVMX_DISK0" "$OVMX_DISK1" "$OVMX_DISK2" "$OVMX_DISK3" "$OVMX_DISK4" "$OVMX_SCSI0"' EXIT
printf '%s\n' "$OUTPUT" > "$OUTPUT_FILE"

if harness_verdict_zero_failures "$OUTPUT_FILE"; then
Expand Down
38 changes: 35 additions & 3 deletions tests/qemu/test_kmod_disk.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ int main(void)
uint32_t vda_maj = 0, vda_min = 0, vdb_maj = 0, vdb_min = 0;
uint32_t vdc_maj = 0, vdc_min = 0, vdd_maj = 0, vdd_min = 0;
uint32_t vde_maj = 0, vde_min = 0;
int have_vda, have_vdb, have_vdc, have_vdd, have_vde;
uint32_t sda_maj = 0, sda_min = 0;
int have_vda, have_vdb, have_vdc, have_vdd, have_vde, have_sda;

printf("=== test_kmod_disk: the executive names the machine's disks ===\n");

Expand Down Expand Up @@ -97,6 +98,14 @@ int main(void)
CHECK(have_vdc, "/dev/vdc is present (third virtio disk attached to the guest)");
CHECK(have_vdd, "/dev/vdd is present (fourth virtio disk attached to the guest)");
CHECK(have_vde, "/dev/vde is present (fifth virtio disk attached to the guest)");
/* run_tests.sh also attaches ONE real virtio-scsi disk (vms-ddc / vms-47d):
* this is the non-virtio-blk disk the executive's probe must ALSO enumerate,
* so that SHOW DEVICE is not hollow on bare-metal boots (where the system
* disk is SATA/SCSI/NVMe, not virtio-blk -- the operator's SHOW DEVICE
* NOSUCHDEV). virtio-scsi presents as /dev/sda -- a real, non-virtio-blk
* kernel node -- exercising the same SATA/SCSI probe path bare metal uses. */
have_sda = (stat_devt("/dev/sda", &sda_maj, &sda_min) == 0);
CHECK(have_sda, "/dev/sda is present (a real virtio-scsi disk attached to the guest)");

/* --------------------------------------------------------------
* 1. VDA0: exists in the executive's table -- nothing in this
Expand Down Expand Up @@ -170,14 +179,37 @@ int main(void)
"VDA400: backing dev_t matches /dev/vde as userspace stat()s it");

/* --------------------------------------------------------------
* 6. Negative controls -- a resolver that always succeeded would be
* 6. SDA0: is the non-virtio-blk disk -- the real proof that the probe
* reaches beyond /dev/vd*. It must exist in the executive's table,
* back onto /dev/sda, and resolve to the SAME major:minor userspace
* stat()s for that node. A probe that only knew virtio-blk would
* leave SDA0: absent (SS$_NOSUCHDEV) -- which is exactly the hollow
* SHOW DEVICE the operator hit on non-virtio hardware.
* -------------------------------------------------------------- */
memset(backing, 0, sizeof(backing));
maj = min = 0;
status = vms_kif_disk_resolve("SDA0:", backing, sizeof(backing), &maj, &min);
CHECK(status == SS_NORMAL,
"SDA0: exists in the executive's table (a non-virtio-blk SCSI disk was enumerated)");
CHECK(strcmp(backing, "sda") == 0,
"SDA0: backing device is sda (the executive's enumeration)");
CHECK(have_sda && maj == sda_maj && min == sda_min,
"SDA0: backing dev_t matches /dev/sda as userspace stat()s it");

/* --------------------------------------------------------------
* 7. Negative controls -- a resolver that always succeeded would be
* indistinguishable from one that works.
* -------------------------------------------------------------- */
/* Five disks are attached (vda..vde), so there is no sixth unit. */
/* Five virtio disks are attached (vda..vde), so there is no sixth unit. */
memset(backing, 0, sizeof(backing));
status = vms_kif_disk_resolve("VDA500:", backing, sizeof(backing), &maj, &min);
CHECK(status == SS_NOSUCHDEV,
"a disk unit that does not exist reports SS$_NOSUCHDEV (no sixth disk attached)");
/* Only ONE virtio-scsi disk is attached, so SDA100: (a second) must miss. */
memset(backing, 0, sizeof(backing));
status = vms_kif_disk_resolve("SDA100:", backing, sizeof(backing), &maj, &min);
CHECK(status == SS_NOSUCHDEV,
"a second SCSI unit that does not exist reports SS$_NOSUCHDEV (only one attached)");

/* OPA0: exists, but it is a TERMINAL -- it has no backing block device. */
memset(backing, 0, sizeof(backing));
Expand Down
Loading