The following pull request was submitted through Github. It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/3266
This e-mail was sent by the LXC bot, direct replies will not reach the author unless they happen to be subscribed to this list. === Description (from pull-request) === Closes #3264. References: https://discuss.linuxcontainers.org/t/storage-pool-default-mount-options/80 Signed-off-by: Christian Brauner <christian.brau...@ubuntu.com>
From a4c7c5c4bfc4b0d5807ba9a903b04e29ff4edfdf Mon Sep 17 00:00:00 2001 From: Christian Brauner <christian.brau...@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.brau...@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.brau...@ubuntu.com> Date: Tue, 2 May 2017 09:34:15 +0200 Subject: [PATCH 2/5] btrfs: add getBtrfsPoolMountOptions() Signed-off-by: Christian Brauner <christian.brau...@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.brau...@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.brau...@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.brau...@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.brau...@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.brau...@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.brau...@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.
_______________________________________________ lxc-devel mailing list lxc-devel@lists.linuxcontainers.org http://lists.linuxcontainers.org/listinfo/lxc-devel