4747 pciAddressRegex = regexp .MustCompile (`^[0-9a-fA-F]{4}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}\.[0-9a-fA-F]$` )
4848)
4949
50+ const (
51+ REDHAT_VENDOR = "0x1af4"
52+ VIRTIO_BLOCK_DEVICE = "1042"
53+ )
54+
5055type IMount interface {
5156 Mounter () * mount.SafeFormatAndMount
5257 ScanForAttach (devicePath string ) error
@@ -125,11 +130,10 @@ func probeVolume() error {
125130 return nil
126131}
127132
128- // GetEmptyPCIeRootPorts returns the number of PCIe Root ports who currently
129- // do not have ANY downstream devices, therefore considered "empty". This
130- // function is used dynamically how many more devices (in this case "volumes")
131- // can be mounted to the given node.
132- func GetEmptyPCIeRootPorts () (int64 , error ) {
133+ // CountNonVirtioBlockDevices returns the number of PCIe Root ports who
134+ // are currently occupied by anything else than an VIRTIO 1.0 Block Device
135+ // returns zero when something went wrong
136+ func CountNonVirtioBlockDevices () (int64 , error ) {
133137 const pciPath = "/sys/bus/pci/devices"
134138
135139 // Get all PCI devices
@@ -138,7 +142,7 @@ func GetEmptyPCIeRootPorts() (int64, error) {
138142 return 0 , fmt .Errorf ("failed to read PCI bus: %w" , err )
139143 }
140144
141- emptyCount := 0
145+ pcieSlotsOccupiedByNonBlockDevice := 0
142146
143147 for _ , dev := range devices {
144148 devPath := filepath .Join (pciPath , dev .Name ())
@@ -158,7 +162,7 @@ func GetEmptyPCIeRootPorts() (int64, error) {
158162 // 2. Check if the port has downstream devices
159163 // If the bridge has children, they appear as subdirectories
160164 // matching the PCI address format (e.g., 0000:01:00.0)
161- hasChild := false
165+ isNonBLockDevice := false
162166 files , err2 := os .ReadDir (devPath )
163167 if err2 != nil {
164168 klog .Errorf ("failed to read dir %s : %v" , devPath , err2 )
@@ -167,20 +171,36 @@ func GetEmptyPCIeRootPorts() (int64, error) {
167171 // Ignore PCI bus directories such as pci001 pci002 and pci010
168172 // Devices must follow <domain:bus:device.function> format
169173 if pciAddressRegex .MatchString (file .Name ()) {
170- hasChild = true
174+ isNonBLockDevice = probePCIeDevice ( devPath , file , isNonBLockDevice )
171175 break
172176 }
173177 }
174178
175- if ! hasChild {
176- emptyCount ++
179+ if ! isNonBLockDevice {
180+ pcieSlotsOccupiedByNonBlockDevice ++
177181 }
178182 } else {
179183 klog .Infof ("skipping class %s: path: %s" , class , devPath )
180184 }
181185 }
182186
183- return int64 (emptyCount ), nil
187+ return int64 (pcieSlotsOccupiedByNonBlockDevice ), nil
188+ }
189+
190+ func probePCIeDevice (devPath string , file os.DirEntry , isNonBLockDevice bool ) bool {
191+ pciDevicePath := filepath .Join (devPath , file .Name ())
192+ deviceBuf , err := os .ReadFile (filepath .Join (pciDevicePath , "device" ))
193+ if err != nil {
194+ klog .Errorf ("failed to read PCI device file %s : %v" , pciDevicePath , err )
195+ }
196+ vendorBuf , err := os .ReadFile (filepath .Join (pciDevicePath , "vendor" ))
197+ if err != nil {
198+ klog .Errorf ("failed to read PCI device vendor %s : %v" , pciDevicePath , err )
199+ }
200+ if strings .TrimSpace (string (vendorBuf )) == REDHAT_VENDOR && strings .TrimSpace (string (deviceBuf )) != VIRTIO_BLOCK_DEVICE {
201+ isNonBLockDevice = true
202+ }
203+ return isNonBLockDevice
184204}
185205
186206// GetDevicePath returns the path of an attached block storage volume, specified by its id.
0 commit comments