[lxc-devel] [lxd/master] dir: use bind-mount for pools outside ${LXD_DIR}
brauner on Github
lxc-bot at linuxcontainers.org
Thu Aug 31 19:14:41 UTC 2017
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 364 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20170831/78a0b83e/attachment.bin>
-------------- next part --------------
From 889adbb2af36dc51c6296a4ee5df66127af39606 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Thu, 31 Aug 2017 20:54:25 +0200
Subject: [PATCH 1/2] dir: use bind-mount for pools outside ${LXD_DIR}
Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
lxd/storage_dir.go | 128 ++++++++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 117 insertions(+), 11 deletions(-)
diff --git a/lxd/storage_dir.go b/lxd/storage_dir.go
index 5aa37c1d5..b5a027880 100644
--- a/lxd/storage_dir.go
+++ b/lxd/storage_dir.go
@@ -5,6 +5,7 @@ import (
"os"
"path/filepath"
"strings"
+ "syscall"
"github.com/gorilla/websocket"
@@ -58,14 +59,11 @@ func (s *storageDir) StoragePoolCreate() error {
source = filepath.Join(shared.VarPath("storage-pools"), s.pool.Name)
s.pool.Config["source"] = source
} else {
- cleanSource := filepath.Clean(source)
- lxdDir := shared.VarPath()
- poolMntPoint := getStoragePoolMountPoint(s.pool.Name)
- if strings.HasPrefix(cleanSource, lxdDir) && cleanSource != poolMntPoint {
- return fmt.Errorf("DIR storage pool requests in LXD directory \"%s\" are only valid under \"%s\"\n(e.g. source=%s)", shared.VarPath(), shared.VarPath("storage-pools"), poolMntPoint)
- }
+ source = filepath.Clean(source)
}
+ poolMntPoint := getStoragePoolMountPoint(s.pool.Name)
+
revert := true
if !shared.PathExists(source) {
err := os.MkdirAll(source, 0711)
@@ -89,14 +87,17 @@ func (s *storageDir) StoragePoolCreate() error {
}
}
- prefix := shared.VarPath("storage-pools")
- if !strings.HasPrefix(source, prefix) {
- // symlink from storage-pools to pool x
- storagePoolSymlink := getStoragePoolMountPoint(s.pool.Name)
- err := os.Symlink(source, storagePoolSymlink)
+ if !shared.PathExists(poolMntPoint) {
+ err := os.MkdirAll(poolMntPoint, 0711)
if err != nil {
return err
}
+ defer func() {
+ if !revert {
+ return
+ }
+ os.Remove(poolMntPoint)
+ }()
}
err := s.StoragePoolCheck()
@@ -104,6 +105,11 @@ func (s *storageDir) StoragePoolCreate() error {
return err
}
+ _, err = s.StoragePoolMount()
+ if err != nil {
+ return err
+ }
+
revert = false
logger.Infof("Created DIR storage pool \"%s\".", s.pool.Name)
@@ -118,6 +124,11 @@ func (s *storageDir) StoragePoolDelete() error {
return fmt.Errorf("no \"source\" property found for the storage pool")
}
+ _, err := s.StoragePoolUmount()
+ if err != nil {
+ return err
+ }
+
if shared.PathExists(source) {
err := os.RemoveAll(source)
if err != nil {
@@ -143,10 +154,105 @@ func (s *storageDir) StoragePoolDelete() error {
}
func (s *storageDir) StoragePoolMount() (bool, error) {
+ source := s.pool.Config["source"]
+ if source == "" {
+ return false, fmt.Errorf("no \"source\" property found for the storage pool")
+ }
+ cleanSource := filepath.Clean(source)
+ poolMntPoint := getStoragePoolMountPoint(s.pool.Name)
+ if cleanSource == poolMntPoint {
+ return true, nil
+ }
+
+ logger.Debugf("Mounting DIR storage pool \"%s\".", s.pool.Name)
+
+ poolMountLockID := getPoolMountLockID(s.pool.Name)
+ lxdStorageMapLock.Lock()
+ if waitChannel, ok := lxdStorageOngoingOperationMap[poolMountLockID]; ok {
+ lxdStorageMapLock.Unlock()
+ if _, ok := <-waitChannel; ok {
+ logger.Warnf("Received value over semaphore. This should not have happened.")
+ }
+ // Give the benefit of the doubt and assume that the other
+ // thread actually succeeded in mounting the storage pool.
+ return false, nil
+ }
+
+ lxdStorageOngoingOperationMap[poolMountLockID] = make(chan bool)
+ lxdStorageMapLock.Unlock()
+
+ removeLockFromMap := func() {
+ lxdStorageMapLock.Lock()
+ if waitChannel, ok := lxdStorageOngoingOperationMap[poolMountLockID]; ok {
+ close(waitChannel)
+ delete(lxdStorageOngoingOperationMap, poolMountLockID)
+ }
+ lxdStorageMapLock.Unlock()
+ }
+ defer removeLockFromMap()
+
+ mountSource := cleanSource
+ mountFlags := syscall.MS_BIND
+
+ err := syscall.Mount(mountSource, poolMntPoint, "", uintptr(mountFlags), "")
+ if err != nil {
+ logger.Errorf(`Failed to mount DIR storage pool "%s" onto `+
+ `"%s": %s`, mountSource, poolMntPoint, err)
+ return false, err
+ }
+
+ logger.Debugf("Mounted DIR storage pool \"%s\".", s.pool.Name)
+
return true, nil
}
func (s *storageDir) StoragePoolUmount() (bool, error) {
+ source := s.pool.Config["source"]
+ if source == "" {
+ return false, fmt.Errorf("no \"source\" property found for the storage pool")
+ }
+ cleanSource := filepath.Clean(source)
+ poolMntPoint := getStoragePoolMountPoint(s.pool.Name)
+ if cleanSource == poolMntPoint {
+ return true, nil
+ }
+
+ logger.Debugf("Unmounting DIR storage pool \"%s\".", s.pool.Name)
+
+ poolUmountLockID := getPoolUmountLockID(s.pool.Name)
+ lxdStorageMapLock.Lock()
+ if waitChannel, ok := lxdStorageOngoingOperationMap[poolUmountLockID]; ok {
+ lxdStorageMapLock.Unlock()
+ if _, ok := <-waitChannel; ok {
+ logger.Warnf("Received value over semaphore. This should not have happened.")
+ }
+ // Give the benefit of the doubt and assume that the other
+ // thread actually succeeded in unmounting the storage pool.
+ return false, nil
+ }
+
+ lxdStorageOngoingOperationMap[poolUmountLockID] = make(chan bool)
+ lxdStorageMapLock.Unlock()
+
+ removeLockFromMap := func() {
+ lxdStorageMapLock.Lock()
+ if waitChannel, ok := lxdStorageOngoingOperationMap[poolUmountLockID]; ok {
+ close(waitChannel)
+ delete(lxdStorageOngoingOperationMap, poolUmountLockID)
+ }
+ lxdStorageMapLock.Unlock()
+ }
+
+ defer removeLockFromMap()
+
+ if shared.IsMountPoint(poolMntPoint) {
+ err := syscall.Unmount(poolMntPoint, 0)
+ if err != nil {
+ return false, err
+ }
+ }
+
+ logger.Debugf("Unmounted DIR pool \"%s\".", s.pool.Name)
return true, nil
}
From 36731caa66c5f9b10a6caa07cb479040d75e5004 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Thu, 31 Aug 2017 21:02:45 +0200
Subject: [PATCH 2/2] patches: make dir pool use bind-mount
Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
lxd/patches.go | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 66 insertions(+)
diff --git a/lxd/patches.go b/lxd/patches.go
index 29aa3df47..94540d73d 100644
--- a/lxd/patches.go
+++ b/lxd/patches.go
@@ -48,6 +48,7 @@ var patches = []patch{
{name: "storage_zfs_noauto", run: patchStorageZFSnoauto},
{name: "storage_zfs_volume_size", run: patchStorageZFSVolumeSize},
{name: "network_dnsmasq_hosts", run: patchNetworkDnsmasqHosts},
+ {name: "storage_api_dir_bind_mount", run: patchStorageApiDirBindMount},
}
type patch struct {
@@ -2618,3 +2619,68 @@ func patchNetworkDnsmasqHosts(name string, d *Daemon) error {
return nil
}
+
+func patchStorageApiDirBindMount(name string, d *Daemon) error {
+ pools, err := db.StoragePools(d.db)
+ if err != nil && err == db.NoSuchObjectError {
+ // No pool was configured in the previous update. So we're on a
+ // pristine LXD instance.
+ return nil
+ } else if err != nil {
+ // Database is screwed.
+ logger.Errorf("Failed to query database: %s", err)
+ return err
+ }
+
+ for _, poolName := range pools {
+ _, pool, err := db.StoragePoolGet(d.db, poolName)
+ if err != nil {
+ logger.Errorf("Failed to query database: %s", err)
+ return err
+ }
+
+ // We only care about dir
+ if pool.Driver != "dir" {
+ continue
+ }
+
+ source := pool.Config["source"]
+ if source == "" {
+ msg := fmt.Sprintf(`No "source" property for storage `+
+ `pool "%s" found`, poolName)
+ logger.Errorf(msg)
+ return fmt.Errorf(msg)
+ }
+ cleanSource := filepath.Clean(source)
+ poolMntPoint := getStoragePoolMountPoint(poolName)
+
+ if cleanSource == poolName {
+ continue
+ }
+
+ if shared.PathExists(poolMntPoint) {
+ err := os.Remove(poolMntPoint)
+ if err != nil {
+ return err
+ }
+ }
+
+ err = os.MkdirAll(poolMntPoint, 0711)
+ if err != nil {
+ return err
+ }
+
+ mountSource := cleanSource
+ mountFlags := syscall.MS_BIND
+
+ err = syscall.Mount(mountSource, poolMntPoint, "", uintptr(mountFlags), "")
+ if err != nil {
+ logger.Errorf(`Failed to mount DIR storage pool "%s" onto `+
+ `"%s": %s`, mountSource, poolMntPoint, err)
+ return err
+ }
+
+ }
+
+ return nil
+}
More information about the lxc-devel
mailing list