[lxc-devel] [lxd/master] do mounts in the right order

tych0 on Github lxc-bot at linuxcontainers.org
Wed Dec 14 17:38:11 UTC 2016


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 609 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20161214/3dc2a26f/attachment.bin>
-------------- next part --------------
From 7507fa1c2fe65ef50f487d26877ec5f5a1515b5d Mon Sep 17 00:00:00 2001
From: Tycho Andersen <tycho.andersen at canonical.com>
Date: Wed, 14 Dec 2016 17:16:38 +0000
Subject: [PATCH] do mounts in the right order

In particular, if there are two paths to be mounted:

/mnt
/mnt/foo

We should always mount /mnt before we mount /mnt/foo, otherwise, the /mnt
mount will overmount /mnt/foo, which is almost certainly not what people
want.

Closes #2717

Signed-off-by: Tycho Andersen <tycho.andersen at canonical.com>
---
 lxd/container_lxc.go  | 59 +++++++++++++++++++++++++++++++++++++++++++--------
 test/suites/config.sh | 20 +++++++++++++++++
 2 files changed, 70 insertions(+), 9 deletions(-)

diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index 5561571..cbbe8c2 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -1577,6 +1577,7 @@ func (c *containerLXC) startCommon() (string, error) {
 	var usbs []usbDevice
 	var gpus []gpuDevice
 	var nvidiaDevices []nvidiaGpuDevices
+	diskDevices := map[string]shared.Device{}
 
 	// Create the devices
 	for _, k := range c.expandedDevices.DeviceNames() {
@@ -1662,12 +1663,8 @@ func (c *containerLXC) startCommon() (string, error) {
 				}
 			}
 		} else if m["type"] == "disk" {
-			// Disk device
 			if m["path"] != "/" {
-				_, err := c.createDiskDevice(k, m)
-				if err != nil {
-					return "", err
-				}
+				diskDevices[k] = m
 			}
 		} else if m["type"] == "nic" {
 			if m["nictype"] == "bridged" && shared.IsTrue(m["security.mac_filtering"]) {
@@ -1710,6 +1707,14 @@ func (c *containerLXC) startCommon() (string, error) {
 		}
 	}
 
+	err = c.addDiskDevices(diskDevices, func(name string, d shared.Device) error {
+		_, err := c.createDiskDevice(name, d)
+		return err
+	})
+	if err != nil {
+		return "", err
+	}
+
 	// Create any missing directory
 	err = os.MkdirAll(c.LogPath(), 0700)
 	if err != nil {
@@ -3412,6 +3417,8 @@ func (c *containerLXC) Update(args containerArgs, userRequested bool) error {
 			}
 		}
 
+		diskDevices := map[string]shared.Device{}
+
 		for k, m := range addDevices {
 			if shared.StringInSlice(m["type"], []string{"unix-char", "unix-block"}) {
 				err = c.insertUnixDevice(m)
@@ -3419,10 +3426,7 @@ func (c *containerLXC) Update(args containerArgs, userRequested bool) error {
 					return err
 				}
 			} else if m["type"] == "disk" && m["path"] != "/" {
-				err = c.insertDiskDevice(k, m)
-				if err != nil {
-					return err
-				}
+				diskDevices[k] = m
 			} else if m["type"] == "nic" {
 				err = c.insertNetworkDevice(k, m)
 				if err != nil {
@@ -3497,6 +3501,11 @@ func (c *containerLXC) Update(args containerArgs, userRequested bool) error {
 			}
 		}
 
+		err = c.addDiskDevices(diskDevices, c.insertDiskDevice)
+		if err != nil {
+			return err
+		}
+
 		updateDiskLimit := false
 		for k, m := range updateDevices {
 			if m["type"] == "disk" {
@@ -5707,6 +5716,38 @@ func (c *containerLXC) insertDiskDevice(name string, m shared.Device) error {
 	return nil
 }
 
+type byPath []shared.Device
+
+func (a byPath) Len() int {
+	return len(a)
+}
+
+func (a byPath) Swap(i, j int) {
+	a[i], a[j] = a[j], a[i]
+}
+
+func (a byPath) Less(i, j int) bool {
+	return a[i]["path"] < a[j]["path"]
+}
+
+func (c *containerLXC) addDiskDevices(devices map[string]shared.Device, handler func(string, shared.Device)error) error {
+	ordered := byPath{}
+
+	for _, d := range devices {
+		ordered = append(ordered, d)
+	}
+
+	sort.Sort(ordered)
+	for _, d := range ordered {
+		err := handler(d["path"], d)
+		if err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
 func (c *containerLXC) removeDiskDevice(name string, m shared.Device) error {
 	// Check that the container is running
 	pid := c.InitPID()
diff --git a/test/suites/config.sh b/test/suites/config.sh
index 74c6d78..3bfbaea 100644
--- a/test/suites/config.sh
+++ b/test/suites/config.sh
@@ -79,6 +79,24 @@ testloopmounts() {
   sed -i "\|^${lpath}|d" "${TEST_DIR}/loops"
 }
 
+test_mount_order() {
+  mkdir -p "${TEST_DIR}/order/empty"
+  mkdir -p "${TEST_DIR}/order/full"
+  touch "${TEST_DIR}/order/full/filler"
+
+  # The idea here is that sometimes (depending on how golang randomizes the
+  # config) the empty dir will have the contents of full in it, but sometimes
+  # it won't depending on whether the devices below are processed in order or
+  # not. This should not be racy, and they should *always* be processed in path
+  # order, so the filler file should always be there.
+  lxc config device add foo order disk source="${TEST_DIR}/order" path=/mnt
+  lxc config device add foo orderFull disk source="${TEST_DIR}/order/full" path=/mnt/empty
+
+  lxc start foo
+  lxc exec foo -- cat /mnt/empty/filler
+  lxc stop foo --force
+}
+
 test_config_profiles() {
   ensure_import_testimage
 
@@ -185,6 +203,8 @@ test_config_profiles() {
 
   testloopmounts
 
+  test_mount_order
+
   lxc delete foo
 
   lxc init testimage foo


More information about the lxc-devel mailing list