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