Skip to content

Commit

Permalink
oci: support for writable extfs img overlay via fuse-overlayfs
Browse files Browse the repository at this point in the history
  • Loading branch information
Omer Preminger committed Jun 6, 2023
1 parent 4962ce3 commit 413c567
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 19 deletions.
11 changes: 6 additions & 5 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,12 @@
`--fakeroot`, for example).
- The `remote status` command will now print the username, realname, and email
of the logged-in user, if available.
- OCI-mode now supports an `--overlay <arg>` flag. `<arg>` can be a writable
directory, in which case changes to the filesystem will persist across runs of
the OCI container. Alternatively, `<arg>` can be `<dir>:ro` or the path of a
squashfs or extfs image, to be mounted as a read-only overlay. Multiple
overlays can be specified, but all but one must be read-only.
- OCI-mode now supports the `--overlay <arg>` flag. `<arg>` can be the path to a
writable directory or writable extfs image, in which case changes to the
filesystem will persist across runs of the OCI container. Alternatively,
`--overlay <arg>:ro` can be used, where `<arg>` is the path to a directory, to
a squashfs image, or to an extfs image, to be mounted as a read-only overlay.
Multiple overlays can be specified, but all but one must be read-only.
- The `tap` CNI plugin, new to github.com/containernetworking/plugins v1.3.0,
is now provided.
- OCI-mode now supports the `--workdir <workdir>` option. If this option is
Expand Down
28 changes: 18 additions & 10 deletions internal/pkg/util/fs/overlay/overlay_item_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,25 +128,31 @@ func (i *Item) GetParentDir() (string, error) {
// this method does not mount the assembled overlay itself. That happens in
// Set.Mount().
func (i *Item) Mount() error {
if i.Writable {
if err := i.prepareWritableOverlay(); err != nil {
return err
}
}

var err error
switch i.Type {
case image.SANDBOX:
return i.mountDir()
err = i.mountDir()
case image.SQUASHFS:
return i.mountWithFuse("squashfuse")
err = i.mountWithFuse("squashfuse")
case image.EXT3:
if i.Writable {
return fmt.Errorf("mounting writable extfs images is not currently supported, please use :ro suffix on image specification for read-only mode")
err = i.mountWithFuse("fuse2fs", "-o", "rw")
} else {
err = i.mountWithFuse("fuse2fs", "-o", "ro")
}
return i.mountWithFuse("fuse2fs", "-o", "ro")
default:
return fmt.Errorf("internal error: unrecognized image type in overlay.Item.Mount() (type: %v)", i.Type)
}

if err != nil {
return err
}

if i.Writable {
return i.prepareWritableOverlay()
}

return nil
}

// mountDir mounts directory-based Items. This involves bind-mounting followed
Expand Down Expand Up @@ -277,6 +283,8 @@ func (i *Item) prepareWritableOverlay() error {
switch i.Type {
case image.SANDBOX:
i.StagingDir = i.SourcePath
fallthrough
case image.EXT3:
if err := EnsureOverlayDir(i.StagingDir, true, 0o755); err != nil {
return err
}
Expand Down
20 changes: 16 additions & 4 deletions internal/pkg/util/fs/overlay/overlay_set_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (

"github.com/samber/lo"
"github.com/sylabs/singularity/internal/pkg/util/bin"
"github.com/sylabs/singularity/pkg/image"
"github.com/sylabs/singularity/pkg/sylog"
)

Expand Down Expand Up @@ -66,7 +67,8 @@ func (s Set) Unmount(rootFsDir string) error {
return fmt.Errorf("while checking for unprivileged overlay support in kernel: %w", err)
}

if unprivOls {
useKernelMount := unprivOls && !s.hasWritableExtfsImg()
if useKernelMount {
err = DetachMount(rootFsDir)
} else {
err = UnmountWithFuse(rootFsDir)
Expand Down Expand Up @@ -108,22 +110,24 @@ func (s Set) performFinalMount(rootFsDir string) error {
return fmt.Errorf("while checking for unprivileged overlay support in kernel: %w", err)
}

if unprivOls {
useKernelMount := unprivOls && !s.hasWritableExtfsImg()

if useKernelMount {
sylog.Debugf("Mounting overlay (via syscall) with rootFsDir %q, options: %q", rootFsDir, options)
if err := syscall.Mount("overlay", rootFsDir, "overlay", syscall.MS_NODEV, options); err != nil {
return fmt.Errorf("failed to mount %s: %w", rootFsDir, err)
}
} else {
fuseOlFsCmd, err := bin.FindBin("fuse-overlayfs")
if err != nil {
return fmt.Errorf("kernel does not support unprivileged overlays, and fuse-overlayfs not available: %w", err)
return fmt.Errorf("'fuse-overlayfs' must be used for this overlay specification, but is not available: %w", err)
}

// Even though fusermount is not needed for this step, we shouldn't perform
// the mount unless we have the necessary tools to eventually unmount it
_, err = bin.FindBin("fusermount")
if err != nil {
return fmt.Errorf("kernel does not support unprivileged overlays, and using fuse-overlayfs fallback requires fusermount to be installed: %w", err)
return fmt.Errorf("'fuse-overlayfs' must be used for this overlay specification, and this also requires 'fusermount' to be installed: %w", err)
}

sylog.Debugf("Mounting overlay (via fuse-overlayfs) with rootFsDir %q, options: %q", rootFsDir, options)
Expand Down Expand Up @@ -156,6 +160,14 @@ func (s Set) options(rootFsDir string) string {
lowerDirJoined, s.WritableOverlay.Upper(), s.WritableOverlay.Work())
}

func (s Set) hasWritableExtfsImg() bool {
if (s.WritableOverlay != nil) && (s.WritableOverlay.Type == image.EXT3) {
return true
}

return false
}

// detachIndividualMounts detaches the bind mounts & remounts created by
// performIndividualMounts, above.
func (s Set) detachIndividualMounts() error {
Expand Down

0 comments on commit 413c567

Please sign in to comment.