diff --git a/types/options.go b/types/options.go index 7189a8e6a4..20bf5057f9 100644 --- a/types/options.go +++ b/types/options.go @@ -305,7 +305,11 @@ func getRootlessStorageOpts(rootlessUID int, systemOpts StoreOptions) (StoreOpti } if opts.GraphDriverName == "" { if len(systemOpts.GraphDriverPriority) == 0 { - opts.GraphDriverName = "vfs" + if canUseRootlessOverlay(opts.GraphRoot, opts.RunRoot) { + opts.GraphDriverName = overlayDriver + } else { + opts.GraphDriverName = "vfs" + } } else { opts.GraphDriverPriority = systemOpts.GraphDriverPriority } diff --git a/types/options_darwin.go b/types/options_darwin.go index eed1a3d94b..3c8ff4e4e8 100644 --- a/types/options_darwin.go +++ b/types/options_darwin.go @@ -11,3 +11,8 @@ const ( var ( defaultOverrideConfigFile = "/etc/containers/storage.conf" ) + +// canUseRootlessOverlay returns true if the overlay driver can be used for rootless containers +func canUseRootlessOverlay(home, runhome string) bool { + return false +} diff --git a/types/options_freebsd.go b/types/options_freebsd.go index afb7ec6b4a..be2bc2f27d 100644 --- a/types/options_freebsd.go +++ b/types/options_freebsd.go @@ -12,3 +12,8 @@ const ( var ( defaultOverrideConfigFile = "/usr/local/etc/containers/storage.conf" ) + +// canUseRootlessOverlay returns true if the overlay driver can be used for rootless containers +func canUseRootlessOverlay(home, runhome string) bool { + return false +} diff --git a/types/options_linux.go b/types/options_linux.go index d44aaf76a3..a28e82883c 100644 --- a/types/options_linux.go +++ b/types/options_linux.go @@ -1,5 +1,13 @@ package types +import ( + "os/exec" + "strconv" + "strings" + + "golang.org/x/sys/unix" +) + const ( // these are default path for run and graph root for rootful users // for rootless path is constructed via getRootlessStorageOpts @@ -12,3 +20,33 @@ const ( var ( defaultOverrideConfigFile = "/etc/containers/storage.conf" ) + +// canUseRootlessOverlay returns true if the overlay driver can be used for rootless containers +func canUseRootlessOverlay(home, runhome string) bool { + // we check first for fuse-overlayfs since it is cheaper. + if path, _ := exec.LookPath("fuse-overlayfs"); path != "" { + return true + } + + // We cannot use overlay.SupportsNativeOverlay since canUseRootlessOverlay is called by Podman + // before we enter the user namespace and the driver we pick here is written in the podman database. + // Checking the kernel version is usually not a good idea since the feature could be back-ported, e.g. RHEL + // but this is just an heuristic and on RHEL we always install the storage.conf file. + // native overlay for rootless was added upstream in 5.13 (at least the first version that we support), so check + // that the kernel is >= 5.13. + var uts unix.Utsname + if err := unix.Uname(&uts); err == nil { + parts := strings.Split(string(uts.Release[:]), ".") + major, _ := strconv.Atoi(parts[0]) + if major >= 6 { + return true + } + if major == 5 && len(parts) > 1 { + minor, _ := strconv.Atoi(parts[1]) + if minor >= 13 { + return true + } + } + } + return false +} diff --git a/types/options_test.go b/types/options_test.go index 53ca9f9179..23bc6d2868 100644 --- a/types/options_test.go +++ b/types/options_test.go @@ -19,6 +19,27 @@ func TestGetRootlessStorageOpts(t *testing.T) { const vfsDriver = "vfs" + t.Run("systemDriver=", func(t *testing.T) { + systemOpts := StoreOptions{} + + td := t.TempDir() + home := filepath.Join(td, "unset-driver-home") + runhome := filepath.Join(td, "unset-driver-runhome") + defer os.RemoveAll(home) + defer os.RemoveAll(runhome) + + systemOpts.GraphRoot = home + systemOpts.RunRoot = runhome + storageOpts, err := getRootlessStorageOpts(os.Geteuid(), systemOpts) + + assert.NilError(t, err) + expectedDriver := vfsDriver + if canUseRootlessOverlay(home, runhome) { + expectedDriver = overlayDriver + } + assert.Equal(t, storageOpts.GraphDriverName, expectedDriver) + }) + t.Run("systemDriver=btrfs", func(t *testing.T) { systemOpts := StoreOptions{} systemOpts.GraphDriverName = "btrfs" diff --git a/types/options_windows.go b/types/options_windows.go index d44aaf76a3..c1bea9fac0 100644 --- a/types/options_windows.go +++ b/types/options_windows.go @@ -12,3 +12,8 @@ const ( var ( defaultOverrideConfigFile = "/etc/containers/storage.conf" ) + +// canUseRootlessOverlay returns true if the overlay driver can be used for rootless containers +func canUseRootlessOverlay(home, runhome string) bool { + return false +}