소스 검색

fix 9939: docker does not remove btrfs subvolumes when destroying container

Signed-off-by: Ma Shimiao <mashimiao.fnst@cn.fujitsu.com>
Ma Shimiao 10 년 전
부모
커밋
dea78fc2ce
1개의 변경된 파일42개의 추가작업 그리고 3개의 파일을 삭제
  1. 42 3
      daemon/graphdriver/btrfs/btrfs.go

+ 42 - 3
daemon/graphdriver/btrfs/btrfs.go

@@ -6,6 +6,7 @@ package btrfs
 #include <stdlib.h>
 #include <dirent.h>
 #include <btrfs/ioctl.h>
+#include <btrfs/ctree.h>
 */
 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 {