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

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) ===
See #5717 
From 8455cc8273c0a62c3d381ae7c7c0ce1f72f40521 Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.h...@canonical.com>
Date: Thu, 2 May 2019 15:04:28 +0200
Subject: [PATCH 1/4] lxd: Move storage cgo to storage package

Signed-off-by: Thomas Hipp <thomas.h...@canonical.com>
---
 lxd/{ => storage}/storage_cgo.go | 16 +++++++++-------
 lxd/storage_btrfs.go             |  3 ++-
 lxd/storage_lvm.go               |  7 ++++---
 3 files changed, 15 insertions(+), 11 deletions(-)
 rename lxd/{ => storage}/storage_cgo.go (93%)

diff --git a/lxd/storage_cgo.go b/lxd/storage/storage_cgo.go
similarity index 93%
rename from lxd/storage_cgo.go
rename to lxd/storage/storage_cgo.go
index 7edba24f92..437e67ef1b 100644
--- a/lxd/storage_cgo.go
+++ b/lxd/storage/storage_cgo.go
@@ -1,7 +1,7 @@
 // +build linux
 // +build cgo
 
-package main
+package storage
 
 /*
 #define _GNU_SOURCE
@@ -19,8 +19,8 @@ package main
 #include <sys/stat.h>
 #include <sys/types.h>
 
-#include "include/macro.h"
-#include "include/memory_utils.h"
+#include "../include/macro.h"
+#include "../include/memory_utils.h"
 
 #define LXD_MAXPATH 4096
 #define LXD_NUMSTRLEN64 21
@@ -256,10 +256,10 @@ import (
 // close.
 const LoFlagsAutoclear int = C.LO_FLAGS_AUTOCLEAR
 
-// prepareLoopDev() detects and sets up a loop device for source. It returns an
+// PrepareLoopDev detects and sets up a loop device for source. It returns an
 // open file descriptor to the free loop device and the path of the free loop
 // device. It's the callers responsibility to close the open file descriptor.
-func prepareLoopDev(source string, flags int) (*os.File, error) {
+func PrepareLoopDev(source string, flags int) (*os.File, error) {
        cLoopDev := C.malloc(C.size_t(C.LO_NAME_SIZE))
        if cLoopDev == nil {
                return nil, fmt.Errorf("Failed to allocate memory in C")
@@ -285,7 +285,8 @@ func prepareLoopDev(source string, flags int) (*os.File, 
error) {
        return os.NewFile(uintptr(loopFd), C.GoString((*C.char)(cLoopDev))), nil
 }
 
-func setAutoclearOnLoopDev(loopFd int) error {
+// SetAutoclearOnLoopDev enables autodestruction of the provided loopback 
device.
+func SetAutoclearOnLoopDev(loopFd int) error {
        ret, err := C.set_autoclear_loop_device(C.int(loopFd))
        if ret < 0 {
                if err != nil {
@@ -297,7 +298,8 @@ func setAutoclearOnLoopDev(loopFd int) error {
        return nil
 }
 
-func unsetAutoclearOnLoopDev(loopFd int) error {
+// UnsetAutoclearOnLoopDev disables autodestruction of the provided loopback 
device.
+func UnsetAutoclearOnLoopDev(loopFd int) error {
        ret, err := C.unset_autoclear_loop_device(C.int(loopFd))
        if ret < 0 {
                if err != nil {
diff --git a/lxd/storage_btrfs.go b/lxd/storage_btrfs.go
index 043b2f7aad..66d541a9ab 100644
--- a/lxd/storage_btrfs.go
+++ b/lxd/storage_btrfs.go
@@ -19,6 +19,7 @@ import (
        "github.com/lxc/lxd/lxd/migration"
        "github.com/lxc/lxd/lxd/project"
        "github.com/lxc/lxd/lxd/state"
+       driver "github.com/lxc/lxd/lxd/storage"
        "github.com/lxc/lxd/lxd/util"
        "github.com/lxc/lxd/shared"
        "github.com/lxc/lxd/shared/api"
@@ -422,7 +423,7 @@ func (s *storageBtrfs) StoragePoolMount() (bool, error) {
                        // Since we mount the loop device LO_FLAGS_AUTOCLEAR is
                        // fine since the loop device will be kept around for as
                        // long as the mount exists.
-                       loopF, loopErr := prepareLoopDev(source, 
LoFlagsAutoclear)
+                       loopF, loopErr := driver.PrepareLoopDev(source, 
driver.LoFlagsAutoclear)
                        if loopErr != nil {
                                return false, loopErr
                        }
diff --git a/lxd/storage_lvm.go b/lxd/storage_lvm.go
index d805035435..97ece383c6 100644
--- a/lxd/storage_lvm.go
+++ b/lxd/storage_lvm.go
@@ -15,6 +15,7 @@ import (
 
        "github.com/lxc/lxd/lxd/migration"
        "github.com/lxc/lxd/lxd/project"
+       driver "github.com/lxc/lxd/lxd/storage"
        "github.com/lxc/lxd/shared"
        "github.com/lxc/lxd/shared/api"
        "github.com/lxc/lxd/shared/ioprogress"
@@ -387,7 +388,7 @@ func (s *storageLvm) StoragePoolDelete() error {
        if s.loopInfo != nil {
                // Set LO_FLAGS_AUTOCLEAR before we remove the loop file
                // otherwise we will get EBADF.
-               err = setAutoclearOnLoopDev(int(s.loopInfo.Fd()))
+               err = driver.SetAutoclearOnLoopDev(int(s.loopInfo.Fd()))
                if err != nil {
                        logger.Warnf("Failed to set LO_FLAGS_AUTOCLEAR on loop 
device: %s, manual cleanup needed", err)
                }
@@ -459,12 +460,12 @@ func (s *storageLvm) StoragePoolMount() (bool, error) {
 
        if filepath.IsAbs(source) && !shared.IsBlockdevPath(source) {
                // Try to prepare new loop device.
-               loopF, loopErr := prepareLoopDev(source, 0)
+               loopF, loopErr := driver.PrepareLoopDev(source, 0)
                if loopErr != nil {
                        return false, loopErr
                }
                // Make sure that LO_FLAGS_AUTOCLEAR is unset.
-               loopErr = unsetAutoclearOnLoopDev(int(loopF.Fd()))
+               loopErr = driver.UnsetAutoclearOnLoopDev(int(loopF.Fd()))
                if loopErr != nil {
                        return false, loopErr
                }

From 3faeabb253bcbf28b08198c7a9e4508414ea69b8 Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.h...@canonical.com>
Date: Tue, 13 Aug 2019 15:04:10 +0200
Subject: [PATCH 2/4] lxd: Move ContainerPath() to storage package

Signed-off-by: Thomas Hipp <thomas.h...@canonical.com>
---
 lxd/api_internal.go    | 10 +++++-----
 lxd/container.go       |  8 --------
 lxd/container_lxc.go   |  3 ++-
 lxd/container_test.go  |  4 ++--
 lxd/storage/storage.go | 12 ++++++++++++
 lxd/storage_dir.go     |  3 ++-
 lxd/storage_zfs.go     |  3 ++-
 7 files changed, 25 insertions(+), 18 deletions(-)
 create mode 100644 lxd/storage/storage.go

diff --git a/lxd/api_internal.go b/lxd/api_internal.go
index fee4d9ebfa..babac2c8d6 100644
--- a/lxd/api_internal.go
+++ b/lxd/api_internal.go
@@ -9,6 +9,7 @@ import (
        "os"
        "path/filepath"
        "runtime"
+       runtimeDebug "runtime/debug"
        "strconv"
        "strings"
 
@@ -21,13 +22,12 @@ import (
        "github.com/lxc/lxd/lxd/db/node"
        "github.com/lxc/lxd/lxd/db/query"
        "github.com/lxc/lxd/lxd/project"
+       driver "github.com/lxc/lxd/lxd/storage"
        "github.com/lxc/lxd/shared"
        "github.com/lxc/lxd/shared/api"
+       log "github.com/lxc/lxd/shared/log15"
        "github.com/lxc/lxd/shared/logger"
        "github.com/lxc/lxd/shared/osarch"
-
-       log "github.com/lxc/lxd/shared/log15"
-       runtimeDebug "runtime/debug"
 )
 
 var apiInternal = []APIEndpoint{
@@ -680,7 +680,7 @@ func internalImport(d *Daemon, r *http.Request) Response {
                                onDiskPoolName = poolName
                        }
                        snapName := fmt.Sprintf("%s/%s", req.Name, od)
-                       snapPath := containerPath(snapName, true)
+                       snapPath := driver.ContainerPath(snapName, true)
                        err = lvmContainerDeleteInternal(projectName, poolName, 
req.Name,
                                true, onDiskPoolName, snapPath)
                case "ceph":
@@ -1022,7 +1022,7 @@ func internalImport(d *Daemon, r *http.Request) Response {
                return SmartError(err)
        }
 
-       containerPath := containerPath(project.Prefix(projectName, req.Name), 
false)
+       containerPath := driver.ContainerPath(project.Prefix(projectName, 
req.Name), false)
        isPrivileged := false
        if backup.Container.Config["security.privileged"] == "" {
                isPrivileged = true
diff --git a/lxd/container.go b/lxd/container.go
index 5b795f3d55..f01f2bc58d 100644
--- a/lxd/container.go
+++ b/lxd/container.go
@@ -75,14 +75,6 @@ func containerGetParentAndSnapshotName(name string) (string, 
string, bool) {
        return fields[0], fields[1], true
 }
 
-func containerPath(name string, isSnapshot bool) string {
-       if isSnapshot {
-               return shared.VarPath("snapshots", name)
-       }
-
-       return shared.VarPath("containers", name)
-}
-
 func containerValidName(name string) error {
        if strings.Contains(name, shared.SnapshotDelimiter) {
                return fmt.Errorf(
diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index 6a97f78242..95400bdb39 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -35,6 +35,7 @@ import (
        "github.com/lxc/lxd/lxd/maas"
        "github.com/lxc/lxd/lxd/project"
        "github.com/lxc/lxd/lxd/state"
+       driver "github.com/lxc/lxd/lxd/storage"
        "github.com/lxc/lxd/lxd/template"
        "github.com/lxc/lxd/lxd/util"
        "github.com/lxc/lxd/shared"
@@ -7858,7 +7859,7 @@ func (c *containerLXC) State() string {
 // Various container paths
 func (c *containerLXC) Path() string {
        name := project.Prefix(c.Project(), c.Name())
-       return containerPath(name, c.IsSnapshot())
+       return driver.ContainerPath(name, c.IsSnapshot())
 }
 
 func (c *containerLXC) DevicesPath() string {
diff --git a/lxd/container_test.go b/lxd/container_test.go
index 4bbebde328..6b0d946f1c 100644
--- a/lxd/container_test.go
+++ b/lxd/container_test.go
@@ -163,7 +163,7 @@ func (suite *containerTestSuite) 
TestContainer_Path_Regular() {
 
        suite.Req.False(c.IsSnapshot(), "Shouldn't be a snapshot.")
        suite.Req.Equal(shared.VarPath("containers", "testFoo"), c.Path())
-       suite.Req.Equal(shared.VarPath("containers", "testFoo2"), 
containerPath("testFoo2", false))
+       suite.Req.Equal(shared.VarPath("containers", "testFoo2"), 
driver.ContainerPath("testFoo2", false))
 }
 
 func (suite *containerTestSuite) TestContainer_Path_Snapshot() {
@@ -184,7 +184,7 @@ func (suite *containerTestSuite) 
TestContainer_Path_Snapshot() {
                c.Path())
        suite.Req.Equal(
                shared.VarPath("snapshots", "test", "snap1"),
-               containerPath("test/snap1", true))
+               driver.ContainerPath("test/snap1", true))
 }
 
 func (suite *containerTestSuite) TestContainer_LogPath() {
diff --git a/lxd/storage/storage.go b/lxd/storage/storage.go
new file mode 100644
index 0000000000..7d378ef50c
--- /dev/null
+++ b/lxd/storage/storage.go
@@ -0,0 +1,12 @@
+package storage
+
+import "github.com/lxc/lxd/shared"
+
+// ContainerPath returns the directory of a container or snapshot.
+func ContainerPath(name string, isSnapshot bool) string {
+       if isSnapshot {
+               return shared.VarPath("snapshots", name)
+       }
+
+       return shared.VarPath("containers", name)
+}
diff --git a/lxd/storage_dir.go b/lxd/storage_dir.go
index 967a4656f1..46482a01aa 100644
--- a/lxd/storage_dir.go
+++ b/lxd/storage_dir.go
@@ -14,6 +14,7 @@ import (
 
        "github.com/lxc/lxd/lxd/migration"
        "github.com/lxc/lxd/lxd/project"
+       driver "github.com/lxc/lxd/lxd/storage"
        "github.com/lxc/lxd/lxd/storage/quota"
        "github.com/lxc/lxd/shared"
        "github.com/lxc/lxd/shared/api"
@@ -1221,7 +1222,7 @@ func (s *storageDir) ContainerBackupLoad(info backupInfo, 
data io.ReadSeeker, ta
 
        // Create mountpoints
        containerMntPoint := getContainerMountPoint(info.Project, s.pool.Name, 
info.Name)
-       err = createContainerMountpoint(containerMntPoint, 
containerPath(project.Prefix(info.Project, info.Name), false), info.Privileged)
+       err = createContainerMountpoint(containerMntPoint, 
driver.ContainerPath(project.Prefix(info.Project, info.Name), false), 
info.Privileged)
        if err != nil {
                return errors.Wrap(err, "Create container mount point")
        }
diff --git a/lxd/storage_zfs.go b/lxd/storage_zfs.go
index 5d9500b9b8..d98f530956 100644
--- a/lxd/storage_zfs.go
+++ b/lxd/storage_zfs.go
@@ -16,6 +16,7 @@ import (
 
        "github.com/lxc/lxd/lxd/migration"
        "github.com/lxc/lxd/lxd/project"
+       driver "github.com/lxc/lxd/lxd/storage"
        "github.com/lxc/lxd/lxd/util"
        "github.com/lxc/lxd/shared"
        "github.com/lxc/lxd/shared/api"
@@ -2131,7 +2132,7 @@ func (s *storageZfs) ContainerBackupCreate(backup backup, 
source container) erro
 func (s *storageZfs) doContainerBackupLoadOptimized(info backupInfo, data 
io.ReadSeeker, tarArgs []string) error {
        containerName, _, _ := containerGetParentAndSnapshotName(info.Name)
        containerMntPoint := getContainerMountPoint(info.Project, s.pool.Name, 
containerName)
-       err := createContainerMountpoint(containerMntPoint, 
containerPath(info.Name, false), info.Privileged)
+       err := createContainerMountpoint(containerMntPoint, 
driver.ContainerPath(info.Name, false), info.Privileged)
        if err != nil {
                return err
        }

From b2405f5831ae5694f742d2f3177a6e3c55218355 Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.h...@canonical.com>
Date: Thu, 15 Aug 2019 12:16:59 +0200
Subject: [PATCH 3/4] lxd: Move storage_utils to storage/utils

Signed-off-by: Thomas Hipp <thomas.h...@canonical.com>
---
 lxd/container_test.go           |   4 +-
 lxd/patches.go                  |  18 +-
 lxd/storage/utils.go            | 362 ++++++++++++++++++++++++++++++++
 lxd/storage_btrfs.go            |  36 ++--
 lxd/storage_ceph.go             |  31 +--
 lxd/storage_ceph_utils.go       |  21 +-
 lxd/storage_cephfs.go           |  15 +-
 lxd/storage_dir.go              |   2 +-
 lxd/storage_lvm.go              |  34 +--
 lxd/storage_lvm_utils.go        |   9 +-
 lxd/storage_pools_utils.go      |  13 +-
 lxd/storage_utils.go            | 339 +-----------------------------
 lxd/storage_volumes_snapshot.go |   3 +-
 lxd/storage_zfs.go              |  30 +--
 lxd/storage_zfs_utils.go        |   5 +-
 15 files changed, 480 insertions(+), 442 deletions(-)
 create mode 100644 lxd/storage/utils.go

diff --git a/lxd/container_test.go b/lxd/container_test.go
index 6b0d946f1c..d6698cbd16 100644
--- a/lxd/container_test.go
+++ b/lxd/container_test.go
@@ -4,12 +4,14 @@ import (
        "fmt"
        "testing"
 
+       "github.com/stretchr/testify/suite"
+
        "github.com/lxc/lxd/lxd/db"
        "github.com/lxc/lxd/lxd/device/config"
+       driver "github.com/lxc/lxd/lxd/storage"
        "github.com/lxc/lxd/shared"
        "github.com/lxc/lxd/shared/api"
        "github.com/lxc/lxd/shared/idmap"
-       "github.com/stretchr/testify/suite"
 )
 
 type containerTestSuite struct {
diff --git a/lxd/patches.go b/lxd/patches.go
index f6023eab95..b876b590de 100644
--- a/lxd/patches.go
+++ b/lxd/patches.go
@@ -10,14 +10,16 @@ import (
        "strings"
        "syscall"
 
+       "github.com/pkg/errors"
+       "golang.org/x/sys/unix"
+
        "github.com/lxc/lxd/lxd/cluster"
        "github.com/lxc/lxd/lxd/db"
        "github.com/lxc/lxd/lxd/db/query"
+       driver "github.com/lxc/lxd/lxd/storage"
        "github.com/lxc/lxd/shared"
        log "github.com/lxc/lxd/shared/log15"
        "github.com/lxc/lxd/shared/logger"
-       "github.com/pkg/errors"
-       "golang.org/x/sys/unix"
 )
 
 /* Patches are one-time actions that are sometimes needed to update
@@ -1088,7 +1090,7 @@ func upgradeFromStorageTypeLvm(name string, d *Daemon, 
defaultPoolName string, d
                // Unmount the logical volume.
                oldContainerMntPoint := shared.VarPath("containers", ct)
                if shared.IsMountPoint(oldContainerMntPoint) {
-                       err := tryUnmount(oldContainerMntPoint, unix.MNT_DETACH)
+                       err := driver.TryUnmount(oldContainerMntPoint, 
unix.MNT_DETACH)
                        if err != nil {
                                logger.Errorf("Failed to unmount LVM logical 
volume \"%s\": %s", oldContainerMntPoint, err)
                                return err
@@ -1263,7 +1265,7 @@ func upgradeFromStorageTypeLvm(name string, d *Daemon, 
defaultPoolName string, d
                                if shared.PathExists(oldLvDevPath) {
                                        // Unmount the logical volume.
                                        if 
shared.IsMountPoint(oldSnapshotMntPoint) {
-                                               err := 
tryUnmount(oldSnapshotMntPoint, unix.MNT_DETACH)
+                                               err := 
driver.TryUnmount(oldSnapshotMntPoint, unix.MNT_DETACH)
                                                if err != nil {
                                                        logger.Errorf("Failed 
to unmount LVM logical volume \"%s\": %s", oldSnapshotMntPoint, err)
                                                        return err
@@ -1366,7 +1368,7 @@ func upgradeFromStorageTypeLvm(name string, d *Daemon, 
defaultPoolName string, d
                }
 
                if !shared.IsMountPoint(newContainerMntPoint) {
-                       err := tryMount(containerLvDevPath, 
newContainerMntPoint, lvFsType, 0, mountOptions)
+                       err := driver.TryMount(containerLvDevPath, 
newContainerMntPoint, lvFsType, 0, mountOptions)
                        if err != nil {
                                logger.Errorf("Failed to mount LVM logical 
\"%s\" onto \"%s\" : %s", containerLvDevPath, newContainerMntPoint, err)
                                return err
@@ -1414,7 +1416,7 @@ func upgradeFromStorageTypeLvm(name string, d *Daemon, 
defaultPoolName string, d
                // Unmount the logical volume.
                oldImageMntPoint := shared.VarPath("images", img+".lv")
                if shared.IsMountPoint(oldImageMntPoint) {
-                       err := tryUnmount(oldImageMntPoint, unix.MNT_DETACH)
+                       err := driver.TryUnmount(oldImageMntPoint, 
unix.MNT_DETACH)
                        if err != nil {
                                return err
                        }
@@ -1614,7 +1616,7 @@ func upgradeFromStorageTypeZfs(name string, d *Daemon, 
defaultPoolName string, d
                        _, err := shared.TryRunCommand("zfs", "unmount", "-f", 
ctDataset)
                        if err != nil {
                                logger.Warnf("Failed to unmount ZFS filesystem 
via zfs unmount, trying lazy umount (MNT_DETACH)...")
-                               err := tryUnmount(oldContainerMntPoint, 
unix.MNT_DETACH)
+                               err := driver.TryUnmount(oldContainerMntPoint, 
unix.MNT_DETACH)
                                if err != nil {
                                        failedUpgradeEntities = 
append(failedUpgradeEntities, fmt.Sprintf("containers/%s: Failed to umount zfs 
filesystem.", ct))
                                        continue
@@ -1762,7 +1764,7 @@ func upgradeFromStorageTypeZfs(name string, d *Daemon, 
defaultPoolName string, d
                        _, err := shared.TryRunCommand("zfs", "unmount", "-f", 
imageDataset)
                        if err != nil {
                                logger.Warnf("Failed to unmount ZFS filesystem 
via zfs unmount, trying lazy umount (MNT_DETACH)...")
-                               err := tryUnmount(oldImageMntPoint, 
unix.MNT_DETACH)
+                               err := driver.TryUnmount(oldImageMntPoint, 
unix.MNT_DETACH)
                                if err != nil {
                                        logger.Warnf("Failed to unmount ZFS 
filesystem: %s", err)
                                }
diff --git a/lxd/storage/utils.go b/lxd/storage/utils.go
new file mode 100644
index 0000000000..d23d4f4171
--- /dev/null
+++ b/lxd/storage/utils.go
@@ -0,0 +1,362 @@
+package storage
+
+import (
+       "fmt"
+       "os"
+       "strings"
+       "time"
+
+       "golang.org/x/sys/unix"
+
+       "github.com/lxc/lxd/lxd/db"
+       "github.com/lxc/lxd/shared"
+       "github.com/lxc/lxd/shared/api"
+       "github.com/lxc/lxd/shared/logger"
+)
+
+// MkfsOptions represents options for filesystem creation.
+type MkfsOptions struct {
+       Label string
+}
+
+// Export the mount options map since we might find it useful in other parts of
+// LXD.
+type mountOptions struct {
+       capture bool
+       flag    uintptr
+}
+
+// MountOptions represents a list of possible mount options.
+var MountOptions = map[string]mountOptions{
+       "async":         {false, unix.MS_SYNCHRONOUS},
+       "atime":         {false, unix.MS_NOATIME},
+       "bind":          {true, unix.MS_BIND},
+       "defaults":      {true, 0},
+       "dev":           {false, unix.MS_NODEV},
+       "diratime":      {false, unix.MS_NODIRATIME},
+       "dirsync":       {true, unix.MS_DIRSYNC},
+       "exec":          {false, unix.MS_NOEXEC},
+       "lazytime":      {true, unix.MS_LAZYTIME},
+       "mand":          {true, unix.MS_MANDLOCK},
+       "noatime":       {true, unix.MS_NOATIME},
+       "nodev":         {true, unix.MS_NODEV},
+       "nodiratime":    {true, unix.MS_NODIRATIME},
+       "noexec":        {true, unix.MS_NOEXEC},
+       "nomand":        {false, unix.MS_MANDLOCK},
+       "norelatime":    {false, unix.MS_RELATIME},
+       "nostrictatime": {false, unix.MS_STRICTATIME},
+       "nosuid":        {true, unix.MS_NOSUID},
+       "rbind":         {true, unix.MS_BIND | unix.MS_REC},
+       "relatime":      {true, unix.MS_RELATIME},
+       "remount":       {true, unix.MS_REMOUNT},
+       "ro":            {true, unix.MS_RDONLY},
+       "rw":            {false, unix.MS_RDONLY},
+       "strictatime":   {true, unix.MS_STRICTATIME},
+       "suid":          {false, unix.MS_NOSUID},
+       "sync":          {true, unix.MS_SYNCHRONOUS},
+}
+
+// LXDResolveMountoptions resolves the provided mount options.
+func LXDResolveMountoptions(options string) (uintptr, string) {
+       mountFlags := uintptr(0)
+       tmp := strings.SplitN(options, ",", -1)
+       for i := 0; i < len(tmp); i++ {
+               opt := tmp[i]
+               do, ok := MountOptions[opt]
+               if !ok {
+                       continue
+               }
+
+               if do.capture {
+                       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, ",")
+}
+
+// TryMount tries mounting a filesystem multiple times. This is useful for 
unreliable backends.
+func TryMount(src string, dst string, fs string, flags uintptr, options 
string) error {
+       var err error
+
+       for i := 0; i < 20; i++ {
+               err = unix.Mount(src, dst, fs, flags, options)
+               if err == nil {
+                       break
+               }
+
+               time.Sleep(500 * time.Millisecond)
+       }
+
+       if err != nil {
+               return err
+       }
+
+       return nil
+}
+
+// TryUnmount tries unmounting a filesystem multiple times. This is useful for 
unreliable backends.
+func TryUnmount(path string, flags int) error {
+       var err error
+
+       for i := 0; i < 20; i++ {
+               err = unix.Unmount(path, flags)
+               if err == nil {
+                       break
+               }
+
+               time.Sleep(500 * time.Millisecond)
+       }
+
+       if err != nil {
+               return err
+       }
+
+       return nil
+}
+
+// ValidName validates the provided name, and returns an error if it's not a 
valid storage name.
+func ValidName(value string) error {
+       if strings.Contains(value, "/") {
+               return fmt.Errorf("Invalid storage volume name \"%s\". Storage 
volumes cannot contain \"/\" in their name", value)
+       }
+
+       return nil
+}
+
+// ConfigDiff returns a diff of the provided configs. Additionally, it returns 
whether or not
+// only user properties have been changed.
+func ConfigDiff(oldConfig map[string]string, newConfig map[string]string) 
([]string, bool) {
+       changedConfig := []string{}
+       userOnly := true
+       for key := range oldConfig {
+               if oldConfig[key] != newConfig[key] {
+                       if !strings.HasPrefix(key, "user.") {
+                               userOnly = false
+                       }
+
+                       if !shared.StringInSlice(key, changedConfig) {
+                               changedConfig = append(changedConfig, key)
+                       }
+               }
+       }
+
+       for key := range newConfig {
+               if oldConfig[key] != newConfig[key] {
+                       if !strings.HasPrefix(key, "user.") {
+                               userOnly = false
+                       }
+
+                       if !shared.StringInSlice(key, changedConfig) {
+                               changedConfig = append(changedConfig, key)
+                       }
+               }
+       }
+
+       // Skip on no change
+       if len(changedConfig) == 0 {
+               return nil, false
+       }
+
+       return changedConfig, userOnly
+}
+
+// StoragePoolsDirMode represents the default permissions for the storage pool 
directory.
+const StoragePoolsDirMode os.FileMode = 0711
+
+// ContainersDirMode represents the default permissions for the containers 
directory.
+const ContainersDirMode os.FileMode = 0711
+
+// CustomDirMode represents the default permissions for the custom directory.
+const CustomDirMode os.FileMode = 0711
+
+// ImagesDirMode represents the default permissions for the images directory.
+const ImagesDirMode os.FileMode = 0700
+
+// SnapshotsDirMode represents the default permissions for the snapshots 
directory.
+const SnapshotsDirMode os.FileMode = 0700
+
+// LXDUsesPool detect whether LXD already uses the given storage pool.
+func LXDUsesPool(dbObj *db.Cluster, onDiskPoolName string, driver string, 
onDiskProperty string) (bool, string, error) {
+       pools, err := dbObj.StoragePools()
+       if err != nil && err != db.ErrNoSuchObject {
+               return false, "", err
+       }
+
+       for _, pool := range pools {
+               _, pl, err := dbObj.StoragePoolGet(pool)
+               if err != nil {
+                       continue
+               }
+
+               if pl.Driver != driver {
+                       continue
+               }
+
+               if pl.Config[onDiskProperty] == onDiskPoolName {
+                       return true, pl.Name, nil
+               }
+       }
+
+       return false, "", nil
+}
+
+// MakeFSType creates the provided filesystem.
+func MakeFSType(path string, fsType string, options *MkfsOptions) (string, 
error) {
+       var err error
+       var msg string
+
+       fsOptions := options
+       if fsOptions == nil {
+               fsOptions = &MkfsOptions{}
+       }
+
+       cmd := []string{fmt.Sprintf("mkfs.%s", fsType), path}
+       if fsOptions.Label != "" {
+               cmd = append(cmd, "-L", fsOptions.Label)
+       }
+
+       if fsType == "ext4" {
+               cmd = append(cmd, "-E", 
"nodiscard,lazy_itable_init=0,lazy_journal_init=0")
+       }
+
+       msg, err = shared.TryRunCommand(cmd[0], cmd[1:]...)
+       if err != nil {
+               return msg, err
+       }
+
+       return "", nil
+}
+
+// FSGenerateNewUUID generates a UUID for the given path for btrfs and xfs 
filesystems.
+func FSGenerateNewUUID(fstype string, lvpath string) (string, error) {
+       switch fstype {
+       case "btrfs":
+               return btrfsGenerateNewUUID(lvpath)
+       case "xfs":
+               return xfsGenerateNewUUID(lvpath)
+       }
+
+       return "", nil
+}
+
+func xfsGenerateNewUUID(devPath string) (string, error) {
+       // Attempt to generate a new UUID
+       msg, err := shared.RunCommand("xfs_admin", "-U", "generate", devPath)
+       if err != nil {
+               return msg, err
+       }
+
+       if msg != "" {
+               // Exit 0 with a msg usually means some log entry getting in 
the way
+               msg, err = shared.RunCommand("xfs_repair", "-o", 
"force_geometry", "-L", devPath)
+               if err != nil {
+                       return msg, err
+               }
+
+               // Attempt to generate a new UUID again
+               msg, err = shared.RunCommand("xfs_admin", "-U", "generate", 
devPath)
+               if err != nil {
+                       return msg, err
+               }
+       }
+
+       return msg, nil
+}
+
+func btrfsGenerateNewUUID(lvpath string) (string, error) {
+       msg, err := shared.RunCommand(
+               "btrfstune",
+               "-f",
+               "-u",
+               lvpath)
+       if err != nil {
+               return msg, err
+       }
+
+       return msg, nil
+}
+
+// GrowFileSystem grows a filesystem if it is supported.
+func GrowFileSystem(fsType string, devPath string, mntpoint string) error {
+       var msg string
+       var err error
+       switch fsType {
+       case "": // if not specified, default to ext4
+               fallthrough
+       case "ext4":
+               msg, err = shared.TryRunCommand("resize2fs", devPath)
+       case "xfs":
+               msg, err = shared.TryRunCommand("xfs_growfs", devPath)
+       case "btrfs":
+               msg, err = shared.TryRunCommand("btrfs", "filesystem", 
"resize", "max", mntpoint)
+       default:
+               return fmt.Errorf(`Growing not supported for filesystem type 
"%s"`, fsType)
+       }
+
+       if err != nil {
+               errorMsg := fmt.Sprintf(`Could not extend underlying %s 
filesystem for "%s": %s`, fsType, devPath, msg)
+               logger.Errorf(errorMsg)
+               return fmt.Errorf(errorMsg)
+       }
+
+       logger.Debugf(`extended underlying %s filesystem for "%s"`, fsType, 
devPath)
+       return nil
+}
+
+// ShrinkFileSystem shrinks a filesystem if it is supported.
+func ShrinkFileSystem(fsType string, devPath string, mntpoint string, byteSize 
int64) error {
+       strSize := fmt.Sprintf("%dK", byteSize/1024)
+
+       switch fsType {
+       case "": // if not specified, default to ext4
+               fallthrough
+       case "ext4":
+               _, err := shared.TryRunCommand("e2fsck", "-f", "-y", devPath)
+               if err != nil {
+                       return err
+               }
+
+               _, err = shared.TryRunCommand("resize2fs", devPath, strSize)
+               if err != nil {
+                       return err
+               }
+       case "btrfs":
+               _, err := shared.TryRunCommand("btrfs", "filesystem", "resize", 
strSize, mntpoint)
+               if err != nil {
+                       return err
+               }
+       default:
+               return fmt.Errorf(`Shrinking not supported for filesystem type 
"%s"`, fsType)
+       }
+
+       return nil
+}
+
+// GetStorageResource returns the available resources of a given path.
+func GetStorageResource(path string) (*api.ResourcesStoragePool, error) {
+       st, err := shared.Statvfs(path)
+       if err != nil {
+               return nil, err
+       }
+
+       res := api.ResourcesStoragePool{}
+       res.Space.Total = st.Blocks * uint64(st.Bsize)
+       res.Space.Used = (st.Blocks - st.Bfree) * uint64(st.Bsize)
+
+       // Some filesystems don't report inodes since they allocate them
+       // dynamically e.g. btrfs.
+       if st.Files > 0 {
+               res.Inodes.Total = st.Files
+               res.Inodes.Used = st.Files - st.Ffree
+       }
+
+       return &res, nil
+}
diff --git a/lxd/storage_btrfs.go b/lxd/storage_btrfs.go
index 66d541a9ab..5be6c321a4 100644
--- a/lxd/storage_btrfs.go
+++ b/lxd/storage_btrfs.go
@@ -157,7 +157,7 @@ func (s *storageBtrfs) StoragePoolCreate() error {
                        return fmt.Errorf("Failed to create sparse file %s: 
%s", source, err)
                }
 
-               output, err := makeFSType(source, "btrfs", &mkfsOptions{label: 
s.pool.Name})
+               output, err := driver.MakeFSType(source, "btrfs", 
&driver.MkfsOptions{Label: s.pool.Name})
                if err != nil {
                        return fmt.Errorf("Failed to create the BTRFS pool: 
%s", output)
                }
@@ -168,7 +168,7 @@ func (s *storageBtrfs) StoragePoolCreate() error {
                if filepath.IsAbs(source) {
                        isBlockDev = shared.IsBlockdevPath(source)
                        if isBlockDev {
-                               output, err := makeFSType(source, "btrfs", 
&mkfsOptions{label: s.pool.Name})
+                               output, err := driver.MakeFSType(source, 
"btrfs", &driver.MkfsOptions{Label: s.pool.Name})
                                if err != nil {
                                        return fmt.Errorf("Failed to create the 
BTRFS pool: %s", output)
                                }
@@ -208,7 +208,7 @@ func (s *storageBtrfs) StoragePoolCreate() error {
 
        poolMntPoint := getStoragePoolMountPoint(s.pool.Name)
        if !shared.PathExists(poolMntPoint) {
-               err := os.MkdirAll(poolMntPoint, storagePoolsDirMode)
+               err := os.MkdirAll(poolMntPoint, driver.StoragePoolsDirMode)
                if err != nil {
                        return err
                }
@@ -216,7 +216,7 @@ func (s *storageBtrfs) StoragePoolCreate() error {
 
        var err1 error
        var devUUID string
-       mountFlags, mountOptions := 
lxdResolveMountoptions(s.getBtrfsMountOptions())
+       mountFlags, mountOptions := 
driver.LXDResolveMountoptions(s.getBtrfsMountOptions())
        mountFlags |= s.remount
        if isBlockDev && filepath.IsAbs(source) {
                devUUID, _ = shared.LookupUUIDByBlockDevPath(source)
@@ -399,7 +399,7 @@ func (s *storageBtrfs) StoragePoolMount() (bool, error) {
 
        // Check whether the mount poolMntPoint exits.
        if !shared.PathExists(poolMntPoint) {
-               err := os.MkdirAll(poolMntPoint, storagePoolsDirMode)
+               err := os.MkdirAll(poolMntPoint, driver.StoragePoolsDirMode)
                if err != nil {
                        return false, err
                }
@@ -409,7 +409,7 @@ func (s *storageBtrfs) StoragePoolMount() (bool, error) {
                return false, nil
        }
 
-       mountFlags, mountOptions := 
lxdResolveMountoptions(s.getBtrfsMountOptions())
+       mountFlags, mountOptions := 
driver.LXDResolveMountoptions(s.getBtrfsMountOptions())
        mountSource := source
        isBlockDev := shared.IsBlockdevPath(source)
        if filepath.IsAbs(source) {
@@ -821,7 +821,7 @@ func (s *storageBtrfs) doContainerCreate(projectName, name 
string, privileged bo
        // doesn't already.
        containerSubvolumePath := s.getContainerSubvolumePath(s.pool.Name)
        if !shared.PathExists(containerSubvolumePath) {
-               err := os.MkdirAll(containerSubvolumePath, containersDirMode)
+               err := os.MkdirAll(containerSubvolumePath, 
driver.ContainersDirMode)
                if err != nil {
                        return err
                }
@@ -876,7 +876,7 @@ func (s *storageBtrfs) ContainerCreateFromImage(container 
container, fingerprint
        // doesn't already.
        containerSubvolumePath := s.getContainerSubvolumePath(s.pool.Name)
        if !shared.PathExists(containerSubvolumePath) {
-               err := os.MkdirAll(containerSubvolumePath, containersDirMode)
+               err := os.MkdirAll(containerSubvolumePath, 
driver.ContainersDirMode)
                if err != nil {
                        return errors.Wrap(err, "Failed to create volume 
directory")
                }
@@ -995,7 +995,7 @@ func (s *storageBtrfs) copyContainer(target container, 
source container) error {
        containersPath := getContainerMountPoint("default", s.pool.Name, "")
        // Ensure that the directories immediately preceding the subvolume 
directory exist.
        if !shared.PathExists(containersPath) {
-               err := os.MkdirAll(containersPath, containersDirMode)
+               err := os.MkdirAll(containersPath, driver.ContainersDirMode)
                if err != nil {
                        return err
                }
@@ -1036,7 +1036,7 @@ func (s *storageBtrfs) copySnapshot(target container, 
source container) error {
 
        // Ensure that the directories immediately preceding the subvolume 
directory exist.
        if !shared.PathExists(containersPath) {
-               err := os.MkdirAll(containersPath, containersDirMode)
+               err := os.MkdirAll(containersPath, driver.ContainersDirMode)
                if err != nil {
                        return err
                }
@@ -1379,7 +1379,7 @@ func (s *storageBtrfs) 
doContainerSnapshotCreate(projectName string, targetName
        // doesn't already.
        snapshotSubvolumePath := getSnapshotSubvolumePath(projectName, 
s.pool.Name, sourceName)
        if !shared.PathExists(snapshotSubvolumePath) {
-               err := os.MkdirAll(snapshotSubvolumePath, containersDirMode)
+               err := os.MkdirAll(snapshotSubvolumePath, 
driver.ContainersDirMode)
                if err != nil {
                        return err
                }
@@ -1389,7 +1389,7 @@ func (s *storageBtrfs) 
doContainerSnapshotCreate(projectName string, targetName
        snapshotMntPointSymlink := shared.VarPath("snapshots", 
project.Prefix(projectName, sourceName))
        if !shared.PathExists(snapshotMntPointSymlink) {
                if !shared.PathExists(snapshotMntPointSymlinkTarget) {
-                       err = os.MkdirAll(snapshotMntPointSymlinkTarget, 
snapshotsDirMode)
+                       err = os.MkdirAll(snapshotMntPointSymlinkTarget, 
driver.SnapshotsDirMode)
                        if err != nil {
                                return err
                        }
@@ -1567,7 +1567,7 @@ func (s *storageBtrfs) 
ContainerSnapshotCreateEmpty(snapshotContainer container)
        snapshotSubvolumePath := 
getSnapshotSubvolumePath(snapshotContainer.Project(), s.pool.Name, sourceName)
        snapshotSubvolumeName := 
getSnapshotMountPoint(snapshotContainer.Project(), s.pool.Name, 
snapshotContainer.Name())
        if !shared.PathExists(snapshotSubvolumePath) {
-               err := os.MkdirAll(snapshotSubvolumePath, containersDirMode)
+               err := os.MkdirAll(snapshotSubvolumePath, 
driver.ContainersDirMode)
                if err != nil {
                        return err
                }
@@ -2000,7 +2000,7 @@ func (s *storageBtrfs) ImageCreate(fingerprint string, 
tracker *ioprogress.Progr
        // doesn't already.
        imageSubvolumePath := s.getImageSubvolumePath(s.pool.Name)
        if !shared.PathExists(imageSubvolumePath) {
-               err := os.MkdirAll(imageSubvolumePath, imagesDirMode)
+               err := os.MkdirAll(imageSubvolumePath, driver.ImagesDirMode)
                if err != nil {
                        return err
                }
@@ -2723,7 +2723,7 @@ func (s *storageBtrfs) MigrationSink(conn 
*websocket.Conn, op *operation, args M
        _, containerPool, _ := args.Container.Storage().GetContainerPoolInfo()
        containersPath := getSnapshotMountPoint(args.Container.Project(), 
containerPool, containerName)
        if !args.ContainerOnly && len(args.Snapshots) > 0 {
-               err := os.MkdirAll(containersPath, containersDirMode)
+               err := os.MkdirAll(containersPath, driver.ContainersDirMode)
                if err != nil {
                        return err
                }
@@ -2961,7 +2961,7 @@ func (s *storageBtrfs) StoragePoolResources() 
(*api.ResourcesStoragePool, error)
 
        // Inode allocation is dynamic so no use in reporting them.
 
-       return storageResource(poolMntPoint)
+       return driver.GetStorageResource(poolMntPoint)
 }
 
 func (s *storageBtrfs) StoragePoolVolumeCopy(source *api.StorageVolumeSource) 
error {
@@ -3037,7 +3037,7 @@ func (s *storageBtrfs) copyVolume(sourcePool string, 
sourceName string, targetNa
        }
 
        if !shared.PathExists(customDir) {
-               err := os.MkdirAll(customDir, customDirMode)
+               err := os.MkdirAll(customDir, driver.CustomDirMode)
                if err != nil {
                        logger.Errorf("Failed to create directory \"%s\" for 
storage volume \"%s\" on storage pool \"%s\": %s", customDir, s.volume.Name, 
s.pool.Name, err)
                        return err
@@ -3163,7 +3163,7 @@ func (s *storageBtrfs) doVolumeSnapshotCreate(sourcePool 
string, sourceName stri
 
        customSnapshotSubvolumeName := 
getStoragePoolVolumeSnapshotMountPoint(s.pool.Name, s.volume.Name)
 
-       err = os.MkdirAll(customSnapshotSubvolumeName, snapshotsDirMode)
+       err = os.MkdirAll(customSnapshotSubvolumeName, driver.SnapshotsDirMode)
        if err != nil && !os.IsNotExist(err) {
                return err
        }
diff --git a/lxd/storage_ceph.go b/lxd/storage_ceph.go
index e603190047..76fff33607 100644
--- a/lxd/storage_ceph.go
+++ b/lxd/storage_ceph.go
@@ -15,6 +15,7 @@ import (
 
        "github.com/lxc/lxd/lxd/db"
        "github.com/lxc/lxd/lxd/project"
+       driver "github.com/lxc/lxd/lxd/storage"
        "github.com/lxc/lxd/shared"
        "github.com/lxc/lxd/shared/api"
        "github.com/lxc/lxd/shared/ioprogress"
@@ -358,7 +359,7 @@ func (s *storageCeph) StoragePoolVolumeCreate() error {
        RBDFilesystem := s.getRBDFilesystem()
        logger.Debugf(`Retrieved filesystem type "%s" of RBD storage volume 
"%s" on storage pool "%s"`, RBDFilesystem, s.volume.Name, s.pool.Name)
 
-       msg, err := makeFSType(RBDDevPath, RBDFilesystem, nil)
+       msg, err := driver.MakeFSType(RBDDevPath, RBDFilesystem, nil)
        if err != nil {
                logger.Errorf(`Failed to create filesystem type "%s" on device 
path "%s" for RBD storage volume "%s" on storage pool "%s": %s`, RBDFilesystem, 
RBDDevPath, s.volume.Name, s.pool.Name, msg)
                return err
@@ -424,7 +425,7 @@ func (s *storageCeph) StoragePoolVolumeDelete() error {
 
        volumeMntPoint := getStoragePoolVolumeMountPoint(s.pool.Name, 
s.volume.Name)
        if shared.IsMountPoint(volumeMntPoint) {
-               err := tryUnmount(volumeMntPoint, unix.MNT_DETACH)
+               err := driver.TryUnmount(volumeMntPoint, unix.MNT_DETACH)
                if err != nil {
                        logger.Errorf(`Failed to unmount RBD storage volume 
"%s" on storage pool "%s": %s`, s.volume.Name, s.pool.Name, err)
                }
@@ -508,8 +509,8 @@ func (s *storageCeph) StoragePoolVolumeMount() (bool, 
error) {
                RBDDevPath, ret = getRBDMappedDevPath(s.ClusterName, 
s.OSDPoolName,
                        storagePoolVolumeTypeNameCustom, s.volume.Name, true,
                        s.UserName)
-               mountFlags, mountOptions := 
lxdResolveMountoptions(s.getRBDMountOptions())
-               customerr = tryMount(
+               mountFlags, mountOptions := 
driver.LXDResolveMountoptions(s.getRBDMountOptions())
+               customerr = driver.TryMount(
                        RBDDevPath,
                        volumeMntPoint,
                        RBDFilesystem,
@@ -560,7 +561,7 @@ func (s *storageCeph) StoragePoolVolumeUmount() (bool, 
error) {
        var customerr error
        ourUmount := false
        if shared.IsMountPoint(volumeMntPoint) {
-               customerr = tryUnmount(volumeMntPoint, unix.MNT_DETACH)
+               customerr = driver.TryUnmount(volumeMntPoint, unix.MNT_DETACH)
                ourUmount = true
        }
 
@@ -1366,7 +1367,7 @@ func (s *storageCeph) ContainerUmount(c container, path 
string) (bool, error) {
        var mounterr error
        ourUmount := false
        if shared.IsMountPoint(containerMntPoint) {
-               mounterr = tryUnmount(containerMntPoint, 0)
+               mounterr = driver.TryUnmount(containerMntPoint, 0)
                ourUmount = true
        }
 
@@ -1804,7 +1805,7 @@ func (s *storageCeph) ContainerSnapshotStart(c container) 
(bool, error) {
 
        containerMntPoint := getSnapshotMountPoint(c.Project(), s.pool.Name, 
containerName)
        RBDFilesystem := s.getRBDFilesystem()
-       mountFlags, mountOptions := 
lxdResolveMountoptions(s.getRBDMountOptions())
+       mountFlags, mountOptions := 
driver.LXDResolveMountoptions(s.getRBDMountOptions())
        if RBDFilesystem == "xfs" {
                idx := strings.Index(mountOptions, "nouuid")
                if idx < 0 {
@@ -1812,7 +1813,7 @@ func (s *storageCeph) ContainerSnapshotStart(c container) 
(bool, error) {
                }
        }
 
-       err = tryMount(
+       err = driver.TryMount(
                RBDDevPath,
                containerMntPoint,
                RBDFilesystem,
@@ -1845,7 +1846,7 @@ func (s *storageCeph) ContainerSnapshotStop(c container) 
(bool, error) {
        }
 
        // Unmount
-       err := tryUnmount(containerMntPoint, unix.MNT_DETACH)
+       err := driver.TryUnmount(containerMntPoint, unix.MNT_DETACH)
        if err != nil {
                logger.Errorf("Failed to unmount %s: %s", containerMntPoint, 
err)
                return false, err
@@ -2103,7 +2104,7 @@ func (s *storageCeph) ImageCreate(fingerprint string, 
tracker *ioprogress.Progre
 
                // get filesystem
                RBDFilesystem := s.getRBDFilesystem()
-               msg, err := makeFSType(RBDDevPath, RBDFilesystem, nil)
+               msg, err := driver.MakeFSType(RBDDevPath, RBDFilesystem, nil)
                if err != nil {
                        logger.Errorf(`Failed to create filesystem "%s" for RBD 
storage volume for image "%s" on storage pool "%s": %s`, RBDFilesystem, 
fingerprint,
                                s.pool.Name, msg)
@@ -2339,7 +2340,7 @@ func (s *storageCeph) ImageMount(fingerprint string) 
(bool, error) {
 
        RBDFilesystem := s.getRBDFilesystem()
        RBDMountOptions := s.getRBDMountOptions()
-       mountFlags, mountOptions := lxdResolveMountoptions(RBDMountOptions)
+       mountFlags, mountOptions := 
driver.LXDResolveMountoptions(RBDMountOptions)
        RBDDevPath, ret := getRBDMappedDevPath(s.ClusterName, s.OSDPoolName,
                storagePoolVolumeTypeNameImage, fingerprint, true, s.UserName)
        errMsg := fmt.Sprintf("Failed to mount RBD device %s onto %s",
@@ -2349,7 +2350,7 @@ func (s *storageCeph) ImageMount(fingerprint string) 
(bool, error) {
                return false, fmt.Errorf(errMsg)
        }
 
-       err := tryMount(RBDDevPath, imageMntPoint, RBDFilesystem, mountFlags, 
mountOptions)
+       err := driver.TryMount(RBDDevPath, imageMntPoint, RBDFilesystem, 
mountFlags, mountOptions)
        if err != nil || ret < 0 {
                return false, err
        }
@@ -2366,7 +2367,7 @@ func (s *storageCeph) ImageUmount(fingerprint string) 
(bool, error) {
                return false, nil
        }
 
-       err := tryUnmount(imageMntPoint, 0)
+       err := driver.TryUnmount(imageMntPoint, 0)
        if err != nil {
                return false, err
        }
@@ -2633,7 +2634,7 @@ func (s *storageCeph) StoragePoolVolumeCopy(source 
*api.StorageVolumeSource) err
                        // create snapshot mountpoint
                        newTargetName := fmt.Sprintf("%s/%s", s.volume.Name, 
snapOnlyName)
                        targetPath := 
getStoragePoolVolumeSnapshotMountPoint(s.pool.Name, newTargetName)
-                       err = os.MkdirAll(targetPath, snapshotsDirMode)
+                       err = os.MkdirAll(targetPath, driver.SnapshotsDirMode)
                        if err != nil {
                                logger.Errorf("Failed to create mountpoint 
\"%s\" for RBD storage volume \"%s\" on storage pool \"%s\": %s", targetPath, 
s.volume.Name, s.pool.Name, err)
                                return err
@@ -2718,7 +2719,7 @@ func (s *storageCeph) 
StoragePoolVolumeSnapshotCreate(target *api.StorageVolumeS
        }
 
        targetPath := getStoragePoolVolumeSnapshotMountPoint(s.pool.Name, 
target.Name)
-       err = os.MkdirAll(targetPath, snapshotsDirMode)
+       err = os.MkdirAll(targetPath, driver.SnapshotsDirMode)
        if err != nil {
                logger.Errorf("Failed to create mountpoint \"%s\" for RBD 
storage volume \"%s\" on storage pool \"%s\": %s", targetPath, s.volume.Name, 
s.pool.Name, err)
                return err
diff --git a/lxd/storage_ceph_utils.go b/lxd/storage_ceph_utils.go
index 9c458ad929..dacfec3b30 100644
--- a/lxd/storage_ceph_utils.go
+++ b/lxd/storage_ceph_utils.go
@@ -16,6 +16,7 @@ import (
 
        "github.com/lxc/lxd/lxd/db"
        "github.com/lxc/lxd/lxd/project"
+       driver "github.com/lxc/lxd/lxd/storage"
        "github.com/lxc/lxd/shared"
        "github.com/lxc/lxd/shared/api"
        "github.com/lxc/lxd/shared/logger"
@@ -705,7 +706,7 @@ func (s *storageCeph) getRBDFilesystem() string {
 // getRBDMountOptions returns the mount options the storage volume is supposed
 // to be mounted with
 // The option string that is returned needs to be passed to the approriate
-// helper (currently named "lxdResolveMountoptions") which will take on the job
+// helper (currently named "LXDResolveMountoptions") which will take on the job
 // of splitting it into appropriate flags and string options.
 func (s *storageCeph) getRBDMountOptions() string {
        if s.volume.Config["block.mount_options"] != "" {
@@ -1556,7 +1557,7 @@ func (s *storageCeph) rbdGrow(path string, size int64, 
fsType string,
        }
 
        // Grow the filesystem
-       return growFileSystem(fsType, path, fsMntPoint)
+       return driver.GrowFileSystem(fsType, path, fsMntPoint)
 }
 
 // copyWithSnapshots creates a non-sparse copy of a container including its
@@ -1647,7 +1648,7 @@ func (s *storageCeph) cephRBDVolumeBackupCreate(tmpPath 
string, backup backup, s
 
        // Generate a new UUID if needed
        RBDFilesystem := s.getRBDFilesystem()
-       msg, err := fsGenerateNewUUID(RBDFilesystem, RBDDevPath)
+       msg, err := driver.FSGenerateNewUUID(RBDFilesystem, RBDDevPath)
        if err != nil {
                logger.Errorf("Failed to create new UUID for filesystem \"%s\": 
%s: %s", RBDFilesystem, msg, err)
                return err
@@ -1666,14 +1667,14 @@ func (s *storageCeph) cephRBDVolumeBackupCreate(tmpPath 
string, backup backup, s
        }
 
        // Mount the volume
-       mountFlags, mountOptions := 
lxdResolveMountoptions(s.getRBDMountOptions())
-       err = tryMount(RBDDevPath, tmpContainerMntPoint, RBDFilesystem, 
mountFlags, mountOptions)
+       mountFlags, mountOptions := 
driver.LXDResolveMountoptions(s.getRBDMountOptions())
+       err = driver.TryMount(RBDDevPath, tmpContainerMntPoint, RBDFilesystem, 
mountFlags, mountOptions)
        if err != nil {
                logger.Errorf("Failed to mount RBD device %s onto %s: %s", 
RBDDevPath, tmpContainerMntPoint, err)
                return err
        }
        logger.Debugf("Mounted RBD device %s onto %s", RBDDevPath, 
tmpContainerMntPoint)
-       defer tryUnmount(tmpContainerMntPoint, unix.MNT_DETACH)
+       defer driver.TryUnmount(tmpContainerMntPoint, unix.MNT_DETACH)
 
        // Figure out the target name
        targetName := sourceContainerName
@@ -1753,7 +1754,7 @@ func (s *storageCeph) doContainerCreate(projectName, name 
string, privileged boo
 
        // get filesystem
        RBDFilesystem := s.getRBDFilesystem()
-       msg, err := makeFSType(RBDDevPath, RBDFilesystem, nil)
+       msg, err := driver.MakeFSType(RBDDevPath, RBDFilesystem, nil)
        if err != nil {
                logger.Errorf(`Failed to create filesystem type "%s" on device 
path "%s" for RBD storage volume for container "%s" on storage pool "%s": %s`, 
RBDFilesystem, RBDDevPath, name, s.pool.Name, msg)
                return err
@@ -1820,8 +1821,8 @@ func (s *storageCeph) doContainerMount(projectName 
string, name string) (bool, e
                        s.OSDPoolName, storagePoolVolumeTypeNameContainer,
                        volumeName, true, s.UserName)
                if ret >= 0 {
-                       mountFlags, mountOptions := 
lxdResolveMountoptions(s.getRBDMountOptions())
-                       mounterr = tryMount(RBDDevPath, containerMntPoint,
+                       mountFlags, mountOptions := 
driver.LXDResolveMountoptions(s.getRBDMountOptions())
+                       mounterr = driver.TryMount(RBDDevPath, 
containerMntPoint,
                                RBDFilesystem, mountFlags, mountOptions)
                        ourMount = true
                }
@@ -2060,7 +2061,7 @@ func (s *storageCeph) cephRBDGenerateUUID(volumeName 
string, volumeType string)
        defer cephRBDVolumeUnmap(s.ClusterName, s.OSDPoolName, volumeName, 
volumeType, s.UserName, true)
 
        // Update the UUID
-       msg, err := fsGenerateNewUUID(s.getRBDFilesystem(), RBDDevPath)
+       msg, err := driver.FSGenerateNewUUID(s.getRBDFilesystem(), RBDDevPath)
        if err != nil {
                return fmt.Errorf("Failed to regenerate UUID for '%v': %v: %v", 
volumeName, err, msg)
        }
diff --git a/lxd/storage_cephfs.go b/lxd/storage_cephfs.go
index 7f4d5f86ec..58651befec 100644
--- a/lxd/storage_cephfs.go
+++ b/lxd/storage_cephfs.go
@@ -15,6 +15,7 @@ import (
 
        "github.com/lxc/lxd/lxd/migration"
        "github.com/lxc/lxd/lxd/state"
+       driver "github.com/lxc/lxd/lxd/storage"
        "github.com/lxc/lxd/shared"
        "github.com/lxc/lxd/shared/api"
        "github.com/lxc/lxd/shared/ioprogress"
@@ -151,13 +152,13 @@ func (s *storageCephFs) StoragePoolCreate() error {
        connected := false
        for _, monAddress := range monAddresses {
                uri := fmt.Sprintf("%s:6789:/", monAddress)
-               err = tryMount(uri, mountPoint, "ceph", 0, 
fmt.Sprintf("name=%v,secret=%v,mds_namespace=%v", s.UserName, userSecret, 
fsName))
+               err = driver.TryMount(uri, mountPoint, "ceph", 0, 
fmt.Sprintf("name=%v,secret=%v,mds_namespace=%v", s.UserName, userSecret, 
fsName))
                if err != nil {
                        continue
                }
 
                connected = true
-               defer tryUnmount(mountPoint, syscall.MNT_DETACH)
+               defer driver.TryUnmount(mountPoint, syscall.MNT_DETACH)
                break
        }
 
@@ -227,13 +228,13 @@ func (s *storageCephFs) StoragePoolDelete() error {
        connected := false
        for _, monAddress := range monAddresses {
                uri := fmt.Sprintf("%s:6789:/", monAddress)
-               err = tryMount(uri, mountPoint, "ceph", 0, 
fmt.Sprintf("name=%v,secret=%v,mds_namespace=%v", s.UserName, userSecret, 
fsName))
+               err = driver.TryMount(uri, mountPoint, "ceph", 0, 
fmt.Sprintf("name=%v,secret=%v,mds_namespace=%v", s.UserName, userSecret, 
fsName))
                if err != nil {
                        continue
                }
 
                connected = true
-               defer tryUnmount(mountPoint, syscall.MNT_DETACH)
+               defer driver.TryUnmount(mountPoint, syscall.MNT_DETACH)
                break
        }
 
@@ -340,7 +341,7 @@ func (s *storageCephFs) StoragePoolMount() (bool, error) {
        connected := false
        for _, monAddress := range monAddresses {
                uri := fmt.Sprintf("%s:6789:/%s", monAddress, fsPath)
-               err = tryMount(uri, poolMntPoint, "ceph", 0, 
fmt.Sprintf("name=%v,secret=%v,mds_namespace=%v", s.UserName, secret, fsName))
+               err = driver.TryMount(uri, poolMntPoint, "ceph", 0, 
fmt.Sprintf("name=%v,secret=%v,mds_namespace=%v", s.UserName, secret, fsName))
                if err != nil {
                        continue
                }
@@ -395,7 +396,7 @@ func (s *storageCephFs) StoragePoolUmount() (bool, error) {
        }
 
        // Unmount
-       err := tryUnmount(poolMntPoint, syscall.MNT_DETACH)
+       err := driver.TryUnmount(poolMntPoint, syscall.MNT_DETACH)
        if err != nil {
                return false, err
        }
@@ -756,7 +757,7 @@ func (s *storageCephFs) StoragePoolResources() 
(*api.ResourcesStoragePool, error
        }
 
        poolMntPoint := getStoragePoolMountPoint(s.pool.Name)
-       return storageResource(poolMntPoint)
+       return driver.GetStorageResource(poolMntPoint)
 }
 
 func (s *storageCephFs) StoragePoolVolumeCopy(source *api.StorageVolumeSource) 
error {
diff --git a/lxd/storage_dir.go b/lxd/storage_dir.go
index 46482a01aa..edd26d8686 100644
--- a/lxd/storage_dir.go
+++ b/lxd/storage_dir.go
@@ -1386,7 +1386,7 @@ func (s *storageDir) StoragePoolResources() 
(*api.ResourcesStoragePool, error) {
 
        poolMntPoint := getStoragePoolMountPoint(s.pool.Name)
 
-       return storageResource(poolMntPoint)
+       return driver.GetStorageResource(poolMntPoint)
 }
 
 func (s *storageDir) StoragePoolVolumeCopy(source *api.StorageVolumeSource) 
error {
diff --git a/lxd/storage_lvm.go b/lxd/storage_lvm.go
index 97ece383c6..c168697b33 100644
--- a/lxd/storage_lvm.go
+++ b/lxd/storage_lvm.go
@@ -302,7 +302,7 @@ func (s *storageLvm) StoragePoolCreate() error {
                }
 
                // Check that we don't already use this volume group.
-               inUse, user, err := lxdUsesPool(s.s.Cluster, poolName, 
s.pool.Driver, "lvm.vg_name")
+               inUse, user, err := driver.LXDUsesPool(s.s.Cluster, poolName, 
s.pool.Driver, "lvm.vg_name")
                if err != nil {
                        return err
                }
@@ -619,8 +619,8 @@ func (s *storageLvm) StoragePoolVolumeMount() (bool, error) 
{
        var customerr error
        ourMount := false
        if !shared.IsMountPoint(customPoolVolumeMntPoint) {
-               mountFlags, mountOptions := 
lxdResolveMountoptions(s.getLvmMountOptions())
-               customerr = tryMount(lvmVolumePath, customPoolVolumeMntPoint, 
lvFsType, mountFlags, mountOptions)
+               mountFlags, mountOptions := 
driver.LXDResolveMountoptions(s.getLvmMountOptions())
+               customerr = driver.TryMount(lvmVolumePath, 
customPoolVolumeMntPoint, lvFsType, mountFlags, mountOptions)
                ourMount = true
        }
 
@@ -662,7 +662,7 @@ func (s *storageLvm) StoragePoolVolumeUmount() (bool, 
error) {
        var customerr error
        ourUmount := false
        if shared.IsMountPoint(customPoolVolumeMntPoint) {
-               customerr = tryUnmount(customPoolVolumeMntPoint, 0)
+               customerr = driver.TryUnmount(customPoolVolumeMntPoint, 0)
                ourUmount = true
        }
 
@@ -1028,7 +1028,7 @@ func (s *storageLvm) ContainerCreateFromImage(container 
container, fingerprint s
        containerLvDevPath := getLvmDevPath(container.Project(), poolName, 
storagePoolVolumeAPIEndpointContainers, containerLvmName)
        // Generate a new xfs's UUID
        lvFsType := s.getLvmFilesystem()
-       msg, err := fsGenerateNewUUID(lvFsType, containerLvDevPath)
+       msg, err := driver.FSGenerateNewUUID(lvFsType, containerLvDevPath)
        if err != nil {
                logger.Errorf("Failed to create new \"%s\" UUID for container 
\"%s\" on storage pool \"%s\": %s", lvFsType, containerName, s.pool.Name, msg)
                return err
@@ -1073,7 +1073,7 @@ func lvmContainerDeleteInternal(projectName, poolName 
string, ctName string, isS
        }
 
        if shared.IsMountPoint(containerMntPoint) {
-               err := tryUnmount(containerMntPoint, 0)
+               err := driver.TryUnmount(containerMntPoint, 0)
                if err != nil {
                        return fmt.Errorf(`Failed to unmount container path `+
                                `"%s": %s`, containerMntPoint, err)
@@ -1265,7 +1265,7 @@ func (s *storageLvm) doContainerMount(project, name 
string, snap bool) (bool, er
        var mounterr error
        ourMount := false
        if !shared.IsMountPoint(containerMntPoint) {
-               mountFlags, mountOptions := 
lxdResolveMountoptions(s.getLvmMountOptions())
+               mountFlags, mountOptions := 
driver.LXDResolveMountoptions(s.getLvmMountOptions())
                if snap && lvFsType == "xfs" {
                        idx := strings.Index(mountOptions, "nouuid")
                        if idx < 0 {
@@ -1273,7 +1273,7 @@ func (s *storageLvm) doContainerMount(project, name 
string, snap bool) (bool, er
                        }
                }
 
-               mounterr = tryMount(containerLvmPath, containerMntPoint, 
lvFsType, mountFlags, mountOptions)
+               mounterr = driver.TryMount(containerLvmPath, containerMntPoint, 
lvFsType, mountFlags, mountOptions)
                ourMount = true
        }
 
@@ -1321,7 +1321,7 @@ func (s *storageLvm) umount(project, name string, path 
string) (bool, error) {
        var imgerr error
        ourUmount := false
        if shared.IsMountPoint(containerMntPoint) {
-               imgerr = tryUnmount(containerMntPoint, 0)
+               imgerr = driver.TryUnmount(containerMntPoint, 0)
                ourUmount = true
        }
 
@@ -1585,7 +1585,7 @@ func (s *storageLvm) ContainerSnapshotStart(container 
container) (bool, error) {
        containerMntPoint := getSnapshotMountPoint(container.Project(), 
s.pool.Name, containerName)
        if !shared.IsMountPoint(containerMntPoint) {
                mntOptString := s.getLvmMountOptions()
-               mountFlags, mountOptions := lxdResolveMountoptions(mntOptString)
+               mountFlags, mountOptions := 
driver.LXDResolveMountoptions(mntOptString)
 
                if lvFsType == "xfs" {
                        idx := strings.Index(mountOptions, "nouuid")
@@ -1594,7 +1594,7 @@ func (s *storageLvm) ContainerSnapshotStart(container 
container) (bool, error) {
                        }
                }
 
-               err = tryMount(containerLvmPath, containerMntPoint, lvFsType, 
mountFlags, mountOptions)
+               err = driver.TryMount(containerLvmPath, containerMntPoint, 
lvFsType, mountFlags, mountOptions)
                if err != nil {
                        logger.Errorf(`Failed to mount LVM snapshot "%s" with 
filesystem "%s" options "%s" onto "%s": %s`, s.volume.Name, lvFsType, 
mntOptString, containerMntPoint, err)
                        return false, err
@@ -1619,7 +1619,7 @@ func (s *storageLvm) ContainerSnapshotStop(container 
container) (bool, error) {
        poolName := s.getOnDiskPoolName()
 
        if shared.IsMountPoint(snapshotMntPoint) {
-               err := tryUnmount(snapshotMntPoint, 0)
+               err := driver.TryUnmount(snapshotMntPoint, 0)
                if err != nil {
                        return false, err
                }
@@ -2028,8 +2028,8 @@ func (s *storageLvm) ImageMount(fingerprint string) 
(bool, error) {
 
        poolName := s.getOnDiskPoolName()
        lvmVolumePath := getLvmDevPath("default", poolName, 
storagePoolVolumeAPIEndpointImages, fingerprint)
-       mountFlags, mountOptions := 
lxdResolveMountoptions(s.getLvmMountOptions())
-       err := tryMount(lvmVolumePath, imageMntPoint, lvmFstype, mountFlags, 
mountOptions)
+       mountFlags, mountOptions := 
driver.LXDResolveMountoptions(s.getLvmMountOptions())
+       err := driver.TryMount(lvmVolumePath, imageMntPoint, lvmFstype, 
mountFlags, mountOptions)
        if err != nil {
                logger.Errorf(fmt.Sprintf("Error mounting image LV for 
unpacking: %s", err))
                return false, fmt.Errorf("Error mounting image LV: %v", err)
@@ -2047,7 +2047,7 @@ func (s *storageLvm) ImageUmount(fingerprint string) 
(bool, error) {
                return false, nil
        }
 
-       err := tryUnmount(imageMntPoint, 0)
+       err := driver.TryUnmount(imageMntPoint, 0)
        if err != nil {
                return false, err
        }
@@ -2287,7 +2287,7 @@ func (s *storageLvm) 
StoragePoolVolumeSnapshotCreate(target *api.StorageVolumeSn
        }
 
        targetPath := getStoragePoolVolumeSnapshotMountPoint(s.pool.Name, 
target.Name)
-       err = os.MkdirAll(targetPath, snapshotsDirMode)
+       err = os.MkdirAll(targetPath, driver.SnapshotsDirMode)
        if err != nil {
                logger.Errorf("Failed to create mountpoint \"%s\" for RBD 
storage volume \"%s\" on storage pool \"%s\": %s", targetPath, s.volume.Name, 
s.pool.Name, err)
                return err
@@ -2303,7 +2303,7 @@ func (s *storageLvm) StoragePoolVolumeSnapshotDelete() 
error {
        snapshotLVName := containerNameToLVName(s.volume.Name)
        storageVolumeSnapshotPath := 
getStoragePoolVolumeSnapshotMountPoint(s.pool.Name, s.volume.Name)
        if shared.IsMountPoint(storageVolumeSnapshotPath) {
-               err := tryUnmount(storageVolumeSnapshotPath, 0)
+               err := driver.TryUnmount(storageVolumeSnapshotPath, 0)
                if err != nil {
                        return fmt.Errorf("Failed to unmount snapshot path 
\"%s\": %s", storageVolumeSnapshotPath, err)
                }
diff --git a/lxd/storage_lvm_utils.go b/lxd/storage_lvm_utils.go
index c35e66bcca..297813efa2 100644
--- a/lxd/storage_lvm_utils.go
+++ b/lxd/storage_lvm_utils.go
@@ -13,6 +13,7 @@ import (
        "github.com/lxc/lxd/lxd/db"
        "github.com/lxc/lxd/lxd/project"
        "github.com/lxc/lxd/lxd/state"
+       driver "github.com/lxc/lxd/lxd/storage"
        "github.com/lxc/lxd/shared"
        "github.com/lxc/lxd/shared/api"
        "github.com/lxc/lxd/shared/logger"
@@ -58,7 +59,7 @@ func (s *storageLvm) lvExtend(lvPath string, lvSize int64, 
fsType string, fsMntP
                        `volume type %d`, volumeType)
        }
 
-       return growFileSystem(fsType, lvPath, fsMntPoint)
+       return driver.GrowFileSystem(fsType, lvPath, fsMntPoint)
 }
 
 func (s *storageLvm) lvReduce(lvPath string, lvSize int64, fsType string, 
fsMntPoint string, volumeType int, data interface{}) error {
@@ -331,7 +332,7 @@ func (s *storageLvm) copyContainerThinpool(target 
container, source container, r
                }
        }
 
-       msg, err := fsGenerateNewUUID(LVFilesystem, containerLvDevPath)
+       msg, err := driver.FSGenerateNewUUID(LVFilesystem, containerLvDevPath)
        if err != nil {
                logger.Errorf("Failed to create new \"%s\" UUID for container 
\"%s\" on storage pool \"%s\": %s", LVFilesystem, containerName, s.pool.Name, 
msg)
                return err
@@ -853,7 +854,7 @@ func lvmCreateLv(projectName, vgName string, thinPoolName 
string, lvName string,
 
        fsPath := getLvmDevPath(projectName, vgName, volumeType, lvName)
 
-       output, err = makeFSType(fsPath, lvFsType, nil)
+       output, err = driver.MakeFSType(fsPath, lvFsType, nil)
        if err != nil {
                logger.Errorf("Filesystem creation failed: %s", output)
                return fmt.Errorf("Error making filesystem on image LV: %v", 
err)
@@ -1078,7 +1079,7 @@ func (s *storageLvm) copyVolumeThinpool(source string, 
target string, readOnly b
 
        lvDevPath := getLvmDevPath("default", poolName, 
storagePoolVolumeAPIEndpointCustom, targetLvmName)
 
-       msg, err := fsGenerateNewUUID(lvFsType, lvDevPath)
+       msg, err := driver.FSGenerateNewUUID(lvFsType, lvDevPath)
        if err != nil {
                logger.Errorf("Failed to create new UUID for filesystem \"%s\" 
for RBD storage volume \"%s\" on storage pool \"%s\": %s: %s", lvFsType, 
s.volume.Name, s.pool.Name, msg, err)
                return err
diff --git a/lxd/storage_pools_utils.go b/lxd/storage_pools_utils.go
index 5b52dc5aa9..1831ea5970 100644
--- a/lxd/storage_pools_utils.go
+++ b/lxd/storage_pools_utils.go
@@ -7,6 +7,7 @@ import (
 
        "github.com/lxc/lxd/lxd/db"
        "github.com/lxc/lxd/lxd/state"
+       driver "github.com/lxc/lxd/lxd/storage"
        "github.com/lxc/lxd/shared"
        "github.com/lxc/lxd/shared/version"
 )
@@ -41,7 +42,7 @@ func storagePoolUpdate(state *state.State, name, 
newDescription string, newConfi
                }
        }()
 
-       changedConfig, userOnly := storageConfigDiff(oldConfig, newConfig)
+       changedConfig, userOnly := driver.ConfigDiff(oldConfig, newConfig)
        // Apply config changes if there are any
        if len(changedConfig) != 0 {
                newWritable.Description = newDescription
@@ -191,15 +192,15 @@ func storagePoolDBCreate(s *state.State, poolName, 
poolDescription string, drive
        return nil
 }
 
-func storagePoolValidate(poolName string, driver string, config 
map[string]string) error {
+func storagePoolValidate(poolName string, driverName string, config 
map[string]string) error {
        // Check if the storage pool name is valid.
-       err := storageValidName(poolName)
+       err := driver.ValidName(poolName)
        if err != nil {
                return err
        }
 
        // Validate the requested storage pool configuration.
-       err = storagePoolValidateConfig(poolName, driver, config, nil)
+       err = storagePoolValidateConfig(poolName, driverName, config, nil)
        if err != nil {
                return err
        }
@@ -229,7 +230,7 @@ func storagePoolCreateInternal(state *state.State, 
poolName, poolDescription str
 }
 
 // This performs all non-db related work needed to create the pool.
-func doStoragePoolCreateInternal(state *state.State, poolName, poolDescription 
string, driver string, config map[string]string, isNotification bool) error {
+func doStoragePoolCreateInternal(state *state.State, poolName, poolDescription 
string, driverName string, config map[string]string, isNotification bool) error 
{
        tryUndo := true
        s, err := storagePoolInit(state, poolName)
        if err != nil {
@@ -263,7 +264,7 @@ func doStoragePoolCreateInternal(state *state.State, 
poolName, poolDescription s
        // callback. So diff the config here to see if something like this has
        // happened.
        postCreateConfig := s.GetStoragePoolWritable().Config
-       configDiff, _ := storageConfigDiff(config, postCreateConfig)
+       configDiff, _ := driver.ConfigDiff(config, postCreateConfig)
        if len(configDiff) > 0 {
                // Create the database entry for the storage pool.
                err = state.Cluster.StoragePoolUpdate(poolName, 
poolDescription, postCreateConfig)
diff --git a/lxd/storage_utils.go b/lxd/storage_utils.go
index 76daed4da1..fd4ecf11bd 100644
--- a/lxd/storage_utils.go
+++ b/lxd/storage_utils.go
@@ -2,326 +2,11 @@ package main
 
 import (
        "fmt"
-       "os"
-       "strings"
-       "time"
 
-       "golang.org/x/sys/unix"
-
-       "github.com/lxc/lxd/lxd/db"
-       "github.com/lxc/lxd/shared"
-       "github.com/lxc/lxd/shared/api"
+       driver "github.com/lxc/lxd/lxd/storage"
        "github.com/lxc/lxd/shared/logger"
 )
 
-// Options for filesystem creation
-type mkfsOptions struct {
-       label string
-}
-
-// Export the mount options map since we might find it useful in other parts of
-// LXD.
-type mountOptions struct {
-       capture bool
-       flag    uintptr
-}
-
-var MountOptions = map[string]mountOptions{
-       "async":         {false, unix.MS_SYNCHRONOUS},
-       "atime":         {false, unix.MS_NOATIME},
-       "bind":          {true, unix.MS_BIND},
-       "defaults":      {true, 0},
-       "dev":           {false, unix.MS_NODEV},
-       "diratime":      {false, unix.MS_NODIRATIME},
-       "dirsync":       {true, unix.MS_DIRSYNC},
-       "exec":          {false, unix.MS_NOEXEC},
-       "lazytime":      {true, unix.MS_LAZYTIME},
-       "mand":          {true, unix.MS_MANDLOCK},
-       "noatime":       {true, unix.MS_NOATIME},
-       "nodev":         {true, unix.MS_NODEV},
-       "nodiratime":    {true, unix.MS_NODIRATIME},
-       "noexec":        {true, unix.MS_NOEXEC},
-       "nomand":        {false, unix.MS_MANDLOCK},
-       "norelatime":    {false, unix.MS_RELATIME},
-       "nostrictatime": {false, unix.MS_STRICTATIME},
-       "nosuid":        {true, unix.MS_NOSUID},
-       "rbind":         {true, unix.MS_BIND | unix.MS_REC},
-       "relatime":      {true, unix.MS_RELATIME},
-       "remount":       {true, unix.MS_REMOUNT},
-       "ro":            {true, unix.MS_RDONLY},
-       "rw":            {false, unix.MS_RDONLY},
-       "strictatime":   {true, unix.MS_STRICTATIME},
-       "suid":          {false, unix.MS_NOSUID},
-       "sync":          {true, unix.MS_SYNCHRONOUS},
-}
-
-func lxdResolveMountoptions(options string) (uintptr, string) {
-       mountFlags := uintptr(0)
-       tmp := strings.SplitN(options, ",", -1)
-       for i := 0; i < len(tmp); i++ {
-               opt := tmp[i]
-               do, ok := MountOptions[opt]
-               if !ok {
-                       continue
-               }
-
-               if do.capture {
-                       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, ",")
-}
-
-// Useful functions for unreliable backends
-func tryMount(src string, dst string, fs string, flags uintptr, options 
string) error {
-       var err error
-
-       for i := 0; i < 20; i++ {
-               err = unix.Mount(src, dst, fs, flags, options)
-               if err == nil {
-                       break
-               }
-
-               time.Sleep(500 * time.Millisecond)
-       }
-
-       if err != nil {
-               return err
-       }
-
-       return nil
-}
-
-func tryUnmount(path string, flags int) error {
-       var err error
-
-       for i := 0; i < 20; i++ {
-               err = unix.Unmount(path, flags)
-               if err == nil {
-                       break
-               }
-
-               time.Sleep(500 * time.Millisecond)
-       }
-
-       if err != nil {
-               return err
-       }
-
-       return nil
-}
-
-func storageValidName(value string) error {
-       if strings.Contains(value, "/") {
-               return fmt.Errorf("Invalid storage volume name \"%s\". Storage 
volumes cannot contain \"/\" in their name", value)
-       }
-
-       return nil
-}
-
-func storageConfigDiff(oldConfig map[string]string, newConfig 
map[string]string) ([]string, bool) {
-       changedConfig := []string{}
-       userOnly := true
-       for key := range oldConfig {
-               if oldConfig[key] != newConfig[key] {
-                       if !strings.HasPrefix(key, "user.") {
-                               userOnly = false
-                       }
-
-                       if !shared.StringInSlice(key, changedConfig) {
-                               changedConfig = append(changedConfig, key)
-                       }
-               }
-       }
-
-       for key := range newConfig {
-               if oldConfig[key] != newConfig[key] {
-                       if !strings.HasPrefix(key, "user.") {
-                               userOnly = false
-                       }
-
-                       if !shared.StringInSlice(key, changedConfig) {
-                               changedConfig = append(changedConfig, key)
-                       }
-               }
-       }
-
-       // Skip on no change
-       if len(changedConfig) == 0 {
-               return nil, false
-       }
-
-       return changedConfig, userOnly
-}
-
-// Default permissions for folders in ${LXD_DIR}
-const storagePoolsDirMode os.FileMode = 0711
-const containersDirMode os.FileMode = 0711
-const customDirMode os.FileMode = 0711
-const imagesDirMode os.FileMode = 0700
-const snapshotsDirMode os.FileMode = 0700
-
-// Detect whether LXD already uses the given storage pool.
-func lxdUsesPool(dbObj *db.Cluster, onDiskPoolName string, driver string, 
onDiskProperty string) (bool, string, error) {
-       pools, err := dbObj.StoragePools()
-       if err != nil && err != db.ErrNoSuchObject {
-               return false, "", err
-       }
-
-       for _, pool := range pools {
-               _, pl, err := dbObj.StoragePoolGet(pool)
-               if err != nil {
-                       continue
-               }
-
-               if pl.Driver != driver {
-                       continue
-               }
-
-               if pl.Config[onDiskProperty] == onDiskPoolName {
-                       return true, pl.Name, nil
-               }
-       }
-
-       return false, "", nil
-}
-
-func makeFSType(path string, fsType string, options *mkfsOptions) (string, 
error) {
-       var err error
-       var msg string
-
-       fsOptions := options
-       if fsOptions == nil {
-               fsOptions = &mkfsOptions{}
-       }
-
-       cmd := []string{fmt.Sprintf("mkfs.%s", fsType), path}
-       if fsOptions.label != "" {
-               cmd = append(cmd, "-L", fsOptions.label)
-       }
-
-       if fsType == "ext4" {
-               cmd = append(cmd, "-E", 
"nodiscard,lazy_itable_init=0,lazy_journal_init=0")
-       }
-
-       msg, err = shared.TryRunCommand(cmd[0], cmd[1:]...)
-       if err != nil {
-               return msg, err
-       }
-
-       return "", nil
-}
-
-func fsGenerateNewUUID(fstype string, lvpath string) (string, error) {
-       switch fstype {
-       case "btrfs":
-               return btrfsGenerateNewUUID(lvpath)
-       case "xfs":
-               return xfsGenerateNewUUID(lvpath)
-       }
-
-       return "", nil
-}
-
-func xfsGenerateNewUUID(devPath string) (string, error) {
-       // Attempt to generate a new UUID
-       msg, err := shared.RunCommand("xfs_admin", "-U", "generate", devPath)
-       if err != nil {
-               return msg, err
-       }
-
-       if msg != "" {
-               // Exit 0 with a msg usually means some log entry getting in 
the way
-               msg, err = shared.RunCommand("xfs_repair", "-o", 
"force_geometry", "-L", devPath)
-               if err != nil {
-                       return msg, err
-               }
-
-               // Attempt to generate a new UUID again
-               msg, err = shared.RunCommand("xfs_admin", "-U", "generate", 
devPath)
-               if err != nil {
-                       return msg, err
-               }
-       }
-
-       return msg, nil
-}
-
-func btrfsGenerateNewUUID(lvpath string) (string, error) {
-       msg, err := shared.RunCommand(
-               "btrfstune",
-               "-f",
-               "-u",
-               lvpath)
-       if err != nil {
-               return msg, err
-       }
-
-       return msg, nil
-}
-
-func growFileSystem(fsType string, devPath string, mntpoint string) error {
-       var msg string
-       var err error
-       switch fsType {
-       case "": // if not specified, default to ext4
-               fallthrough
-       case "ext4":
-               msg, err = shared.TryRunCommand("resize2fs", devPath)
-       case "xfs":
-               msg, err = shared.TryRunCommand("xfs_growfs", devPath)
-       case "btrfs":
-               msg, err = shared.TryRunCommand("btrfs", "filesystem", 
"resize", "max", mntpoint)
-       default:
-               return fmt.Errorf(`Growing not supported for filesystem type 
"%s"`, fsType)
-       }
-
-       if err != nil {
-               errorMsg := fmt.Sprintf(`Could not extend underlying %s 
filesystem for "%s": %s`, fsType, devPath, msg)
-               logger.Errorf(errorMsg)
-               return fmt.Errorf(errorMsg)
-       }
-
-       logger.Debugf(`extended underlying %s filesystem for "%s"`, fsType, 
devPath)
-       return nil
-}
-
-func shrinkFileSystem(fsType string, devPath string, mntpoint string, byteSize 
int64) error {
-       strSize := fmt.Sprintf("%dK", byteSize/1024)
-
-       switch fsType {
-       case "": // if not specified, default to ext4
-               fallthrough
-       case "ext4":
-               _, err := shared.TryRunCommand("e2fsck", "-f", "-y", devPath)
-               if err != nil {
-                       return err
-               }
-
-               _, err = shared.TryRunCommand("resize2fs", devPath, strSize)
-               if err != nil {
-                       return err
-               }
-       case "btrfs":
-               _, err := shared.TryRunCommand("btrfs", "filesystem", "resize", 
strSize, mntpoint)
-               if err != nil {
-                       return err
-               }
-       default:
-               return fmt.Errorf(`Shrinking not supported for filesystem type 
"%s"`, fsType)
-       }
-
-       return nil
-}
-
 func shrinkVolumeFilesystem(s storage, volumeType int, fsType string, devPath 
string, mntpoint string, byteSize int64, data interface{}) (func() (bool, 
error), error) {
        var cleanupFunc func() (bool, error)
        switch fsType {
@@ -359,26 +44,6 @@ func shrinkVolumeFilesystem(s storage, volumeType int, 
fsType string, devPath st
                return nil, fmt.Errorf(`Shrinking not supported for filesystem 
type "%s"`, fsType)
        }
 
-       err := shrinkFileSystem(fsType, devPath, mntpoint, byteSize)
+       err := driver.ShrinkFileSystem(fsType, devPath, mntpoint, byteSize)
        return cleanupFunc, err
 }
-
-func storageResource(path string) (*api.ResourcesStoragePool, error) {
-       st, err := shared.Statvfs(path)
-       if err != nil {
-               return nil, err
-       }
-
-       res := api.ResourcesStoragePool{}
-       res.Space.Total = st.Blocks * uint64(st.Bsize)
-       res.Space.Used = (st.Blocks - st.Bfree) * uint64(st.Bsize)
-
-       // Some filesystems don't report inodes since they allocate them
-       // dynamically e.g. btrfs.
-       if st.Files > 0 {
-               res.Inodes.Total = st.Files
-               res.Inodes.Used = st.Files - st.Ffree
-       }
-
-       return &res, nil
-}
diff --git a/lxd/storage_volumes_snapshot.go b/lxd/storage_volumes_snapshot.go
index 8e87a6e925..6de54b156b 100644
--- a/lxd/storage_volumes_snapshot.go
+++ b/lxd/storage_volumes_snapshot.go
@@ -9,6 +9,7 @@ import (
        "github.com/gorilla/mux"
 
        "github.com/lxc/lxd/lxd/db"
+       driver "github.com/lxc/lxd/lxd/storage"
        "github.com/lxc/lxd/lxd/util"
        "github.com/lxc/lxd/shared"
        "github.com/lxc/lxd/shared/api"
@@ -66,7 +67,7 @@ func storagePoolVolumeSnapshotsTypePost(d *Daemon, r 
*http.Request) Response {
        }
 
        // Validate the name
-       err = storageValidName(req.Name)
+       err = driver.ValidName(req.Name)
        if err != nil {
                return BadRequest(err)
        }
diff --git a/lxd/storage_zfs.go b/lxd/storage_zfs.go
index d98f530956..cabdc2f993 100644
--- a/lxd/storage_zfs.go
+++ b/lxd/storage_zfs.go
@@ -273,14 +273,14 @@ func (s *storageZfs) zfsPoolCreate() error {
        }
 
        fixperms := shared.VarPath("storage-pools", s.pool.Name, "containers")
-       err = os.MkdirAll(fixperms, containersDirMode)
+       err = os.MkdirAll(fixperms, driver.ContainersDirMode)
        if err != nil && !os.IsNotExist(err) {
                return err
        }
 
-       err = os.Chmod(fixperms, containersDirMode)
+       err = os.Chmod(fixperms, driver.ContainersDirMode)
        if err != nil {
-               logger.Warnf("Failed to chmod \"%s\" to \"0%s\": %s", fixperms, 
strconv.FormatInt(int64(containersDirMode), 8), err)
+               logger.Warnf("Failed to chmod \"%s\" to \"0%s\": %s", fixperms, 
strconv.FormatInt(int64(driver.ContainersDirMode), 8), err)
        }
 
        dataset = fmt.Sprintf("%s/images", poolName)
@@ -291,13 +291,13 @@ func (s *storageZfs) zfsPoolCreate() error {
        }
 
        fixperms = shared.VarPath("storage-pools", s.pool.Name, "images")
-       err = os.MkdirAll(fixperms, imagesDirMode)
+       err = os.MkdirAll(fixperms, driver.ImagesDirMode)
        if err != nil && !os.IsNotExist(err) {
                return err
        }
-       err = os.Chmod(fixperms, imagesDirMode)
+       err = os.Chmod(fixperms, driver.ImagesDirMode)
        if err != nil {
-               logger.Warnf("Failed to chmod \"%s\" to \"0%s\": %s", fixperms, 
strconv.FormatInt(int64(imagesDirMode), 8), err)
+               logger.Warnf("Failed to chmod \"%s\" to \"0%s\": %s", fixperms, 
strconv.FormatInt(int64(driver.ImagesDirMode), 8), err)
        }
 
        dataset = fmt.Sprintf("%s/custom", poolName)
@@ -308,13 +308,13 @@ func (s *storageZfs) zfsPoolCreate() error {
        }
 
        fixperms = shared.VarPath("storage-pools", s.pool.Name, "custom")
-       err = os.MkdirAll(fixperms, customDirMode)
+       err = os.MkdirAll(fixperms, driver.CustomDirMode)
        if err != nil && !os.IsNotExist(err) {
                return err
        }
-       err = os.Chmod(fixperms, customDirMode)
+       err = os.Chmod(fixperms, driver.CustomDirMode)
        if err != nil {
-               logger.Warnf("Failed to chmod \"%s\" to \"0%s\": %s", fixperms, 
strconv.FormatInt(int64(customDirMode), 8), err)
+               logger.Warnf("Failed to chmod \"%s\" to \"0%s\": %s", fixperms, 
strconv.FormatInt(int64(driver.CustomDirMode), 8), err)
        }
 
        dataset = fmt.Sprintf("%s/deleted", poolName)
@@ -332,13 +332,13 @@ func (s *storageZfs) zfsPoolCreate() error {
        }
 
        fixperms = shared.VarPath("storage-pools", s.pool.Name, 
"containers-snapshots")
-       err = os.MkdirAll(fixperms, snapshotsDirMode)
+       err = os.MkdirAll(fixperms, driver.SnapshotsDirMode)
        if err != nil && !os.IsNotExist(err) {
                return err
        }
-       err = os.Chmod(fixperms, snapshotsDirMode)
+       err = os.Chmod(fixperms, driver.SnapshotsDirMode)
        if err != nil {
-               logger.Warnf("Failed to chmod \"%s\" to \"0%s\": %s", fixperms, 
strconv.FormatInt(int64(snapshotsDirMode), 8), err)
+               logger.Warnf("Failed to chmod \"%s\" to \"0%s\": %s", fixperms, 
strconv.FormatInt(int64(driver.SnapshotsDirMode), 8), err)
        }
 
        dataset = fmt.Sprintf("%s/custom-snapshots", poolName)
@@ -349,13 +349,13 @@ func (s *storageZfs) zfsPoolCreate() error {
        }
 
        fixperms = shared.VarPath("storage-pools", s.pool.Name, 
"custom-snapshots")
-       err = os.MkdirAll(fixperms, snapshotsDirMode)
+       err = os.MkdirAll(fixperms, driver.SnapshotsDirMode)
        if err != nil && !os.IsNotExist(err) {
                return err
        }
-       err = os.Chmod(fixperms, snapshotsDirMode)
+       err = os.Chmod(fixperms, driver.SnapshotsDirMode)
        if err != nil {
-               logger.Warnf("Failed to chmod \"%s\" to \"0%s\": %s", fixperms, 
strconv.FormatInt(int64(snapshotsDirMode), 8), err)
+               logger.Warnf("Failed to chmod \"%s\" to \"0%s\": %s", fixperms, 
strconv.FormatInt(int64(driver.SnapshotsDirMode), 8), err)
        }
 
        return nil
diff --git a/lxd/storage_zfs_utils.go b/lxd/storage_zfs_utils.go
index 7e42cab87c..6bd0403d59 100644
--- a/lxd/storage_zfs_utils.go
+++ b/lxd/storage_zfs_utils.go
@@ -14,6 +14,7 @@ import (
        "golang.org/x/sys/unix"
 
        "github.com/lxc/lxd/lxd/project"
+       driver "github.com/lxc/lxd/lxd/storage"
        "github.com/lxc/lxd/shared"
        "github.com/lxc/lxd/shared/logger"
 )
@@ -519,7 +520,7 @@ func zfsUmount(poolName string, path string, mountpoint 
string) error {
                fmt.Sprintf("%s/%s", poolName, path))
        if err != nil {
                logger.Warnf("Failed to unmount ZFS filesystem via zfs unmount: 
%s. Trying lazy umount (MNT_DETACH)...", output)
-               err := tryUnmount(mountpoint, unix.MNT_DETACH)
+               err := driver.TryUnmount(mountpoint, unix.MNT_DETACH)
                if err != nil {
                        logger.Warnf("Failed to unmount ZFS filesystem via lazy 
umount (MNT_DETACH)...")
                        return err
@@ -682,7 +683,7 @@ func (s *storageZfs) doContainerMount(projectName, name 
string, privileged bool)
        if !shared.IsMountPoint(containerPoolVolumeMntPoint) {
                source := fmt.Sprintf("%s/%s", s.getOnDiskPoolName(), fs)
                zfsMountOptions := fmt.Sprintf("rw,zfsutil,mntpoint=%s", 
containerPoolVolumeMntPoint)
-               mounterr := tryMount(source, containerPoolVolumeMntPoint, 
"zfs", 0, zfsMountOptions)
+               mounterr := driver.TryMount(source, 
containerPoolVolumeMntPoint, "zfs", 0, zfsMountOptions)
                if mounterr != nil {
                        if mounterr != unix.EBUSY {
                                logger.Errorf("Failed to mount ZFS dataset 
\"%s\" onto \"%s\": %v", source, containerPoolVolumeMntPoint, mounterr)

From 30ac4707cec720a8f3b25b3558f37295a35b2061 Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.h...@canonical.com>
Date: Thu, 15 Aug 2019 15:17:01 +0200
Subject: [PATCH 4/4] test: Lint storage package

Signed-off-by: Thomas Hipp <thomas.h...@canonical.com>
---
 test/suites/static_analysis.sh | 1 +
 1 file changed, 1 insertion(+)

diff --git a/test/suites/static_analysis.sh b/test/suites/static_analysis.sh
index 1c601e9019..cd2da54018 100644
--- a/test/suites/static_analysis.sh
+++ b/test/suites/static_analysis.sh
@@ -82,6 +82,7 @@ test_static_analysis() {
       #golint -set_exit_status lxd/migration
       golint -set_exit_status lxd/node
       golint -set_exit_status lxd/state
+      golint -set_exit_status lxd/storage
       golint -set_exit_status lxd/sys
       golint -set_exit_status lxd/task
       golint -set_exit_status lxd/template
_______________________________________________
lxc-devel mailing list
lxc-devel@lists.linuxcontainers.org
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to