Add configurable mount options to overlay

Allows default mount options to be provided through configuration.

Signed-off-by: Derek McGowan <derek@mcg.dev>
This commit is contained in:
Derek McGowan 2023-06-10 22:49:51 -07:00
parent 98b7dfb870
commit d115129d1e
No known key found for this signature in database
GPG Key ID: F58C5D0A4405ACDB
3 changed files with 53 additions and 21 deletions

View File

@ -44,6 +44,7 @@ const upperdirKey = "containerd.io/snapshot/overlay.upperdir"
type SnapshotterConfig struct { type SnapshotterConfig struct {
asyncRemove bool asyncRemove bool
upperdirLabel bool upperdirLabel bool
mountOptions []string
} }
// Opt is an option to configure the overlay snapshotter // Opt is an option to configure the overlay snapshotter
@ -67,13 +68,21 @@ func WithUpperdirLabel(config *SnapshotterConfig) error {
return nil return nil
} }
// WithMountOptions defines the default mount options used for the overlay mount.
// NOTE: Options are not applied to bind mounts.
func WithMountOptions(options []string) Opt {
return func(config *SnapshotterConfig) error {
config.mountOptions = append(config.mountOptions, options...)
return nil
}
}
type snapshotter struct { type snapshotter struct {
root string root string
ms *storage.MetaStore ms *storage.MetaStore
asyncRemove bool asyncRemove bool
upperdirLabel bool upperdirLabel bool
indexOff bool options []string
userxattr bool // whether to enable "userxattr" mount option
} }
// NewSnapshotter returns a Snapshotter which uses overlayfs. The overlayfs // NewSnapshotter returns a Snapshotter which uses overlayfs. The overlayfs
@ -105,10 +114,20 @@ func NewSnapshotter(root string, opts ...Opt) (snapshots.Snapshotter, error) {
if err := os.Mkdir(filepath.Join(root, "snapshots"), 0700); err != nil && !os.IsExist(err) { if err := os.Mkdir(filepath.Join(root, "snapshots"), 0700); err != nil && !os.IsExist(err) {
return nil, err return nil, err
} }
// figure out whether "userxattr" option is recognized by the kernel && needed
userxattr, err := overlayutils.NeedsUserXAttr(root) if !hasOption(config.mountOptions, "userxattr", false) {
if err != nil { // figure out whether "userxattr" option is recognized by the kernel && needed
logrus.WithError(err).Warnf("cannot detect whether \"userxattr\" option needs to be used, assuming to be %v", userxattr) userxattr, err := overlayutils.NeedsUserXAttr(root)
if err != nil {
logrus.WithError(err).Warnf("cannot detect whether \"userxattr\" option needs to be used, assuming to be %v", userxattr)
}
if userxattr {
config.mountOptions = append(config.mountOptions, "userxattr")
}
}
if !hasOption(config.mountOptions, "index", false) && supportsIndex() {
config.mountOptions = append(config.mountOptions, "index=off")
} }
return &snapshotter{ return &snapshotter{
@ -116,11 +135,23 @@ func NewSnapshotter(root string, opts ...Opt) (snapshots.Snapshotter, error) {
ms: ms, ms: ms,
asyncRemove: config.asyncRemove, asyncRemove: config.asyncRemove,
upperdirLabel: config.upperdirLabel, upperdirLabel: config.upperdirLabel,
indexOff: supportsIndex(), options: config.mountOptions,
userxattr: userxattr,
}, nil }, nil
} }
func hasOption(options []string, key string, hasValue bool) bool {
for _, option := range options {
if hasValue {
if strings.HasPrefix(option, key) && len(option) > len(key) && option[len(key)] == '=' {
return true
}
} else if option == key {
return true
}
}
return false
}
// Stat returns the info for an active or committed snapshot by name or // Stat returns the info for an active or committed snapshot by name or
// key. // key.
// //
@ -453,17 +484,8 @@ func (o *snapshotter) mounts(s storage.Snapshot) []mount.Mount {
}, },
} }
} }
var options []string
// set index=off when mount overlayfs
if o.indexOff {
options = append(options, "index=off")
}
if o.userxattr {
options = append(options, "userxattr")
}
options := o.options
if s.Kind == snapshots.KindActive { if s.Kind == snapshots.KindActive {
options = append(options, options = append(options,
fmt.Sprintf("workdir=%s", o.workPath(s.ID)), fmt.Sprintf("workdir=%s", o.workPath(s.ID)),

View File

@ -70,7 +70,7 @@ func TestOverlay(t *testing.T) {
testOverlayOverlayRead(t, newSnapshotter) testOverlayOverlayRead(t, newSnapshotter)
}) })
t.Run("TestOverlayView", func(t *testing.T) { t.Run("TestOverlayView", func(t *testing.T) {
testOverlayView(t, newSnapshotter) testOverlayView(t, newSnapshotterWithOpts(append(opts, WithMountOptions([]string{"volatile"}))...))
}) })
}) })
} }
@ -329,7 +329,7 @@ func testOverlayView(t *testing.T, newSnapshotter testsuite.SnapshotterFunc) {
} }
supportsIndex := supportsIndex() supportsIndex := supportsIndex()
expectedOptions := 2 expectedOptions := 3
if !supportsIndex { if !supportsIndex {
expectedOptions-- expectedOptions--
} }
@ -346,13 +346,16 @@ func testOverlayView(t *testing.T, newSnapshotter testsuite.SnapshotterFunc) {
} }
lowers := getParents(ctx, o, root, "/tmp/view2") lowers := getParents(ctx, o, root, "/tmp/view2")
expected = fmt.Sprintf("lowerdir=%s:%s", lowers[0], lowers[1]) expected = fmt.Sprintf("lowerdir=%s:%s", lowers[0], lowers[1])
optIdx := 1 optIdx := 2
if !supportsIndex { if !supportsIndex {
optIdx-- optIdx--
} }
if userxattr { if userxattr {
optIdx++ optIdx++
} }
if m.Options[0] != "volatile" {
t.Error("expected option first option to be provided option \"volatile\"")
}
if m.Options[optIdx] != expected { if m.Options[optIdx] != expected {
t.Errorf("expected option %q but received %q", expected, m.Options[optIdx]) t.Errorf("expected option %q but received %q", expected, m.Options[optIdx])
} }

View File

@ -32,6 +32,9 @@ type Config struct {
RootPath string `toml:"root_path"` RootPath string `toml:"root_path"`
UpperdirLabel bool `toml:"upperdir_label"` UpperdirLabel bool `toml:"upperdir_label"`
SyncRemove bool `toml:"sync_remove"` SyncRemove bool `toml:"sync_remove"`
// MountOptions are options used for the overlay mount (not used on bind mounts)
MountOptions []string `toml:"mount_options"`
} }
func init() { func init() {
@ -60,6 +63,10 @@ func init() {
oOpts = append(oOpts, overlay.AsynchronousRemove) oOpts = append(oOpts, overlay.AsynchronousRemove)
} }
if len(config.MountOptions) > 0 {
oOpts = append(oOpts, overlay.WithMountOptions(config.MountOptions))
}
ic.Meta.Exports["root"] = root ic.Meta.Exports["root"] = root
return overlay.NewSnapshotter(root, oOpts...) return overlay.NewSnapshotter(root, oOpts...)
}, },