Browse code

devmapper: Allow specifying filesystem for thin devices

This adds the following --storage-opts for the daemon:
dm.fs: The filesystem to use for the base image
dm.mkfsarg: Add an argument to the mkfs command for the base image
dm.mountopt: Add a mount option for devicemapper mount

Currently supported filesystems are xfs and ext4.

Docker-DCO-1.1-Signed-off-by: Alexander Larsson <alexl@redhat.com> (github: alexlarsson)

Alexander Larsson authored on 2014/03/18 22:23:43
Showing 3 changed files
... ...
@@ -71,3 +71,27 @@ Here is the list of supported options:
71 71
 
72 72
     ``docker -d --storage-opt dm.loopmetadatasize=4G``
73 73
 
74
+ *  `dm.fs`
75
+
76
+    Specifies the filesystem type to use for the base device. The supported
77
+    options are "ext4" and "xfs". The default is "ext4"
78
+
79
+    Example use:
80
+
81
+    ``docker -d --storage-opt dm.fs=xfs``
82
+
83
+ *  `dm.mkfsarg`
84
+
85
+    Specifies extra mkfs arguments to be used when creating the base device.
86
+
87
+    Example use:
88
+
89
+    ``docker -d --storage-opt "dm.mkfsarg=-O ^has_journal"``
90
+
91
+ *  `dm.mountopt`
92
+
93
+    Specifies extra mount options used when mounting the thin devices.
94
+
95
+    Example use:
96
+
97
+    ``docker -d --storage-opt dm.mountopt=nodiscard``
... ...
@@ -72,6 +72,9 @@ type DeviceSet struct {
72 72
 	dataLoopbackSize     int64
73 73
 	metaDataLoopbackSize int64
74 74
 	baseFsSize           uint64
75
+	filesystem           string
76
+	mountOptions         string
77
+	mkfsArgs             []string
75 78
 }
76 79
 
77 80
 type DiskUsage struct {
... ...
@@ -281,14 +284,30 @@ func (devices *DeviceSet) activateDeviceIfNeeded(info *DevInfo) error {
281 281
 func (devices *DeviceSet) createFilesystem(info *DevInfo) error {
282 282
 	devname := info.DevName()
283 283
 
284
-	err := exec.Command("mkfs.ext4", "-E", "nodiscard,lazy_itable_init=0,lazy_journal_init=0", devname).Run()
285
-	if err != nil {
286
-		err = exec.Command("mkfs.ext4", "-E", "nodiscard,lazy_itable_init=0", devname).Run()
284
+	args := []string{}
285
+	for _, arg := range devices.mkfsArgs {
286
+		args = append(args, arg)
287
+	}
288
+
289
+	args = append(args, devname)
290
+
291
+	var err error
292
+	switch devices.filesystem {
293
+	case "xfs":
294
+		err = exec.Command("mkfs.xfs", args...).Run()
295
+	case "ext4":
296
+		err = exec.Command("mkfs.ext4", append([]string{"-E", "nodiscard,lazy_itable_init=0,lazy_journal_init=0"}, args...)...).Run()
297
+		if err != nil {
298
+			err = exec.Command("mkfs.ext4", append([]string{"-E", "nodiscard,lazy_itable_init=0"}, args...)...).Run()
299
+		}
300
+	default:
301
+		err = fmt.Errorf("Unsupported filesystem type %s", devices.filesystem)
287 302
 	}
288 303
 	if err != nil {
289 304
 		utils.Debugf("\n--->Err: %s\n", err)
290 305
 		return err
291 306
 	}
307
+
292 308
 	return nil
293 309
 }
294 310
 
... ...
@@ -926,11 +945,19 @@ func (devices *DeviceSet) MountDevice(hash, path, mountLabel string) error {
926 926
 		return err
927 927
 	}
928 928
 
929
-	mountOptions := label.FormatMountLabel("discard", mountLabel)
930
-	err = syscall.Mount(info.DevName(), path, fstype, flags, mountOptions)
929
+	options := ""
930
+
931
+	if fstype == "xfs" {
932
+		// XFS needs nouuid or it can't mount filesystems with the same fs
933
+		options = joinMountOptions(options, "nouuid")
934
+	}
935
+
936
+	options = joinMountOptions(options, devices.mountOptions)
937
+	options = joinMountOptions(options, label.FormatMountLabel("", mountLabel))
938
+
939
+	err = syscall.Mount(info.DevName(), path, fstype, flags, joinMountOptions("discard", options))
931 940
 	if err != nil && err == syscall.EINVAL {
932
-		mountOptions = label.FormatMountLabel("", mountLabel)
933
-		err = syscall.Mount(info.DevName(), path, fstype, flags, mountOptions)
941
+		err = syscall.Mount(info.DevName(), path, fstype, flags, options)
934 942
 	}
935 943
 	if err != nil {
936 944
 		return fmt.Errorf("Error mounting '%s' on '%s': %s", info.DevName(), path, err)
... ...
@@ -1112,6 +1139,7 @@ func NewDeviceSet(root string, doInit bool, options []string) (*DeviceSet, error
1112 1112
 		dataLoopbackSize:     DefaultDataLoopbackSize,
1113 1113
 		metaDataLoopbackSize: DefaultMetaDataLoopbackSize,
1114 1114
 		baseFsSize:           DefaultBaseFsSize,
1115
+		filesystem:           "ext4",
1115 1116
 	}
1116 1117
 
1117 1118
 	for _, option := range options {
... ...
@@ -1139,6 +1167,15 @@ func NewDeviceSet(root string, doInit bool, options []string) (*DeviceSet, error
1139 1139
 				return nil, err
1140 1140
 			}
1141 1141
 			devices.metaDataLoopbackSize = size
1142
+		case "dm.fs":
1143
+			if val != "ext4" && val != "xfs" {
1144
+				return nil, fmt.Errorf("Unsupported filesystem %s\n", val)
1145
+			}
1146
+			devices.filesystem = val
1147
+		case "dm.mkfsarg":
1148
+			devices.mkfsArgs = append(devices.mkfsArgs, val)
1149
+		case "dm.mountopt":
1150
+			devices.mountOptions = joinMountOptions(devices.mountOptions, val)
1142 1151
 		default:
1143 1152
 			return nil, fmt.Errorf("Unknown option %s\n", key)
1144 1153
 		}
... ...
@@ -74,3 +74,13 @@ func ProbeFsType(device string) (string, error) {
74 74
 
75 75
 	return "", fmt.Errorf("Unknown filesystem type on %s", device)
76 76
 }
77
+
78
+func joinMountOptions(a, b string) string {
79
+	if a == "" {
80
+		return b
81
+	}
82
+	if b == "" {
83
+		return a
84
+	}
85
+	return a + "," + b
86
+}