Signed-off-by: Jessica Frazelle <acidburn@docker.com>
| ... | ... |
@@ -4,7 +4,7 @@ |
| 4 | 4 |
|
| 5 | 5 |
FROM debian:wheezy-backports |
| 6 | 6 |
|
| 7 |
-RUN apt-get update && apt-get install -y bash-completion btrfs-tools build-essential curl ca-certificates debhelper dh-systemd git libapparmor-dev libdevmapper-dev libsqlite3-dev --no-install-recommends && rm -rf /var/lib/apt/lists/* |
|
| 7 |
+RUN apt-get update && apt-get install -y bash-completion btrfs-tools/wheezy-backports build-essential curl ca-certificates debhelper dh-systemd git libapparmor-dev libdevmapper-dev libsqlite3-dev --no-install-recommends && rm -rf /var/lib/apt/lists/* |
|
| 8 | 8 |
|
| 9 | 9 |
ENV GO_VERSION 1.4.2 |
| 10 | 10 |
RUN curl -fSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
|
| ... | ... |
@@ -73,6 +73,12 @@ for version in "${versions[@]}"; do
|
| 73 | 73 |
extraBuildTags+=' exclude_graphdriver_btrfs' |
| 74 | 74 |
fi |
| 75 | 75 |
|
| 76 |
+ if [ "$suite" = 'wheezy' ]; then |
|
| 77 |
+ # pull btrfs-toold from backports |
|
| 78 |
+ backports="/$suite-backports" |
|
| 79 |
+ packages=( "${packages[@]/btrfs-tools/btrfs-tools$backports}" )
|
|
| 80 |
+ fi |
|
| 81 |
+ |
|
| 76 | 82 |
echo "RUN apt-get update && apt-get install -y ${packages[*]} --no-install-recommends && rm -rf /var/lib/apt/lists/*" >> "$version/Dockerfile"
|
| 77 | 83 |
|
| 78 | 84 |
echo >> "$version/Dockerfile" |
| ... | ... |
@@ -26,21 +26,6 @@ func init() {
|
| 26 | 26 |
graphdriver.Register("btrfs", Init)
|
| 27 | 27 |
} |
| 28 | 28 |
|
| 29 |
-func is_subvolume(dirpath string) (bool, error) {
|
|
| 30 |
- rootdir := path.Dir(dirpath) |
|
| 31 |
- |
|
| 32 |
- var bufStat syscall.Stat_t |
|
| 33 |
- if err := syscall.Lstat(rootdir, &bufStat); err != nil {
|
|
| 34 |
- return false, err |
|
| 35 |
- } |
|
| 36 |
- |
|
| 37 |
- if bufStat.Ino != C.BTRFS_FIRST_FREE_OBJECTID {
|
|
| 38 |
- return false, nil |
|
| 39 |
- } |
|
| 40 |
- |
|
| 41 |
- return true, nil |
|
| 42 |
-} |
|
| 43 |
- |
|
| 44 | 29 |
// Init returns a new BTRFS driver. |
| 45 | 30 |
// An error is returned if BTRFS is not supported. |
| 46 | 31 |
func Init(home string, options []string) (graphdriver.Driver, error) {
|
| ... | ... |
@@ -177,6 +162,16 @@ func subvolSnapshot(src, dest, name string) error {
|
| 177 | 177 |
return nil |
| 178 | 178 |
} |
| 179 | 179 |
|
| 180 |
+func isSubvolume(p string) (bool, error) {
|
|
| 181 |
+ var bufStat syscall.Stat_t |
|
| 182 |
+ if err := syscall.Lstat(p, &bufStat); err != nil {
|
|
| 183 |
+ return false, err |
|
| 184 |
+ } |
|
| 185 |
+ |
|
| 186 |
+ // return true if it is a btrfs subvolume |
|
| 187 |
+ return bufStat.Ino == C.BTRFS_FIRST_FREE_OBJECTID, nil |
|
| 188 |
+} |
|
| 189 |
+ |
|
| 180 | 190 |
func subvolDelete(dirpath, name string) error {
|
| 181 | 191 |
dir, err := openDir(dirpath) |
| 182 | 192 |
if err != nil {
|
| ... | ... |
@@ -186,35 +181,36 @@ func subvolDelete(dirpath, name string) error {
|
| 186 | 186 |
|
| 187 | 187 |
var args C.struct_btrfs_ioctl_vol_args |
| 188 | 188 |
|
| 189 |
- filepath.Walk(dirpath, |
|
| 190 |
- func(dirpath string, f os.FileInfo, err error) error {
|
|
| 191 |
- if f.IsDir() {
|
|
| 192 |
- isSubvolumes, err := is_subvolume(path.Join(dirpath, f.Name())) |
|
| 193 |
- if err != nil {
|
|
| 194 |
- return err |
|
| 195 |
- } |
|
| 196 |
- if isSubvolumes {
|
|
| 197 |
- for i, c := range []byte(f.Name()) {
|
|
| 198 |
- args.name[i] = C.char(c) |
|
| 199 |
- } |
|
| 200 |
- _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, getDirFd(dir), C.BTRFS_IOC_SNAP_DESTROY, |
|
| 201 |
- uintptr(unsafe.Pointer(&args))) |
|
| 202 |
- if errno != 0 {
|
|
| 203 |
- return fmt.Errorf("Failed to destroy btrfs snapshot: %v", errno.Error())
|
|
| 204 |
- } |
|
| 189 |
+ // walk the btrfs subvolumes |
|
| 190 |
+ walkSubvolumes := func(p string, f os.FileInfo, err error) error {
|
|
| 191 |
+ // we want to check children only so skip itself |
|
| 192 |
+ // it will be removed after the filepath walk anyways |
|
| 193 |
+ if f.IsDir() && p != path.Join(dirpath, name) {
|
|
| 194 |
+ sv, err := isSubvolume(p) |
|
| 195 |
+ if err != nil {
|
|
| 196 |
+ return fmt.Errorf("Failed to test if %s is a btrfs subvolume: %v", p, err)
|
|
| 197 |
+ } |
|
| 198 |
+ if sv {
|
|
| 199 |
+ if err := subvolDelete(p, f.Name()); err != nil {
|
|
| 200 |
+ return fmt.Errorf("Failed to destroy btrfs child subvolume (%s) of parent (%s): %v", p, dirpath, err)
|
|
| 205 | 201 |
} |
| 206 |
- return nil |
|
| 207 | 202 |
} |
| 208 |
- return nil |
|
| 209 |
- }) |
|
| 203 |
+ } |
|
| 204 |
+ return nil |
|
| 205 |
+ } |
|
| 206 |
+ if err := filepath.Walk(path.Join(dirpath, name), walkSubvolumes); err != nil {
|
|
| 207 |
+ return fmt.Errorf("Recursively walking subvolumes for %s failed: %v", dirpath, err)
|
|
| 208 |
+ } |
|
| 210 | 209 |
|
| 210 |
+ // all subvolumes have been removed |
|
| 211 |
+ // now remove the one originally passed in |
|
| 211 | 212 |
for i, c := range []byte(name) {
|
| 212 | 213 |
args.name[i] = C.char(c) |
| 213 | 214 |
} |
| 214 | 215 |
_, _, errno := syscall.Syscall(syscall.SYS_IOCTL, getDirFd(dir), C.BTRFS_IOC_SNAP_DESTROY, |
| 215 | 216 |
uintptr(unsafe.Pointer(&args))) |
| 216 | 217 |
if errno != 0 {
|
| 217 |
- return fmt.Errorf("Failed to destroy btrfs snapshot: %v", errno.Error())
|
|
| 218 |
+ return fmt.Errorf("Failed to destroy btrfs snapshot %s for %s: %v", dirpath, name, errno.Error())
|
|
| 218 | 219 |
} |
| 219 | 220 |
return nil |
| 220 | 221 |
} |