Merge pull request #8789 from slonopotamus/macos-bind-mount
Add support for bind-mounts on Darwin (a.k.a. "make native snapshotter work")
This commit is contained in:
commit
e5a49e6ceb
@ -1,47 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright The containerd Authors.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package apply
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/containerd/containerd/archive"
|
|
||||||
"github.com/containerd/containerd/mount"
|
|
||||||
)
|
|
||||||
|
|
||||||
func apply(ctx context.Context, mounts []mount.Mount, r io.Reader) error {
|
|
||||||
// We currently do not support mounts nor bind mounts on MacOS in the containerd daemon.
|
|
||||||
// Using this as an exception to enable native snapshotter and allow further research.
|
|
||||||
if len(mounts) == 1 && mounts[0].Type == "bind" {
|
|
||||||
opts := []archive.ApplyOpt{}
|
|
||||||
|
|
||||||
if os.Getuid() != 0 {
|
|
||||||
opts = append(opts, archive.WithNoSameOwner())
|
|
||||||
}
|
|
||||||
|
|
||||||
path := mounts[0].Source
|
|
||||||
_, err := archive.Apply(ctx, path, r, opts...)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return mount.WithTempMount(ctx, mounts, func(root string) error {
|
|
||||||
_, err := archive.Apply(ctx, root, r)
|
|
||||||
return err
|
|
||||||
})
|
|
||||||
}
|
|
@ -1,4 +1,4 @@
|
|||||||
//go:build !linux && !darwin
|
//go:build !linux
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Copyright The containerd Authors.
|
Copyright The containerd Authors.
|
||||||
|
50
mount/fuse_linux.go
Normal file
50
mount/fuse_linux.go
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
Copyright The containerd Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package mount
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os/exec"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
// fuseSuperMagic is defined in statfs(2)
|
||||||
|
const fuseSuperMagic = 0x65735546
|
||||||
|
|
||||||
|
func isFUSE(dir string) bool {
|
||||||
|
var st unix.Statfs_t
|
||||||
|
if err := unix.Statfs(dir, &st); err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return st.Type == fuseSuperMagic
|
||||||
|
}
|
||||||
|
|
||||||
|
// unmountFUSE attempts to unmount using fusermount/fusermount3 helper binary.
|
||||||
|
//
|
||||||
|
// For FUSE mounts, using these helper binaries is preferred, see:
|
||||||
|
// https://github.com/containerd/containerd/pull/3765#discussion_r342083514
|
||||||
|
func unmountFUSE(target string) error {
|
||||||
|
var err error
|
||||||
|
for _, helperBinary := range []string{"fusermount3", "fusermount"} {
|
||||||
|
cmd := exec.Command(helperBinary, "-u", target)
|
||||||
|
err = cmd.Run()
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
30
mount/fuse_unsupported.go
Normal file
30
mount/fuse_unsupported.go
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
//go:build !linux && !windows
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright The containerd Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package mount
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func isFUSE(dir string) bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// unmountFUSE is not implemented on this platform
|
||||||
|
func unmountFUSE(target string) error {
|
||||||
|
return fmt.Errorf("FUSE is not supported on this platform")
|
||||||
|
}
|
42
mount/mount_darwin.go
Normal file
42
mount/mount_darwin.go
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
Copyright The containerd Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package mount
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os/exec"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Mount to the provided target.
|
||||||
|
func (m *Mount) mount(target string) error {
|
||||||
|
// See https://github.com/slonopotamus/containerd-darwin-mount-helper for reference implementation
|
||||||
|
const commandName = "containerd-darwin-mount-helper"
|
||||||
|
|
||||||
|
args := []string{"-t", m.Type}
|
||||||
|
for _, option := range m.Options {
|
||||||
|
args = append(args, "-o", option)
|
||||||
|
}
|
||||||
|
args = append(args, m.Source, target)
|
||||||
|
|
||||||
|
cmd := exec.Command(commandName, args...)
|
||||||
|
output, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("%s [%v] failed: %q: %w", commandName, args, string(output), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
@ -19,18 +19,11 @@ package mount
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os/exec"
|
||||||
"time"
|
|
||||||
|
|
||||||
exec "golang.org/x/sys/execabs"
|
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
|
||||||
// ErrNotImplementOnUnix is returned for methods that are not implemented
|
|
||||||
ErrNotImplementOnUnix = errors.New("not implemented under unix")
|
|
||||||
)
|
|
||||||
|
|
||||||
// Mount to the provided target.
|
// Mount to the provided target.
|
||||||
//
|
//
|
||||||
// The "syscall" and "golang.org/x/sys/unix" packages do not define a Mount
|
// The "syscall" and "golang.org/x/sys/unix" packages do not define a Mount
|
||||||
@ -77,57 +70,3 @@ func (m *Mount) mount(target string) error {
|
|||||||
}
|
}
|
||||||
return fmt.Errorf("mount [%v] failed with ECHILD (retried %d times)", args, retriesOnECHILD)
|
return fmt.Errorf("mount [%v] failed with ECHILD (retried %d times)", args, retriesOnECHILD)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unmount the provided mount path with the flags
|
|
||||||
func Unmount(target string, flags int) error {
|
|
||||||
if err := unmount(target, flags); err != nil && err != unix.EINVAL {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func unmount(target string, flags int) error {
|
|
||||||
for i := 0; i < 50; i++ {
|
|
||||||
if err := unix.Unmount(target, flags); err != nil {
|
|
||||||
switch err {
|
|
||||||
case unix.EBUSY:
|
|
||||||
time.Sleep(50 * time.Millisecond)
|
|
||||||
continue
|
|
||||||
default:
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return fmt.Errorf("failed to unmount target %s: %w", target, unix.EBUSY)
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnmountAll repeatedly unmounts the given mount point until there
|
|
||||||
// are no mounts remaining (EINVAL is returned by mount), which is
|
|
||||||
// useful for undoing a stack of mounts on the same mount point.
|
|
||||||
// UnmountAll all is noop when the first argument is an empty string.
|
|
||||||
// This is done when the containerd client did not specify any rootfs
|
|
||||||
// mounts (e.g. because the rootfs is managed outside containerd)
|
|
||||||
// UnmountAll is noop when the mount path does not exist.
|
|
||||||
func UnmountAll(mount string, flags int) error {
|
|
||||||
if mount == "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if _, err := os.Stat(mount); os.IsNotExist(err) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
for {
|
|
||||||
if err := unmount(mount, flags); err != nil {
|
|
||||||
// EINVAL is returned if the target is not a
|
|
||||||
// mount point, indicating that we are
|
|
||||||
// done. It can also indicate a few other
|
|
||||||
// things (such as invalid flags) which we
|
|
||||||
// unfortunately end up squelching here too.
|
|
||||||
if err == unix.EINVAL {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -23,7 +23,6 @@ import (
|
|||||||
"path"
|
"path"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
exec "golang.org/x/sys/execabs"
|
exec "golang.org/x/sys/execabs"
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
@ -120,92 +119,6 @@ func (m *Mount) mount(target string) (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unmount the provided mount path with the flags
|
|
||||||
func Unmount(target string, flags int) error {
|
|
||||||
if err := unmount(target, flags); err != nil && err != unix.EINVAL {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// fuseSuperMagic is defined in statfs(2)
|
|
||||||
const fuseSuperMagic = 0x65735546
|
|
||||||
|
|
||||||
func isFUSE(dir string) bool {
|
|
||||||
var st unix.Statfs_t
|
|
||||||
if err := unix.Statfs(dir, &st); err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return st.Type == fuseSuperMagic
|
|
||||||
}
|
|
||||||
|
|
||||||
// unmountFUSE attempts to unmount using fusermount/fusermount3 helper binary.
|
|
||||||
//
|
|
||||||
// For FUSE mounts, using these helper binaries is preferred, see:
|
|
||||||
// https://github.com/containerd/containerd/pull/3765#discussion_r342083514
|
|
||||||
func unmountFUSE(target string) error {
|
|
||||||
var err error
|
|
||||||
for _, helperBinary := range []string{"fusermount3", "fusermount"} {
|
|
||||||
cmd := exec.Command(helperBinary, "-u", target)
|
|
||||||
err = cmd.Run()
|
|
||||||
if err == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func unmount(target string, flags int) error {
|
|
||||||
if isFUSE(target) {
|
|
||||||
if err := unmountFUSE(target); err == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for i := 0; i < 50; i++ {
|
|
||||||
if err := unix.Unmount(target, flags); err != nil {
|
|
||||||
switch err {
|
|
||||||
case unix.EBUSY:
|
|
||||||
time.Sleep(50 * time.Millisecond)
|
|
||||||
continue
|
|
||||||
default:
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return fmt.Errorf("failed to unmount target %s: %w", target, unix.EBUSY)
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnmountAll repeatedly unmounts the given mount point until there
|
|
||||||
// are no mounts remaining (EINVAL is returned by mount), which is
|
|
||||||
// useful for undoing a stack of mounts on the same mount point.
|
|
||||||
// UnmountAll all is noop when the first argument is an empty string.
|
|
||||||
// This is done when the containerd client did not specify any rootfs
|
|
||||||
// mounts (e.g. because the rootfs is managed outside containerd)
|
|
||||||
// UnmountAll is noop when the mount path does not exist.
|
|
||||||
func UnmountAll(mount string, flags int) error {
|
|
||||||
if mount == "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if _, err := os.Stat(mount); os.IsNotExist(err) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
for {
|
|
||||||
if err := unmount(mount, flags); err != nil {
|
|
||||||
// EINVAL is returned if the target is not a
|
|
||||||
// mount point, indicating that we are
|
|
||||||
// done. It can also indicate a few other
|
|
||||||
// things (such as invalid flags) which we
|
|
||||||
// unfortunately end up squelching here too.
|
|
||||||
if err == unix.EINVAL {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// parseMountOptions takes fstab style mount options and parses them for
|
// parseMountOptions takes fstab style mount options and parses them for
|
||||||
// use with a standard mount() syscall
|
// use with a standard mount() syscall
|
||||||
func parseMountOptions(options []string) (int, []string, bool) {
|
func parseMountOptions(options []string) (int, []string, bool) {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
//go:build !windows && !darwin && !openbsd
|
//go:build !windows && !openbsd
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Copyright The containerd Authors.
|
Copyright The containerd Authors.
|
||||||
@ -19,9 +19,13 @@
|
|||||||
package mount
|
package mount
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
"sort"
|
"sort"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/moby/sys/mountinfo"
|
"github.com/moby/sys/mountinfo"
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
)
|
)
|
||||||
|
|
||||||
// UnmountRecursive unmounts the target and all mounts underneath, starting
|
// UnmountRecursive unmounts the target and all mounts underneath, starting
|
||||||
@ -59,3 +63,64 @@ func UnmountRecursive(target string, flags int) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func unmount(target string, flags int) error {
|
||||||
|
if isFUSE(target) {
|
||||||
|
// TODO: Why error is ignored?
|
||||||
|
// Shouldn't this just be "return unmountFUSE(target)"?
|
||||||
|
if err := unmountFUSE(target); err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i := 0; i < 50; i++ {
|
||||||
|
if err := unix.Unmount(target, flags); err != nil {
|
||||||
|
switch err {
|
||||||
|
case unix.EBUSY:
|
||||||
|
time.Sleep(50 * time.Millisecond)
|
||||||
|
continue
|
||||||
|
default:
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return fmt.Errorf("failed to unmount target %s: %w", target, unix.EBUSY)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmount the provided mount path with the flags
|
||||||
|
func Unmount(target string, flags int) error {
|
||||||
|
if err := unmount(target, flags); err != nil && err != unix.EINVAL {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmountAll repeatedly unmounts the given mount point until there
|
||||||
|
// are no mounts remaining (EINVAL is returned by mount), which is
|
||||||
|
// useful for undoing a stack of mounts on the same mount point.
|
||||||
|
// UnmountAll all is noop when the first argument is an empty string.
|
||||||
|
// This is done when the containerd client did not specify any rootfs
|
||||||
|
// mounts (e.g. because the rootfs is managed outside containerd)
|
||||||
|
// UnmountAll is noop when the mount path does not exist.
|
||||||
|
func UnmountAll(mount string, flags int) error {
|
||||||
|
if mount == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if _, err := os.Stat(mount); os.IsNotExist(err) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
if err := unmount(mount, flags); err != nil {
|
||||||
|
// EINVAL is returned if the target is not a
|
||||||
|
// mount point, indicating that we are
|
||||||
|
// done. It can also indicate a few other
|
||||||
|
// things (such as invalid flags) which we
|
||||||
|
// unfortunately end up squelching here too.
|
||||||
|
if err == unix.EINVAL {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
//go:build darwin || openbsd
|
//go:build openbsd
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Copyright The containerd Authors.
|
Copyright The containerd Authors.
|
||||||
@ -18,29 +18,26 @@
|
|||||||
|
|
||||||
package mount
|
package mount
|
||||||
|
|
||||||
import "errors"
|
import (
|
||||||
|
"github.com/containerd/containerd/errdefs"
|
||||||
var (
|
|
||||||
// ErrNotImplementOnUnix is returned for methods that are not implemented
|
|
||||||
ErrNotImplementOnUnix = errors.New("not implemented under unix")
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Mount is not implemented on this platform
|
// Mount is not implemented on this platform
|
||||||
func (m *Mount) mount(target string) error {
|
func (m *Mount) mount(target string) error {
|
||||||
return ErrNotImplementOnUnix
|
return errdefs.ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unmount is not implemented on this platform
|
// Unmount is not implemented on this platform
|
||||||
func Unmount(mount string, flags int) error {
|
func Unmount(mount string, flags int) error {
|
||||||
return ErrNotImplementOnUnix
|
return errdefs.ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmountAll is not implemented on this platform
|
// UnmountAll is not implemented on this platform
|
||||||
func UnmountAll(mount string, flags int) error {
|
func UnmountAll(mount string, flags int) error {
|
||||||
return ErrNotImplementOnUnix
|
return errdefs.ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmountRecursive is not implemented on this platform
|
// UnmountRecursive is not implemented on this platform
|
||||||
func UnmountRecursive(mount string, flags int) error {
|
func UnmountRecursive(mount string, flags int) error {
|
||||||
return ErrNotImplementOnUnix
|
return errdefs.ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
@ -33,11 +33,6 @@ import (
|
|||||||
|
|
||||||
const sourceStreamName = "containerd.io-source"
|
const sourceStreamName = "containerd.io-source"
|
||||||
|
|
||||||
var (
|
|
||||||
// ErrNotImplementOnWindows is returned when an action is not implemented for windows
|
|
||||||
ErrNotImplementOnWindows = errors.New("not implemented under windows")
|
|
||||||
)
|
|
||||||
|
|
||||||
// Mount to the provided target.
|
// Mount to the provided target.
|
||||||
func (m *Mount) mount(target string) (retErr error) {
|
func (m *Mount) mount(target string) (retErr error) {
|
||||||
if m.Type != "windows-layer" {
|
if m.Type != "windows-layer" {
|
||||||
|
@ -19,12 +19,13 @@
|
|||||||
package os
|
package os
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/containerd/containerd/errdefs"
|
||||||
"github.com/containerd/containerd/mount"
|
"github.com/containerd/containerd/mount"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Mount will call unix.Mount to mount the file.
|
// Mount will call unix.Mount to mount the file.
|
||||||
func (RealOS) Mount(source string, target string, fstype string, flags uintptr, data string) error {
|
func (RealOS) Mount(source string, target string, fstype string, flags uintptr, data string) error {
|
||||||
return mount.ErrNotImplementOnUnix
|
return errdefs.ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unmount will call Unmount to unmount the file.
|
// Unmount will call Unmount to unmount the file.
|
||||||
|
@ -21,7 +21,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
|
||||||
|
|
||||||
"github.com/containerd/containerd/identifiers"
|
"github.com/containerd/containerd/identifiers"
|
||||||
"github.com/containerd/containerd/mount"
|
"github.com/containerd/containerd/mount"
|
||||||
@ -129,11 +128,9 @@ type Bundle struct {
|
|||||||
func (b *Bundle) Delete() error {
|
func (b *Bundle) Delete() error {
|
||||||
work, werr := os.Readlink(filepath.Join(b.Path, "work"))
|
work, werr := os.Readlink(filepath.Join(b.Path, "work"))
|
||||||
rootfs := filepath.Join(b.Path, "rootfs")
|
rootfs := filepath.Join(b.Path, "rootfs")
|
||||||
if runtime.GOOS != "darwin" {
|
|
||||||
if err := mount.UnmountRecursive(rootfs, 0); err != nil {
|
if err := mount.UnmountRecursive(rootfs, 0); err != nil {
|
||||||
return fmt.Errorf("unmount rootfs %s: %w", rootfs, err)
|
return fmt.Errorf("unmount rootfs %s: %w", rootfs, err)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if err := os.Remove(rootfs); err != nil && !os.IsNotExist(err) {
|
if err := os.Remove(rootfs); err != nil && !os.IsNotExist(err) {
|
||||||
return fmt.Errorf("failed to remove bundle rootfs: %w", err)
|
return fmt.Errorf("failed to remove bundle rootfs: %w", err)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user