The following pull request was submitted through Github. It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/4537
This e-mail was sent by the LXC bot, direct replies will not reach the author unless they happen to be subscribed to this list. === Description (from pull-request) === Copy the mode of a devices for: - Implicitly Added Devices: Some device types (e.g. infiniband or (Nvidia) gpu) implicitly add devices to guarantee correct functionality. - Nvidia GPUs: In order for Nvidia tools to correctly function we need to copy the mode of the devices. We should do this for GPUs in general. - Hotplugged Devices: We can retrieve the mode of devices that are supposed to be hotplugged. Closes #4534. Signed-off-by: Christian Brauner <[email protected]>
From 23b844ff06b51d03fa94df5c9556ba37cde04aa5 Mon Sep 17 00:00:00 2001 From: Christian Brauner <[email protected]> Date: Sat, 5 May 2018 13:35:54 +0200 Subject: [PATCH] devices: clone mode of device Copy the mode of a devices for: - Implicitly Added Devices: Some device types (e.g. infiniband or (Nvidia) gpu) implicitly add devices to guarantee correct functionality. - Nvidia GPUs: In order for Nvidia tools to correctly function we need to copy the mode of the devices. We should do this for GPUs in general. - Hotplugged Devices: We can retrieve the mode of devices that are supposed to be hotplugged. Closes #4534. Signed-off-by: Christian Brauner <[email protected]> --- lxd/container_lxc.go | 67 +++++++++++++++++++++++++++------------------------- lxd/devices.go | 6 ++--- shared/util_linux.go | 17 +++++++++++++ 3 files changed, 55 insertions(+), 35 deletions(-) diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go index 26376e62ed..5d8aba4b74 100644 --- a/lxd/container_lxc.go +++ b/lxd/container_lxc.go @@ -1745,7 +1745,7 @@ func (c *containerLXC) expandDevices() error { // setupUnixDevice() creates the unix device and sets up the necessary low-level // liblxc configuration items. -func (c *containerLXC) setupUnixDevice(prefix string, dev types.Device, major int, minor int, path string, createMustSucceed bool) error { +func (c *containerLXC) setupUnixDevice(prefix string, dev types.Device, major int, minor int, path string, createMustSucceed bool, defaultMode bool) error { if c.IsPrivileged() && !c.state.OS.RunningInUserNS && c.state.OS.CGroupDevicesController { err := lxcSetConfigItem(c.c, "lxc.cgroup.devices.allow", fmt.Sprintf("c %d:%d rwm", major, minor)) if err != nil { @@ -1754,7 +1754,8 @@ func (c *containerLXC) setupUnixDevice(prefix string, dev types.Device, major in } temp := types.Device{} - if err := shared.DeepCopy(&dev, &temp); err != nil { + err := shared.DeepCopy(&dev, &temp) + if err != nil { return err } @@ -1762,24 +1763,21 @@ func (c *containerLXC) setupUnixDevice(prefix string, dev types.Device, major in temp["minor"] = fmt.Sprintf("%d", minor) temp["path"] = path - paths, err := c.createUnixDevice(prefix, temp) + paths, err := c.createUnixDevice(prefix, temp, defaultMode) if err != nil { - logger.Debug("failed to create device", log.Ctx{"err": err, "device": prefix}) + logger.Debug("Failed to create device", log.Ctx{"err": err, "device": prefix}) if createMustSucceed { return err } + return nil } - devPath := paths[0] - tgtPath := paths[1] - err = lxcSetConfigItem(c.c, "lxc.mount.entry", - fmt.Sprintf("%s %s none bind,create=file", - shared.EscapePathFstab(devPath), shared.EscapePathFstab(tgtPath))) - if err != nil { - return err - } - return nil + devPath := shared.EscapePathFstab(paths[0]) + tgtPath := shared.EscapePathFstab(paths[1]) + val := fmt.Sprintf("%s %s none bind,create=file", devPath, tgtPath) + + return lxcSetConfigItem(c.c, "lxc.mount.entry", val) } // Start functions @@ -1980,7 +1978,7 @@ func (c *containerLXC) startCommon() (string, error) { m := c.expandedDevices[k] if shared.StringInSlice(m["type"], []string{"unix-char", "unix-block"}) { // Unix device - paths, err := c.createUnixDevice(fmt.Sprintf("unix.%s", k), m) + paths, err := c.createUnixDevice(fmt.Sprintf("unix.%s", k), m, true) if err != nil { // Deal with device hotplug if m["required"] == "" || shared.IsTrue(m["required"]) { @@ -2028,7 +2026,7 @@ func (c *containerLXC) startCommon() (string, error) { continue } - err := c.setupUnixDevice(fmt.Sprintf("unix.%s", k), m, usb.major, usb.minor, usb.path, shared.IsTrue(m["required"])) + err := c.setupUnixDevice(fmt.Sprintf("unix.%s", k), m, usb.major, usb.minor, usb.path, shared.IsTrue(m["required"]), false) if err != nil { return "", err } @@ -2053,7 +2051,7 @@ func (c *containerLXC) startCommon() (string, error) { found = true - err := c.setupUnixDevice(fmt.Sprintf("unix.%s", k), m, gpu.major, gpu.minor, gpu.path, true) + err := c.setupUnixDevice(fmt.Sprintf("unix.%s", k), m, gpu.major, gpu.minor, gpu.path, true, false) if err != nil { return "", err } @@ -2062,7 +2060,7 @@ func (c *containerLXC) startCommon() (string, error) { continue } - err = c.setupUnixDevice(fmt.Sprintf("unix.%s", k), m, gpu.nvidia.major, gpu.nvidia.minor, gpu.nvidia.path, true) + err = c.setupUnixDevice(fmt.Sprintf("unix.%s", k), m, gpu.nvidia.major, gpu.nvidia.minor, gpu.nvidia.path, true, false) if err != nil { return "", err } @@ -2072,7 +2070,7 @@ func (c *containerLXC) startCommon() (string, error) { if sawNvidia && !shared.IsTrue(c.expandedConfig["nvidia.runtime"]) { for _, gpu := range nvidiaDevices { - err := c.setupUnixDevice(fmt.Sprintf("unix.%s", k), m, gpu.major, gpu.minor, gpu.path, true) + err := c.setupUnixDevice(fmt.Sprintf("unix.%s", k), m, gpu.major, gpu.minor, gpu.path, true, false) if err != nil { return "", err } @@ -4313,7 +4311,7 @@ func (c *containerLXC) Update(args db.ContainerArgs, userRequested bool) error { diskDevices := map[string]types.Device{} for k, m := range addDevices { if shared.StringInSlice(m["type"], []string{"unix-char", "unix-block"}) { - err = c.insertUnixDevice(fmt.Sprintf("unix.%s", k), m) + err = c.insertUnixDevice(fmt.Sprintf("unix.%s", k), m, true) if err != nil { if m["required"] == "" || shared.IsTrue(m["required"]) { return err @@ -4366,7 +4364,7 @@ func (c *containerLXC) Update(args db.ContainerArgs, userRequested bool) error { continue } - err = c.insertUnixDeviceNum(fmt.Sprintf("unix.%s", k), m, usb.major, usb.minor, usb.path) + err = c.insertUnixDeviceNum(fmt.Sprintf("unix.%s", k), m, usb.major, usb.minor, usb.path, false) if err != nil { logger.Error("failed to insert usb device", log.Ctx{"err": err, "usb": usb, "container": c.Name()}) } @@ -4391,7 +4389,7 @@ func (c *containerLXC) Update(args db.ContainerArgs, userRequested bool) error { found = true - err = c.insertUnixDeviceNum(fmt.Sprintf("unix.%s", k), m, gpu.major, gpu.minor, gpu.path) + err = c.insertUnixDeviceNum(fmt.Sprintf("unix.%s", k), m, gpu.major, gpu.minor, gpu.path, false) if err != nil { logger.Error("Failed to insert GPU device.", log.Ctx{"err": err, "gpu": gpu, "container": c.Name()}) return err @@ -4401,7 +4399,7 @@ func (c *containerLXC) Update(args db.ContainerArgs, userRequested bool) error { continue } - err = c.insertUnixDeviceNum(fmt.Sprintf("unix.%s", k), m, gpu.nvidia.major, gpu.nvidia.minor, gpu.nvidia.path) + err = c.insertUnixDeviceNum(fmt.Sprintf("unix.%s", k), m, gpu.nvidia.major, gpu.nvidia.minor, gpu.nvidia.path, false) if err != nil { logger.Error("Failed to insert GPU device.", log.Ctx{"err": err, "gpu": gpu, "container": c.Name()}) return err @@ -4415,7 +4413,7 @@ func (c *containerLXC) Update(args db.ContainerArgs, userRequested bool) error { if c.deviceExistsInDevicesFolder(k, gpu.path) { continue } - err = c.insertUnixDeviceNum(fmt.Sprintf("unix.%s", k), m, gpu.major, gpu.minor, gpu.path) + err = c.insertUnixDeviceNum(fmt.Sprintf("unix.%s", k), m, gpu.major, gpu.minor, gpu.path, false) if err != nil { logger.Error("failed to insert GPU device", log.Ctx{"err": err, "gpu": gpu, "container": c.Name()}) return err @@ -6130,7 +6128,7 @@ func (c *containerLXC) deviceExistsInDevicesFolder(prefix string, path string) b } // Unix devices handling -func (c *containerLXC) createUnixDevice(prefix string, m types.Device) ([]string, error) { +func (c *containerLXC) createUnixDevice(prefix string, m types.Device, defaultMode bool) ([]string, error) { var err error var major, minor int @@ -6178,6 +6176,11 @@ func (c *containerLXC) createUnixDevice(prefix string, m types.Device) ([]string return nil, fmt.Errorf("Bad mode %s in device %s", m["mode"], m["path"]) } mode = os.FileMode(tmp) + } else if !defaultMode { + mode, err = shared.GetPathMode(srcPath) + if err != nil { + return nil, fmt.Errorf("Failed to retrieve mode of device %s: %s", m["path"], err) + } } if m["type"] == "unix-block" { @@ -6263,14 +6266,14 @@ func (c *containerLXC) createUnixDevice(prefix string, m types.Device) ([]string return []string{devPath, relativeDestPath}, nil } -func (c *containerLXC) insertUnixDevice(prefix string, m types.Device) error { +func (c *containerLXC) insertUnixDevice(prefix string, m types.Device, defaultMode bool) error { // Check that the container is running if !c.IsRunning() { return fmt.Errorf("Can't insert device into stopped container") } // Create the device on the host - paths, err := c.createUnixDevice(prefix, m) + paths, err := c.createUnixDevice(prefix, m, defaultMode) if err != nil { return fmt.Errorf("Failed to setup device: %s", err) } @@ -6325,7 +6328,7 @@ func (c *containerLXC) insertUnixDevice(prefix string, m types.Device) error { return nil } -func (c *containerLXC) insertUnixDeviceNum(name string, m types.Device, major int, minor int, path string) error { +func (c *containerLXC) insertUnixDeviceNum(name string, m types.Device, major int, minor int, path string, defaultMode bool) error { temp := types.Device{} if err := shared.DeepCopy(&m, &temp); err != nil { return err @@ -6335,7 +6338,7 @@ func (c *containerLXC) insertUnixDeviceNum(name string, m types.Device, major in temp["minor"] = fmt.Sprintf("%d", minor) temp["path"] = path - return c.insertUnixDevice(name, temp) + return c.insertUnixDevice(name, temp, defaultMode) } func (c *containerLXC) removeUnixDevice(prefix string, m types.Device, eject bool) error { @@ -6483,14 +6486,14 @@ func (c *containerLXC) addInfinibandDevicesPerPort(deviceName string, ifDev *IBF } if inject && !deviceExists { - err := c.insertUnixDevice(devPrefix, dummyDevice) + err := c.insertUnixDevice(devPrefix, dummyDevice, false) if err != nil { return err } continue } - paths, err := c.createUnixDevice(devPrefix, dummyDevice) + paths, err := c.createUnixDevice(devPrefix, dummyDevice, false) if err != nil { return err } @@ -6539,7 +6542,7 @@ func (c *containerLXC) addInfinibandDevicesPerFun(deviceName string, ifDev *IBF, } if inject { - err := c.insertUnixDevice(uniqueDevPrefix, dummyDevice) + err := c.insertUnixDevice(uniqueDevPrefix, dummyDevice, false) if err != nil { return err } @@ -6552,7 +6555,7 @@ func (c *containerLXC) addInfinibandDevicesPerFun(deviceName string, ifDev *IBF, return err } - paths, err := c.createUnixDevice(uniqueDevPrefix, dummyDevice) + paths, err := c.createUnixDevice(uniqueDevPrefix, dummyDevice, false) if err != nil { return err } diff --git a/lxd/devices.go b/lxd/devices.go index 8aa057dcc4..d543906fcf 100644 --- a/lxd/devices.go +++ b/lxd/devices.go @@ -798,7 +798,7 @@ func deviceUSBEvent(s *state.State, usb usbDevice) { } if usb.action == "add" { - err := c.insertUnixDeviceNum(fmt.Sprintf("unix.%s", name), m, usb.major, usb.minor, usb.path) + err := c.insertUnixDeviceNum(fmt.Sprintf("unix.%s", name), m, usb.major, usb.minor, usb.path, false) if err != nil { logger.Error("failed to create usb device", log.Ctx{"err": err, "usb": usb, "container": c.Name()}) return @@ -1829,7 +1829,7 @@ func deviceInotifyDirRescan(s *state.State) { } cleanDevPath := filepath.Clean(cmp) if shared.PathExists(cleanDevPath) { - c.insertUnixDevice(fmt.Sprintf("unix.%s", name), m) + c.insertUnixDevice(fmt.Sprintf("unix.%s", name), m, false) } else { c.removeUnixDevice(fmt.Sprintf("unix.%s", name), m, true) } @@ -2011,7 +2011,7 @@ func deviceInotifyFileEvent(s *state.State, target *sys.InotifyTargetInfo) { } if (target.Mask & syscall.IN_CREATE) > 0 { - err := c.insertUnixDevice(fmt.Sprintf("unix.%s", name), m) + err := c.insertUnixDevice(fmt.Sprintf("unix.%s", name), m, false) if err != nil { logger.Error("Failed to create unix device", log.Ctx{"err": err, "dev": m, "container": c.Name()}) continue diff --git a/shared/util_linux.go b/shared/util_linux.go index b6d83794f4..88613479ad 100644 --- a/shared/util_linux.go +++ b/shared/util_linux.go @@ -335,6 +335,23 @@ func GetFileStat(p string) (uid int, gid int, major int, minor int, return } +// FileCopy copies a file, overwriting the target if it exists. +func GetPathMode(path string) (os.FileMode, error) { + s, err := os.Open(path) + if err != nil { + return os.FileMode(0000), err + } + defer s.Close() + + fi, err := s.Stat() + if err != nil { + return os.FileMode(0000), err + } + + mode, _, _ := GetOwnerMode(fi) + return mode, nil +} + func parseMountinfo(name string) int { // In case someone uses symlinks we need to look for the actual // mountpoint.
_______________________________________________ lxc-devel mailing list [email protected] http://lists.linuxcontainers.org/listinfo/lxc-devel
