Merge pull request #9555 from KodieGlosserIBM/strip-volatile-option-tmp-mounts

Remove overlayfs volatile option on temp mounts
This commit is contained in:
Phil Estes 2024-01-20 03:32:54 +00:00 committed by GitHub
commit e73942d23d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 150 additions and 1 deletions

View File

@ -148,3 +148,114 @@ func TestReadonlyMounts(t *testing.T) {
} }
} }
} }
func TestRemoveVolatileTempMount(t *testing.T) {
testCases := []struct {
desc string
input []Mount
expected []Mount
}{
{
desc: "remove volatile option from overlay mounts, ignore non overlay",
input: []Mount{
{
Type: "overlay",
Source: "overlay",
Options: []string{
"index=off",
"workdir=/path/to/snapshots/4/work",
"upperdir=/path/to/snapshots/4/fs",
"lowerdir=/path/to/snapshots/1/fs",
"volatile",
},
},
{
Type: "underlay",
Source: "underlay",
Options: []string{
"index=on",
"lowerdir=/another/path/to/snapshots/2/fs",
"volatile",
},
},
},
expected: []Mount{
{
Type: "overlay",
Source: "overlay",
Options: []string{
"index=off",
"workdir=/path/to/snapshots/4/work",
"upperdir=/path/to/snapshots/4/fs",
"lowerdir=/path/to/snapshots/1/fs",
},
},
{
Type: "underlay",
Source: "underlay",
Options: []string{
"index=on",
"lowerdir=/another/path/to/snapshots/2/fs",
"volatile",
},
},
},
},
{
desc: "return original slice since no volatile options on overlay",
input: []Mount{
{
Type: "overlay",
Source: "overlay",
Options: []string{
"index=off",
"workdir=/path/to/snapshots/4/work",
"upperdir=/path/to/snapshots/4/fs",
"lowerdir=/path/to/snapshots/1/fs",
},
},
{
Type: "underlay",
Source: "underlay",
Options: []string{
"index=on",
"lowerdir=/another/path/to/snapshots/2/fs",
"volatile",
},
},
},
expected: []Mount{
{
Type: "overlay",
Source: "overlay",
Options: []string{
"index=off",
"workdir=/path/to/snapshots/4/work",
"upperdir=/path/to/snapshots/4/fs",
"lowerdir=/path/to/snapshots/1/fs",
},
},
{
Type: "underlay",
Source: "underlay",
Options: []string{
"index=on",
"lowerdir=/another/path/to/snapshots/2/fs",
"volatile",
},
},
},
},
}
for _, tc := range testCases {
original := copyMounts(tc.input)
actual := removeVolatileTempMount(tc.input)
if !reflect.DeepEqual(actual, tc.expected) {
t.Fatalf("incorrectly modified mounts: %s.\n\n Expected: %v\n\n, Actual: %v", tc.desc, tc.expected, actual)
}
if !reflect.DeepEqual(original, tc.input) {
t.Fatalf("modified original mounts: %s.\n\n Expected: %v\n\n, Actual: %v", tc.desc, original, tc.input)
}
}
}

View File

@ -28,6 +28,7 @@ var tempMountLocation = getTempDir()
// WithTempMount mounts the provided mounts to a temp dir, and pass the temp dir to f. // WithTempMount mounts the provided mounts to a temp dir, and pass the temp dir to f.
// The mounts are valid during the call to the f. // The mounts are valid during the call to the f.
// The volatile option of overlayfs doesn't allow to mount again using the same upper / work dirs. Since it's a temp mount, avoid using that option here if found.
// Finally we will unmount and remove the temp dir regardless of the result of f. // Finally we will unmount and remove the temp dir regardless of the result of f.
func WithTempMount(ctx context.Context, mounts []Mount, f func(root string) error) (err error) { func WithTempMount(ctx context.Context, mounts []Mount, f func(root string) error) (err error) {
root, uerr := os.MkdirTemp(tempMountLocation, "containerd-mount") root, uerr := os.MkdirTemp(tempMountLocation, "containerd-mount")
@ -58,7 +59,8 @@ func WithTempMount(ctx context.Context, mounts []Mount, f func(root string) erro
} }
} }
}() }()
if uerr = All(mounts, root); uerr != nil {
if uerr = All(removeVolatileTempMount(mounts), root); uerr != nil {
return fmt.Errorf("failed to mount %s: %w", root, uerr) return fmt.Errorf("failed to mount %s: %w", root, uerr)
} }
if err := f(root); err != nil { if err := f(root); err != nil {
@ -67,6 +69,42 @@ func WithTempMount(ctx context.Context, mounts []Mount, f func(root string) erro
return nil return nil
} }
// removeVolatileTempMount The volatile option of overlayfs doesn't allow to mount again using the
// same upper / work dirs. Since it's a temp mount, avoid using that
// option here. Reference: https://docs.kernel.org/filesystems/overlayfs.html#volatile-mount
// TODO: Make this logic conditional once the kernel supports reusing
// overlayfs volatile mounts.
func removeVolatileTempMount(mounts []Mount) []Mount {
var out []Mount
for i, m := range mounts {
if m.Type != "overlay" {
continue
}
for j, opt := range m.Options {
if opt == "volatile" {
if out == nil {
out = copyMounts(mounts)
}
out[i].Options = append(out[i].Options[:j], out[i].Options[j+1:]...)
break
}
}
}
if out != nil {
return out
}
return mounts
}
// copyMounts creates a copy of the original slice to allow for modification and not altering the original
func copyMounts(in []Mount) []Mount {
out := make([]Mount, len(in))
copy(out, in)
return out
}
// WithReadonlyTempMount mounts the provided mounts to a temp dir as readonly, // WithReadonlyTempMount mounts the provided mounts to a temp dir as readonly,
// and pass the temp dir to f. The mounts are valid during the call to the f. // and pass the temp dir to f. The mounts are valid during the call to the f.
// Finally we will unmount and remove the temp dir regardless of the result of f. // Finally we will unmount and remove the temp dir regardless of the result of f.