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

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) ===

From 92a386c356dcaa9e31efd3aa7ebd92b311477079 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brau...@ubuntu.com>
Date: Sun, 5 Mar 2017 13:25:05 +0100
Subject: [PATCH 1/2] btrfs: correctly handle loop-backed pools

We allow users to create loop-backed btrfs pools even it they are on a btrfs
filesystem already. However, until recently StoragePoolMount() did not correctly
handle this case. This commit ensure that mounting a loop-backed storage pool on
a btrfs filesystem works correctly.

Signed-off-by: Christian Brauner <christian.brau...@ubuntu.com>
---
 lxd/storage_btrfs.go | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/lxd/storage_btrfs.go b/lxd/storage_btrfs.go
index d1b3b1d..eb77824 100644
--- a/lxd/storage_btrfs.go
+++ b/lxd/storage_btrfs.go
@@ -341,8 +341,13 @@ func (s *storageBtrfs) StoragePoolMount() (bool, error) {
        }
 
        mountSource := source
+       isBlockDev := shared.IsBlockdevPath(source)
        if filepath.IsAbs(source) {
-               if !shared.IsBlockdevPath(source) && s.d.BackingFs != "btrfs" {
+               loopFilePath := shared.VarPath("disks", s.pool.Name+".img")
+               if !isBlockDev && source == loopFilePath {
+                       // If source == "${LXD_DIR}"/disks/{pool_name} it is a
+                       // loop file we're dealing with.
+                       //
                        // 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.
@@ -352,9 +357,11 @@ func (s *storageBtrfs) StoragePoolMount() (bool, error) {
                        }
                        mountSource = loopF.Name()
                        defer loopF.Close()
-               } else {
+               } else if !isBlockDev && s.d.BackingFs == "btrfs" {
+                       // User is using btrfs subvolume as pool.
                        return false, nil
                }
+               // User is using block device path.
        } else {
                // Try to lookup the disk device by UUID but don't fail. If we
                // don't find one this might just mean we have been given the

From ab64dd7aa13d26e11ae18019925bdaf07bf468f7 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brau...@ubuntu.com>
Date: Sun, 5 Mar 2017 20:02:33 +0100
Subject: [PATCH 2/2] btrfs: handle custom subvolume paths

This improves handling:

1. lxc storage create pool1 source=/path/to/subvolume
- create /path/to/subvolume if it doesn't already exist and bind-mount onto
  ${LXD_DIR}/storage-pools/pool1

2. lxc storage create pool1 source=${LXD_DIR}/storage-pools/pool1
  - create subvolume if LXD is located on btrfs

3. lxc storage create pool1 
source=/path-somewhere-under-${LXD_DIR}-but-not-under-storage-pools-subdir
  - This is considered invalid (As it might mess with LXD's on-disk layout).
    The following error message is given:

        
chb@conventiont|~/source/go/src/github.com/lxc/lxd|2017-03-05/btrfs_improvements
 *$%>
        > lxc storage create pool1 btrfs source=/home/chb/mnt/l1/storage-pools/
        error: BTRFS subvolumes requests in LXD directory "/home/chb/mnt/l1" 
are only valid under "/home/chb/mnt/l1/storage-pools"
        (e.g. source=/home/chb/mnt/l1/storage-pools/pool1)

    I really wouldn't want to allow users to create subvolumes under say e.g.
    ${LXD_DIR}/containers or the like. This will just cause trouble.

Signed-off-by: Christian Brauner <christian.brau...@ubuntu.com>
---
 lxd/storage_btrfs.go | 76 +++++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 57 insertions(+), 19 deletions(-)

diff --git a/lxd/storage_btrfs.go b/lxd/storage_btrfs.go
index eb77824..c563c47 100644
--- a/lxd/storage_btrfs.go
+++ b/lxd/storage_btrfs.go
@@ -138,13 +138,32 @@ func (s *storageBtrfs) StoragePoolCreate() error {
                                        return fmt.Errorf("Failed to create the 
BTRFS pool: %s", output)
                                }
                        } else {
-                               if isBtrfsSubVolume(source) || s.d.BackingFs == 
"btrfs" {
+                               if isBtrfsSubVolume(source) {
+                                       subvols, err := 
btrfsSubVolumesGet(source)
+                                       if err != nil {
+                                               return fmt.Errorf("Could not 
determine if existing BTRFS subvolume ist empty: %s.", err)
+                                       }
+                                       if len(subvols) > 0 {
+                                               return fmt.Errorf("Requested 
BTRFS subvolume exists but is not empty.")
+                                       }
+                               } else {
+                                       cleanSource := filepath.Clean(source)
+                                       lxdDir := shared.VarPath()
+                                       poolMntPoint := 
getStoragePoolMountPoint(s.pool.Name)
+                                       if shared.PathExists(source) && 
!isOnBtrfs(source) {
+                                               return fmt.Errorf("Existing 
path is neither a BTRFS subvolume nor does it reside on a BTRFS filesystem.")
+                                       } else if 
strings.HasPrefix(cleanSource, lxdDir) {
+                                               if cleanSource != poolMntPoint {
+                                                       return 
fmt.Errorf("BTRFS subvolumes requests in LXD directory \"%s\" are only valid 
under \"%s\"\n(e.g. source=%s)", shared.VarPath(), 
shared.VarPath("storage-pools"), poolMntPoint)
+                                               } else if s.d.BackingFs != 
"btrfs" {
+                                                       return 
fmt.Errorf("Creation of BTRFS subvolume requested but \"%s\" does not reside on 
BTRFS filesystem.", source)
+                                               }
+                                       }
+
                                        err := btrfsSubVolumeCreate(source)
                                        if err != nil {
                                                return err
                                        }
-                               } else {
-                                       return fmt.Errorf("Custom loop file 
locations are not supported.")
                                }
                        }
                } else {
@@ -274,11 +293,14 @@ func (s *storageBtrfs) StoragePoolDelete() error {
                shared.LogDebugf(msg)
        } else {
                var err error
-               if s.d.BackingFs == "btrfs" {
-                       err = btrfsSubVolumesDelete(source)
-               } else {
+               cleanSource := filepath.Clean(source)
+               sourcePath := shared.VarPath("disks", s.pool.Name)
+               loopFilePath := sourcePath + ".img"
+               if cleanSource == loopFilePath {
                        // This is a loop file --> simply remove it.
                        err = os.Remove(source)
+               } else {
+                       err = btrfsSubVolumesDelete(source)
                }
                if err != nil {
                        return err
@@ -340,9 +362,12 @@ func (s *storageBtrfs) StoragePoolMount() (bool, error) {
                return false, nil
        }
 
+       mountFlags := uintptr(0)
        mountSource := source
        isBlockDev := shared.IsBlockdevPath(source)
        if filepath.IsAbs(source) {
+               cleanSource := filepath.Clean(source)
+               poolMntPoint := getStoragePoolMountPoint(s.pool.Name)
                loopFilePath := shared.VarPath("disks", s.pool.Name+".img")
                if !isBlockDev && source == loopFilePath {
                        // If source == "${LXD_DIR}"/disks/{pool_name} it is a
@@ -357,8 +382,10 @@ func (s *storageBtrfs) StoragePoolMount() (bool, error) {
                        }
                        mountSource = loopF.Name()
                        defer loopF.Close()
-               } else if !isBlockDev && s.d.BackingFs == "btrfs" {
-                       // User is using btrfs subvolume as pool.
+               } else if !isBlockDev && cleanSource != poolMntPoint {
+                       mountSource = source
+                       mountFlags = syscall.MS_BIND
+               } else if !isBlockDev && cleanSource == poolMntPoint && 
s.d.BackingFs == "btrfs" {
                        return false, nil
                }
                // User is using block device path.
@@ -382,7 +409,7 @@ func (s *storageBtrfs) StoragePoolMount() (bool, error) {
        }
 
        // This is a block device.
-       err := syscall.Mount(mountSource, poolMntPoint, "btrfs", 0, 
btrfsMntOptions)
+       err := syscall.Mount(mountSource, poolMntPoint, "btrfs", mountFlags, 
btrfsMntOptions)
        if err != nil {
                return false, err
        }
@@ -1313,7 +1340,8 @@ func (s *storageBtrfs) ImageUmount(fingerprint string) 
(bool, error) {
 func btrfsSubVolumeCreate(subvol string) error {
        parentDestPath := filepath.Dir(subvol)
        if !shared.PathExists(parentDestPath) {
-               if err := os.MkdirAll(parentDestPath, 0711); err != nil {
+               err := os.MkdirAll(parentDestPath, 0711)
+               if err != nil {
                        return err
                }
        }
@@ -1324,11 +1352,8 @@ func btrfsSubVolumeCreate(subvol string) error {
                "create",
                subvol).CombinedOutput()
        if err != nil {
-               return fmt.Errorf(
-                       "btrfs subvolume create failed, subvol=%s, output%s",
-                       subvol,
-                       string(output),
-               )
+               shared.LogErrorf("Failed to create BTRFS subvolume \"%s\": 
%s.", subvol, string(output))
+               return err
        }
 
        return nil
@@ -1526,10 +1551,8 @@ func (s *storageBtrfs) btrfsPoolVolumesSnapshot(source 
string, dest string, read
        return nil
 }
 
-/*
- * isBtrfsSubVolume returns true if the given Path is a btrfs subvolume
- * else false.
- */
+// isBtrfsSubVolume returns true if the given Path is a btrfs subvolume else
+// false.
 func isBtrfsSubVolume(subvolPath string) bool {
        fs := syscall.Stat_t{}
        err := syscall.Lstat(subvolPath, &fs)
@@ -1545,6 +1568,21 @@ func isBtrfsSubVolume(subvolPath string) bool {
        return true
 }
 
+func isOnBtrfs(path string) bool {
+       fs := syscall.Statfs_t{}
+
+       err := syscall.Statfs(path, &fs)
+       if err != nil {
+               return false
+       }
+
+       if fs.Type != filesystemSuperMagicBtrfs {
+               return false
+       }
+
+       return true
+}
+
 func btrfsSubVolumesGet(path string) ([]string, error) {
        result := []string{}
 
_______________________________________________
lxc-devel mailing list
lxc-devel@lists.linuxcontainers.org
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to