Browse code

devmapper.shutdown: optimize

Move the "unmount and deactivate" code into a separate method, and
optimize it a bit:

1. Do not use filepath.Walk() as there's no requirement to recursively
go into every directory under home/mnt; a list of directories in mnt
is sufficient. With filepath.Walk(), in case some container will fail
to unmount, it'll go through the whole container filesystem which is
excessive and useless.

2. Do not use GetMounts() and check if a directory is mounted; just
unmount it and ignore "not mounted" error. Note the same error
is returned in case of wrong flags set, but as flags are hardcoded
we can safely ignore such case.

While at it, promote "can't unmount" log level from debug to warning.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>

Kir Kolyshkin authored on 2018/02/14 09:10:53
Showing 1 changed files
... ...
@@ -2223,6 +2223,38 @@ func (devices *DeviceSet) cancelDeferredRemoval(info *devInfo) error {
2223 2223
 	return err
2224 2224
 }
2225 2225
 
2226
+func (devices *DeviceSet) unmountAndDeactivateAll(dir string) {
2227
+	files, err := ioutil.ReadDir(dir)
2228
+	if err != nil {
2229
+		logrus.Warnf("devmapper: unmountAndDeactivate: %s", err)
2230
+		return
2231
+	}
2232
+
2233
+	for _, d := range files {
2234
+		if !d.IsDir() {
2235
+			continue
2236
+		}
2237
+
2238
+		name := d.Name()
2239
+		fullname := path.Join(dir, name)
2240
+
2241
+		// We use MNT_DETACH here in case it is still busy in some running
2242
+		// container. This means it'll go away from the global scope directly,
2243
+		// and the device will be released when that container dies.
2244
+		if err := unix.Unmount(fullname, unix.MNT_DETACH); err != nil && err != unix.EINVAL {
2245
+			logrus.Warnf("devmapper: Shutdown unmounting %s, error: %s", fullname, err)
2246
+		}
2247
+
2248
+		if devInfo, err := devices.lookupDevice(name); err != nil {
2249
+			logrus.Debugf("devmapper: Shutdown lookup device %s, error: %s", name, err)
2250
+		} else {
2251
+			if err := devices.deactivateDevice(devInfo); err != nil {
2252
+				logrus.Debugf("devmapper: Shutdown deactivate %s, error: %s", devInfo.Hash, err)
2253
+			}
2254
+		}
2255
+	}
2256
+}
2257
+
2226 2258
 // Shutdown shuts down the device by unmounting the root.
2227 2259
 func (devices *DeviceSet) Shutdown(home string) error {
2228 2260
 	logrus.Debugf("devmapper: [deviceset %s] Shutdown()", devices.devicePrefix)
... ...
@@ -2244,45 +2276,7 @@ func (devices *DeviceSet) Shutdown(home string) error {
2244 2244
 	// will be killed and we will not get a chance to save deviceset
2245 2245
 	// metadata. Hence save this early before trying to deactivate devices.
2246 2246
 	devices.saveDeviceSetMetaData()
2247
-
2248
-	// ignore the error since it's just a best effort to not try to unmount something that's mounted
2249
-	mounts, _ := mount.GetMounts()
2250
-	mounted := make(map[string]bool, len(mounts))
2251
-	for _, mnt := range mounts {
2252
-		mounted[mnt.Mountpoint] = true
2253
-	}
2254
-
2255
-	if err := filepath.Walk(path.Join(home, "mnt"), func(p string, info os.FileInfo, err error) error {
2256
-		if err != nil {
2257
-			return err
2258
-		}
2259
-		if !info.IsDir() {
2260
-			return nil
2261
-		}
2262
-
2263
-		if mounted[p] {
2264
-			// We use MNT_DETACH here in case it is still busy in some running
2265
-			// container. This means it'll go away from the global scope directly,
2266
-			// and the device will be released when that container dies.
2267
-			if err := unix.Unmount(p, unix.MNT_DETACH); err != nil {
2268
-				logrus.Debugf("devmapper: Shutdown unmounting %s, error: %s", p, err)
2269
-			}
2270
-		}
2271
-
2272
-		if devInfo, err := devices.lookupDevice(path.Base(p)); err != nil {
2273
-			logrus.Debugf("devmapper: Shutdown lookup device %s, error: %s", path.Base(p), err)
2274
-		} else {
2275
-			if err := devices.deactivateDevice(devInfo); err != nil {
2276
-				logrus.Debugf("devmapper: Shutdown deactivate %s , error: %s", devInfo.Hash, err)
2277
-			}
2278
-		}
2279
-
2280
-		return nil
2281
-	}); err != nil && !os.IsNotExist(err) {
2282
-		devices.Unlock()
2283
-		return err
2284
-	}
2285
-
2247
+	devices.unmountAndDeactivateAll(path.Join(home, "mnt"))
2286 2248
 	devices.Unlock()
2287 2249
 
2288 2250
 	info, _ := devices.lookupDeviceWithLock("")