[lxc-devel] [lxd/master] devices: clone mode of device

brauner on Github lxc-bot at linuxcontainers.org
Sat May 5 11:45:04 UTC 2018


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 810 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20180505/66624be8/attachment.bin>
-------------- next part --------------
From 23b844ff06b51d03fa94df5c9556ba37cde04aa5 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
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 <christian.brauner at ubuntu.com>
---
 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.


More information about the lxc-devel mailing list