Add symlink follow into unmount util.

Signed-off-by: Lantao Liu <lantaol@google.com>
This commit is contained in:
Lantao Liu 2018-03-23 23:31:19 +00:00
parent 94df315de8
commit f4c9ef2647
4 changed files with 54 additions and 32 deletions

View File

@ -25,6 +25,7 @@ import (
containerdmount "github.com/containerd/containerd/mount" containerdmount "github.com/containerd/containerd/mount"
"github.com/containerd/fifo" "github.com/containerd/fifo"
"github.com/docker/docker/pkg/mount" "github.com/docker/docker/pkg/mount"
"github.com/docker/docker/pkg/symlink"
"golang.org/x/net/context" "golang.org/x/net/context"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
) )
@ -37,6 +38,7 @@ type OS interface {
OpenFifo(ctx context.Context, fn string, flag int, perm os.FileMode) (io.ReadWriteCloser, error) OpenFifo(ctx context.Context, fn string, flag int, perm os.FileMode) (io.ReadWriteCloser, error)
Stat(name string) (os.FileInfo, error) Stat(name string) (os.FileInfo, error)
ResolveSymbolicLink(name string) (string, error) ResolveSymbolicLink(name string) (string, error)
FollowSymlinkInScope(path, scope string) (string, error)
CopyFile(src, dest string, perm os.FileMode) error CopyFile(src, dest string, perm os.FileMode) error
WriteFile(filename string, data []byte, perm os.FileMode) error WriteFile(filename string, data []byte, perm os.FileMode) error
Mount(source string, target string, fstype string, flags uintptr, data string) error Mount(source string, target string, fstype string, flags uintptr, data string) error
@ -79,6 +81,11 @@ func (RealOS) ResolveSymbolicLink(path string) (string, error) {
return filepath.EvalSymlinks(path) return filepath.EvalSymlinks(path)
} }
// FollowSymlinkInScope will call symlink.FollowSymlinkInScope.
func (RealOS) FollowSymlinkInScope(path, scope string) (string, error) {
return symlink.FollowSymlinkInScope(path, scope)
}
// CopyFile will copy src file to dest file // CopyFile will copy src file to dest file
func (RealOS) CopyFile(src, dest string, perm os.FileMode) error { func (RealOS) CopyFile(src, dest string, perm os.FileMode) error {
in, err := os.Open(src) in, err := os.Open(src)
@ -107,17 +114,21 @@ func (RealOS) Mount(source string, target string, fstype string, flags uintptr,
return unix.Mount(source, target, fstype, flags, data) return unix.Mount(source, target, fstype, flags, data)
} }
// Unmount will call unix.Unmount to unmount the file. The function doesn't // Unmount will call Unmount to unmount the file.
// return error if target is not mounted.
func (RealOS) Unmount(target string, flags int) error { func (RealOS) Unmount(target string, flags int) error {
// TODO(random-liu): Follow symlink to make sure the result is correct. return Unmount(target, flags)
if mounted, err := mount.Mounted(target); err != nil || !mounted {
return err
}
return unix.Unmount(target, flags)
} }
// LookupMount gets mount info of a given path. // LookupMount gets mount info of a given path.
func (RealOS) LookupMount(path string) (containerdmount.Info, error) { func (RealOS) LookupMount(path string) (containerdmount.Info, error) {
return containerdmount.Lookup(path) return containerdmount.Lookup(path)
} }
// Unmount will call unix.Unmount to unmount the file. The function doesn't
// return error if target is not mounted.
func Unmount(target string, flags int) error {
if mounted, err := mount.Mounted(target); err != nil || !mounted {
return err
}
return unix.Unmount(target, flags)
}

View File

@ -45,6 +45,7 @@ type FakeOS struct {
OpenFifoFn func(context.Context, string, int, os.FileMode) (io.ReadWriteCloser, error) OpenFifoFn func(context.Context, string, int, os.FileMode) (io.ReadWriteCloser, error)
StatFn func(string) (os.FileInfo, error) StatFn func(string) (os.FileInfo, error)
ResolveSymbolicLinkFn func(string) (string, error) ResolveSymbolicLinkFn func(string) (string, error)
FollowSymlinkInScopeFn func(string, string) (string, error)
CopyFileFn func(string, string, os.FileMode) error CopyFileFn func(string, string, os.FileMode) error
WriteFileFn func(string, []byte, os.FileMode) error WriteFileFn func(string, []byte, os.FileMode) error
MountFn func(source string, target string, fstype string, flags uintptr, data string) error MountFn func(source string, target string, fstype string, flags uintptr, data string) error
@ -176,6 +177,19 @@ func (f *FakeOS) ResolveSymbolicLink(path string) (string, error) {
return path, nil return path, nil
} }
// FollowSymlinkInScope is a fake call that invokes FollowSymlinkInScope or returns its input
func (f *FakeOS) FollowSymlinkInScope(path, scope string) (string, error) {
f.appendCalls("FollowSymlinkInScope", path, scope)
if err := f.getError("FollowSymlinkInScope"); err != nil {
return "", err
}
if f.FollowSymlinkInScopeFn != nil {
return f.FollowSymlinkInScopeFn(path, scope)
}
return path, nil
}
// CopyFile is a fake call that invokes CopyFileFn or just return nil. // CopyFile is a fake call that invokes CopyFileFn or just return nil.
func (f *FakeOS) CopyFile(src, dest string, perm os.FileMode) error { func (f *FakeOS) CopyFile(src, dest string, perm os.FileMode) error {
f.appendCalls("CopyFile", src, dest, perm) f.appendCalls("CopyFile", src, dest, perm)

View File

@ -491,8 +491,12 @@ func parseDNSOptions(servers, searches, options []string) (string, error) {
// 2) The mount point doesn't exist. // 2) The mount point doesn't exist.
func (c *criService) unmountSandboxFiles(id string, config *runtime.PodSandboxConfig) error { func (c *criService) unmountSandboxFiles(id string, config *runtime.PodSandboxConfig) error {
if config.GetLinux().GetSecurityContext().GetNamespaceOptions().GetIpc() != runtime.NamespaceMode_NODE { if config.GetLinux().GetSecurityContext().GetNamespaceOptions().GetIpc() != runtime.NamespaceMode_NODE {
if err := c.os.Unmount(c.getSandboxDevShm(id), unix.MNT_DETACH); err != nil && !os.IsNotExist(err) { path, err := c.os.FollowSymlinkInScope(c.getSandboxDevShm(id), "/")
return err if err != nil {
return errors.Wrap(err, "failed to follow symlink")
}
if err := c.os.Unmount(path, unix.MNT_DETACH); err != nil && !os.IsNotExist(err) {
return errors.Wrapf(err, "failed to unmount %q", path)
} }
} }
return nil return nil

View File

@ -21,10 +21,11 @@ import (
"sync" "sync"
cnins "github.com/containernetworking/plugins/pkg/ns" cnins "github.com/containernetworking/plugins/pkg/ns"
"github.com/docker/docker/pkg/mount"
"github.com/docker/docker/pkg/symlink" "github.com/docker/docker/pkg/symlink"
"github.com/pkg/errors" "github.com/pkg/errors"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
osinterface "github.com/containerd/cri/pkg/os"
) )
// ErrClosedNetNS is the error returned when network namespace is closed. // ErrClosedNetNS is the error returned when network namespace is closed.
@ -81,7 +82,6 @@ func (n *NetNS) Remove() error {
} }
if n.restored { if n.restored {
path := n.ns.Path() path := n.ns.Path()
// TODO(random-liu): Add util function for unmount.
// Check netns existence. // Check netns existence.
if _, err := os.Stat(path); err != nil { if _, err := os.Stat(path); err != nil {
if os.IsNotExist(err) { if os.IsNotExist(err) {
@ -93,16 +93,9 @@ func (n *NetNS) Remove() error {
if err != nil { if err != nil {
return errors.Wrap(err, "failed to follow symlink") return errors.Wrap(err, "failed to follow symlink")
} }
mounted, err := mount.Mounted(path) if err := osinterface.Unmount(path, unix.MNT_DETACH); err != nil && !os.IsNotExist(err) {
if err != nil {
return errors.Wrap(err, "failed to check netns mounted")
}
if mounted {
err := unix.Unmount(path, unix.MNT_DETACH)
if err != nil && !os.IsNotExist(err) {
return errors.Wrap(err, "failed to umount netns") return errors.Wrap(err, "failed to umount netns")
} }
}
if err := os.RemoveAll(path); err != nil { if err := os.RemoveAll(path); err != nil {
return errors.Wrap(err, "failed to remove netns") return errors.Wrap(err, "failed to remove netns")
} }