[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