diff --git a/docs/containers-storage.conf.5.md b/docs/containers-storage.conf.5.md index cf12f31dda..7ac3f98e2d 100644 --- a/docs/containers-storage.conf.5.md +++ b/docs/containers-storage.conf.5.md @@ -58,6 +58,10 @@ The `storage.options` table supports the following options: **mount_program**="" Specifies the path to a custom program to use instead for mounting the file system. +**mountopt**="" + + Comma separated list of default options to be used to mount container images. Suggested value "nodev". + [storage.options.thinpool] Storage Options for thinpool @@ -112,10 +116,6 @@ Specifies the min free space percent in a thin pool required for new device crea Specifies extra mkfs arguments to be used when creating the base device. -**mountopt**="" - -Specifies extra mount options used when mounting the thin devices. - **use_deferred_removal**="" Marks devicemapper block device for deferred removal. If the device is in use when its driver attempts to remove it, the driver tells the kernel to remove the device as soon as possible. Note this does not free up the disk space, use deferred deletion to fully remove the thinpool. (default: true). diff --git a/drivers/aufs/aufs.go b/drivers/aufs/aufs.go index bbbe9e4af8..ff367a1262 100644 --- a/drivers/aufs/aufs.go +++ b/drivers/aufs/aufs.go @@ -42,6 +42,7 @@ import ( "github.com/containers/storage/pkg/idtools" "github.com/containers/storage/pkg/locker" mountpk "github.com/containers/storage/pkg/mount" + "github.com/containers/storage/pkg/parsers" "github.com/containers/storage/pkg/system" rsystem "github.com/opencontainers/runc/libcontainer/system" "github.com/opencontainers/selinux/go-selinux/label" @@ -77,6 +78,7 @@ type Driver struct { pathCache map[string]string naiveDiff graphdriver.DiffDriver locker *locker.Locker + mountOptions string } // Init returns a new AUFS driver. @@ -103,6 +105,20 @@ func Init(root string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap return nil, errors.Wrapf(graphdriver.ErrIncompatibleFS, "AUFS is not supported over %q", backingFs) } + var mountOptions string + for _, option := range options { + key, val, err := parsers.ParseKeyValueOpt(option) + if err != nil { + return nil, err + } + key = strings.ToLower(key) + switch key { + case "aufs.mountopt": + mountOptions = val + default: + return nil, fmt.Errorf("option %s not supported", option) + } + } paths := []string{ "mnt", "diff", @@ -110,12 +126,13 @@ func Init(root string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap } a := &Driver{ - root: root, - uidMaps: uidMaps, - gidMaps: gidMaps, - pathCache: make(map[string]string), - ctr: graphdriver.NewRefCounter(graphdriver.NewFsChecker(graphdriver.FsMagicAufs)), - locker: locker.New(), + root: root, + uidMaps: uidMaps, + gidMaps: gidMaps, + pathCache: make(map[string]string), + ctr: graphdriver.NewRefCounter(graphdriver.NewFsChecker(graphdriver.FsMagicAufs)), + locker: locker.New(), + mountOptions: mountOptions, } rootUID, rootGID, err := idtools.GetRootUIDGID(uidMaps, gidMaps) @@ -653,6 +670,10 @@ func (a *Driver) aufsMount(ro []string, rw, target, mountLabel string) (err erro } opts := "dio,xino=/dev/shm/aufs.xino" + if a.mountOptions != "" { + opts += fmt.Sprintf(",%s", a.mountOptions) + } + if useDirperm() { opts += ",dirperm1" } diff --git a/drivers/btrfs/btrfs.go b/drivers/btrfs/btrfs.go index 4b9699fdb3..842079a1c8 100644 --- a/drivers/btrfs/btrfs.go +++ b/drivers/btrfs/btrfs.go @@ -110,6 +110,8 @@ func parseOptions(opt []string) (btrfsOptions, bool, error) { } userDiskQuota = true options.minSpace = uint64(minSpace) + case "btrfs.mountopt": + return options, userDiskQuota, fmt.Errorf("btrfs driver does not support mount options") default: return options, userDiskQuota, fmt.Errorf("Unknown option %s", key) } diff --git a/drivers/devmapper/deviceset.go b/drivers/devmapper/deviceset.go index 0fab980b9b..cbf67b3eb5 100644 --- a/drivers/devmapper/deviceset.go +++ b/drivers/devmapper/deviceset.go @@ -2690,7 +2690,7 @@ func NewDeviceSet(root string, doInit bool, options []string, uidMaps, gidMaps [ devices.filesystem = val case "dm.mkfsarg": devices.mkfsArgs = append(devices.mkfsArgs, val) - case "dm.mountopt": + case "dm.mountopt", "devicemapper.mountopt": devices.mountOptions = joinMountOptions(devices.mountOptions, val) case "dm.metadatadev": devices.metadataDevice = val diff --git a/drivers/overlay/overlay.go b/drivers/overlay/overlay.go index fbe36f4a46..d2f7c373ae 100644 --- a/drivers/overlay/overlay.go +++ b/drivers/overlay/overlay.go @@ -88,6 +88,7 @@ type overlayOptions struct { mountProgram string ostreeRepo string skipMountHome bool + mountOptions string } // Driver contains information about the home directory and the list of active mounts that are created using this driver. @@ -222,6 +223,8 @@ func parseOptions(options []string) (*overlayOptions, error) { if err != nil { return nil, err } + case ".mountopt", "overlay.mountopt", "overlay2.mountopt": + o.mountOptions = val case ".size", "overlay.size", "overlay2.size": logrus.Debugf("overlay: size=%s", val) size, err := units.RAMInBytes(val) @@ -716,6 +719,9 @@ func (d *Driver) Get(id, mountLabel string) (_ string, retErr error) { if len(mountData) > pageSize || d.options.mountProgram != "" { //FIXME: We need to figure out to get this to work with additional stores opts = fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", strings.Join(relLowers, ":"), path.Join(id, "diff"), path.Join(id, "work")) + if d.options.mountOptions != "" { + opts = fmt.Sprintf("%s,%s", d.options.mountOptions, opts) + } mountData = label.FormatMountLabel(opts, mountLabel) if len(mountData) > pageSize { return "", fmt.Errorf("cannot mount layer, mount label too large %d", len(mountData)) diff --git a/drivers/vfs/driver.go b/drivers/vfs/driver.go index 9314cb8760..ed9f70094a 100644 --- a/drivers/vfs/driver.go +++ b/drivers/vfs/driver.go @@ -55,6 +55,9 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap } d.ostreeRepo = option[13:] } + if strings.HasPrefix(option, "vfs.mountopt=") { + return nil, fmt.Errorf("vfs driver does not support mount options") + } } if d.ostreeRepo != "" { rootUID, rootGID, err := idtools.GetRootUIDGID(uidMaps, gidMaps) diff --git a/drivers/windows/windows.go b/drivers/windows/windows.go index 1d84b0b6af..15c90b54dc 100644 --- a/drivers/windows/windows.go +++ b/drivers/windows/windows.go @@ -86,6 +86,14 @@ type Driver struct { func InitFilter(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) { logrus.Debugf("WindowsGraphDriver InitFilter at %s", home) + for _, option := range options { + if strings.HasPrefix(option, "windows.mountopt=") { + return nil, fmt.Errorf("windows driver does not support mount options") + } else { + return nil, fmt.Errorf("option %s not supported", option) + } + } + fsType, err := getFileSystemType(string(home[0])) if err != nil { return nil, err diff --git a/drivers/zfs/zfs.go b/drivers/zfs/zfs.go index 886ebc8bdb..598cc0699f 100644 --- a/drivers/zfs/zfs.go +++ b/drivers/zfs/zfs.go @@ -24,8 +24,9 @@ import ( ) type zfsOptions struct { - fsName string - mountPath string + fsName string + mountPath string + mountOptions string } func init() { @@ -134,6 +135,8 @@ func parseOptions(opt []string) (zfsOptions, error) { switch key { case "zfs.fsname": options.fsName = val + case "zfs.mountopt": + options.mountOptions = val default: return options, fmt.Errorf("Unknown option %s", key) } @@ -364,7 +367,7 @@ func (d *Driver) Get(id, mountLabel string) (string, error) { } filesystem := d.zfsPath(id) - options := label.FormatMountLabel("", mountLabel) + options := label.FormatMountLabel(d.options.mountOptions, mountLabel) logrus.Debugf(`[zfs] mount("%s", "%s", "%s")`, filesystem, mountpoint, options) rootUID, rootGID, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps) diff --git a/storage.conf b/storage.conf index 636fe72c8d..b0ca16283e 100644 --- a/storage.conf +++ b/storage.conf @@ -32,6 +32,9 @@ size = "" # OverrideKernelCheck tells the driver to ignore kernel checks based on kernel version override_kernel_check = "false" +# mountopt specifies comma separated list of extra mount options +mountopt = "nodev" + # Remap-UIDs/GIDs is the mapping from UIDs/GIDs as they should appear inside of # a container, to UIDs/GIDs as they should appear outside of the container, and # the length of the range of UIDs/GIDs. Additional mapped sets can be listed @@ -103,9 +106,6 @@ override_kernel_check = "false" # device. # mkfsarg = "" -# mountopt specifies extra mount options used when mounting the thin devices. -# mountopt = "" - # use_deferred_removal marks devicemapper block device for deferred removal. # If the thinpool is in use when the driver attempts to remove it, the driver # tells the kernel to remove it as soon as possible. Note this does not free diff --git a/store.go b/store.go index bdfbb1c2cb..c7e2d48ea9 100644 --- a/store.go +++ b/store.go @@ -3015,6 +3015,9 @@ type OptionsConfig struct { // Alternative program to use for the mount of the file system MountProgram string `toml:"mount_program"` + + // MountOpt specifies extra mount options used when mounting + MountOpt string `toml:"mountopt"` } // TOML-friendly explicit tables used for conversions. @@ -3086,7 +3089,7 @@ func ReloadConfigurationFile(configFile string, storeOptions *StoreOptions) { storeOptions.GraphDriverOptions = append(storeOptions.GraphDriverOptions, fmt.Sprintf("dm.mkfsarg=%s", config.Storage.Options.Thinpool.MkfsArg)) } if config.Storage.Options.Thinpool.MountOpt != "" { - storeOptions.GraphDriverOptions = append(storeOptions.GraphDriverOptions, fmt.Sprintf("dm.mountopt=%s", config.Storage.Options.Thinpool.MountOpt)) + storeOptions.GraphDriverOptions = append(storeOptions.GraphDriverOptions, fmt.Sprintf("%s.mountopt=%s", config.Storage.Driver, config.Storage.Options.Thinpool.MountOpt)) } if config.Storage.Options.Thinpool.UseDeferredDeletion != "" { storeOptions.GraphDriverOptions = append(storeOptions.GraphDriverOptions, fmt.Sprintf("dm.use_deferred_deletion=%s", config.Storage.Options.Thinpool.UseDeferredDeletion)) @@ -3112,6 +3115,9 @@ func ReloadConfigurationFile(configFile string, storeOptions *StoreOptions) { if config.Storage.Options.MountProgram != "" { storeOptions.GraphDriverOptions = append(storeOptions.GraphDriverOptions, fmt.Sprintf("%s.mount_program=%s", config.Storage.Driver, config.Storage.Options.MountProgram)) } + if config.Storage.Options.MountOpt != "" { + storeOptions.GraphDriverOptions = append(storeOptions.GraphDriverOptions, fmt.Sprintf("%s.mountopt=%s", config.Storage.Driver, config.Storage.Options.MountOpt)) + } if config.Storage.Options.OverrideKernelCheck != "" { storeOptions.GraphDriverOptions = append(storeOptions.GraphDriverOptions, fmt.Sprintf("%s.override_kernel_check=%s", config.Storage.Driver, config.Storage.Options.OverrideKernelCheck)) }