[lxc-devel] [lxd/master] Add recursive bind mount support
tych0 on Github
lxc-bot at linuxcontainers.org
Fri Mar 11 22:59:29 UTC 2016
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 301 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20160311/e54c9502/attachment.bin>
-------------- next part --------------
From a9357506f4038d69fbee138d2dbbf7bea1e474dd Mon Sep 17 00:00:00 2001
From: Tycho Andersen <tycho.andersen at canonical.com>
Date: Fri, 11 Mar 2016 10:51:08 -0700
Subject: [PATCH 1/4] devices: allow recursive bind mounts
Signed-off-by: Tycho Andersen <tycho.andersen at canonical.com>
---
lxd/container.go | 6 ++++++
lxd/container_lxc.go | 20 +++++++++++++++++---
lxd/devices.go | 5 ++++-
lxd/nsexec.go | 2 +-
specs/configuration.md | 1 +
5 files changed, 29 insertions(+), 5 deletions(-)
diff --git a/lxd/container.go b/lxd/container.go
index 57fa9ba..73b16d2 100644
--- a/lxd/container.go
+++ b/lxd/container.go
@@ -185,6 +185,8 @@ func containerValidDeviceConfigKey(t, k string) bool {
return true
case "source":
return true
+ case "recursive":
+ return true
default:
return false
}
@@ -262,6 +264,10 @@ func containerValidDevices(devices shared.Devices, profile bool, expanded bool)
if m["size"] != "" && m["path"] != "/" {
return fmt.Errorf("Only the root disk may have a size quota.")
}
+
+ if m["path"] == "/" && m["recursive"] != "" {
+ return fmt.Errorf("recursive only makes sense on non-rootfs entries")
+ }
} else if shared.StringInSlice(m["type"], []string{"unix-char", "unix-block"}) {
if m["path"] == "" {
return fmt.Errorf("Unix device entry is missing the required \"path\" property.")
diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index 017127d..ced4c26 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -758,6 +758,7 @@ func (c *containerLXC) initLXC() error {
// Various option checks
isOptional := m["optional"] == "1" || m["optional"] == "true"
isReadOnly := m["readonly"] == "1" || m["readonly"] == "true"
+ isRecursive := m["recursive"] == "1" || m["recursive"] == "true"
isFile := !shared.IsDir(srcPath) && !deviceIsBlockdev(srcPath)
// Deal with a rootfs
@@ -776,6 +777,7 @@ func (c *containerLXC) initLXC() error {
}
}
} else {
+ rbind := ""
options := []string{}
if isReadOnly {
options = append(options, "ro")
@@ -785,13 +787,17 @@ func (c *containerLXC) initLXC() error {
options = append(options, "optional")
}
+ if isRecursive {
+ rbind = "r"
+ }
+
if isFile {
options = append(options, "create=file")
} else {
options = append(options, "create=dir")
}
- err = lxcSetConfigItem(cc, "lxc.mount.entry", fmt.Sprintf("%s %s none bind,%s", devPath, tgtPath, strings.Join(options, ",")))
+ err = lxcSetConfigItem(cc, "lxc.mount.entry", fmt.Sprintf("%s %s none %sbind,%s", devPath, tgtPath, rbind, strings.Join(options, ",")))
if err != nil {
return err
}
@@ -3638,6 +3644,7 @@ func (c *containerLXC) createDiskDevice(name string, m shared.Device) (string, e
// Check if read-only
isOptional := m["optional"] == "1" || m["optional"] == "true"
isReadOnly := m["readonly"] == "1" || m["readonly"] == "true"
+ isRecursive := m["recursive"] == "1" || m["recursive"] == "true"
isFile := !shared.IsDir(srcPath) && !deviceIsBlockdev(srcPath)
// Check if the source exists
@@ -3680,7 +3687,7 @@ func (c *containerLXC) createDiskDevice(name string, m shared.Device) (string, e
}
// Mount the fs
- err := deviceMountDisk(srcPath, devPath, isReadOnly)
+ err := deviceMountDisk(srcPath, devPath, isReadOnly, isRecursive)
if err != nil {
return "", err
}
@@ -3694,15 +3701,22 @@ func (c *containerLXC) insertDiskDevice(name string, m shared.Device) error {
return fmt.Errorf("Can't insert device into stopped container")
}
+ isRecursive := m["recursive"] == "1" || m["recursive"] == "true"
+
// Create the device on the host
devPath, err := c.createDiskDevice(name, m)
if err != nil {
return fmt.Errorf("Failed to setup device: %s", err)
}
+ flags := syscall.MS_BIND
+ if isRecursive {
+ flags |= syscall.MS_REC
+ }
+
// Bind-mount it into the container
tgtPath := strings.TrimSuffix(m["path"], "/")
- err = c.insertMount(devPath, tgtPath, "none", syscall.MS_BIND)
+ err = c.insertMount(devPath, tgtPath, "none", flags)
if err != nil {
return fmt.Errorf("Failed to add mount for device: %s", err)
}
diff --git a/lxd/devices.go b/lxd/devices.go
index 6b12c30..f22bf89 100644
--- a/lxd/devices.go
+++ b/lxd/devices.go
@@ -516,7 +516,7 @@ func deviceRemoveInterface(nic string) error {
return exec.Command("ip", "link", "del", nic).Run()
}
-func deviceMountDisk(srcPath string, dstPath string, readonly bool) error {
+func deviceMountDisk(srcPath string, dstPath string, readonly bool, recursive bool) error {
var err error
// Prepare the mount flags
@@ -534,6 +534,9 @@ func deviceMountDisk(srcPath string, dstPath string, readonly bool) error {
}
} else {
flags |= syscall.MS_BIND
+ if recursive {
+ flags |= syscall.MS_REC
+ }
}
// Mount the filesystem
diff --git a/lxd/nsexec.go b/lxd/nsexec.go
index 03d6a55..b321191 100644
--- a/lxd/nsexec.go
+++ b/lxd/nsexec.go
@@ -283,7 +283,7 @@ void forkmount(char *buf, char *cur, ssize_t size) {
_exit(1);
}
- if (mount(src, dest, "none", MS_MOVE, NULL) < 0) {
+ if (mount(src, dest, "none", MS_MOVE | MS_REC, NULL) < 0) {
fprintf(stderr, "Failed mounting %s onto %s: %s\n", src, dest, strerror(errno));
_exit(1);
}
diff --git a/specs/configuration.md b/specs/configuration.md
index b32ffce..1edfa7d 100644
--- a/specs/configuration.md
+++ b/specs/configuration.md
@@ -210,6 +210,7 @@ source | string | - | yes | Path on the host,
optional | boolean | false | no | Controls whether to fail if the source doesn't exist
readonly | boolean | false | no | Controls whether to make the mount read-only
size | string | - | no | Disk size in bytes (supports kB, MB, GB, TB, PB and EB suffixes). This is only supported for the rootfs (/).
+recursive | boolean | false | no | Whether or not to make a bind mount recursive.
If multiple disks, backed by the same block device, have I/O limits set,
the average of the limits will be used.
From 5955b09adf542e5240dbe49357acc6edffcf8be8 Mon Sep 17 00:00:00 2001
From: Tycho Andersen <tycho.andersen at canonical.com>
Date: Fri, 11 Mar 2016 12:04:55 -0700
Subject: [PATCH 2/4] log the actual error as well as semantic error
Signed-off-by: Tycho Andersen <tycho.andersen at canonical.com>
---
lxd/container_lxc.go | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index ced4c26..31dd652 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -1417,13 +1417,13 @@ func (c *containerLXC) OnStop(target string) error {
// Clean all the unix devices
err = c.removeUnixDevices()
if err != nil {
- shared.Log.Error("Unable to remove unix devices")
+ shared.Log.Error("Unable to remove unix devices", "err", err)
}
// Clean all the disk devices
err = c.removeDiskDevices()
if err != nil {
- shared.Log.Error("Unable to remove disk devices")
+ shared.Log.Error("Unable to remove disk devices", "err", err)
}
// Reboot the container
From f4184e3f3e1302399e63208ae524ce76047c8243 Mon Sep 17 00:00:00 2001
From: Tycho Andersen <tycho.andersen at canonical.com>
Date: Fri, 11 Mar 2016 15:18:14 -0700
Subject: [PATCH 3/4] disk devices: remount the device as MS_SLAVE
It's annoying that these are mounted MS_SHARED for development (thanks
systemd), and in the case where we are doing recursive mounts, our
MNT_DETACH unmounts the mounts on the host. So let's remount them as
slaves.
Signed-off-by: Tycho Andersen <tycho.andersen at canonical.com>
---
lxd/devices.go | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/lxd/devices.go b/lxd/devices.go
index f22bf89..db018ca 100644
--- a/lxd/devices.go
+++ b/lxd/devices.go
@@ -544,6 +544,11 @@ func deviceMountDisk(srcPath string, dstPath string, readonly bool, recursive bo
return fmt.Errorf("Unable to mount %s at %s: %s", srcPath, dstPath, err)
}
+ flags = syscall.MS_REC | syscall.MS_SLAVE
+ if err = syscall.Mount("", dstPath, "", uintptr(flags), ""); err != nil {
+ return fmt.Errorf("unable to make mount %s private: %s", dstPath, err)
+ }
+
return nil
}
From 0d84af5445071dfd83a1c306e9c3eedf9dae74bc Mon Sep 17 00:00:00 2001
From: Tycho Andersen <tycho.andersen at canonical.com>
Date: Fri, 11 Mar 2016 15:46:30 -0700
Subject: [PATCH 4/4] fix copy pasted error message
Signed-off-by: Tycho Andersen <tycho.andersen at canonical.com>
---
lxd/container_lxc.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index 31dd652..938add6 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -3109,7 +3109,7 @@ func (c *containerLXC) removeMount(mount string) error {
pid := c.InitPID()
if pid == -1 {
// Container isn't running
- return fmt.Errorf("Can't insert mount into stopped container")
+ return fmt.Errorf("Can't remove mount from stopped container")
}
// Remove the mount from the container
More information about the lxc-devel
mailing list