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..14d8a23a8f 100644 --- a/drivers/aufs/aufs.go +++ b/drivers/aufs/aufs.go @@ -103,6 +103,13 @@ func Init(root string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap return nil, errors.Wrapf(graphdriver.ErrIncompatibleFS, "AUFS is not supported over %q", backingFs) } + for _, option := range options { + if strings.HasPrefix(option, "aufs.mountopt=") { + return nil, fmt.Errorf("aufs driver does not support mount options") + } else { + return nil, fmt.Errorf("option %s not supported", option) + } + } paths := []string{ "mnt", "diff", diff --git a/drivers/btrfs/btrfs.go b/drivers/btrfs/btrfs.go index 4b9699fdb3..28049f4ada 100644 --- a/drivers/btrfs/btrfs.go +++ b/drivers/btrfs/btrfs.go @@ -43,8 +43,9 @@ func init() { } type btrfsOptions struct { - minSpace uint64 - size uint64 + minSpace uint64 + size uint64 + mountOptions string } // Init returns a new BTRFS driver. @@ -110,6 +111,8 @@ func parseOptions(opt []string) (btrfsOptions, bool, error) { } userDiskQuota = true options.minSpace = uint64(minSpace) + case "btrfs.mountopt": + options.mountOptions = val default: return options, userDiskQuota, fmt.Errorf("Unknown option %s", key) } diff --git a/drivers/devmapper/deviceset.go b/drivers/devmapper/deviceset.go index 0fab980b9b..f2ea75ff4e 100644 --- a/drivers/devmapper/deviceset.go +++ b/drivers/devmapper/deviceset.go @@ -2664,6 +2664,8 @@ func NewDeviceSet(root string, doInit bool, options []string, uidMaps, gidMaps [ } key = strings.ToLower(key) switch key { + case "devicemapper.mountopt": + devices.mountOptions = joinMountOptions(devices.mountOptions, val) case "dm.basesize": size, err := units.RAMInBytes(val) if err != nil { @@ -2690,8 +2692,6 @@ 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": - devices.mountOptions = joinMountOptions(devices.mountOptions, val) case "dm.metadatadev": devices.metadataDevice = val case "dm.datadev": 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..42675c90d4 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) } @@ -300,6 +303,10 @@ func (d *Driver) create(id, parent string, storageOpt map[string]string) error { } if parent == "" { mountoptions := map[string]string{"mountpoint": "legacy"} + for _, opt := range strings.Split(d.options.mountOptions, ",") { + val := strings.SplitN(opt, "=", 2) + mountoptions[val[0]] = val[1] + } fs, err := zfs.CreateFilesystem(name, mountoptions) if err == nil { err = setQuota(name, quota) 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 bafe011bf4..0c31e8b0fc 100644 --- a/store.go +++ b/store.go @@ -2945,10 +2945,6 @@ type ThinpoolOptionsConfig struct { // basedevice. MkfsArg string `toml:"mkfsarg"` - // MountOpt specifies extra mount options used when mounting the thin - // devices. - MountOpt string `toml:"mountopt"` - // UseDeferredDeletion marks device for deferred deletion UseDeferredDeletion string `toml:"use_deferred_deletion"` @@ -2995,6 +2991,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. @@ -3065,9 +3064,6 @@ func ReloadConfigurationFile(configFile string, storeOptions *StoreOptions) { if config.Storage.Options.Thinpool.MkfsArg != "" { 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)) - } if config.Storage.Options.Thinpool.UseDeferredDeletion != "" { storeOptions.GraphDriverOptions = append(storeOptions.GraphDriverOptions, fmt.Sprintf("dm.use_deferred_deletion=%s", config.Storage.Options.Thinpool.UseDeferredDeletion)) } @@ -3092,6 +3088,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)) }