Merge branch 'master' into master

This commit is contained in:
Pål-Magnus Slåtto
2023-03-26 18:26:28 +02:00
committed by GitHub
174 changed files with 2762 additions and 1428 deletions
+1 -1
View File
@@ -24,7 +24,7 @@ function install_pkgs() {
}
install_pkgs make linux-libc-dev graphviz jq curl binutils gnupg gnupg-agent \
gcc pkg-config apt-transport-https ca-certificates \
software-properties-common rsync kmod systemd
software-properties-common rsync kmod systemd unzip
# Install headers, only if available.
if test -n "$(apt-cache search --names-only "^linux-headers-$(uname -r)$")"; then
+4 -4
View File
@@ -12,14 +12,14 @@ name: "Go"
- master
- "feature/**"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
generate:
runs-on: ubuntu-latest
steps:
- name: Cancel previous
uses: styfle/cancel-workflow-action@0.11.0
with:
access_token: ${{ github.token }}
- id: setup
run: |
if ! [[ -z "${{ secrets.GO_TOKEN }}" ]]; then
+1 -1
View File
@@ -120,7 +120,7 @@ build_test(
# The files in this tree are symlinks to the true sources.
go_path(
name = "gopath",
mode = "link",
mode = "archive",
deps = [
# Main binaries.
#
+2 -2
View File
@@ -1485,8 +1485,8 @@ http_file(
http_file(
name = "github_workflow_schema",
sha256 = "60603d1095b11d136e04a8b95be83a23ad8044169e46f82f925c320c1cf47a49",
urls = ["https://raw.githubusercontent.com/SchemaStore/schemastore/27612065234778feaac216ce14dd47846fe0a2dd/src/schemas/json/github-workflow.json"],
sha256 = "7499ccb3e75975504ea1ee7c70291e0c9f6c1f684678091d013061fe263e3ddb",
urls = ["https://raw.githubusercontent.com/SchemaStore/schemastore/166136b96a14f103a948053903e9339e63ad9170/src/schemas/json/github-workflow.json"],
)
# External Go repositories.
+1 -1
View File
@@ -265,7 +265,7 @@ non-human-friendly hexadecimal strings.
In order to provide more user-friendly labels, the metric server will pick up
the `io.kubernetes.cri.sandbox-name` and `io.kubernetes.cri.sandbox-namespace`
annotations provided by `containerd`, and automatically add these as labels
(`pod` and `namespace` respectively) for each per-sandbox metric.
(`pod_name` and `namespace_name` respectively) for each per-sandbox metric.
## Metrics exported
+1 -1
View File
@@ -25,6 +25,6 @@ RUN curl https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud
ln -s /google-cloud-sdk/bin/gcloud /usr/bin/gcloud
# Download the official bazel binary. The APT repository isn't used because there is not packages for arm64.
RUN sh -c 'curl -o /usr/local/bin/bazel https://releases.bazel.build/6.0.0/release/bazel-6.0.0-linux-$(uname -m | sed s/aarch64/arm64/) && chmod ugo+x /usr/local/bin/bazel'
RUN sh -c 'curl -o /usr/local/bin/bazel https://releases.bazel.build/6.1.1/release/bazel-6.1.1-linux-$(uname -m | sed s/aarch64/arm64/) && chmod ugo+x /usr/local/bin/bazel'
WORKDIR /workspace
ENTRYPOINT ["/usr/local/bin/bazel"]
+2 -2
View File
@@ -274,8 +274,8 @@ type Statx struct {
// String implements fmt.Stringer.String.
func (s *Statx) String() string {
return fmt.Sprintf("Statx{Mask: %d, Blksize: %d, Attributes: %d, Nlink: %d, UID: %d, GID: %d, Mode: %d, Ino: %d, Size: %d, Blocks: %d, AttributesMask: %d, Atime: %d, Btime: %d, Ctime: %d, Mtime: %d, RdevMajor: %d, RdevMinor: %d, DevMajor: %d, DevMinor: %d}",
s.Mask, s.Blksize, s.Attributes, s.Nlink, s.UID, s.GID, s.Mode, s.Ino, s.Size, s.Blocks, s.AttributesMask, s.Atime, s.Btime, s.Ctime, s.Mtime, s.RdevMajor, s.RdevMinor, s.DevMajor, s.DevMinor)
return fmt.Sprintf("Statx{Mask: %#x, Mode: %s, UID: %d, GID: %d, Ino: %d, DevMajor: %d, DevMinor: %d, Size: %d, Blocks: %d, Blksize: %d, Nlink: %d, Atime: %s, Btime: %s, Ctime: %s, Mtime: %s, Attributes: %d, AttributesMask: %d, RdevMajor: %d, RdevMinor: %d}",
s.Mask, FileMode(s.Mode), s.UID, s.GID, s.Ino, s.DevMajor, s.DevMinor, s.Size, s.Blocks, s.Blksize, s.Nlink, s.Atime.ToTime(), s.Btime.ToTime(), s.Ctime.ToTime(), s.Mtime.ToTime(), s.Attributes, s.AttributesMask, s.RdevMajor, s.RdevMinor)
}
// SizeOfStatx is the size of a Statx struct.
+5
View File
@@ -274,6 +274,11 @@ func NsecToStatxTimestamp(nsec int64) (ts StatxTimestamp) {
}
}
// ToTime returns the Go time.Time representation.
func (sxts StatxTimestamp) ToTime() time.Time {
return time.Unix(sxts.Sec, int64(sxts.Nsec))
}
// Utime represents struct utimbuf used by utimes(2).
//
// +marshal
+1
View File
@@ -892,6 +892,7 @@ func LinkAtHandler(c *Connection, comm Communicator, payloadLen uint32) (uint32,
if err != nil {
return 0, err
}
defer targetFD.DecRef(nil)
if targetFD.IsDir() {
// Can not create hard link to directory.
return 0, unix.EPERM
+58 -19
View File
@@ -270,9 +270,7 @@ type StringArray []string
func (s *StringArray) String() string {
var b strings.Builder
b.WriteString("[")
for _, str := range *s {
b.WriteString(fmt.Sprintf("%s, ", str))
}
b.WriteString(strings.Join(*s, ", "))
b.WriteString("]")
return b.String()
}
@@ -331,6 +329,10 @@ type Inode struct {
Stat linux.Statx
}
func (i *Inode) String() string {
return fmt.Sprintf("Inode{ControlFD: %d, Stat: %s}", i.ControlFD, i.Stat.String())
}
// MountReq is an empty request to Mount on the connection.
type MountReq struct{ EmptyMessage }
@@ -351,7 +353,7 @@ type MountResp struct {
// String implements fmt.Stringer.String.
func (m *MountResp) String() string {
return fmt.Sprintf("MountResp{Root: %+v, MaxMessageSize: %d, SupportedMs: %+v}", m.Root, m.MaxMessageSize, m.SupportedMs)
return fmt.Sprintf("MountResp{Root: %s, MaxMessageSize: %d, SupportedMs: %+v}", m.Root.String(), m.MaxMessageSize, m.SupportedMs)
}
// SizeBytes implements marshal.Marshallable.SizeBytes.
@@ -453,8 +455,8 @@ type SetStatReq struct {
// String implements fmt.Stringer.String.
func (s *SetStatReq) String() string {
return fmt.Sprintf("SetStatReq{FD: %d, Mask: %d, Mode: %d, UID: %d, GID: %d, Size: %d, Atime: %+v, Mtime: %+v}",
s.FD, s.Mask, s.Mode, s.UID, s.GID, s.Size, s.Atime, s.Mtime)
return fmt.Sprintf("SetStatReq{FD: %d, Mask: %#x, Mode: %d, UID: %d, GID: %d, Size: %d, Atime: %s, Mtime: %s}",
s.FD, s.Mask, s.Mode, s.UID, s.GID, s.Size, s.Atime.ToTime(), s.Mtime.ToTime())
}
// SetStatResp is used to communicate SetStat results. It contains a mask
@@ -470,7 +472,7 @@ type SetStatResp struct {
// String implements fmt.Stringer.String.
func (s *SetStatResp) String() string {
return fmt.Sprintf("SetStatResp{FailureMask: %d, FailureErrNo: %d}", s.FailureMask, s.FailureErrNo)
return fmt.Sprintf("SetStatResp{FailureMask: %#x, FailureErrNo: %d}", s.FailureMask, s.FailureErrNo)
}
// WalkReq is used to request to walk multiple path components at once. This
@@ -530,6 +532,19 @@ const (
WalkComponentSymlink
)
func walkStatusToString(ws WalkStatus) string {
switch ws {
case WalkSuccess:
return "Success"
case WalkComponentDoesNotExist:
return "ComponentDoesNotExist"
case WalkComponentSymlink:
return "ComponentSymlink"
default:
panic(fmt.Sprintf("Unknown WalkStatus: %d", ws))
}
}
// WalkResp is used to communicate the inodes walked by the server. In memory,
// the inode array is preceded by a uint16 integer denoting array length.
type WalkResp struct {
@@ -544,10 +559,13 @@ func (w *WalkResp) String() string {
var arrB strings.Builder
arrB.WriteString("[")
for i := range w.Inodes {
arrB.WriteString(fmt.Sprintf("%+v, ", w.Inodes[i]))
if i > 0 {
arrB.WriteString(", ")
}
arrB.WriteString(w.Inodes[i].String())
}
arrB.WriteString("]")
return fmt.Sprintf("WalkResp{Status: %d, Inodes: %s}", w.Status, arrB.String())
return fmt.Sprintf("WalkResp{Status: %s, Inodes: %s}", walkStatusToString(w.Status), arrB.String())
}
// SizeBytes implements marshal.Marshallable.SizeBytes.
@@ -595,7 +613,16 @@ type WalkStatResp struct {
// String implements fmt.Stringer.String.
func (w *WalkStatResp) String() string {
return fmt.Sprintf("WalkStatResp{Stats: %+v}", w.Stats)
var arrB strings.Builder
arrB.WriteString("[")
for i := range w.Stats {
if i > 0 {
arrB.WriteString(", ")
}
arrB.WriteString(w.Stats[i].String())
}
arrB.WriteString("]")
return fmt.Sprintf("WalkStatResp{Stats: %s}", arrB.String())
}
// SizeBytes implements marshal.Marshallable.SizeBytes.
@@ -716,7 +743,7 @@ type OpenCreateAtResp struct {
// String implements fmt.Stringer.String.
func (o *OpenCreateAtResp) String() string {
return fmt.Sprintf("OpenCreateAtResp{Child: %+v, NewFD: %d}", o.Child, o.NewFD)
return fmt.Sprintf("OpenCreateAtResp{Child: %s, NewFD: %d}", o.Child.String(), o.NewFD)
}
// FdArray is a utility struct which implements a marshallable type for
@@ -730,8 +757,11 @@ type FdArray []FDID
func (f *FdArray) String() string {
var b strings.Builder
b.WriteString("[")
for _, fd := range *f {
b.WriteString(fmt.Sprintf("%d, ", fd))
for i, fd := range *f {
if i > 0 {
b.WriteString(", ")
}
b.WriteString(fmt.Sprintf("%d", fd))
}
b.WriteString("]")
return b.String()
@@ -985,7 +1015,7 @@ type MkdirAtResp struct {
// String implements fmt.Stringer.String.
func (m *MkdirAtResp) String() string {
return fmt.Sprintf("MkdirAtResp{ChildDir: %+v}", m.ChildDir)
return fmt.Sprintf("MkdirAtResp{ChildDir: %s}", m.ChildDir.String())
}
// MknodAtReq is used to make MknodAt requests.
@@ -1038,7 +1068,7 @@ type MknodAtResp struct {
// String implements fmt.Stringer.String.
func (m *MknodAtResp) String() string {
return fmt.Sprintf("MknodAtResp{Child: %+v}", m.Child)
return fmt.Sprintf("MknodAtResp{Child: %s}", m.Child.String())
}
// SymlinkAtReq is used to make SymlinkAt request.
@@ -1098,7 +1128,7 @@ type SymlinkAtResp struct {
// String implements fmt.Stringer.String.
func (s *SymlinkAtResp) String() string {
return fmt.Sprintf("SymlinkAtResp{Symlink: %+v}", s.Symlink)
return fmt.Sprintf("SymlinkAtResp{Symlink: %s}", s.Symlink.String())
}
// LinkAtReq is used to make LinkAt requests.
@@ -1148,7 +1178,7 @@ type LinkAtResp struct {
// String implements fmt.Stringer.String.
func (l *LinkAtResp) String() string {
return fmt.Sprintf("LinkAtResp{Link: %+v}", l.Link)
return fmt.Sprintf("LinkAtResp{Link: %s}", l.Link.String())
}
// FStatFSReq is used to request StatFS results for the specified FD.
@@ -1336,7 +1366,7 @@ type BindAtResp struct {
// String implements fmt.Stringer.String.
func (b *BindAtResp) String() string {
return fmt.Sprintf("BindAtResp{Child: %+v, BoundSocketFD: %v}", b.Child, b.BoundSocketFD)
return fmt.Sprintf("BindAtResp{Child: %s, BoundSocketFD: %d}", b.Child.String(), b.BoundSocketFD)
}
// ListenReq is used to make Listen requests.
@@ -1571,7 +1601,16 @@ type Getdents64Resp struct {
// String implements fmt.Stringer.String.
func (g *Getdents64Resp) String() string {
return fmt.Sprintf("Getdents64Resp{Dirents: %+v}", g.Dirents)
var b strings.Builder
b.WriteString("[")
for i, dirent := range g.Dirents {
if i > 0 {
b.WriteString(", ")
}
b.WriteString(dirent.String())
}
b.WriteString("]")
return fmt.Sprintf("Getdents64Resp{Dirents: %s}", b.String())
}
// SizeBytes implements marshal.Marshallable.SizeBytes.
+2 -1
View File
@@ -490,7 +490,8 @@ func testHardLink(ctx context.Context, t *testing.T, tester Tester, root lisafs.
defer closeFD(ctx, t, fd)
defer unix.Close(hostFD)
link, linkStat := link(ctx, t, root, name, controlFile)
linkName := "linkFile"
link, linkStat := link(ctx, t, root, linkName, controlFile)
defer closeFD(ctx, t, link)
if linkStat.Ino != fileIno.Ino {
+2 -2
View File
@@ -35,8 +35,8 @@ var timeNow = time.Now
// Prometheus label names used to identify each sandbox.
const (
SandboxIDLabel = "sandbox"
PodNameLabel = "pod"
NamespaceLabel = "namespace"
PodNameLabel = "pod_name"
NamespaceLabel = "namespace_name"
IterationIDLabel = "iteration"
)
+22
View File
@@ -364,6 +364,28 @@ func TestVerifier(t *testing.T) {
),
WantVerifierCreationErr: true,
},
{
Name: "Prometheus metric name starts with reserved prefix",
Registration: newMetricRegistration(&metricMetadata{
PB: &pb.MetricMetadata{
Name: "metaFooBar",
PrometheusName: "meta_foo_bar",
Type: pb.MetricMetadata_TYPE_UINT64,
}},
),
WantVerifierCreationErr: true,
},
{
Name: "Prometheus metric name does not starts with reserved prefix but non-Prometheus metric name does",
Registration: newMetricRegistration(&metricMetadata{
PB: &pb.MetricMetadata{
Name: "metaFooBar",
PrometheusName: "not_meta_foo_bar",
Type: pb.MetricMetadata_TYPE_UINT64,
}},
),
WantVerifierCreationErr: false,
},
{
Name: "no buckets",
Registration: newMetricRegistration(&metricMetadata{
+8
View File
@@ -30,6 +30,11 @@ const (
// maxExportStaleness is the maximum allowed age of a snapshot when it is verified.
// Used to avoid exporting snapshots from bogus times from ages past.
maxExportStaleness = 10 * time.Second
// MetaMetricPrefix is a prefix used for metrics defined by the metric server,
// as opposed to metrics generated by each sandbox.
// For this reason, this prefix is not allowed to be used in sandbox metrics.
MetaMetricPrefix = "meta_"
)
// internedStringMap allows for interning strings.
@@ -260,6 +265,9 @@ func newVerifiableMetric(metadata *pb.MetricMetadata, verifier *Verifier) (*veri
if metadata.GetName() == "" || metadata.GetPrometheusName() == "" {
return nil, errors.New("metric has no name")
}
if strings.HasPrefix(metadata.GetPrometheusName(), MetaMetricPrefix) {
return nil, fmt.Errorf("metric name %q starts with %q which is a reserved prefix", metadata.GetPrometheusName(), "meta_")
}
if !unicode.IsLower(rune(metadata.GetPrometheusName()[0])) {
return nil, fmt.Errorf("invalid initial character in prometheus metric name: %q", metadata.GetPrometheusName())
}
+61 -10
View File
@@ -18,6 +18,7 @@ import (
"bytes"
"encoding/json"
"fmt"
"os"
"sort"
"strings"
"text/tabwriter"
@@ -44,6 +45,41 @@ type Proc struct {
Kernel *kernel.Kernel
}
// FilePayload aids to ensure that len(urpc.FilePayload.Files) == len(GuestFDs)
// when instantiated through the NewFDMap helper method.
type FilePayload struct {
// FilePayload is the file payload that is transferred via RPC.
urpc.FilePayload
// GuestFDs are the file descriptors in the file descriptor map of the
// executed application. They correspond 1:1 to the files in the
// urpc.FilePayload.
GuestFDs []int
}
// NewFDMap returns a FilePayload that maps file descriptors to files inside
// the executed process.
func NewFDMap(fdMap map[int]*os.File) FilePayload {
files := make([]*os.File, 0, len(fdMap))
// Make the map iteration order deterministic for the sake of testing.
// Otherwise, the order is randomized and tests relying on the comparison
// of equality will fail.
guestFDs := make([]int, 0, len(fdMap))
for key := range fdMap {
guestFDs = append(guestFDs, key)
}
sort.Ints(guestFDs)
for _, guestFD := range guestFDs {
files = append(files, fdMap[guestFD])
}
return FilePayload{
FilePayload: urpc.FilePayload{Files: files},
GuestFDs: guestFDs,
}
}
// ExecArgs is the set of arguments to exec.
type ExecArgs struct {
// Filename is the filename to load.
@@ -84,7 +120,7 @@ type ExecArgs struct {
StdioIsPty bool
// FilePayload determines the files to give to the new process.
urpc.FilePayload
FilePayload
// ContainerID is the container for the process being executed.
ContainerID string
@@ -97,7 +133,7 @@ type ExecArgs struct {
}
// String prints the arguments as a string.
func (args ExecArgs) String() string {
func (args *ExecArgs) String() string {
if len(args.Argv) == 0 {
return args.Filename
}
@@ -189,19 +225,15 @@ func (proc *Proc) execAsync(args *ExecArgs) (*kernel.ThreadGroup, kernel.ThreadI
}
initArgs.Filename = resolved
fds, err := fd.NewFromFiles(args.Files)
fdMap, err := args.createFDMap()
if err != nil {
return nil, 0, nil, fmt.Errorf("duplicating payload files: %w", err)
return nil, 0, nil, fmt.Errorf("creating fd map: %w", err)
}
defer func() {
for _, fd := range fds {
_ = fd.Close()
for _, hostFD := range fdMap {
_ = hostFD.Close()
}
}()
fdMap := make(map[int]*fd.FD, len(fds))
for appFD, hostFD := range fds {
fdMap[appFD] = hostFD
}
ttyFile, err := fdimport.Import(ctx, fdTable, args.StdioIsPty, args.KUID, args.KGID, fdMap)
if err != nil {
return nil, 0, nil, err
@@ -404,3 +436,22 @@ func ContainerUsage(kr *kernel.Kernel) map[string]uint64 {
}
return cusage
}
// createFDMap creates the file descriptor map from the unmarshalled ExecArgs.
func (args *ExecArgs) createFDMap() (map[int]*fd.FD, error) {
if len(args.Files) != len(args.GuestFDs) {
return nil, fmt.Errorf("length of payload files does not match length of file descriptor array")
}
fdMap := make(map[int]*fd.FD, len(args.Files))
for i, file := range args.Files {
var appFD int
// GuestFDs are the indexes of our FD map.
appFD = args.GuestFDs[i]
hostFD, err := fd.NewFromFile(file)
if err != nil {
return nil, fmt.Errorf("duplicating payload files: %w", err)
}
fdMap[appFD] = hostFD
}
return fdMap, nil
}
+1 -1
View File
@@ -69,7 +69,7 @@ type tunFD struct {
}
// Ioctl implements vfs.FileDescriptionImpl.Ioctl.
func (fd *tunFD) Ioctl(ctx context.Context, uio usermem.IO, args arch.SyscallArguments) (uintptr, error) {
func (fd *tunFD) Ioctl(ctx context.Context, uio usermem.IO, sysno uintptr, args arch.SyscallArguments) (uintptr, error) {
request := args[1].Uint()
data := args[2].Pointer()
+4 -4
View File
@@ -135,7 +135,7 @@ func (mfd *masterFileDescription) Write(ctx context.Context, src usermem.IOSeque
}
// Ioctl implements vfs.FileDescriptionImpl.Ioctl.
func (mfd *masterFileDescription) Ioctl(ctx context.Context, io usermem.IO, args arch.SyscallArguments) (uintptr, error) {
func (mfd *masterFileDescription) Ioctl(ctx context.Context, io usermem.IO, sysno uintptr, args arch.SyscallArguments) (uintptr, error) {
t := kernel.TaskFromContext(ctx)
if t == nil {
// ioctl(2) may only be called from a task goroutine.
@@ -193,7 +193,7 @@ func (mfd *masterFileDescription) Ioctl(ctx context.Context, io usermem.IO, args
}
return 0, t.ThreadGroup().SetForegroundProcessGroupID(mfd.t.masterKTTY, kernel.ProcessGroupID(pgid))
default:
maybeEmitUnimplementedEvent(ctx, cmd)
maybeEmitUnimplementedEvent(ctx, sysno, cmd)
return 0, linuxerr.ENOTTY
}
}
@@ -212,7 +212,7 @@ func (mfd *masterFileDescription) Stat(ctx context.Context, opts vfs.StatOptions
}
// maybeEmitUnimplementedEvent emits unimplemented event if cmd is valid.
func maybeEmitUnimplementedEvent(ctx context.Context, cmd uint32) {
func maybeEmitUnimplementedEvent(ctx context.Context, sysno uintptr, cmd uint32) {
switch cmd {
case linux.TCGETS,
linux.TCSETS,
@@ -244,6 +244,6 @@ func maybeEmitUnimplementedEvent(ctx context.Context, cmd uint32) {
linux.TIOCSSERIAL,
linux.TIOCGPTPEER:
unimpl.EmitUnimplementedEvent(ctx)
unimpl.EmitUnimplementedEvent(ctx, sysno)
}
}
+2 -2
View File
@@ -148,7 +148,7 @@ func (rfd *replicaFileDescription) Write(ctx context.Context, src usermem.IOSequ
}
// Ioctl implements vfs.FileDescriptionImpl.Ioctl.
func (rfd *replicaFileDescription) Ioctl(ctx context.Context, io usermem.IO, args arch.SyscallArguments) (uintptr, error) {
func (rfd *replicaFileDescription) Ioctl(ctx context.Context, io usermem.IO, sysno uintptr, args arch.SyscallArguments) (uintptr, error) {
t := kernel.TaskFromContext(ctx)
if t == nil {
// ioctl(2) may only be called from a task goroutine.
@@ -199,7 +199,7 @@ func (rfd *replicaFileDescription) Ioctl(ctx context.Context, io usermem.IO, arg
}
return 0, t.ThreadGroup().SetForegroundProcessGroupID(rfd.inode.t.replicaKTTY, kernel.ProcessGroupID(pgid))
default:
maybeEmitUnimplementedEvent(ctx, cmd)
maybeEmitUnimplementedEvent(ctx, sysno, cmd)
return 0, linuxerr.ENOTTY
}
}
-1
View File
@@ -98,7 +98,6 @@ go_library(
"//pkg/sentry/fsimpl/lock",
"//pkg/sentry/fsmetric",
"//pkg/sentry/fsutil",
"//pkg/sentry/fsutil/chdir",
"//pkg/sentry/hostfd",
"//pkg/sentry/kernel",
"//pkg/sentry/kernel/auth",
+4 -2
View File
@@ -325,7 +325,9 @@ func (d *dentry) mknod(ctx context.Context, name string, creds *auth.Credentials
}
}
// Precondition: !d.isSynthetic().
// Preconditions:
// - !d.isSynthetic().
// - d.fs.renameMu must be locked.
func (d *dentry) link(ctx context.Context, target *dentry, name string) (*dentry, error) {
switch dt := d.impl.(type) {
case *lisafsDentry:
@@ -490,7 +492,7 @@ func (fs *filesystem) restoreRoot(ctx context.Context, opts *vfs.CompleteRestore
case *lisafsDentry:
return dt.restoreFile(ctx, &rootInode, opts)
case *directfsDentry:
dt.rootControlFDLisa = fs.client.NewFD(rootInode.ControlFD)
dt.controlFDLisa = fs.client.NewFD(rootInode.ControlFD)
return dt.restoreFile(ctx, rootHostFD, opts)
default:
panic("unknown dentry implementation")

Some files were not shown because too many files have changed in this diff Show More