@@ -473,7 +473,7 @@ for VM in "${VMS[@]}"; do
473473 # -- MDEV hostdevs: use xmlstarlet to extract UUIDs --
474474 while IFS= read -r UUID; do
475475 [[ -n " $UUID " ]] && mdev_to_vm[" $UUID " ]=" $VM "
476- done < <( echo " $xml " | xmlstarlet sel -T -t -m " //hostdev[@type='mdev']" -v " @uuid" -n 2> /dev/null || true)
476+ done < <( echo " $xml " | xmlstarlet sel -T -t -m " //hostdev[@type='mdev']/source/address " -v " @uuid" -n 2> /dev/null || true)
477477done
478478
479479# Helper: convert a VM name to JSON value (quoted string or null)
@@ -516,6 +516,55 @@ parse_and_add_gpu_properties() {
516516 fi
517517}
518518
519+ # Finds and formats mdev instances for a given PCI device (PF or VF).
520+ # Appends JSON strings for each found mdev instance to the global 'vlist' array.
521+ # Arguments:
522+ # $1: mdev_base_path (e.g., /sys/bus/pci/devices/.../mdev_supported_types)
523+ # $2: bdf (e.g., 01:00.0)
524+ process_mdev_instances () {
525+ local mdev_base_path=" $1 "
526+ local bdf=" $2 "
527+
528+ if [[ ! -d " $mdev_base_path " ]]; then
529+ return
530+ fi
531+
532+ for PROF_DIR in " $mdev_base_path " /* ; do
533+ [[ -d " $PROF_DIR " ]] || continue
534+
535+ local PROFILE_NAME
536+ if [[ -f " $PROF_DIR /name" ]]; then
537+ PROFILE_NAME=$( < " $PROF_DIR /name" )
538+ else
539+ PROFILE_NAME=$( basename " $PROF_DIR " )
540+ fi
541+
542+ parse_and_add_gpu_properties " $PROF_DIR /description"
543+
544+ local DEVICE_DIR=" $PROF_DIR /devices"
545+ if [[ -d " $DEVICE_DIR " ]]; then
546+ for UDIR in " $DEVICE_DIR " /* ; do
547+ [[ -d " $UDIR " ]] || continue
548+ local MDEV_UUID
549+ MDEV_UUID=$( basename " $UDIR " )
550+
551+ local DOMAIN=" 0x0000"
552+ local BUS=" 0x${bdf: 0: 2} "
553+ local SLOT=" 0x${bdf: 3: 2} "
554+ local FUNC=" 0x${bdf: 6: 1} "
555+
556+ local raw
557+ raw=" ${mdev_to_vm[$MDEV_UUID]:- } "
558+ local USED_JSON
559+ USED_JSON=$( to_json_vm " $raw " )
560+
561+ vlist+=(
562+ " {\" mdev_uuid\" :\" $MDEV_UUID \" ,\" profile_name\" :$( json_escape " $PROFILE_NAME " ) ,\" max_instances\" :$MAX_INSTANCES ,\" video_ram\" :$VIDEO_RAM ,\" max_heads\" :$MAX_HEADS ,\" max_resolution_x\" :$MAX_RESOLUTION_X ,\" max_resolution_y\" :$MAX_RESOLUTION_Y ,\" libvirt_address\" :{\" domain\" :\" $DOMAIN \" ,\" bus\" :\" $BUS \" ,\" slot\" :\" $SLOT \" ,\" function\" :\" $FUNC \" },\" used_by_vm\" :$USED_JSON }" )
563+ done
564+ fi
565+ done
566+ }
567+
519568# === GPU Discovery ===
520569
521570mapfile -t LINES < <( lspci -nnm)
@@ -588,51 +637,9 @@ for LINE in "${LINES[@]}"; do
588637 # === vGPU (MDEV) instances ===
589638 VGPU_ARRAY=" []"
590639 declare -a vlist=()
640+ # Process mdev on the Physical Function
591641 MDEV_BASE=" /sys/bus/pci/devices/0000:$PCI_ADDR /mdev_supported_types"
592- if [[ -d " $MDEV_BASE " ]]; then
593- for PROF_DIR in " $MDEV_BASE " /* ; do
594- [[ -d " $PROF_DIR " ]] || continue
595-
596- # Read the human-readable profile name from the 'name' file
597- if [[ -f " $PROF_DIR /name" ]]; then
598- PROFILE_NAME=$( < " $PROF_DIR /name" )
599- else
600- PROFILE_NAME=$( basename " $PROF_DIR " )
601- fi
602-
603- # Fetch max_instance from the description file, if present
604- parse_and_add_gpu_properties " $PROF_DIR /description"
605-
606- # Under each profile, existing UUIDs appear in:
607- # /sys/bus/pci/devices/0000:$PCI_ADDR/mdev_supported_types/<PROFILE>/devices/*
608- DEVICE_DIR=" $PROF_DIR /devices"
609- if [[ -d " $DEVICE_DIR " ]]; then
610- for UDIR in " $DEVICE_DIR " /* ; do
611- [[ -d $UDIR ]] || continue
612- MDEV_UUID=$( basename " $UDIR " )
613-
614- # libvirt_address uses PF BDF
615- DOMAIN=" 0x0000"
616- BUS=" 0x${PCI_ADDR: 0: 2} "
617- SLOT=" 0x${PCI_ADDR: 3: 2} "
618- FUNC=" 0x${PCI_ADDR: 6: 1} "
619-
620- # Determine which VM uses this UUID
621- raw=" ${mdev_to_vm[$MDEV_UUID]:- } "
622- USED_JSON=$( to_json_vm " $raw " )
623-
624- vlist+=(
625- " {\" mdev_uuid\" :\" $MDEV_UUID \" ,\" profile_name\" :$( json_escape " $PROFILE_NAME " ) ,\" max_instances\" :$MAX_INSTANCES ,\" video_ram\" :$VIDEO_RAM ,\" max_heads\" :$MAX_HEADS ,\" max_resolution_x\" :$MAX_RESOLUTION_X ,\" max_resolution_y\" :$MAX_RESOLUTION_Y ,\" libvirt_address\" :{\" domain\" :\" $DOMAIN \" ,\" bus\" :\" $BUS \" ,\" slot\" :\" $SLOT \" ,\" function\" :\" $FUNC \" },\" used_by_vm\" :$USED_JSON }" )
626- done
627- fi
628- done
629- if [ ${# vlist[@]} -gt 0 ]; then
630- VGPU_ARRAY=" [$(
631- IFS=,
632- echo " ${vlist[*]} "
633- ) ]"
634- fi
635- fi
642+ process_mdev_instances " $MDEV_BASE " " $PCI_ADDR "
636643
637644 # === VF instances (SR-IOV / MIG) ===
638645 VF_ARRAY=" []"
@@ -644,6 +651,12 @@ for LINE in "${LINES[@]}"; do
644651 VF_ADDR=${VF_PATH##*/ } # e.g. "0000:65:00.2"
645652 VF_BDF=" ${VF_ADDR: 5} " # "65:00.2"
646653
654+ # For NVIDIA SR-IOV, check for vGPU (mdev) on the VF itself
655+ if [[ " $VENDOR_ID " == " 10de" ]]; then
656+ VF_MDEV_BASE=" $VF_PATH /mdev_supported_types"
657+ process_mdev_instances " $VF_MDEV_BASE " " $VF_BDF "
658+ fi
659+
647660 DOMAIN=" 0x0000"
648661 BUS=" 0x${VF_BDF: 0: 2} "
649662 SLOT=" 0x${VF_BDF: 3: 2} "
@@ -674,6 +687,14 @@ for LINE in "${LINES[@]}"; do
674687 fi
675688 fi
676689
690+ # Consolidate all vGPU instances (from PF and VFs)
691+ if [ ${# vlist[@]} -gt 0 ]; then
692+ VGPU_ARRAY=" [$(
693+ IFS=,
694+ echo " ${vlist[*]} "
695+ ) ]"
696+ fi
697+
677698 # === full_passthrough block ===
678699 # If vgpu_instances and vf_instances are empty, we can assume full passthrough
679700 FP_ENABLED=0
0 commit comments