summaryrefslogtreecommitdiffhomepage
path: root/runsc/boot/fs.go
diff options
context:
space:
mode:
Diffstat (limited to 'runsc/boot/fs.go')
-rw-r--r--runsc/boot/fs.go143
1 files changed, 50 insertions, 93 deletions
diff --git a/runsc/boot/fs.go b/runsc/boot/fs.go
index 42e011beb..ea825e571 100644
--- a/runsc/boot/fs.go
+++ b/runsc/boot/fs.go
@@ -103,9 +103,14 @@ func createMountNamespace(userCtx context.Context, rootCtx context.Context, spec
return nil, fmt.Errorf("failed to create root mount namespace: %v", err)
}
- if err := setMounts(rootCtx, conf, mns, fds, mounts); err != nil {
- return nil, fmt.Errorf("failed to configure mounts: %v", err)
+ root := mns.Root()
+ defer root.DecRef()
+ for _, m := range mounts {
+ if err := mountSubmount(rootCtx, conf, mns, root, fds, m, mounts); err != nil {
+ return nil, fmt.Errorf("mount submount: %v", err)
+ }
}
+
if !fds.empty() {
return nil, fmt.Errorf("not all mount points were consumed, remaining: %v", fds)
}
@@ -184,17 +189,6 @@ func compileMounts(spec *specs.Spec) []specs.Mount {
return mounts
}
-// setMounts iterates over mounts and mounts them in the specified
-// mount namespace.
-func setMounts(ctx context.Context, conf *Config, mns *fs.MountNamespace, fds *fdDispenser, mounts []specs.Mount) error {
- for _, m := range mounts {
- if err := mountSubmount(ctx, conf, mns, fds, m, mounts, m.Destination); err != nil {
- return err
- }
- }
- return nil
-}
-
// createRootMount creates the root filesystem.
func createRootMount(ctx context.Context, spec *specs.Spec, conf *Config, fds *fdDispenser, mounts []specs.Mount) (*fs.Inode, error) {
// First construct the filesystem from the spec.Root.
@@ -207,9 +201,9 @@ func createRootMount(ctx context.Context, spec *specs.Spec, conf *Config, fds *f
fd := fds.remove()
log.Infof("Mounting root over 9P, ioFD: %d", fd)
- hostFS := mustFindFilesystem("9p")
+ p9FS := mustFindFilesystem("9p")
opts := p9MountOptions(fd, conf.FileAccess)
- rootInode, err = hostFS.Mount(ctx, rootDevice, mf, strings.Join(opts, ","))
+ rootInode, err = p9FS.Mount(ctx, rootDevice, mf, strings.Join(opts, ","))
if err != nil {
return nil, fmt.Errorf("failed to generate root mount point: %v", err)
}
@@ -294,7 +288,11 @@ func getMountNameAndOptions(conf *Config, m specs.Mount, fds *fdDispenser) (stri
return fsName, opts, useOverlay, err
}
-func mountSubmount(ctx context.Context, conf *Config, mns *fs.MountNamespace, fds *fdDispenser, m specs.Mount, mounts []specs.Mount, dest string) error {
+// mountSubmount mounts volumes inside the container's root. Because mounts may
+// be readonly, a lower ramfs overlay is added to create the mount point dir.
+// Another overlay is added with tmpfs on top if Config.Overlay is true.
+// 'm.Destination' must be an absolute path with '..' and symlinks resolved.
+func mountSubmount(ctx context.Context, conf *Config, mns *fs.MountNamespace, root *fs.Dirent, fds *fdDispenser, m specs.Mount, mounts []specs.Mount) error {
// Map mount type to filesystem name, and parse out the options that we are
// capable of dealing with.
fsName, opts, useOverlay, err := getMountNameAndOptions(conf, m, fds)
@@ -340,60 +338,16 @@ func mountSubmount(ctx context.Context, conf *Config, mns *fs.MountNamespace, fd
}
}
- // Create destination in case it doesn't exist. This is required, in addition
- // to 'addSubmountOverlay', in case there are symlinks to create directories
- // in the right location, e.g.
- // mount: /var/run/secrets, may be created in '/run/secrets' if
- // '/var/run' => '/var'.
- if err := mkdirAll(ctx, mns, dest); err != nil {
- return err
- }
-
- root := mns.Root()
- defer root.DecRef()
- dirent, err := mns.FindInode(ctx, root, nil, dest, linux.MaxSymlinkTraversals)
+ dirent, err := mns.FindInode(ctx, root, root, m.Destination, 0 /* maxTraversals */)
if err != nil {
- return fmt.Errorf("failed to find mount destination %q: %v", dest, err)
+ return fmt.Errorf("failed to find mount destination %q: %v", m.Destination, err)
}
defer dirent.DecRef()
if err := mns.Mount(ctx, dirent, inode); err != nil {
- return fmt.Errorf("failed to mount at destination %q: %v", dest, err)
+ return fmt.Errorf("failed to mount at destination %q: %v", m.Destination, err)
}
- log.Infof("Mounted %q to %q type %s", m.Source, dest, m.Type)
- return nil
-}
-
-func mkdirAll(ctx context.Context, mns *fs.MountNamespace, path string) error {
- log.Infof("mkdirAll called with path %s", path)
- root := mns.Root()
- defer root.DecRef()
-
- // Starting at the root, walk the path.
- parent := root
- ps := strings.Split(filepath.Clean(path), string(filepath.Separator))
- for _, pathElem := range ps {
- if pathElem == "" {
- // This will be case for the first and last element, if the path
- // begins or ends with '/'. Note that we always treat the path as
- // absolute, regardless of what the first character contains.
- continue
- }
- d, err := mns.FindInode(ctx, root, parent, pathElem, fs.DefaultTraversalLimit)
- if err == syserror.ENOENT {
- // If we encounter a path that does not exist, then
- // create it.
- if err := parent.CreateDirectory(ctx, root, pathElem, fs.FilePermsFromMode(0755)); err != nil {
- return fmt.Errorf("failed to create directory %q: %v", pathElem, err)
- }
- if d, err = parent.Walk(ctx, root, pathElem); err != nil {
- return fmt.Errorf("walk to %q failed: %v", pathElem, err)
- }
- } else if err != nil {
- return fmt.Errorf("failed to find inode %q: %v", pathElem, err)
- }
- parent = d
- }
+ log.Infof("Mounted %q to %q type %s", m.Source, m.Destination, m.Type)
return nil
}
@@ -437,14 +391,6 @@ func parseAndFilterOptions(opts []string, allowedKeys ...string) ([]string, erro
return out, nil
}
-func destinations(mounts []specs.Mount, extra ...string) []string {
- var ds []string
- for _, m := range mounts {
- ds = append(ds, m.Destination)
- }
- return append(ds, extra...)
-}
-
// mountDevice returns a device string based on the fs type and target
// of the mount.
func mountDevice(m specs.Mount) string {
@@ -544,7 +490,8 @@ func mustFindFilesystem(name string) fs.Filesystem {
func addSubmountOverlay(ctx context.Context, inode *fs.Inode, submounts []string) (*fs.Inode, error) {
// There is no real filesystem backing this ramfs tree, so we pass in
// "nil" here.
- mountTree, err := ramfs.MakeDirectoryTree(ctx, fs.NewNonCachingMountSource(nil, fs.MountSourceFlags{}), submounts)
+ msrc := fs.NewNonCachingMountSource(nil, fs.MountSourceFlags{})
+ mountTree, err := ramfs.MakeDirectoryTree(ctx, msrc, submounts)
if err != nil {
return nil, fmt.Errorf("error creating mount tree: %v", err)
}
@@ -608,12 +555,16 @@ func setupContainerFS(procArgs *kernel.CreateProcessArgs, spec *specs.Spec, conf
// namespace.
mns := k.RootMountNamespace()
if mns == nil {
+ // Setup the root container.
+
// Create the virtual filesystem.
mns, err := createMountNamespace(ctx, rootCtx, spec, conf, goferFDs)
if err != nil {
return fmt.Errorf("error creating mounts: %v", err)
}
k.SetRootMountNamespace(mns)
+
+ // We're done with root container.
return nil
}
@@ -627,42 +578,48 @@ func setupContainerFS(procArgs *kernel.CreateProcessArgs, spec *specs.Spec, conf
return fmt.Errorf("error creating filesystem for container: %v", err)
}
- // Make directories for submounts within the container.
- rootDir := mns.Root()
- defer rootDir.DecRef()
- containerRoot := filepath.Join(ChildContainersDir, cid)
- mkdirAll(ctx, mns, containerRoot)
+ globalRoot := mns.Root()
+ defer globalRoot.DecRef()
- // Mount the container's root filesystem to the newly created
- // mount point.
- containerRootDirent, err := mns.FindInode(ctx, rootDir, nil, containerRoot, linux.MaxSymlinkTraversals)
+ // Create mount point for the container's rootfs.
+ contDir, err := mns.FindInode(ctx, globalRoot, nil, ChildContainersDir, 0 /* TraversalLimit */)
if err != nil {
- return fmt.Errorf("failed to find mount destination: %q: %v", containerRoot, err)
+ return fmt.Errorf("couldn't find child container dir %q: %v", ChildContainersDir, err)
}
- if err := mns.Mount(ctx, containerRootDirent, rootInode); err != nil {
- return fmt.Errorf("failed to mount at destination %q: %v", containerRoot, err)
+ if err := contDir.CreateDirectory(ctx, globalRoot, cid, fs.FilePermsFromMode(0755)); err != nil {
+ return fmt.Errorf("create directory %q: %v", cid, err)
+ }
+ containerRoot, err := contDir.Walk(ctx, globalRoot, cid)
+ if err != nil {
+ return fmt.Errorf("walk to %q failed: %v", cid, err)
+ }
+ defer containerRoot.DecRef()
+
+ // Mount the container's root filesystem to the newly created mount point.
+ if err := mns.Mount(ctx, containerRoot, rootInode); err != nil {
+ return fmt.Errorf("mount container root: %v", err)
}
- containerRootDirent.DecRef()
// We have to re-walk to the dirent to find the mounted
// directory. The old dirent is invalid at this point.
- containerRootDirent, err = mns.FindInode(ctx, rootDir, nil, containerRoot, linux.MaxSymlinkTraversals)
+ containerRoot, err = contDir.Walk(ctx, globalRoot, cid)
if err != nil {
- return fmt.Errorf("failed to find mount destination2: %q: %v", containerRoot, err)
+ return fmt.Errorf("find container mount point %q: %v", cid, err)
}
- log.Infof("Mounted child's root fs to %q", containerRoot)
+
+ log.Infof("Mounted child's root fs to %q", filepath.Join(ChildContainersDir, cid))
// Mount all submounts.
mounts := compileMounts(spec)
for _, m := range mounts {
- dest := filepath.Join(containerRoot, m.Destination)
- if err := mountSubmount(rootCtx, conf, k.RootMountNamespace(), fds, m, mounts, dest); err != nil {
+ if err := mountSubmount(rootCtx, conf, k.RootMountNamespace(), containerRoot, fds, m, mounts); err != nil {
+ containerRoot.DecRef()
return fmt.Errorf("error mounting filesystem for container: %v", err)
}
}
// Set the procArgs root directory.
- procArgs.Root = containerRootDirent
+ procArgs.Root = containerRoot
return nil
}
@@ -686,7 +643,7 @@ func destroyContainerFS(ctx context.Context, cid string, k *kernel.Kernel) error
mnsRoot := mns.Root()
defer mnsRoot.DecRef()
containerRoot := path.Join(ChildContainersDir, cid)
- containerRootDirent, err := mns.FindInode(ctx, mnsRoot, nil, containerRoot, linux.MaxSymlinkTraversals)
+ containerRootDirent, err := mns.FindInode(ctx, mnsRoot, nil, containerRoot, 0 /* maxTraversals */)
if err == syserror.ENOENT {
// Container must have been destroyed already. That's fine.
return nil
@@ -720,7 +677,7 @@ func destroyContainerFS(ctx context.Context, cid string, k *kernel.Kernel) error
// Get a reference to the parent directory and remove the root
// container directory.
- containersDirDirent, err := mns.FindInode(ctx, mnsRoot, nil, ChildContainersDir, linux.MaxSymlinkTraversals)
+ containersDirDirent, err := mns.FindInode(ctx, mnsRoot, nil, ChildContainersDir, 0 /* maxTraversals */)
if err != nil {
return fmt.Errorf("error finding containers directory %q: %v", ChildContainersDir, err)
}