diff --git a/components/engine/daemon/graphdriver/btrfs/btrfs.go b/components/engine/daemon/graphdriver/btrfs/btrfs.go index c8a56fe094..7ea4dafca9 100644 --- a/components/engine/daemon/graphdriver/btrfs/btrfs.go +++ b/components/engine/daemon/graphdriver/btrfs/btrfs.go @@ -6,6 +6,7 @@ package btrfs #include #include #include +#include */ import "C" @@ -13,6 +14,7 @@ import ( "fmt" "os" "path" + "path/filepath" "syscall" "unsafe" @@ -24,6 +26,21 @@ func init() { graphdriver.Register("btrfs", Init) } +func is_subvolume(dirpath string) (bool, error) { + rootdir := path.Dir(dirpath) + + var bufStat syscall.Stat_t + if err := syscall.Lstat(rootdir, &bufStat); err != nil { + return false, err + } + + if bufStat.Ino != C.BTRFS_FIRST_FREE_OBJECTID { + return false, nil + } + + return true, nil +} + // Init returns a new BTRFS driver. // An error is returned if BTRFS is not supported. func Init(home string, options []string) (graphdriver.Driver, error) { @@ -160,18 +177,40 @@ func subvolSnapshot(src, dest, name string) error { return nil } -func subvolDelete(path, name string) error { - dir, err := openDir(path) +func subvolDelete(dirpath, name string) error { + dir, err := openDir(dirpath) if err != nil { return err } defer closeDir(dir) var args C.struct_btrfs_ioctl_vol_args + + filepath.Walk(dirpath, + func(dirpath string, f os.FileInfo, err error) error { + if f.IsDir() { + isSubvolumes, err := is_subvolume(path.Join(dirpath, f.Name())) + if err != nil { + return err + } + if isSubvolumes { + for i, c := range []byte(f.Name()) { + args.name[i] = C.char(c) + } + _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, getDirFd(dir), C.BTRFS_IOC_SNAP_DESTROY, + uintptr(unsafe.Pointer(&args))) + if errno != 0 { + return fmt.Errorf("Failed to destroy btrfs snapshot: %v", errno.Error()) + } + } + return nil + } + return nil + }) + for i, c := range []byte(name) { args.name[i] = C.char(c) } - _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, getDirFd(dir), C.BTRFS_IOC_SNAP_DESTROY, uintptr(unsafe.Pointer(&args))) if errno != 0 {