Skip to content

Commit

Permalink
lxd/storage/drivers: Collect subvolumes via filepath traversal if in …
Browse files Browse the repository at this point in the history
…nested container.

Signed-off-by: Mark Laing <mark.laing@canonical.com>
  • Loading branch information
markylaing committed Nov 29, 2023
1 parent b373fce commit e967d4c
Showing 1 changed file with 53 additions and 19 deletions.
72 changes: 53 additions & 19 deletions lxd/storage/drivers/driver_btrfs_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"context"
"fmt"
"io"
"io/fs"
"os"
"os/exec"
"path/filepath"
Expand Down Expand Up @@ -107,39 +108,72 @@ func (d *btrfs) hasSubvolumes(path string) (bool, error) {
}

func (d *btrfs) getSubvolumes(path string) ([]string, error) {
// Make sure the path has a trailing slash.
if !strings.HasSuffix(path, "/") {
path = path + "/"
}

poolMountPath := GetPoolMountPath(d.name)
if !strings.HasPrefix(path, poolMountPath+"/") {
return nil, fmt.Errorf("%q is outside pool mount path %q", path, poolMountPath)
}

path = strings.TrimPrefix(path, poolMountPath+"/")
var result []string

// Make sure the path has a trailing slash.
if !strings.HasSuffix(path, "/") {
path = path + "/"
}
if d.state.OS.RunningInUserNS {
// If using BTRFS in a nested container we cannot use "btrfs subvolume list" due to a permission error.
// So instead walk the directory tree testing each directory to see if it is subvolume.
err := filepath.Walk(path, func(fpath string, entry fs.FileInfo, err error) error {
if err != nil {
return err
}

var stdout bytes.Buffer
err := shared.RunCommandWithFds(d.state.ShutdownCtx, nil, &stdout, "btrfs", "subvolume", "list", poolMountPath)
if err != nil {
return nil, err
}
// Ignore the base path.
if strings.TrimRight(fpath, "/") == strings.TrimRight(path, "/") {
return nil
}

result := []string{}
// Subvolumes can only be directories.
if !entry.IsDir() {
return nil
}

scanner := bufio.NewScanner(&stdout)
for scanner.Scan() {
fields := strings.Fields(scanner.Text())
// Check if directory is a subvolume.
if d.isSubvolume(fpath) {
result = append(result, strings.TrimPrefix(fpath, path))
}

if len(fields) != 9 {
continue
return nil
})
if err != nil {
return nil, err
}
} else {
// If not running inside a nested container we can use "btrfs subvolume list" to get subvolumes which is more
// performant than walking the directory tree.
var stdout bytes.Buffer
err := shared.RunCommandWithFds(d.state.ShutdownCtx, nil, &stdout, "btrfs", "subvolume", "list", poolMountPath)
if err != nil {
return nil, err
}

if !strings.HasPrefix(fields[8], path) {
continue
path = strings.TrimPrefix(path, poolMountPath+"/")
scanner := bufio.NewScanner(&stdout)
for scanner.Scan() {
fields := strings.Fields(scanner.Text())

if len(fields) != 9 {
continue
}

if !strings.HasPrefix(fields[8], path) {
continue
}

result = append(result, strings.TrimPrefix(fields[8], path))
}

result = append(result, strings.TrimPrefix(fields[8], path))
return result, nil
}

return result, nil
Expand Down

0 comments on commit e967d4c

Please sign in to comment.