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
