Browse code

Check Propagation properties of source mount point

Whether a shared/slave volume propagation will work or not also depends on
where source directory is mounted on and what are the propagation properties
of that mount point. For example, for shared volume mount to work, source
mount point should be shared. For slave volume mount to work, source mount
point should be either shared/slave.

This patch determines the mount point on which directory is mounted and
checks for desired minimum propagation properties of that mount point. It
errors out of configuration does not seem right.

Signed-off-by: Vivek Goyal <vgoyal@redhat.com>

Vivek Goyal authored on 2015/10/24 05:57:57
Showing 1 changed files
... ...
@@ -293,6 +293,102 @@ func checkResetVolumePropagation(container *configs.Config) {
293 293
 	}
294 294
 }
295 295
 
296
+func getMountInfo(mountinfo []*mount.Info, dir string) *mount.Info {
297
+	for _, m := range mountinfo {
298
+		if m.Mountpoint == dir {
299
+			return m
300
+		}
301
+	}
302
+	return nil
303
+}
304
+
305
+// Get the source mount point of directory passed in as argument. Also return
306
+// optional fields.
307
+func getSourceMount(source string) (string, string, error) {
308
+	// Ensure any symlinks are resolved.
309
+	sourcePath, err := filepath.EvalSymlinks(source)
310
+	if err != nil {
311
+		return "", "", err
312
+	}
313
+
314
+	mountinfos, err := mount.GetMounts()
315
+	if err != nil {
316
+		return "", "", err
317
+	}
318
+
319
+	mountinfo := getMountInfo(mountinfos, sourcePath)
320
+	if mountinfo != nil {
321
+		return sourcePath, mountinfo.Optional, nil
322
+	}
323
+
324
+	path := sourcePath
325
+	for {
326
+		path = filepath.Dir(path)
327
+
328
+		mountinfo = getMountInfo(mountinfos, path)
329
+		if mountinfo != nil {
330
+			return path, mountinfo.Optional, nil
331
+		}
332
+
333
+		if path == "/" {
334
+			break
335
+		}
336
+	}
337
+
338
+	// If we are here, we did not find parent mount. Something is wrong.
339
+	return "", "", fmt.Errorf("Could not find source mount of %s", source)
340
+}
341
+
342
+// Ensure mount point on which path is mouted, is shared.
343
+func ensureShared(path string) error {
344
+	sharedMount := false
345
+
346
+	sourceMount, optionalOpts, err := getSourceMount(path)
347
+	if err != nil {
348
+		return err
349
+	}
350
+	// Make sure source mount point is shared.
351
+	optsSplit := strings.Split(optionalOpts, " ")
352
+	for _, opt := range optsSplit {
353
+		if strings.HasPrefix(opt, "shared:") {
354
+			sharedMount = true
355
+			break
356
+		}
357
+	}
358
+
359
+	if !sharedMount {
360
+		return fmt.Errorf("Path %s is mounted on %s but it is not a shared mount.", path, sourceMount)
361
+	}
362
+	return nil
363
+}
364
+
365
+// Ensure mount point on which path is mounted, is either shared or slave.
366
+func ensureSharedOrSlave(path string) error {
367
+	sharedMount := false
368
+	slaveMount := false
369
+
370
+	sourceMount, optionalOpts, err := getSourceMount(path)
371
+	if err != nil {
372
+		return err
373
+	}
374
+	// Make sure source mount point is shared.
375
+	optsSplit := strings.Split(optionalOpts, " ")
376
+	for _, opt := range optsSplit {
377
+		if strings.HasPrefix(opt, "shared:") {
378
+			sharedMount = true
379
+			break
380
+		} else if strings.HasPrefix(opt, "master:") {
381
+			slaveMount = true
382
+			break
383
+		}
384
+	}
385
+
386
+	if !sharedMount && !slaveMount {
387
+		return fmt.Errorf("Path %s is mounted on %s but it is not a shared or slave mount.", path, sourceMount)
388
+	}
389
+	return nil
390
+}
391
+
296 392
 func (d *Driver) setupMounts(container *configs.Config, c *execdriver.Command) error {
297 393
 	userMounts := make(map[string]struct{})
298 394
 	for _, m := range c.Mounts {
... ...
@@ -370,11 +466,17 @@ func (d *Driver) setupMounts(container *configs.Config, c *execdriver.Command) e
370 370
 
371 371
 		pFlag = mountPropagationMap[m.Propagation]
372 372
 		if pFlag == mount.SHARED || pFlag == mount.RSHARED {
373
+			if err := ensureShared(m.Source); err != nil {
374
+				return err
375
+			}
373 376
 			rootpg := container.RootPropagation
374 377
 			if rootpg != mount.SHARED && rootpg != mount.RSHARED {
375 378
 				execdriver.SetRootPropagation(container, mount.SHARED)
376 379
 			}
377 380
 		} else if pFlag == mount.SLAVE || pFlag == mount.RSLAVE {
381
+			if err := ensureSharedOrSlave(m.Source); err != nil {
382
+				return err
383
+			}
378 384
 			rootpg := container.RootPropagation
379 385
 			if rootpg != mount.SHARED && rootpg != mount.RSHARED && rootpg != mount.SLAVE && rootpg != mount.RSLAVE {
380 386
 				execdriver.SetRootPropagation(container, mount.RSLAVE)