From 7dcd9061702afb281b400a80073dd4fd566f7663 Mon Sep 17 00:00:00 2001 From: Ayush Ranjan Date: Wed, 11 Jan 2023 14:58:19 -0800 Subject: [PATCH] Use gofer filesystem's aname option in runsc. In runsc, the lisafs connection on the gofer side is set up to return the FD to the right mount point. The gofer client's aname option is always set to "/" with runsc. Change that so that now aname is set to Mount.Destination and on the gofer side we always return the FD to the root of the container filesystem. Then the gofer client will walk manually to the right place. This has no change in behavior. This is needed for supporting directfs later. PiperOrigin-RevId: 501387753 --- runsc/boot/vfs.go | 7 ++++--- runsc/cmd/gofer.go | 19 +++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/runsc/boot/vfs.go b/runsc/boot/vfs.go index 1a1d64de9..bf64bc72c 100644 --- a/runsc/boot/vfs.go +++ b/runsc/boot/vfs.go @@ -253,9 +253,10 @@ func compileMounts(spec *specs.Spec, conf *config.Config) []specs.Mount { } // goferMountData creates a slice of gofer mount data. -func goferMountData(fd int, fa config.FileAccessType) []string { +func goferMountData(fd int, fa config.FileAccessType, dstPath string) []string { opts := []string{ "trans=fd", + "aname=" + dstPath, "rfdno=" + strconv.Itoa(fd), "wfdno=" + strconv.Itoa(fd), } @@ -401,7 +402,7 @@ func (c *containerMounter) mountAll(conf *config.Config, procArgs *kernel.Create // createMountNamespace creates the container's root mount and namespace. func (c *containerMounter) createMountNamespace(ctx context.Context, conf *config.Config, creds *auth.Credentials) (*vfs.MountNamespace, error) { fd := c.fds.remove() - data := goferMountData(fd, conf.FileAccess) + data := goferMountData(fd, conf.FileAccess, "/") // We can't check for overlayfs here because sandbox is chroot'ed and gofer // can only send mount options for specs.Mounts (specs.Root is missing @@ -711,7 +712,7 @@ func (c *containerMounter) getMountNameAndOptions(conf *config.Config, m *mountA // but unlikely to be correct in this context. return "", nil, false, fmt.Errorf("gofer mount requires a connection FD") } - data = goferMountData(m.fd, c.getMountAccessType(conf, m.mount)) + data = goferMountData(m.fd, c.getMountAccessType(conf, m.mount), m.mount.Destination) internalData = gofer.InternalFilesystemOptions{ UniqueID: m.mount.Destination, } diff --git a/runsc/cmd/gofer.go b/runsc/cmd/gofer.go index e9409bb80..a28d3a7c0 100644 --- a/runsc/cmd/gofer.go +++ b/runsc/cmd/gofer.go @@ -246,9 +246,8 @@ func newSocket(ioFD int) *unet.Socket { func (g *Gofer) serve(spec *specs.Spec, conf *config.Config, root string) subcommands.ExitStatus { type connectionConfig struct { - sock *unet.Socket - mountPath string - readonly bool + sock *unet.Socket + readonly bool } cfgs := make([]connectionConfig, 0, len(spec.Mounts)+1) server := fsgofer.NewLisafsServer(fsgofer.Config{ @@ -261,9 +260,8 @@ func (g *Gofer) serve(spec *specs.Spec, conf *config.Config, root string) subcom // Start with root mount, then add any other additional mount as needed. cfgs = append(cfgs, connectionConfig{ - sock: newSocket(g.ioFDs[0]), - mountPath: "/", // fsgofer process is always chroot()ed. So serve root. - readonly: spec.Root.Readonly || overlay2.RootMount, + sock: newSocket(g.ioFDs[0]), + readonly: spec.Root.Readonly || overlay2.RootMount, }) log.Infof("Serving %q mapped to %q on FD %d (ro: %t)", "/", root, g.ioFDs[0], cfgs[0].readonly) @@ -281,9 +279,8 @@ func (g *Gofer) serve(spec *specs.Spec, conf *config.Config, root string) subcom } cfgs = append(cfgs, connectionConfig{ - sock: newSocket(g.ioFDs[mountIdx]), - mountPath: m.Destination, - readonly: isReadonlyMount(m.Options) || overlay2.SubMounts, + sock: newSocket(g.ioFDs[mountIdx]), + readonly: isReadonlyMount(m.Options) || overlay2.SubMounts, }) log.Infof("Serving %q mapped on FD %d (ro: %t)", m.Destination, g.ioFDs[mountIdx], cfgs[mountIdx].readonly) @@ -296,7 +293,9 @@ func (g *Gofer) serve(spec *specs.Spec, conf *config.Config, root string) subcom cfgs = cfgs[:mountIdx] for _, cfg := range cfgs { - conn, err := server.CreateConnection(cfg.sock, cfg.mountPath, cfg.readonly) + // fsgofer process is always chroot()ed. So we can serve root. The gofer + // client should walk to the right mount point from the root. + conn, err := server.CreateConnection(cfg.sock, "/", cfg.readonly) if err != nil { util.Fatalf("starting connection on FD %d for gofer mount failed: %v", cfg.sock.FD(), err) }