summaryrefslogtreecommitdiffhomepage
path: root/runsc/boot/vfs.go
diff options
context:
space:
mode:
authorAyush Ranjan <ayushranjan@google.com>2020-08-07 20:06:39 -0700
committergVisor bot <gvisor-bot@google.com>2020-08-07 20:08:47 -0700
commit3be26a271cd0fc9618fbcb34e1a2a84c4f234c86 (patch)
tree1ff6717aae2104543670375cb9c90010b2efccf4 /runsc/boot/vfs.go
parent977618c8e155c0178979ff9f8ea05bbb5c0886b5 (diff)
[vfs2] Fix tmpfs mounting.
Earlier we were using NLink to decide if /tmp is empty or not. However, NLink at best tells us about the number of subdirectories (via the ".." entries). NLink = n + 2 for n subdirectories. But it does not tell us if the directory is empty. There still might be non-directory files. We could also not rely on NLink because host overlayfs always returned 1. VFS1 uses Readdir to decide if the directory is empty. Used a similar approach. We now use IterDirents to decide if the "/tmp" directory is empty. Fixes #3369 PiperOrigin-RevId: 325554234
Diffstat (limited to 'runsc/boot/vfs.go')
-rw-r--r--runsc/boot/vfs.go27
1 files changed, 19 insertions, 8 deletions
diff --git a/runsc/boot/vfs.go b/runsc/boot/vfs.go
index e7d6035bb..08dce8b6c 100644
--- a/runsc/boot/vfs.go
+++ b/runsc/boot/vfs.go
@@ -400,21 +400,28 @@ func (c *containerMounter) mountTmpVFS2(ctx context.Context, conf *Config, creds
Path: fspath.Parse("/tmp"),
}
// TODO(gvisor.dev/issue/2782): Use O_PATH when available.
- statx, err := c.k.VFS().StatAt(ctx, creds, &pop, &vfs.StatOptions{})
+ fd, err := c.k.VFS().OpenAt(ctx, creds, &pop, &vfs.OpenOptions{Flags: linux.O_RDONLY | linux.O_DIRECTORY})
switch err {
case nil:
- // Found '/tmp' in filesystem, check if it's empty.
- if linux.FileMode(statx.Mode).FileType() != linux.ModeDirectory {
- // Not a dir?! Leave it be.
+ defer fd.DecRef(ctx)
+
+ err := fd.IterDirents(ctx, vfs.IterDirentsCallbackFunc(func(dirent vfs.Dirent) error {
+ if dirent.Name != "." && dirent.Name != ".." {
+ return syserror.ENOTEMPTY
+ }
return nil
- }
- if statx.Nlink > 2 {
+ }))
+ switch err {
+ case nil:
+ log.Infof(`Mounting internal tmpfs on top of empty "/tmp"`)
+ case syserror.ENOTEMPTY:
// If more than "." and ".." is found, skip internal tmpfs to prevent
// hiding existing files.
log.Infof(`Skipping internal tmpfs mount for "/tmp" because it's not empty`)
return nil
+ default:
+ return err
}
- log.Infof(`Mounting internal tmpfs on top of empty "/tmp"`)
fallthrough
case syserror.ENOENT:
@@ -429,8 +436,12 @@ func (c *containerMounter) mountTmpVFS2(ctx context.Context, conf *Config, creds
}
return c.mountSubmountVFS2(ctx, conf, mns, creds, &mountAndFD{Mount: tmpMount})
+ case syserror.ENOTDIR:
+ // Not a dir?! Let it be.
+ return nil
+
default:
- return fmt.Errorf(`stating "/tmp" inside container: %w`, err)
+ return fmt.Errorf(`opening "/tmp" inside container: %w`, err)
}
}