[lxc-devel] [lxd/master] devices: switch to improved device naming scheme

brauner on Github lxc-bot at linuxcontainers.org
Fri Nov 24 21:13:38 UTC 2017


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 416 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20171124/7ac3975e/attachment.bin>
-------------- next part --------------
From 8d0dc2b85950522e784831fa9c38ab358fe8eae3 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Fri, 24 Nov 2017 15:30:33 +0100
Subject: [PATCH 1/3] devices: pass the name of the device

This is done in preparation for our new device handling whereby each device
gets a new subfolder named after the name of the device.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 lxd/container_lxc.go | 84 +++++++++++++++++++++++++++-------------------------
 lxd/devices.go       |  4 +--
 2 files changed, 45 insertions(+), 43 deletions(-)

diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index ea1201cd2..a47a6f84c 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -1634,7 +1634,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(devType string, dev types.Device, major int, minor int, path string, createMustSucceed bool) error {
+func (c *containerLXC) setupUnixDevice(name string, dev types.Device, major int, minor int, path string, createMustSucceed 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 {
@@ -1651,9 +1651,9 @@ func (c *containerLXC) setupUnixDevice(devType string, dev types.Device, major i
 	temp["minor"] = fmt.Sprintf("%d", minor)
 	temp["path"] = path
 
-	paths, err := c.createUnixDevice(temp)
+	paths, err := c.createUnixDevice(name, temp)
 	if err != nil {
-		logger.Debug("failed to create device", log.Ctx{"err": err, "device": devType})
+		logger.Debug("failed to create device", log.Ctx{"err": err, "device": name})
 		if createMustSucceed {
 			return err
 		}
@@ -1855,7 +1855,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(m)
+			paths, err := c.createUnixDevice(k, m)
 			if err != nil {
 				return "", err
 			}
@@ -3862,7 +3862,7 @@ func (c *containerLXC) Update(args db.ContainerArgs, userRequested bool) error {
 		// Live update the devices
 		for k, m := range removeDevices {
 			if shared.StringInSlice(m["type"], []string{"unix-char", "unix-block"}) {
-				err = c.removeUnixDevice(m)
+				err = c.removeUnixDevice(k, m)
 				if err != nil {
 					return err
 				}
@@ -3890,7 +3890,7 @@ func (c *containerLXC) Update(args db.ContainerArgs, userRequested bool) error {
 						continue
 					}
 
-					err := c.removeUnixDeviceNum(m, usb.major, usb.minor, usb.path)
+					err := c.removeUnixDeviceNum(k, m, usb.major, usb.minor, usb.path)
 					if err != nil {
 						return err
 					}
@@ -3911,7 +3911,7 @@ func (c *containerLXC) Update(args db.ContainerArgs, userRequested bool) error {
 						continue
 					}
 
-					err := c.removeUnixDeviceNum(m, gpu.major, gpu.minor, gpu.path)
+					err := c.removeUnixDeviceNum(k, m, gpu.major, gpu.minor, gpu.path)
 					if err != nil {
 						logger.Error("Failed to remove GPU device.", log.Ctx{"err": err, "gpu": gpu, "container": c.Name()})
 						return err
@@ -3921,7 +3921,7 @@ func (c *containerLXC) Update(args db.ContainerArgs, userRequested bool) error {
 						continue
 					}
 
-					err = c.removeUnixDeviceNum(m, gpu.nvidia.major, gpu.nvidia.minor, gpu.nvidia.path)
+					err = c.removeUnixDeviceNum(k, m, gpu.nvidia.major, gpu.nvidia.minor, gpu.nvidia.path)
 					if err != nil {
 						logger.Error("Failed to remove GPU device.", log.Ctx{"err": err, "gpu": gpu, "container": c.Name()})
 						return err
@@ -3931,7 +3931,7 @@ func (c *containerLXC) Update(args db.ContainerArgs, userRequested bool) error {
 				nvidiaExists := false
 				for _, gpu := range gpus {
 					if gpu.nvidia.path != "" {
-						if c.deviceExists(gpu.path) {
+						if c.deviceExists(k, gpu.path) {
 							nvidiaExists = true
 							break
 						}
@@ -3940,10 +3940,10 @@ func (c *containerLXC) Update(args db.ContainerArgs, userRequested bool) error {
 
 				if !nvidiaExists {
 					for _, gpu := range nvidiaDevices {
-						if !c.deviceExists(gpu.path) {
+						if !c.deviceExists(k, gpu.path) {
 							continue
 						}
-						err = c.removeUnixDeviceNum(m, gpu.major, gpu.minor, gpu.path)
+						err = c.removeUnixDeviceNum(k, m, gpu.major, gpu.minor, gpu.path)
 						if err != nil {
 							logger.Error("Failed to remove GPU device.", log.Ctx{"err": err, "gpu": gpu, "container": c.Name()})
 							return err
@@ -3957,7 +3957,7 @@ func (c *containerLXC) Update(args db.ContainerArgs, userRequested bool) error {
 
 		for k, m := range addDevices {
 			if shared.StringInSlice(m["type"], []string{"unix-char", "unix-block"}) {
-				err = c.insertUnixDevice(m)
+				err = c.insertUnixDevice(k, m)
 				if err != nil {
 					return err
 				}
@@ -3981,7 +3981,7 @@ func (c *containerLXC) Update(args db.ContainerArgs, userRequested bool) error {
 						continue
 					}
 
-					err = c.insertUnixDeviceNum(m, usb.major, usb.minor, usb.path)
+					err = c.insertUnixDeviceNum(k, m, usb.major, usb.minor, usb.path)
 					if err != nil {
 						logger.Error("failed to insert usb device", log.Ctx{"err": err, "usb": usb, "container": c.Name()})
 					}
@@ -4006,7 +4006,7 @@ func (c *containerLXC) Update(args db.ContainerArgs, userRequested bool) error {
 
 					found = true
 
-					err = c.insertUnixDeviceNum(m, gpu.major, gpu.minor, gpu.path)
+					err = c.insertUnixDeviceNum(k, m, gpu.major, gpu.minor, gpu.path)
 					if err != nil {
 						logger.Error("Failed to insert GPU device.", log.Ctx{"err": err, "gpu": gpu, "container": c.Name()})
 						return err
@@ -4016,7 +4016,7 @@ func (c *containerLXC) Update(args db.ContainerArgs, userRequested bool) error {
 						continue
 					}
 
-					err = c.insertUnixDeviceNum(m, gpu.nvidia.major, gpu.nvidia.minor, gpu.nvidia.path)
+					err = c.insertUnixDeviceNum(k, m, gpu.nvidia.major, gpu.nvidia.minor, gpu.nvidia.path)
 					if err != nil {
 						logger.Error("Failed to insert GPU device.", log.Ctx{"err": err, "gpu": gpu, "container": c.Name()})
 						return err
@@ -4027,10 +4027,10 @@ func (c *containerLXC) Update(args db.ContainerArgs, userRequested bool) error {
 
 				if sawNvidia {
 					for _, gpu := range nvidiaDevices {
-						if c.deviceExists(gpu.path) {
+						if c.deviceExists(k, gpu.path) {
 							continue
 						}
-						err = c.insertUnixDeviceNum(m, gpu.major, gpu.minor, gpu.path)
+						err = c.insertUnixDeviceNum(k, m, gpu.major, gpu.minor, gpu.path)
 						if err != nil {
 							logger.Error("failed to insert GPU device", log.Ctx{"err": err, "gpu": gpu, "container": c.Name()})
 							return err
@@ -5602,7 +5602,7 @@ func (c *containerLXC) removeMount(mount string) error {
 }
 
 // Check if the unix device already exists.
-func (c *containerLXC) deviceExists(path string) bool {
+func (c *containerLXC) deviceExists(name string, path string) bool {
 	tgtPath := strings.TrimPrefix(path, "/")
 	devName := fmt.Sprintf("unix.%s", strings.Replace(tgtPath, "/", "-", -1))
 	devPath := filepath.Join(c.DevicesPath(), devName)
@@ -5610,7 +5610,7 @@ func (c *containerLXC) deviceExists(path string) bool {
 }
 
 // Unix devices handling
-func (c *containerLXC) createUnixDevice(m types.Device) ([]string, error) {
+func (c *containerLXC) createUnixDevice(name string, m types.Device) ([]string, error) {
 	var err error
 	var major, minor int
 
@@ -5619,9 +5619,11 @@ func (c *containerLXC) createUnixDevice(m types.Device) ([]string, error) {
 	if !exist {
 		srcPath = m["path"]
 	}
+
 	relativeSrcPath := strings.TrimPrefix(srcPath, "/")
-	devName := fmt.Sprintf("unix.%s", strings.Replace(relativeSrcPath, "/", "-", -1))
-	devPath := filepath.Join(c.DevicesPath(), devName)
+
+	devNameLegacy := fmt.Sprintf("unix.%s", strings.Replace(relativeSrcPath, "/", "-", -1))
+	devPathLegacy := filepath.Join(c.DevicesPath(), devNameLegacy)
 
 	// Extra checks for nesting
 	if c.state.OS.RunningInUserNS {
@@ -5696,12 +5698,12 @@ func (c *containerLXC) createUnixDevice(m types.Device) ([]string, error) {
 	}
 
 	// Clean any existing entry
-	if shared.PathExists(devPath) {
+	if shared.PathExists(devPathLegacy) {
 		if c.state.OS.RunningInUserNS {
-			syscall.Unmount(devPath, syscall.MNT_DETACH)
+			syscall.Unmount(devPathLegacy, syscall.MNT_DETACH)
 		}
 
-		err = os.Remove(devPath)
+		err = os.Remove(devPathLegacy)
 		if err != nil {
 			return nil, fmt.Errorf("Failed to remove existing entry: %s", err)
 		}
@@ -5710,17 +5712,17 @@ func (c *containerLXC) createUnixDevice(m types.Device) ([]string, error) {
 	// Create the new entry
 	if !c.state.OS.RunningInUserNS {
 		encoded_device_number := (minor & 0xff) | (major << 8) | ((minor & ^0xff) << 12)
-		if err := syscall.Mknod(devPath, uint32(mode), encoded_device_number); err != nil {
-			return nil, fmt.Errorf("Failed to create device %s for %s: %s", devPath, m["path"], err)
+		if err := syscall.Mknod(devPathLegacy, uint32(mode), encoded_device_number); err != nil {
+			return nil, fmt.Errorf("Failed to create device %s for %s: %s", devPathLegacy, m["path"], err)
 		}
 
-		if err := os.Chown(devPath, uid, gid); err != nil {
-			return nil, fmt.Errorf("Failed to chown device %s: %s", devPath, err)
+		if err := os.Chown(devPathLegacy, uid, gid); err != nil {
+			return nil, fmt.Errorf("Failed to chown device %s: %s", devPathLegacy, err)
 		}
 
 		// Needed as mknod respects the umask
-		if err := os.Chmod(devPath, mode); err != nil {
-			return nil, fmt.Errorf("Failed to chmod device %s: %s", devPath, err)
+		if err := os.Chmod(devPathLegacy, mode); err != nil {
+			return nil, fmt.Errorf("Failed to chmod device %s: %s", devPathLegacy, err)
 		}
 
 		idmapset, err := c.IdmapSet()
@@ -5729,19 +5731,19 @@ func (c *containerLXC) createUnixDevice(m types.Device) ([]string, error) {
 		}
 
 		if idmapset != nil {
-			if err := idmapset.ShiftFile(devPath); err != nil {
+			if err := idmapset.ShiftFile(devPathLegacy); err != nil {
 				// uidshift failing is weird, but not a big problem.  Log and proceed
 				logger.Debugf("Failed to uidshift device %s: %s\n", m["path"], err)
 			}
 		}
 	} else {
-		f, err := os.Create(devPath)
+		f, err := os.Create(devPathLegacy)
 		if err != nil {
 			return nil, err
 		}
 		f.Close()
 
-		err = deviceMountDisk(srcPath, devPath, false, false)
+		err = deviceMountDisk(srcPath, devPathLegacy, false, false)
 		if err != nil {
 			return nil, err
 		}
@@ -5753,17 +5755,17 @@ func (c *containerLXC) createUnixDevice(m types.Device) ([]string, error) {
 		tgtPath = m["source"]
 	}
 	relativeTgtPath := strings.TrimPrefix(tgtPath, "/")
-	return []string{devPath, relativeTgtPath}, nil
+	return []string{devPathLegacy, relativeTgtPath}, nil
 }
 
-func (c *containerLXC) insertUnixDevice(m types.Device) error {
+func (c *containerLXC) insertUnixDevice(name string, m types.Device) 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(m)
+	paths, err := c.createUnixDevice(name, m)
 	if err != nil {
 		return fmt.Errorf("Failed to setup device: %s", err)
 	}
@@ -5818,7 +5820,7 @@ func (c *containerLXC) insertUnixDevice(m types.Device) error {
 	return nil
 }
 
-func (c *containerLXC) insertUnixDeviceNum(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) error {
 	temp := types.Device{}
 	if err := shared.DeepCopy(&m, &temp); err != nil {
 		return err
@@ -5828,10 +5830,10 @@ func (c *containerLXC) insertUnixDeviceNum(m types.Device, major int, minor int,
 	temp["minor"] = fmt.Sprintf("%d", minor)
 	temp["path"] = path
 
-	return c.insertUnixDevice(temp)
+	return c.insertUnixDevice(name, temp)
 }
 
-func (c *containerLXC) removeUnixDevice(m types.Device) error {
+func (c *containerLXC) removeUnixDevice(name string, m types.Device) error {
 	// Check that the container is running
 	pid := c.InitPID()
 	if pid == -1 {
@@ -5919,7 +5921,7 @@ func (c *containerLXC) removeUnixDevice(m types.Device) error {
 	return nil
 }
 
-func (c *containerLXC) removeUnixDeviceNum(m types.Device, major int, minor int, path string) error {
+func (c *containerLXC) removeUnixDeviceNum(name string, m types.Device, major int, minor int, path string) error {
 	pid := c.InitPID()
 	if pid == -1 {
 		return fmt.Errorf("Can't remove device from stopped container")
@@ -5934,7 +5936,7 @@ func (c *containerLXC) removeUnixDeviceNum(m types.Device, major int, minor int,
 	temp["minor"] = fmt.Sprintf("%d", minor)
 	temp["path"] = path
 
-	err := c.removeUnixDevice(temp)
+	err := c.removeUnixDevice(name, temp)
 	if err != nil {
 		logger.Error("failed to remove device", log.Ctx{"err": err, m["type"]: path, "container": c.Name()})
 		return err
diff --git a/lxd/devices.go b/lxd/devices.go
index bf2772a83..bda6fdfbb 100644
--- a/lxd/devices.go
+++ b/lxd/devices.go
@@ -795,13 +795,13 @@ func deviceUSBEvent(s *state.State, usb usbDevice) {
 			}
 
 			if usb.action == "add" {
-				err := c.insertUnixDeviceNum(m, usb.major, usb.minor, usb.path)
+				err := c.insertUnixDeviceNum(name, m, usb.major, usb.minor, usb.path)
 				if err != nil {
 					logger.Error("failed to create usb device", log.Ctx{"err": err, "usb": usb, "container": c.Name()})
 					return
 				}
 			} else if usb.action == "remove" {
-				err := c.removeUnixDeviceNum(m, usb.major, usb.minor, usb.path)
+				err := c.removeUnixDeviceNum(name, m, usb.major, usb.minor, usb.path)
 				if err != nil {
 					logger.Error("failed to remove usb device", log.Ctx{"err": err, "usb": usb, "container": c.Name()})
 					return

From de3df2d944d29a1b3e5af795879795b4dad25db4 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Fri, 24 Nov 2017 19:36:33 +0100
Subject: [PATCH 2/3] devices: add new unix-{char,block} format

The new device creation format encodes the device name into the device file:

/var/lib/lxd/devices/<container-name>/unix.<device name>.<container path>

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 lxd/container_lxc.go | 123 +++++++++++++++++++++++++++++----------------------
 1 file changed, 71 insertions(+), 52 deletions(-)

diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index a47a6f84c..f508bb07c 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -1339,22 +1339,16 @@ func (c *containerLXC) initLXC(config bool) error {
 	for _, k := range c.expandedDevices.DeviceNames() {
 		m := c.expandedDevices[k]
 		if shared.StringInSlice(m["type"], []string{"unix-char", "unix-block"}) {
-			// Prepare all the paths
-			srcPath, exist := m["source"]
+			// destination paths
+			destPath, exist := m["path"]
 			if !exist {
-				srcPath = m["path"]
+				destPath = m["source"]
 			}
-			relativeSrcPath := strings.TrimPrefix(srcPath, "/")
-			devName := fmt.Sprintf("unix.%s", strings.Replace(relativeSrcPath, "/", "-", -1))
-			devPath := filepath.Join(c.DevicesPath(), devName)
-			tgtPath, exist := m["path"]
-			if !exist {
-				tgtPath = m["source"]
-			}
-			relativeTgtPath := strings.TrimPrefix(tgtPath, "/")
+			relativeDestPath := strings.TrimPrefix(destPath, "/")
+			sourceDevPath := filepath.Join(c.DevicesPath(), fmt.Sprintf("unix.%s.%s", k, strings.Replace(relativeDestPath, "/", "-", -1)))
 
-			// Set the bind-mount entry
-			err = lxcSetConfigItem(cc, "lxc.mount.entry", fmt.Sprintf("%s %s none bind,create=file", devPath, relativeTgtPath))
+			// inform liblxc about the mount
+			err = lxcSetConfigItem(cc, "lxc.mount.entry", fmt.Sprintf("%s %s none bind,create=file", sourceDevPath, relativeDestPath))
 			if err != nil {
 				return err
 			}
@@ -5603,9 +5597,18 @@ func (c *containerLXC) removeMount(mount string) error {
 
 // Check if the unix device already exists.
 func (c *containerLXC) deviceExists(name string, path string) bool {
-	tgtPath := strings.TrimPrefix(path, "/")
-	devName := fmt.Sprintf("unix.%s", strings.Replace(tgtPath, "/", "-", -1))
-	devPath := filepath.Join(c.DevicesPath(), devName)
+	relativeDestPath := strings.TrimPrefix(path, "/")
+	devPath := ""
+	if name == "" {
+		// legacy style
+		devName := fmt.Sprintf("unix.%s", strings.Replace(relativeDestPath, "/", "-", -1))
+		devPath = filepath.Join(c.DevicesPath(), devName)
+	} else {
+		// new style
+		devName := fmt.Sprintf("unix.%s.%s", name, strings.Replace(relativeDestPath, "/", "-", -1))
+		devPath = filepath.Join(c.DevicesPath(), devName)
+	}
+
 	return shared.PathExists(devPath)
 }
 
@@ -5614,17 +5617,6 @@ func (c *containerLXC) createUnixDevice(name string, m types.Device) ([]string,
 	var err error
 	var major, minor int
 
-	// Our device paths
-	srcPath, exist := m["source"]
-	if !exist {
-		srcPath = m["path"]
-	}
-
-	relativeSrcPath := strings.TrimPrefix(srcPath, "/")
-
-	devNameLegacy := fmt.Sprintf("unix.%s", strings.Replace(relativeSrcPath, "/", "-", -1))
-	devPathLegacy := filepath.Join(c.DevicesPath(), devNameLegacy)
-
 	// Extra checks for nesting
 	if c.state.OS.RunningInUserNS {
 		for key, value := range m {
@@ -5634,6 +5626,8 @@ func (c *containerLXC) createUnixDevice(name string, m types.Device) ([]string,
 		}
 	}
 
+	srcPath := shared.HostPath(m["source"])
+
 	// Get the major/minor of the device we want to create
 	if m["major"] == "" && m["minor"] == "" {
 		// If no major and minor are set, use those from the device on the host
@@ -5697,6 +5691,22 @@ func (c *containerLXC) createUnixDevice(name string, m types.Device) ([]string,
 		}
 	}
 
+	relativeSrcPath := strings.TrimPrefix(m["source"], "/")
+
+	// legacy style unix device creation
+	devName := fmt.Sprintf("unix.%s", strings.Replace(relativeSrcPath, "/", "-", -1))
+	devPathLegacy := filepath.Join(c.DevicesPath(), devName)
+
+	destPath, exist := m["path"]
+	if !exist {
+		destPath = m["source"]
+	}
+	relativeDestPath := strings.TrimPrefix(destPath, "/")
+
+	// new style unix device creation
+	devName = fmt.Sprintf("unix.%s.%s", name, strings.Replace(relativeDestPath, "/", "-", -1))
+	devPathDeviceNameEncoded := filepath.Join(c.DevicesPath(), devName)
+
 	// Clean any existing entry
 	if shared.PathExists(devPathLegacy) {
 		if c.state.OS.RunningInUserNS {
@@ -5712,17 +5722,17 @@ func (c *containerLXC) createUnixDevice(name string, m types.Device) ([]string,
 	// Create the new entry
 	if !c.state.OS.RunningInUserNS {
 		encoded_device_number := (minor & 0xff) | (major << 8) | ((minor & ^0xff) << 12)
-		if err := syscall.Mknod(devPathLegacy, uint32(mode), encoded_device_number); err != nil {
-			return nil, fmt.Errorf("Failed to create device %s for %s: %s", devPathLegacy, m["path"], err)
+		if err := syscall.Mknod(devPathDeviceNameEncoded, uint32(mode), encoded_device_number); err != nil {
+			return nil, fmt.Errorf("Failed to create device %s for %s: %s", devPathDeviceNameEncoded, m["path"], err)
 		}
 
-		if err := os.Chown(devPathLegacy, uid, gid); err != nil {
-			return nil, fmt.Errorf("Failed to chown device %s: %s", devPathLegacy, err)
+		if err := os.Chown(devPathDeviceNameEncoded, uid, gid); err != nil {
+			return nil, fmt.Errorf("Failed to chown device %s: %s", devPathDeviceNameEncoded, err)
 		}
 
 		// Needed as mknod respects the umask
-		if err := os.Chmod(devPathLegacy, mode); err != nil {
-			return nil, fmt.Errorf("Failed to chmod device %s: %s", devPathLegacy, err)
+		if err := os.Chmod(devPathDeviceNameEncoded, mode); err != nil {
+			return nil, fmt.Errorf("Failed to chmod device %s: %s", devPathDeviceNameEncoded, err)
 		}
 
 		idmapset, err := c.IdmapSet()
@@ -5731,31 +5741,25 @@ func (c *containerLXC) createUnixDevice(name string, m types.Device) ([]string,
 		}
 
 		if idmapset != nil {
-			if err := idmapset.ShiftFile(devPathLegacy); err != nil {
+			if err := idmapset.ShiftFile(devPathDeviceNameEncoded); err != nil {
 				// uidshift failing is weird, but not a big problem.  Log and proceed
 				logger.Debugf("Failed to uidshift device %s: %s\n", m["path"], err)
 			}
 		}
 	} else {
-		f, err := os.Create(devPathLegacy)
+		f, err := os.Create(devPathDeviceNameEncoded)
 		if err != nil {
 			return nil, err
 		}
 		f.Close()
 
-		err = deviceMountDisk(srcPath, devPathLegacy, false, false)
+		err = deviceMountDisk(srcPath, devPathDeviceNameEncoded, false, false)
 		if err != nil {
 			return nil, err
 		}
 	}
 
-	// generate relative target path
-	tgtPath, exist := m["path"]
-	if !exist {
-		tgtPath = m["source"]
-	}
-	relativeTgtPath := strings.TrimPrefix(tgtPath, "/")
-	return []string{devPathLegacy, relativeTgtPath}, nil
+	return []string{devPathDeviceNameEncoded, relativeDestPath}, nil
 }
 
 func (c *containerLXC) insertUnixDevice(name string, m types.Device) error {
@@ -5840,15 +5844,6 @@ func (c *containerLXC) removeUnixDevice(name string, m types.Device) error {
 		return fmt.Errorf("Can't remove device from stopped container")
 	}
 
-	// Figure out the paths
-	srcPath, exist := m["source"]
-	if !exist {
-		srcPath = m["path"]
-	}
-	relativeSrcPath := strings.TrimPrefix(srcPath, "/")
-	devName := fmt.Sprintf("unix.%s", strings.Replace(relativeSrcPath, "/", "-", -1))
-	devPath := filepath.Join(c.DevicesPath(), devName)
-
 	// Check if we've been passed major and minor numbers already.
 	var tmp int
 	var err error
@@ -5875,6 +5870,30 @@ func (c *containerLXC) removeUnixDevice(name string, m types.Device) error {
 		dType = "b"
 	}
 
+	// Figure out the paths
+	srcPath, exist := m["source"]
+	if !exist {
+		srcPath = m["path"]
+	}
+
+	relativeSrcPath := strings.TrimPrefix(srcPath, "/")
+
+	// legacy style unix device creation
+	devName := fmt.Sprintf("unix.%s", strings.Replace(relativeSrcPath, "/", "-", -1))
+	devPath := filepath.Join(c.DevicesPath(), devName)
+	if !shared.PathExists(devPath) {
+		// Figure out the paths
+		destPath, exist := m["path"]
+		if !exist {
+			destPath = m["source"]
+		}
+
+		relativeDestPath := strings.TrimPrefix(destPath, "/")
+		// new style unix device creation
+		devName = fmt.Sprintf("unix.%s.%s", name, strings.Replace(relativeDestPath, "/", "-", -1))
+		devPath = filepath.Join(c.DevicesPath(), devName)
+	}
+
 	if dType == "" || dMajor < 0 || dMinor < 0 {
 		dType, dMajor, dMinor, err = deviceGetAttributes(devPath)
 		if err != nil {

From d32e404a597520cc3280d5ca2163a5467202e32a Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Fri, 24 Nov 2017 21:32:11 +0100
Subject: [PATCH 3/3] devices: add new disk-{char,block} format

The new device creation format encodes the device name into the device file:

/var/lib/lxd/devices/<container-name>/disk.<device name>.<container path>

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 lxd/container_lxc.go | 68 +++++++++++++++++++++++++++++++++-------------------
 1 file changed, 44 insertions(+), 24 deletions(-)

diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index f508bb07c..b747cbfc5 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -1451,11 +1451,16 @@ func (c *containerLXC) initLXC(config bool) error {
 			// bump network index
 			networkidx++
 		} else if m["type"] == "disk" {
-			// Prepare all the paths
+			isRootfs := isRootDiskDevice(m)
+
+			// source paths
 			srcPath := shared.HostPath(m["source"])
-			tgtPath := strings.TrimPrefix(m["path"], "/")
-			devName := fmt.Sprintf("disk.%s", strings.Replace(tgtPath, "/", "-", -1))
-			devPath := filepath.Join(c.DevicesPath(), devName)
+
+			// destination paths
+			destPath := m["path"]
+			relativeDestPath := strings.TrimPrefix(destPath, "/")
+
+			sourceDevPath := filepath.Join(c.DevicesPath(), fmt.Sprintf("disk.%s.%s", k, strings.Replace(relativeDestPath, "/", "-", -1)))
 
 			// Various option checks
 			isOptional := shared.IsTrue(m["optional"])
@@ -1471,7 +1476,7 @@ func (c *containerLXC) initLXC(config bool) error {
 			}
 
 			// Deal with a rootfs
-			if tgtPath == "" {
+			if isRootfs {
 				if !util.RuntimeLiblxcVersionAtLeast(2, 1, 0) {
 					// Set the rootfs backend type if supported (must happen before any other lxc.rootfs)
 					err := lxcSetConfigItem(cc, "lxc.rootfs.backend", "dir")
@@ -1523,7 +1528,7 @@ func (c *containerLXC) initLXC(config bool) error {
 					options = append(options, "create=dir")
 				}
 
-				err = lxcSetConfigItem(cc, "lxc.mount.entry", fmt.Sprintf("%s %s none %sbind,%s", devPath, tgtPath, rbind, strings.Join(options, ",")))
+				err = lxcSetConfigItem(cc, "lxc.mount.entry", fmt.Sprintf("%s %s none %sbind,%s", sourceDevPath, relativeDestPath, rbind, strings.Join(options, ",")))
 				if err != nil {
 					return err
 				}
@@ -6545,11 +6550,11 @@ func (c *containerLXC) removeNetworkDevice(name string, m types.Device) error {
 
 // Disk device handling
 func (c *containerLXC) createDiskDevice(name string, m types.Device) (string, error) {
-	// Prepare all the paths
-	srcPath := shared.HostPath(m["source"])
-	tgtPath := strings.TrimPrefix(m["path"], "/")
-	devName := fmt.Sprintf("disk.%s", strings.Replace(tgtPath, "/", "-", -1))
+	// source paths
+	relativeDestPath := strings.TrimPrefix(m["path"], "/")
+	devName := fmt.Sprintf("disk.%s.%s", name, strings.Replace(relativeDestPath, "/", "-", -1))
 	devPath := filepath.Join(c.DevicesPath(), devName)
+	srcPath := shared.HostPath(m["source"])
 
 	// Check if read-only
 	isOptional := shared.IsTrue(m["optional"])
@@ -6691,8 +6696,8 @@ func (c *containerLXC) insertDiskDevice(name string, m types.Device) error {
 	}
 
 	// Bind-mount it into the container
-	tgtPath := strings.TrimSuffix(m["path"], "/")
-	err = c.insertMount(devPath, tgtPath, "none", flags)
+	destPath := strings.TrimSuffix(m["path"], "/")
+	err = c.insertMount(devPath, destPath, "none", flags)
 	if err != nil {
 		return fmt.Errorf("Failed to add mount for device: %s", err)
 	}
@@ -6723,7 +6728,16 @@ func (c *containerLXC) addDiskDevices(devices map[string]types.Device, handler f
 
 	sort.Sort(ordered)
 	for _, d := range ordered {
-		err := handler(d["path"], d)
+		key := ""
+		for k, dd := range devices {
+			key = ""
+			if reflect.DeepEqual(d, dd) {
+				key = k
+				break
+			}
+		}
+
+		err := handler(key, d)
 		if err != nil {
 			return err
 		}
@@ -6740,25 +6754,31 @@ func (c *containerLXC) removeDiskDevice(name string, m types.Device) error {
 	}
 
 	// Figure out the paths
-	tgtPath := strings.TrimPrefix(m["path"], "/")
-	devName := fmt.Sprintf("disk.%s", strings.Replace(tgtPath, "/", "-", -1))
+	destPath := strings.TrimPrefix(m["path"], "/")
+
+	// legacy style
+	devName := fmt.Sprintf("disk.%s", strings.Replace(destPath, "/", "-", -1))
 	devPath := filepath.Join(c.DevicesPath(), devName)
 
-	// The dsk device doesn't exist and cannot be mounted.
 	if !shared.PathExists(devPath) {
-		return nil
+		// new style
+		devName = fmt.Sprintf("disk.%s.%s", name, strings.Replace(destPath, "/", "-", -1))
+		devPath = filepath.Join(c.DevicesPath(), devName)
+
+		// The disk device doesn't exist.
+		if !shared.PathExists(devPath) {
+			return nil
+		}
 	}
 
 	// Remove the bind-mount from the container
-	if c.FileExists(tgtPath) == nil {
-		err := c.removeMount(m["path"])
-		if err != nil {
-			return fmt.Errorf("Error unmounting the device: %s", err)
-		}
+	err := c.removeMount(m["path"])
+	if err != nil {
+		return fmt.Errorf("Error unmounting the device: %s", err)
 	}
 
 	// Unmount the host side
-	err := syscall.Unmount(devPath, syscall.MNT_DETACH)
+	err = syscall.Unmount(devPath, syscall.MNT_DETACH)
 	if err != nil {
 		return err
 	}
@@ -6786,7 +6806,7 @@ func (c *containerLXC) removeDiskDevices() error {
 
 	// Go through all the unix devices
 	for _, f := range dents {
-		// Skip non-Unix devices
+		// Skip non-disk devices
 		if !strings.HasPrefix(f.Name(), "disk.") {
 			continue
 		}


More information about the lxc-devel mailing list