Browse code

In the case of remounting with changed data, need to call mount

The case where we are trying to do a remount with changed filesystem specific options was missing,
we need to call `mount` as well here to change those options.

See #33844 for where we need this, as we change `tmpfs` options.

Signed-off-by: Justin Cormack <justin.cormack@docker.com>

Justin Cormack authored on 2017/07/12 23:17:02
Showing 2 changed files
... ...
@@ -29,8 +29,9 @@ func isremount(device string, flags uintptr) bool {
29 29
 
30 30
 func mount(device, target, mType string, flags uintptr, data string) error {
31 31
 	oflags := flags &^ ptypes
32
-	if !isremount(device, flags) {
33
-		// Initial call applying all non-propagation flags.
32
+	if !isremount(device, flags) || data != "" {
33
+		// Initial call applying all non-propagation flags for mount
34
+		// or remount with changed data
34 35
 		if err := unix.Mount(device, target, mType, oflags, data); err != nil {
35 36
 			return err
36 37
 		}
... ...
@@ -26,7 +26,7 @@ func TestMount(t *testing.T) {
26 26
 		t.Fatal(err)
27 27
 	}
28 28
 	defer ensureUnmount(t, source)
29
-	validateMount(t, source, "", "")
29
+	validateMount(t, source, "", "", "")
30 30
 	if t.Failed() {
31 31
 		t.FailNow()
32 32
 	}
... ...
@@ -43,27 +43,31 @@ func TestMount(t *testing.T) {
43 43
 		options          string
44 44
 		expectedOpts     string
45 45
 		expectedOptional string
46
+		expectedVFS      string
46 47
 	}{
47 48
 		// No options
48
-		{"tmpfs", "tmpfs", "", "", ""},
49
+		{"tmpfs", "tmpfs", "", "", "", ""},
49 50
 		// Default rw / ro test
50
-		{source, "", "bind", "", ""},
51
-		{source, "", "bind,private", "", ""},
52
-		{source, "", "bind,shared", "", "shared"},
53
-		{source, "", "bind,slave", "", "master"},
54
-		{source, "", "bind,unbindable", "", "unbindable"},
51
+		{source, "", "bind", "", "", ""},
52
+		{source, "", "bind,private", "", "", ""},
53
+		{source, "", "bind,shared", "", "shared", ""},
54
+		{source, "", "bind,slave", "", "master", ""},
55
+		{source, "", "bind,unbindable", "", "unbindable", ""},
55 56
 		// Read Write tests
56
-		{source, "", "bind,rw", "rw", ""},
57
-		{source, "", "bind,rw,private", "rw", ""},
58
-		{source, "", "bind,rw,shared", "rw", "shared"},
59
-		{source, "", "bind,rw,slave", "rw", "master"},
60
-		{source, "", "bind,rw,unbindable", "rw", "unbindable"},
57
+		{source, "", "bind,rw", "rw", "", ""},
58
+		{source, "", "bind,rw,private", "rw", "", ""},
59
+		{source, "", "bind,rw,shared", "rw", "shared", ""},
60
+		{source, "", "bind,rw,slave", "rw", "master", ""},
61
+		{source, "", "bind,rw,unbindable", "rw", "unbindable", ""},
61 62
 		// Read Only tests
62
-		{source, "", "bind,ro", "ro", ""},
63
-		{source, "", "bind,ro,private", "ro", ""},
64
-		{source, "", "bind,ro,shared", "ro", "shared"},
65
-		{source, "", "bind,ro,slave", "ro", "master"},
66
-		{source, "", "bind,ro,unbindable", "ro", "unbindable"},
63
+		{source, "", "bind,ro", "ro", "", ""},
64
+		{source, "", "bind,ro,private", "ro", "", ""},
65
+		{source, "", "bind,ro,shared", "ro", "shared", ""},
66
+		{source, "", "bind,ro,slave", "ro", "master", ""},
67
+		{source, "", "bind,ro,unbindable", "ro", "unbindable", ""},
68
+		// Remount tests to change per filesystem options
69
+		{"", "", "remount,size=128k", "rw", "", "rw,size=128k"},
70
+		{"", "", "remount,ro,size=128k", "ro", "", "ro,size=128k"},
67 71
 	}
68 72
 
69 73
 	for _, tc := range tests {
... ...
@@ -87,11 +91,17 @@ func TestMount(t *testing.T) {
87 87
 					}
88 88
 				}()
89 89
 			}
90
+			if strings.Contains(tc.options, "remount") {
91
+				// create a new mount to remount first
92
+				if err := Mount("tmpfs", target, "tmpfs", ""); err != nil {
93
+					t.Fatal(err)
94
+				}
95
+			}
90 96
 			if err := Mount(tc.source, target, tc.ftype, tc.options); err != nil {
91 97
 				t.Fatal(err)
92 98
 			}
93 99
 			defer ensureUnmount(t, target)
94
-			validateMount(t, target, tc.expectedOpts, tc.expectedOptional)
100
+			validateMount(t, target, tc.expectedOpts, tc.expectedOptional, tc.expectedVFS)
95 101
 		})
96 102
 	}
97 103
 }
... ...
@@ -104,7 +114,7 @@ func ensureUnmount(t *testing.T, mnt string) {
104 104
 }
105 105
 
106 106
 // validateMount checks that mnt has the given options
107
-func validateMount(t *testing.T, mnt string, opts, optional string) {
107
+func validateMount(t *testing.T, mnt string, opts, optional, vfs string) {
108 108
 	info, err := GetMounts()
109 109
 	if err != nil {
110 110
 		t.Fatal(err)
... ...
@@ -124,6 +134,13 @@ func validateMount(t *testing.T, mnt string, opts, optional string) {
124 124
 		}
125 125
 	}
126 126
 
127
+	wantedVFS := make(map[string]struct{})
128
+	if vfs != "" {
129
+		for _, opt := range strings.Split(vfs, ",") {
130
+			wantedVFS[opt] = struct{}{}
131
+		}
132
+	}
133
+
127 134
 	mnts := make(map[int]*Info, len(info))
128 135
 	for _, mi := range info {
129 136
 		mnts[mi.ID] = mi
... ...
@@ -177,6 +194,22 @@ func validateMount(t *testing.T, mnt string, opts, optional string) {
177 177
 			t.Errorf("missing optional field %q found %q", field, mi.Optional)
178 178
 		}
179 179
 
180
+		// Validate VFS if set
181
+		if vfs != "" {
182
+			if mi.VfsOpts != "" {
183
+				for _, opt := range strings.Split(mi.VfsOpts, ",") {
184
+					opt = clean(opt)
185
+					if !has(wantedVFS, opt) {
186
+						t.Errorf("unexpected mount option %q expected %q", opt, vfs)
187
+					}
188
+					delete(wantedVFS, opt)
189
+				}
190
+			}
191
+			for opt := range wantedVFS {
192
+				t.Errorf("missing mount option %q found %q", opt, mi.VfsOpts)
193
+			}
194
+		}
195
+
180 196
 		return
181 197
 	}
182 198