[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