[vfs] Create recursive dir creation util.

Refactored the recursive dir creation util in runsc/boot/vfs.go to be more
flexible.

PiperOrigin-RevId: 327719100
This commit is contained in:
Ayush Ranjan
2020-08-20 16:28:31 -07:00
committed by gVisor bot
parent e8a25a2834
commit 73c69cb4d8
2 changed files with 35 additions and 30 deletions
+33
View File
@@ -36,6 +36,7 @@ package vfs
import (
"fmt"
"path"
"gvisor.dev/gvisor/pkg/abi/linux"
"gvisor.dev/gvisor/pkg/context"
@@ -782,6 +783,38 @@ func (vfs *VirtualFilesystem) SyncAllFilesystems(ctx context.Context) error {
return retErr
}
// MkdirAllAt recursively creates non-existent directories on the given path
// (including the last component).
func (vfs *VirtualFilesystem) MkdirAllAt(ctx context.Context, currentPath string, root VirtualDentry, creds *auth.Credentials, mkdirOpts *MkdirOptions) error {
pop := &PathOperation{
Root: root,
Start: root,
Path: fspath.Parse(currentPath),
}
stat, err := vfs.StatAt(ctx, creds, pop, &StatOptions{Mask: linux.STATX_TYPE})
switch err {
case nil:
if stat.Mask&linux.STATX_TYPE == 0 || stat.Mode&linux.FileTypeMask != linux.ModeDirectory {
return syserror.ENOTDIR
}
// Directory already exists.
return nil
case syserror.ENOENT:
// Expected, we will create the dir.
default:
return fmt.Errorf("stat failed for %q during directory creation: %w", currentPath, err)
}
// Recurse to ensure parent is created and then create the final directory.
if err := vfs.MkdirAllAt(ctx, path.Dir(currentPath), root, creds, mkdirOpts); err != nil {
return err
}
if err := vfs.MkdirAt(ctx, creds, pop, mkdirOpts); err != nil {
return fmt.Errorf("failed to create directory %q: %w", currentPath, err)
}
return nil
}
// A VirtualDentry represents a node in a VFS tree, by combining a Dentry
// (which represents a node in a Filesystem's tree) and a Mount (which
// represents the Filesystem's position in a VFS mount tree).
+2 -30
View File
@@ -16,7 +16,6 @@ package boot
import (
"fmt"
"path"
"sort"
"strings"
@@ -274,7 +273,7 @@ func (c *containerMounter) mountSubmountVFS2(ctx context.Context, conf *config.C
return nil
}
if err := c.makeSyntheticMount(ctx, submount.Destination, root, creds); err != nil {
if err := c.k.VFS().MkdirAllAt(ctx, submount.Destination, root, creds, &vfs.MkdirOptions{Mode: 0777, ForSyntheticMountpoint: true}); err != nil {
return err
}
if err := c.k.VFS().MountAt(ctx, creds, "", target, fsName, opts); err != nil {
@@ -348,33 +347,6 @@ func (c *containerMounter) getMountNameAndOptionsVFS2(conf *config.Config, m *mo
return fsName, opts, nil
}
func (c *containerMounter) makeSyntheticMount(ctx context.Context, currentPath string, root vfs.VirtualDentry, creds *auth.Credentials) error {
target := &vfs.PathOperation{
Root: root,
Start: root,
Path: fspath.Parse(currentPath),
}
_, err := c.k.VFS().StatAt(ctx, creds, target, &vfs.StatOptions{})
if err == nil {
log.Debugf("Mount point %q already exists", currentPath)
return nil
}
if err != syserror.ENOENT {
return fmt.Errorf("stat failed for %q during mount point creation: %w", currentPath, err)
}
// Recurse to ensure parent is created and then create the mount point.
if err := c.makeSyntheticMount(ctx, path.Dir(currentPath), root, creds); err != nil {
return err
}
log.Debugf("Creating dir %q for mount point", currentPath)
mkdirOpts := &vfs.MkdirOptions{Mode: 0777, ForSyntheticMountpoint: true}
if err := c.k.VFS().MkdirAt(ctx, creds, target, mkdirOpts); err != nil {
return fmt.Errorf("failed to create directory %q for mount: %w", currentPath, err)
}
return nil
}
// mountTmpVFS2 mounts an internal tmpfs at '/tmp' if it's safe to do so.
// Technically we don't have to mount tmpfs at /tmp, as we could just rely on
// the host /tmp, but this is a nice optimization, and fixes some apps that call
@@ -503,7 +475,7 @@ func (c *containerMounter) mountSharedSubmountVFS2(ctx context.Context, conf *co
root := mns.Root()
defer root.DecRef(ctx)
if err := c.makeSyntheticMount(ctx, mount.Destination, root, creds); err != nil {
if err := c.k.VFS().MkdirAllAt(ctx, mount.Destination, root, creds, &vfs.MkdirOptions{Mode: 0777, ForSyntheticMountpoint: true}); err != nil {
return err
}