The following pull request was submitted through Github.
It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/3748

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) ===
Signed-off-by: Christian Brauner <[email protected]>
From 889adbb2af36dc51c6296a4ee5df66127af39606 Mon Sep 17 00:00:00 2001
From: Christian Brauner <[email protected]>
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 <[email protected]>
---
 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 <[email protected]>
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 <[email protected]>
---
 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
+}
_______________________________________________
lxc-devel mailing list
[email protected]
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to