Create a new test dimension that mounts a FUSE fs on /tmp.

If you add "use_fusefs=True" to a syscall test, it generates a new test
target denoted with _fuse at the end. This target runs a shim binary
that mounts a FUSE fs at /tmp and runs a server that forwards all
filesystem ops to /fuse. Once the FUSE is mounted, the shim execs the normal
test binary.

This new dimension should help test the correctness of our FUSE implementation.
All relevant tests that already pass have the use_fusefs enabled. The rest
are still broken.

PiperOrigin-RevId: 501059036
This commit is contained in:
Lucas Manning
2023-01-10 12:13:09 -08:00
committed by gVisor bot
parent c4976f7d81
commit 2e3e5b6067
9 changed files with 125 additions and 2 deletions
+7
View File
@@ -1888,3 +1888,10 @@ go_repository(
sum = "h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=",
version = "v1.2.0",
)
go_repository(
name = "com_github_hanwen_go_fuse_v2",
importpath = "github.com/hanwen/go-fuse/v2",
sum = "h1:fOTuYWxywhaliwMobGTP/6NUCgGdal6pCpuch4MHCnU=",
version = "v2.1.1-0.20220627082937-d01fda7edf17",
)
+1
View File
@@ -48,6 +48,7 @@ require (
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/gofuzz v1.0.0 // indirect
github.com/googleapis/gnostic v0.4.0 // indirect
github.com/hanwen/go-fuse/v2 v2.1.1-0.20220627082937-d01fda7edf17 // indirect
github.com/hashicorp/errwrap v1.0.0 // indirect
github.com/hashicorp/go-multierror v1.1.0 // indirect
github.com/json-iterator/go v1.1.7 // indirect
+3
View File
@@ -233,6 +233,8 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmg
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/hanwen/go-fuse/v2 v2.1.1-0.20220627082937-d01fda7edf17 h1:fOTuYWxywhaliwMobGTP/6NUCgGdal6pCpuch4MHCnU=
github.com/hanwen/go-fuse/v2 v2.1.1-0.20220627082937-d01fda7edf17/go.mod h1:B1nGE/6RBFyBRC1RRnf23UpwCdyJ31eukw34oAKukAc=
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI=
@@ -266,6 +268,7 @@ github.com/kr/pty v1.1.4-0.20190131011033-7dc38fb350b1 h1:zc0R6cOw98cMengLA0fvU5
github.com/kr/pty v1.1.4-0.20190131011033-7dc38fb350b1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mattbaird/jsonpatch v0.0.0-20171005235357-81af80346b1a h1:+J2gw7Bw77w/fbK7wnNJJDKmw1IbWft2Ul5BzrG1Qm8=
+1
View File
@@ -8,6 +8,7 @@ go_binary(
srcs = ["main.go"],
data = [
"//runsc",
"//test/runner/fuse",
"//test/runner/setup_container",
],
visibility = ["//:sandbox"],
+18
View File
@@ -72,6 +72,7 @@ def _syscall_test(
iouring = False,
container = None,
one_sandbox = True,
use_fusefs = False,
**kwargs):
# Prepend "runsc" to non-native platform names.
full_platform = platform if platform == "native" else "runsc_" + platform
@@ -84,6 +85,8 @@ def _syscall_test(
name += "_overlay"
if network != "none":
name += "_" + network + "net"
if use_fusefs:
name += "_fuse"
# Apply all tags.
if tags == None:
@@ -131,6 +134,7 @@ def _syscall_test(
"--platform-support=" + platform_support,
"--network=" + network,
"--use-tmpfs=" + str(use_tmpfs),
"--use-fusefs=" + str(use_fusefs),
"--file-access=" + file_access,
"--overlay=" + str(overlay),
"--add-host-communication=" + str(add_host_communication),
@@ -163,6 +167,7 @@ def all_platforms():
def syscall_test(
test,
use_tmpfs = False,
use_fusefs = False,
add_overlay = False,
add_host_communication = False,
add_hostinet = False,
@@ -263,3 +268,16 @@ def syscall_test(
file_access = "shared",
**kwargs
)
if use_fusefs:
_syscall_test(
test = test,
platform = default_platform,
use_tmpfs = True,
use_fusefs = True,
add_host_communication = add_host_communication,
tags = platforms.get(default_platform, []) + tags,
debug = debug,
container = container,
one_sandbox = one_sandbox,
**kwargs
)
+14
View File
@@ -0,0 +1,14 @@
load("//tools:defs.bzl", "go_binary")
package(licenses = ["notice"])
go_binary(
name = "fuse",
srcs = ["fuse.go"],
visibility = ["//test/runner:__subpackages__"],
deps = [
"//pkg/log",
"@com_github_hanwen_go_fuse_v2//fs:go_default_library",
"@com_github_hanwen_go_fuse_v2//fuse:go_default_library",
],
)
+59
View File
@@ -0,0 +1,59 @@
// Copyright 2022 The gVisor 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.
// Binary main starts a fuse server that forwards filesystem operations from
// /tmp to /fuse.
package main
import (
"os"
"os/exec"
"github.com/hanwen/go-fuse/v2/fs"
"github.com/hanwen/go-fuse/v2/fuse"
"gvisor.dev/gvisor/pkg/log"
)
func main() {
loopbackRoot, err := fs.NewLoopbackRoot("/fuse")
if err != nil {
log.Warningf("could not create loopback root: %v", err)
os.Exit(1)
}
opts := &fuse.MountOptions{DirectMount: true}
rawFS := fs.NewNodeFS(loopbackRoot, &fs.Options{})
server, err := fuse.NewServer(rawFS, "/tmp", opts)
if err != nil {
log.Warningf("could not create fuse server: %v", err)
os.Exit(1)
}
go server.Serve()
defer func() {
server.Unmount()
server.Wait()
}()
if err := server.WaitMount(); err != nil {
// We don't shutdown the serve loop. If the mount does
// not succeed, the loop won't work and exit.
log.Warningf(`Could not mount fuse submount "/tmp": %v`, err)
os.Exit(1)
}
cmd := exec.Command(os.Args[1], os.Args[2:]...)
if err := cmd.Run(); err != nil {
log.Warningf(err.Error())
os.Exit(1)
}
os.Exit(0)
}
+19 -2
View File
@@ -49,6 +49,7 @@ var (
platformSupport = flag.String("platform-support", "", "String passed to the test as GVISOR_PLATFORM_SUPPORT environment variable. Used to determine which syscall tests are expected to work with the current platform.")
network = flag.String("network", "none", "network stack to run on (sandbox, host, none)")
useTmpfs = flag.Bool("use-tmpfs", false, "mounts tmpfs for /tmp")
useFUSEfs = flag.Bool("use-fusefs", false, "mounts a fusefs for /tmp")
fileAccess = flag.String("file-access", "exclusive", "mounts root in exclusive or shared mode")
overlay = flag.Bool("overlay", false, "wrap filesystem mounts with writable tmpfs overlay")
container = flag.Bool("container", false, "run tests in their own namespaces (user ns, network ns, etc), pretending to be root. Implicitly enabled if network=host, or if using network namespaces")
@@ -376,8 +377,16 @@ func runTestCaseRunsc(testBin string, tc *gtest.TestCase, args []string, t *test
if args == nil {
args = tc.Args()
}
spec := testutil.NewSpecWithArgs(append([]string{testBin}, args...)...)
var spec *specs.Spec
if *useFUSEfs {
fuseServer, err := testutil.FindFile("test/runner/fuse/fuse")
if err != nil {
fatalf("cannot find fuse: %v", err)
}
spec = testutil.NewSpecWithArgs(append([]string{fuseServer, testBin}, args...)...)
} else {
spec = testutil.NewSpecWithArgs(append([]string{testBin}, args...)...)
}
// Mark the root as writeable, as some tests attempt to
// write to the rootfs, and expect EACCES, not EROFS.
spec.Root.Readonly = false
@@ -424,6 +433,14 @@ func runTestCaseRunsc(testBin string, tc *gtest.TestCase, args []string, t *test
testTmpDir = "/tmp"
}
}
if *useFUSEfs {
// In fuse tests, the fuse server forwards all filesystem ops from /tmp
// to /fuse.
spec.Mounts = append(spec.Mounts, specs.Mount{
Destination: "/fuse",
Type: "tmpfs",
})
}
// Set environment variables that indicate we are running in gVisor with
// the given platform, network, and filesystem stack.
+3
View File
@@ -327,6 +327,7 @@ syscall_test(
syscall_test(
add_overlay = True,
test = "//test/syscalls/linux:mknod_test",
use_fusefs = True,
)
syscall_test(
@@ -913,12 +914,14 @@ syscall_test(
syscall_test(
add_overlay = True,
test = "//test/syscalls/linux:statfs_test",
use_fusefs = True,
use_tmpfs = True, # Test specifically relies on TEST_TMPDIR to be tmpfs.
)
syscall_test(
add_overlay = True,
test = "//test/syscalls/linux:stat_test",
use_fusefs = True,
)
syscall_test(