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

Reply via email to