Skip to content

Commit

Permalink
lxd/device: Add support for discovering multiple unix hotplug devices
Browse files Browse the repository at this point in the history
Signed-off-by: Kadin Sayani <[email protected]>
  • Loading branch information
kadinsayani committed Nov 12, 2024
1 parent 9ac2433 commit a3f9709
Showing 1 changed file with 42 additions and 31 deletions.
73 changes: 42 additions & 31 deletions lxd/device/unix_hotplug.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,7 @@ func (d *unixHotplug) validateConfig(instConf instance.ConfigReader) error {

// Register is run after the device is started or when LXD starts.
func (d *unixHotplug) Register() error {
// Extract variables needed to run the event hook so that the reference to this device
// struct is not needed to be kept in memory.
// Extract variables needed to run the event hook so that the reference to this device struct is not required to be stored in memory.
devicesPath := d.inst.DevicesPath()
devConfig := d.config
deviceName := d.name
Expand Down Expand Up @@ -149,29 +148,36 @@ func (d *unixHotplug) Start() (*deviceConfig.RunConfig, error) {
runConf := deviceConfig.RunConfig{}
runConf.PostHooks = []func() error{d.Register}

device := d.loadUnixDevice()
if d.isRequired() && device == nil {
devices := d.loadUnixDevices()
if d.isRequired() && devices == nil {
return nil, fmt.Errorf("Required Unix Hotplug device not found")
}

if device == nil {
if devices == nil {
return &runConf, nil
}

devnum := device.Devnum()
major := uint32(devnum.Major())
minor := uint32(devnum.Minor())
for _, device := range devices {
devnum := device.Devnum()
major := uint32(devnum.Major())
minor := uint32(devnum.Minor())

// Setup device.
var err error
if device.Subsystem() == "block" {
err = unixDeviceSetupBlockNum(d.state, d.inst.DevicesPath(), "unix", d.name, d.config, major, minor, device.Devnode(), false, &runConf)
} else {
err = unixDeviceSetupCharNum(d.state, d.inst.DevicesPath(), "unix", d.name, d.config, major, minor, device.Devnode(), false, &runConf)
}

// setup device
var err error
if device.Subsystem() == "block" {
err = unixDeviceSetupBlockNum(d.state, d.inst.DevicesPath(), "unix", d.name, d.config, major, minor, device.Devnode(), false, &runConf)
} else {
err = unixDeviceSetupCharNum(d.state, d.inst.DevicesPath(), "unix", d.name, d.config, major, minor, device.Devnode(), false, &runConf)
}
if err != nil {
err := unixDeviceRemove(d.inst.DevicesPath(), "unix", d.name, "", &runConf)
if err != nil {
return nil, err
}

if err != nil {
return nil, err
return nil, err
}
}

return &runConf, nil
Expand Down Expand Up @@ -203,9 +209,9 @@ func (d *unixHotplug) postStop() error {
return nil
}

// loadUnixDevice scans the host machine for unix devices with matching product/vendor ids
// and returns the first matching device with the subsystem type char or block.
func (d *unixHotplug) loadUnixDevice() *udev.Device {
// loadUnixDevices scans the host machine for unix devices with matching product/vendor ids
// and returns the matching devices with subsystem types of char or block.
func (d *unixHotplug) loadUnixDevices() []*udev.Device {
// Find device if exists
u := udev.Udev{}
e := u.NewEnumerate()
Expand All @@ -230,27 +236,32 @@ func (d *unixHotplug) loadUnixDevice() *udev.Device {
}

devices, _ := e.Devices()
var device *udev.Device
var matchingDevices []*udev.Device
for i := range devices {
device = devices[i]
device := devices[i]

if device == nil {
if device == nil || device.Devnum().Major() == 0 || device.Devnode() == "" || strings.HasPrefix(device.Subsystem(), "usb") {
continue
}

devnum := device.Devnum()
if devnum.Major() == 0 || devnum.Minor() == 0 {
continue
match := false
vendorIDMatch := device.PropertyValue("ID_VENDOR_ID") == d.config["vendorid"]
productIDMatch := device.PropertyValue("ID_MODEL_ID") == d.config["productid"]

if d.config["vendorid"] != "" && d.config["productid"] != "" {
match = vendorIDMatch && productIDMatch
} else if d.config["vendorid"] != "" {
match = vendorIDMatch
} else if d.config["productid"] != "" {
match = productIDMatch
}

if device.Devnode() == "" {
if !match {
continue
}

if !strings.HasPrefix(device.Subsystem(), "usb") {
return device
}
matchingDevices = append(matchingDevices, device)
}

return nil
return matchingDevices
}

0 comments on commit a3f9709

Please sign in to comment.