⬢ DragonFlyBSD Kernel Audit
DF-4751 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/disk/dm/device-mapper.c
+++ b/sys/dev/disk/dm/device-mapper.c
@@ -153,14 +153,19 @@
 
 	case MOD_UNLOAD:
 		/*
-		 * Disable unloading of dm module if there are any devices
-		 * defined in driver. This is probably too strong we need
-		 * to disable auto-unload only if there is mounted dm device
-		 * present.
+		 * Quiesce the control device first: destroy_dev() drains
+		 * in-flight ioctls, so once it returns no NETBSD_DM_IOCTL
+		 * can be running and dm_dev_counter is stable for the
+		 * check below.
 		 */
-		if (dm_dev_counter > 0)
+		destroy_dev(dmcdev);
+		sync_devs();
+		if (dm_dev_counter > 0) {
+			/* A device snuck in before/during the drain: re-arm. */
+			dmcdev = make_dev(&dmctl_ops, 0, UID_ROOT,
+			    GID_OPERATOR, 0640, "mapper/control");
 			return EBUSY;
-		/* race window here */
+		}
 
 		error = dmdestroy();
 		if (error)
@@ -187,12 +192,16 @@
 static int
 dmdestroy(void)
 {
-	destroy_dev(dmcdev);
-
+	/* dmcdev was already destroyed by MOD_UNLOAD before the counter
+	 * check, so in-flight control ioctls have drained. */
 	dm_dev_uninit();
 	dm_pdev_uninit();
 	dm_target_uninit();
 
+	/* wait for async devfs destroy of the block devices' cdevsw
+	 * revectors before the module text goes away */
+	sync_devs();
+
 	return 0;
 }