Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion runsc/boot/vfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -812,10 +812,12 @@ func (c *containerMounter) prepareMounts() ([]mountInfo, error) {
hint: c.hints.FindMount(c.mounts[i].Source),
}
specutils.MaybeConvertToBindMount(info.mount)
if specutils.IsGoferMount(*info.mount) {
if specutils.IsGoferMount(*info.mount) || specutils.IsErofsMount(*info.mount) {
info.goferMountConf = c.goferMountConfs[goferMntIdx]
if info.goferMountConf.ShouldUseLisafs() {
info.goferFD = c.goferFDs.removeAsFD()
} else if info.goferMountConf.ShouldUseErofs() {
info.goferFD = c.goferFDs.removeAsFD()
}
if info.goferMountConf.IsFilestorePresent() {
info.filestoreFD = c.goferFilestoreFDs.removeAsFD()
Expand Down Expand Up @@ -988,6 +990,18 @@ func getMountNameAndOptions(spec *specs.Spec, conf *config.Config, m *mountInfo,
return "", nil, err
}

case erofs.Name:
if m.goferFD == nil {
return "", nil, fmt.Errorf("EROFS mount requires an image file FD")
}
data = []string{fmt.Sprintf("ifd=%d", m.goferFD.Release())}
internalData = erofs.InternalFilesystemOptions{
UniqueID: vfs.RestoreID{
ContainerName: containerName,
Path: m.mount.Destination,
},
}

default:
log.Warningf("ignoring unknown filesystem type %q", m.mount.Type)
return "", nil, nil
Expand Down
16 changes: 16 additions & 0 deletions runsc/cmd/gofer.go
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,11 @@ func (g *Gofer) serve(spec *specs.Spec, conf *config.Config, root string, ruid i

mountIdx := 1 // first one is the root
for _, m := range spec.Mounts {
// EROFS mounts are in goferMountConfs but gofer doesn't serve them
if specutils.IsErofsMount(m) {
mountIdx++
continue
}
if !specutils.IsGoferMount(m) {
continue
}
Expand Down Expand Up @@ -528,6 +533,11 @@ func (g *Gofer) setupRootFS(spec *specs.Spec, conf *config.Config, goferToHostRP
func (g *Gofer) setupMounts(conf *config.Config, mounts []specs.Mount, root, procPath string, goferToHostRPC *urpc.Client) (retErr error) {
mountIdx := 1 // First index is for rootfs.
for _, m := range mounts {
// EROFS mounts are in goferMountConfs but gofer doesn't set them up
if specutils.IsErofsMount(m) {
mountIdx++
continue
}
if !specutils.IsGoferMount(m) {
continue
}
Expand Down Expand Up @@ -690,6 +700,12 @@ func (g *Gofer) resolveMounts(conf *config.Config, mounts []specs.Mount, root st
mountIdx := 1 // First index is for rootfs.
cleanMounts := make([]specs.Mount, 0, len(mounts))
for _, m := range mounts {
// EROFS mounts are in goferMountConfs but gofer doesn't resolve them
if specutils.IsErofsMount(m) {
cleanMounts = append(cleanMounts, m)
mountIdx++
continue
}
if !specutils.IsGoferMount(m) {
cleanMounts = append(cleanMounts, m)
continue
Expand Down
50 changes: 44 additions & 6 deletions runsc/container/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -911,6 +911,11 @@ func (c *Container) forEachSelfMount(fn func(mountSrc string)) {
}
goferMntIdx := 1 // First index is for rootfs.
for i := range c.Spec.Mounts {
// EROFS mounts are in goferMountConfs but don't have self-backed filestores
if specutils.IsErofsMount(c.Spec.Mounts[i]) {
goferMntIdx++
continue
}
if !specutils.IsGoferMount(c.Spec.Mounts[i]) {
continue
}
Expand Down Expand Up @@ -985,12 +990,17 @@ func (c *Container) initGoferConfs(ovlConf config.Overlay2, mountHints *boot.Pod

// Handle bind mounts.
for i := range c.Spec.Mounts {
if !specutils.IsGoferMount(c.Spec.Mounts[i]) {
if !specutils.IsGoferMount(c.Spec.Mounts[i]) && !specutils.IsErofsMount(c.Spec.Mounts[i]) {
continue
}
// Determine mount type: Bind for gofer mounts, erofs.Name for EROFS mounts
mountType := boot.Bind
if specutils.IsErofsMount(c.Spec.Mounts[i]) {
mountType = erofs.Name
}

overlayMedium := ovlConf.SubMountOverlayMedium()
overlaySize := ovlConf.SubMountOverlaySize()
mountType = boot.Bind
if specutils.IsReadonlyMount(c.Spec.Mounts[i].Options) {
overlayMedium = config.NoOverlay
}
Expand Down Expand Up @@ -1037,6 +1047,11 @@ func (c *Container) createGoferFilestores(ovlConf config.Overlay2, mountHints *b
// Then handle all the bind mounts.
mountIdx := 1 // first one is the root
for _, m := range c.Spec.Mounts {
// EROFS mounts are in goferMountConfs but don't need filestore processing
if specutils.IsErofsMount(m) {
mountIdx++
continue
}
if !specutils.IsGoferMount(m) {
continue
}
Expand Down Expand Up @@ -1377,7 +1392,19 @@ func (c *Container) createGoferProcess(conf *config.Config, mountHints *boot.Pod
}

sandEnds := make([]*os.File, 0, ioFileCount)
// Track which spec.Mount corresponds to which goferMountConf
mountIdx := 0
for i, cfg := range c.GoferMountConfs {
// Align spec mount with gofer mount conf by skipping non-gofer/non-erofs mounts
// Skip alignment for root mount (i == 0) because it is not present in spec.Mounts
if i > 0 {
for mountIdx < len(c.Spec.Mounts) &&
!specutils.IsGoferMount(c.Spec.Mounts[mountIdx]) &&
!specutils.IsErofsMount(c.Spec.Mounts[mountIdx]) {
mountIdx++
}
}

switch {
case cfg.ShouldUseLisafs():
fds, err := unix.Socketpair(unix.AF_UNIX, unix.SOCK_STREAM|unix.SOCK_CLOEXEC, 0)
Expand All @@ -1390,15 +1417,26 @@ func (c *Container) createGoferProcess(conf *config.Config, mountHints *boot.Pod
donations.DonateAndClose("io-fds", goferEnd)

case cfg.ShouldUseErofs():
if i > 0 {
return nil, nil, nil, nil, fmt.Errorf("EROFS lower layer is only supported for root mount")
// Get the source for the EROFS image
var mountSrc string
if i == 0 {
// Root mount
mountSrc = rootfsHint.Mount.Source
} else {
// Non-root mount: use the aligned mountIdx
mountSrc = c.Spec.Mounts[mountIdx].Source
}
f, err := os.Open(rootfsHint.Mount.Source)
f, err := os.Open(mountSrc)
if err != nil {
return nil, nil, nil, nil, fmt.Errorf("opening rootfs image %q: %v", rootfsHint.Mount.Source, err)
return nil, nil, nil, nil, fmt.Errorf("opening EROFS image %q: %v", mountSrc, err)
}
sandEnds = append(sandEnds, f)
}

// Move to next mount in spec (for non-root mounts)
if i > 0 {
mountIdx++
}
}
var devSandEnd *os.File
if shouldCreateDeviceGofer(c.Spec, conf) {
Expand Down
1 change: 1 addition & 0 deletions runsc/specutils/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ go_library(
"//pkg/abi/linux",
"//pkg/log",
"//pkg/sentry/devices/nvproxy/nvconf",
"//pkg/sentry/fsimpl/erofs",
"//pkg/sentry/kernel/auth",
"//runsc/config",
"//runsc/flag",
Expand Down
6 changes: 6 additions & 0 deletions runsc/specutils/specutils.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import (
"golang.org/x/sys/unix"
"gvisor.dev/gvisor/pkg/abi/linux"
"gvisor.dev/gvisor/pkg/log"
"gvisor.dev/gvisor/pkg/sentry/fsimpl/erofs"
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
"gvisor.dev/gvisor/runsc/config"
"gvisor.dev/gvisor/runsc/flag"
Expand Down Expand Up @@ -502,6 +503,11 @@ func IsGoferMount(m specs.Mount) bool {
return m.Type == "bind" && m.Source != ""
}

// IsErofsMount returns true if the given mount can be mounted as EROFS.
func IsErofsMount(m specs.Mount) bool {
return m.Type == erofs.Name
}

// MaybeConvertToBindMount converts mount type to "bind" in case any of the
// mount options are either "bind" or "rbind" as required by the OCI spec.
//
Expand Down