[lxc-devel] [lxd/master] api extension: btrfs.mount_options

brauner on Github lxc-bot at linuxcontainers.org
Tue May 2 09:44:48 UTC 2017


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 470 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20170502/30ed9636/attachment.bin>
-------------- next part --------------
From a4c7c5c4bfc4b0d5807ba9a903b04e29ff4edfdf Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Tue, 2 May 2017 09:28:16 +0200
Subject: [PATCH 1/5] storage pools config: keep things alphabetically

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

diff --git a/lxd/storage_pools_config.go b/lxd/storage_pools_config.go
index 5f12423..e49e35b 100644
--- a/lxd/storage_pools_config.go
+++ b/lxd/storage_pools_config.go
@@ -86,8 +86,8 @@ func storagePoolValidateConfig(name string, driver string, config map[string]str
 		}
 
 		prfx := strings.HasPrefix
-		if driver != "zfs" {
-			if prfx(key, "volume.zfs.") || prfx(key, "zfs.") {
+		if driver == "dir" {
+			if key == "size" {
 				return fmt.Errorf("the key %s cannot be used with %s storage pools", key, strings.ToUpper(driver))
 			}
 		}
@@ -98,8 +98,8 @@ func storagePoolValidateConfig(name string, driver string, config map[string]str
 			}
 		}
 
-		if driver == "dir" {
-			if key == "size" {
+		if driver != "zfs" {
+			if prfx(key, "volume.zfs.") || prfx(key, "zfs.") {
 				return fmt.Errorf("the key %s cannot be used with %s storage pools", key, strings.ToUpper(driver))
 			}
 		}

From 4db4a8cac18a59e18ea336b02174a9dad2693149 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Tue, 2 May 2017 09:34:15 +0200
Subject: [PATCH 2/5] btrfs: add getBtrfsPoolMountOptions()

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 lxd/storage_btrfs.go | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/lxd/storage_btrfs.go b/lxd/storage_btrfs.go
index c9a1b52..ded31ce 100644
--- a/lxd/storage_btrfs.go
+++ b/lxd/storage_btrfs.go
@@ -20,12 +20,14 @@ import (
 	"github.com/lxc/lxd/shared/logger"
 )
 
-var btrfsMntOptions = "user_subvol_rm_allowed"
-
 type storageBtrfs struct {
 	storageShared
 }
 
+func (s *storageBtrfs) getBtrfsPoolMountOptions() string {
+	return "user_subvol_rm_allowed"
+}
+
 // ${LXD_DIR}/storage-pools/<pool>/containers
 func (s *storageBtrfs) getContainerSubvolumePath(poolName string) string {
 	return shared.VarPath("storage-pools", poolName, "containers")
@@ -201,7 +203,7 @@ func (s *storageBtrfs) StoragePoolCreate() error {
 		// cannot call StoragePoolMount() since it will try to do the
 		// reverse operation. So instead we shamelessly mount using the
 		// block device path at the time of pool creation.
-		err1 = syscall.Mount(source, poolMntPoint, "btrfs", 0, btrfsMntOptions)
+		err1 = syscall.Mount(source, poolMntPoint, "btrfs", 0, s.getBtrfsPoolMountOptions())
 	} else {
 		_, err1 = s.StoragePoolMount()
 	}
@@ -410,7 +412,7 @@ func (s *storageBtrfs) StoragePoolMount() (bool, error) {
 	}
 
 	// This is a block device.
-	err := syscall.Mount(mountSource, poolMntPoint, "btrfs", mountFlags, btrfsMntOptions)
+	err := syscall.Mount(mountSource, poolMntPoint, "btrfs", mountFlags, s.getBtrfsPoolMountOptions())
 	if err != nil {
 		return false, err
 	}

From 59cf63ba4763a8e96a219dbe0bdde3172265c755 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Tue, 2 May 2017 11:13:53 +0200
Subject: [PATCH 3/5] doc storage: fix ordering

- none namespaced keys
- namespaced keys

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 doc/storage.md | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/doc/storage.md b/doc/storage.md
index 84b7cb7..f9a7ddd 100644
--- a/doc/storage.md
+++ b/doc/storage.md
@@ -10,17 +10,17 @@ Key                             | Type      | Condition
 :--                             | :--       | :--                               | :--               | :--
 size                            | string    | appropriate driver and source     | 0                 | Size of the storage pool in bytes (suffixes supported). (Currently valid for loop based pools and zfs.)
 source                          | string    | -                                 | -                 | Path to block device or loop file or filesystem entry
-volume.block.filesystem         | string    | block based driver (lvm)          | ext4              | Filesystem to use for new volumes
-volume.block.mount\_options     | string    | block based driver (lvm)          | discard           | Mount options for block devices
 lvm.thinpool\_name              | string    | lvm driver                        | LXDPool           | Thin pool where images and containers are created.
 lvm.use\_thinpool               | bool      | lvm driver                        | true              | Whether the storage pool uses a thinpool for logical volumes.
 lvm.vg\_name                    | string    | lvm driver                        | name of the pool  | Name of the volume group to create.
 rsync.bwlimit                   | string    | -                                 | 0 (no limit)      | Specifies the upper limit to be placed on the socket I/O whenever rsync has to be used to transfer storage entities.
+volume.block.filesystem         | string    | block based driver (lvm)          | ext4              | Filesystem to use for new volumes
+volume.block.mount\_options     | string    | block based driver (lvm)          | discard           | Mount options for block devices
 volume.size                     | string    | appropriate driver                | 0                 | Default volume size
 volume.zfs.remove\_snapshots    | bool      | zfs driver                        | false             | Remove snapshots as needed
 volume.zfs.use\_refquota        | bool      | zfs driver                        | false             | Use refquota instead of quota for space.
-zfs.pool\_name                  | string    | zfs driver                        | name of the pool  | Name of the zpool
 zfs.clone\_copy                 | bool      | zfs driver                        | true              | Whether to use ZFS lightweight clones rather than full dataset copies.
+zfs.pool\_name                  | string    | zfs driver                        | name of the pool  | Name of the zpool
 
 Storage pool configuration keys can be set using the lxc tool with:
 

From 50e74f8c08357b3f91afd7194c245c335fc1f57a Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Tue, 2 May 2017 11:16:12 +0200
Subject: [PATCH 4/5] btrfs: introduce btrfs.mount_options pool property

Closes #3264.

References: https://discuss.linuxcontainers.org/t/storage-pool-default-mount-options/80
Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 doc/api-extensions.md       |  5 +++++
 doc/storage.md              | 31 ++++++++++++++++---------------
 lxd/api_1.0.go              |  1 +
 lxd/storage_btrfs.go        | 39 ++++++++++++++++++++++++++++++++++-----
 lxd/storage_pools_config.go |  7 +++++++
 lxd/storage_utils.go        | 36 ++++++++++++++++++++++++++++++++++++
 6 files changed, 99 insertions(+), 20 deletions(-)

diff --git a/doc/api-extensions.md b/doc/api-extensions.md
index 8cf17f3..ee37780 100644
--- a/doc/api-extensions.md
+++ b/doc/api-extensions.md
@@ -264,3 +264,8 @@ places an upper limit on the amount of socket I/O allowed.
 This introduces a new tunnel.NAME.interface option for networks.
 
 This key control what host network interface is used for a VXLAN tunnel.
+
+## storage\_btrfs\_mount\_options
+This introduces the btrfs.mount\_options property for btrfs storage pools.
+
+This key controls what mount options will be used for the btrfs storage pool.
diff --git a/doc/storage.md b/doc/storage.md
index f9a7ddd..c5cc8e8 100644
--- a/doc/storage.md
+++ b/doc/storage.md
@@ -6,21 +6,22 @@ overridden on a per-volume basis.
 
 ## Storage pool configuration
 
-Key                             | Type      | Condition                         | Default           | Description
-:--                             | :--       | :--                               | :--               | :--
-size                            | string    | appropriate driver and source     | 0                 | Size of the storage pool in bytes (suffixes supported). (Currently valid for loop based pools and zfs.)
-source                          | string    | -                                 | -                 | Path to block device or loop file or filesystem entry
-lvm.thinpool\_name              | string    | lvm driver                        | LXDPool           | Thin pool where images and containers are created.
-lvm.use\_thinpool               | bool      | lvm driver                        | true              | Whether the storage pool uses a thinpool for logical volumes.
-lvm.vg\_name                    | string    | lvm driver                        | name of the pool  | Name of the volume group to create.
-rsync.bwlimit                   | string    | -                                 | 0 (no limit)      | Specifies the upper limit to be placed on the socket I/O whenever rsync has to be used to transfer storage entities.
-volume.block.filesystem         | string    | block based driver (lvm)          | ext4              | Filesystem to use for new volumes
-volume.block.mount\_options     | string    | block based driver (lvm)          | discard           | Mount options for block devices
-volume.size                     | string    | appropriate driver                | 0                 | Default volume size
-volume.zfs.remove\_snapshots    | bool      | zfs driver                        | false             | Remove snapshots as needed
-volume.zfs.use\_refquota        | bool      | zfs driver                        | false             | Use refquota instead of quota for space.
-zfs.clone\_copy                 | bool      | zfs driver                        | true              | Whether to use ZFS lightweight clones rather than full dataset copies.
-zfs.pool\_name                  | string    | zfs driver                        | name of the pool  | Name of the zpool
+Key                             | Type      | Condition                         | Default                 | Description
+:--                             | :--       | :--                               | :--                     | :--
+size                            | string    | appropriate driver and source     | 0                       | Size of the storage pool in bytes (suffixes supported). (Currently valid for loop based pools and zfs.)
+source                          | string    | -                                 | -                       | Path to block device or loop file or filesystem entry
+btrfs.mount\_options            | string    | btrfs driver                      | user_subvol_rm_allowed  | Mount options for block devices
+lvm.thinpool\_name              | string    | lvm driver                        | LXDPool                 | Thin pool where images and containers are created.
+lvm.use\_thinpool               | bool      | lvm driver                        | true                    | Whether the storage pool uses a thinpool for logical volumes.
+lvm.vg\_name                    | string    | lvm driver                        | name of the pool        | Name of the volume group to create.
+rsync.bwlimit                   | string    | -                                 | 0 (no limit)            | Specifies the upper limit to be placed on the socket I/O whenever rsync has to be used to transfer storage entities.
+volume.block.filesystem         | string    | block based driver (lvm)          | ext4                    | Filesystem to use for new volumes
+volume.block.mount\_options     | string    | block based driver (lvm)          | discard                 | Mount options for block devices
+volume.size                     | string    | appropriate driver                | 0                       | Default volume size
+volume.zfs.remove\_snapshots    | bool      | zfs driver                        | false                   | Remove snapshots as needed
+volume.zfs.use\_refquota        | bool      | zfs driver                        | false                   | Use refquota instead of quota for space.
+zfs.clone\_copy                 | bool      | zfs driver                        | true                    | Whether to use ZFS lightweight clones rather than full dataset copies.
+zfs.pool\_name                  | string    | zfs driver                        | name of the pool        | Name of the zpool
 
 Storage pool configuration keys can be set using the lxc tool with:
 
diff --git a/lxd/api_1.0.go b/lxd/api_1.0.go
index f043c72..beb4f79 100644
--- a/lxd/api_1.0.go
+++ b/lxd/api_1.0.go
@@ -104,6 +104,7 @@ func api10Get(d *Daemon, r *http.Request) Response {
 			"storage_lvm_use_thinpool",
 			"storage_rsync_bwlimit",
 			"network_vxlan_interface",
+			"storage_btrfs_mount_options",
 		},
 		APIStatus:  "stable",
 		APIVersion: version.APIVersion,
diff --git a/lxd/storage_btrfs.go b/lxd/storage_btrfs.go
index ded31ce..499f559 100644
--- a/lxd/storage_btrfs.go
+++ b/lxd/storage_btrfs.go
@@ -24,8 +24,35 @@ type storageBtrfs struct {
 	storageShared
 }
 
-func (s *storageBtrfs) getBtrfsPoolMountOptions() string {
-	return "user_subvol_rm_allowed"
+func (s *storageBtrfs) getBtrfsPoolMountOptions() (uintptr, string) {
+	mountFlags := uintptr(0)
+	opts := s.pool.Config["btrfs.mount_options"]
+	if opts == "" {
+		return mountFlags, "user_subvol_rm_allowed"
+	}
+
+	tmp := strings.SplitN(opts, ",", -1)
+	for i := 0; i < len(tmp); i++ {
+		opt := tmp[i]
+		logger.Errorf("1111: %s", opt)
+		do, ok := MountOptions[opt]
+		if !ok {
+			continue
+		}
+
+		if do.unset {
+			mountFlags &= ^do.flag
+		} else {
+			mountFlags |= do.flag
+		}
+
+		copy(tmp[i:], tmp[i+1:])
+		tmp[len(tmp)-1] = ""
+		tmp = tmp[:len(tmp)-1]
+		i--
+	}
+
+	return mountFlags, strings.Join(tmp, ",")
 }
 
 // ${LXD_DIR}/storage-pools/<pool>/containers
@@ -183,6 +210,7 @@ func (s *storageBtrfs) StoragePoolCreate() error {
 
 	var err1 error
 	var devUUID string
+	mountFlags, mountOptions := s.getBtrfsPoolMountOptions()
 	if isBlockDev && filepath.IsAbs(source) {
 		devUUID, _ = shared.LookupUUIDByBlockDevPath(source)
 		// The symlink might not have been created even with the delay
@@ -203,7 +231,7 @@ func (s *storageBtrfs) StoragePoolCreate() error {
 		// cannot call StoragePoolMount() since it will try to do the
 		// reverse operation. So instead we shamelessly mount using the
 		// block device path at the time of pool creation.
-		err1 = syscall.Mount(source, poolMntPoint, "btrfs", 0, s.getBtrfsPoolMountOptions())
+		err1 = syscall.Mount(source, poolMntPoint, "btrfs", mountFlags, mountOptions)
 	} else {
 		_, err1 = s.StoragePoolMount()
 	}
@@ -411,9 +439,10 @@ func (s *storageBtrfs) StoragePoolMount() (bool, error) {
 
 	}
 
-	// This is a block device.
-	err := syscall.Mount(mountSource, poolMntPoint, "btrfs", mountFlags, s.getBtrfsPoolMountOptions())
+	mountFlags, mountOptions := s.getBtrfsPoolMountOptions()
+	err := syscall.Mount(mountSource, poolMntPoint, "btrfs", mountFlags, mountOptions)
 	if err != nil {
+		logger.Errorf("failed to mount BTRFS storage pool \"%s\" onto \"%s\" with mountoptions \"%s\": %s", mountSource, poolMntPoint, mountOptions, err)
 		return false, err
 	}
 
diff --git a/lxd/storage_pools_config.go b/lxd/storage_pools_config.go
index e49e35b..96644ae 100644
--- a/lxd/storage_pools_config.go
+++ b/lxd/storage_pools_config.go
@@ -10,6 +10,13 @@ import (
 )
 
 var storagePoolConfigKeys = map[string]func(value string) error{
+	// valid drivers: btrfs
+	// (Note, that we can't be smart in detecting mount options since a lot
+	// of filesystems come with their own additional ones (e.g.
+	// "user_subvol_rm_allowed" for btrfs or "zfsutils" for zfs). So
+	// shared.IsAny() must do.)
+	"btrfs.mount_options": shared.IsAny,
+
 	// valid drivers: lvm
 	"lvm.thinpool_name": shared.IsAny,
 	"lvm.use_thinpool":  shared.IsBool,
diff --git a/lxd/storage_utils.go b/lxd/storage_utils.go
index 3952865..a6db607 100644
--- a/lxd/storage_utils.go
+++ b/lxd/storage_utils.go
@@ -2,10 +2,46 @@ package main
 
 import (
 	"strings"
+	"syscall"
 
 	"github.com/lxc/lxd/shared"
 )
 
+// Export the mount options map since we might find it useful in other parts of
+// LXD.
+type mountOptions struct {
+	unset bool
+	flag  uintptr
+}
+
+var MountOptions = map[string]mountOptions{
+	"async":         {true, syscall.MS_SYNCHRONOUS},
+	"atime":         {true, syscall.MS_NOATIME},
+	"bind":          {false, syscall.MS_BIND},
+	"defaults":      {false, 0},
+	"dev":           {true, syscall.MS_NODEV},
+	"diratime":      {true, syscall.MS_NODIRATIME},
+	"dirsync":       {false, syscall.MS_DIRSYNC},
+	"exec":          {true, syscall.MS_NOEXEC},
+	"mand":          {false, syscall.MS_MANDLOCK},
+	"noatime":       {false, syscall.MS_NOATIME},
+	"nodev":         {false, syscall.MS_NODEV},
+	"nodiratime":    {false, syscall.MS_NODIRATIME},
+	"noexec":        {false, syscall.MS_NOEXEC},
+	"nomand":        {true, syscall.MS_MANDLOCK},
+	"norelatime":    {true, syscall.MS_RELATIME},
+	"nostrictatime": {true, syscall.MS_STRICTATIME},
+	"nosuid":        {false, syscall.MS_NOSUID},
+	"rbind":         {false, syscall.MS_BIND | syscall.MS_REC},
+	"relatime":      {false, syscall.MS_RELATIME},
+	"remount":       {false, syscall.MS_REMOUNT},
+	"ro":            {false, syscall.MS_RDONLY},
+	"rw":            {true, syscall.MS_RDONLY},
+	"strictatime":   {false, syscall.MS_STRICTATIME},
+	"suid":          {true, syscall.MS_NOSUID},
+	"sync":          {false, syscall.MS_SYNCHRONOUS},
+}
+
 func storageValidName(value string) error {
 	return nil
 }

From 678d041087c7d36912d35870fcf1ecaf53490f5b Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Tue, 2 May 2017 11:41:47 +0200
Subject: [PATCH 5/5] test: add btrfs.mount_options test

Closes #3264.

References: https://discuss.linuxcontainers.org/t/storage-pool-default-mount-options/80
Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 test/suites/storage.sh | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/test/suites/storage.sh b/test/suites/storage.sh
index 0efe42f..0f4442f 100644
--- a/test/suites/storage.sh
+++ b/test/suites/storage.sh
@@ -89,6 +89,9 @@ test_storage() {
 
       lxc storage create "lxdtest-$(basename "${LXD_DIR}")-valid-btrfs-pool-config" btrfs rsync.bwlimit=1024
       lxc storage delete "lxdtest-$(basename "${LXD_DIR}")-valid-btrfs-pool-config"
+
+      lxc storage create "lxdtest-$(basename "${LXD_DIR}")-valid-btrfs-pool-config" btrfs btrfs.mount_options="rw,strictatime,nospace_cache,user_subvol_rm_allowed"
+      lxc storage delete "lxdtest-$(basename "${LXD_DIR}")-valid-btrfs-pool-config"
     fi
 
     # Create dir pool.


More information about the lxc-devel mailing list