Module Name:    src
Committed By:   christos
Date:           Fri Jan  5 14:22:05 UTC 2018

Modified Files:
        src/sys/dev/dm: dm_ioctl.c dm_target_linear.c dm_target_snapshot.c

Log Message:
PR/52900: Tomohiro Kusumi: Fix kernel panic when target's ->init() failed
Reliably unbusy the target in the *all* the destroy routines, so ioctl
does not need to do it.


To generate a diff of this commit:
cvs rdiff -u -r1.31 -r1.32 src/sys/dev/dm/dm_ioctl.c
cvs rdiff -u -r1.16 -r1.17 src/sys/dev/dm/dm_target_linear.c
cvs rdiff -u -r1.18 -r1.19 src/sys/dev/dm/dm_target_snapshot.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/dm/dm_ioctl.c
diff -u src/sys/dev/dm/dm_ioctl.c:1.31 src/sys/dev/dm/dm_ioctl.c:1.32
--- src/sys/dev/dm/dm_ioctl.c:1.31	Wed May 31 22:45:09 2017
+++ src/sys/dev/dm/dm_ioctl.c	Fri Jan  5 09:22:05 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: dm_ioctl.c,v 1.31 2017/06/01 02:45:09 chs Exp $      */
+/* $NetBSD: dm_ioctl.c,v 1.32 2018/01/05 14:22:05 christos Exp $      */
 
 /*
  * Copyright (c) 2008 The NetBSD Foundation, Inc.
@@ -28,6 +28,8 @@
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  */
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: dm_ioctl.c,v 1.32 2018/01/05 14:22:05 christos Exp $");
 
 /*
  * Locking is used to synchronise between ioctl calls and between dm_table's
@@ -158,6 +160,7 @@ dm_dbg_print_flags(int flags)
 
 	return 0;
 }
+
 /*
  * Get version ioctl call I do it as default therefore this
  * function is unused now.
@@ -168,6 +171,7 @@ dm_get_version_ioctl(prop_dictionary_t d
 
 	return 0;
 }
+
 /*
  * Get list of all available targets from global
  * target list and sent them back to libdevmapper.
@@ -190,6 +194,7 @@ dm_list_versions_ioctl(prop_dictionary_t
 
 	return 0;
 }
+
 /*
  * Create in-kernel entry for device. Device attributes such as name, uuid are
  * taken from proplib dictionary.
@@ -271,6 +276,7 @@ dm_dev_create_ioctl(prop_dictionary_t dm
 
 	return r;
 }
+
 /*
  * Get list of created device-mapper devices fromglobal list and
  * send it to kernel.
@@ -309,6 +315,7 @@ dm_dev_list_ioctl(prop_dictionary_t dm_d
 
 	return 0;
 }
+
 /*
  * Rename selected devices old name is in struct dm_ioctl.
  * newname is taken from dictionary
@@ -366,6 +373,7 @@ dm_dev_rename_ioctl(prop_dictionary_t dm
 
 	return 0;
 }
+
 /*
  * Remove device from global list I have to remove active
  * and inactive tables first.
@@ -408,6 +416,7 @@ dm_dev_remove_ioctl(prop_dictionary_t dm
 	 */
 	return config_detach(devt, DETACH_QUIET);
 }
+
 /*
  * Return actual state of device to libdevmapper.
  */
@@ -461,6 +470,7 @@ dm_dev_status_ioctl(prop_dictionary_t dm
 
 	return 0;
 }
+
 /*
  * Set only flag to suggest that device is suspended. This call is
  * not supported in NetBSD.
@@ -501,6 +511,7 @@ dm_dev_suspend_ioctl(prop_dictionary_t d
 
 	return 0;
 }
+
 /*
  * Simulate Linux behaviour better and switch tables here and not in
  * dm_table_load_ioctl.
@@ -551,6 +562,7 @@ dm_dev_resume_ioctl(prop_dictionary_t dm
 
 	return 0;
 }
+
 /*
  * Table management routines
  * lvm2tools doens't send name/uuid to kernel with table
@@ -596,6 +608,7 @@ dm_table_clear_ioctl(prop_dictionary_t d
 
 	return 0;
 }
+
 /*
  * Get list of physical devices for active table.
  * Get dev_t from pdev vnode and insert it into cmd_array.
@@ -661,6 +674,7 @@ dm_table_deps_ioctl(prop_dictionary_t dm
 
 	return 0;
 }
+
 /*
  * Load new table/tables to device.
  * Call apropriate target init routine open all physical pdev's and
@@ -788,7 +802,6 @@ dm_table_load_ioctl(prop_dictionary_t dm
 			free(str, M_TEMP);
 
 			dm_dev_unbusy(dmv);
-			dm_target_unbusy(target);
 			prop_object_iterator_release(iter);
 			return ret;
 		}
@@ -804,6 +817,7 @@ dm_table_load_ioctl(prop_dictionary_t dm
 	dm_dev_unbusy(dmv);
 	return 0;
 }
+
 /*
  * Get description of all tables loaded to device from kernel
  * and send it to libdevmapper.
@@ -935,7 +949,6 @@ dm_table_status_ioctl(prop_dictionary_t 
 	return 0;
 }
 
-
 /*
  * For every call I have to set kernel driver version.
  * Because I can have commands supported only in other

Index: src/sys/dev/dm/dm_target_linear.c
diff -u src/sys/dev/dm/dm_target_linear.c:1.16 src/sys/dev/dm/dm_target_linear.c:1.17
--- src/sys/dev/dm/dm_target_linear.c:1.16	Sun Jun  4 04:54:38 2017
+++ src/sys/dev/dm/dm_target_linear.c	Fri Jan  5 09:22:05 2018
@@ -1,4 +1,4 @@
-/*        $NetBSD: dm_target_linear.c,v 1.16 2017/06/04 08:54:38 mbalmer Exp $      */
+/*        $NetBSD: dm_target_linear.c,v 1.17 2018/01/05 14:22:05 christos Exp $      */
 
 /*
  * Copyright (c) 2008 The NetBSD Foundation, Inc.
@@ -28,7 +28,8 @@
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  */
-
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: dm_target_linear.c,v 1.17 2018/01/05 14:22:05 christos Exp $");
 
 /*
  * This file implements initial version of device-mapper dklinear target.
@@ -95,6 +96,7 @@ dm_target_linear_init(dm_dev_t * dmv, vo
 
 	return 0;
 }
+
 /*
  * Status routine is called to get params string, which is target
  * specific. When dm_table_status_ioctl is called with flag
@@ -118,6 +120,7 @@ dm_target_linear_status(void *target_con
 
 	return params;
 }
+
 /*
  * Do IO operation, called from dmstrategy routine.
  */
@@ -138,6 +141,7 @@ dm_target_linear_strategy(dm_table_entry
 	return 0;
 
 }
+
 /*
  * Sync underlying disk caches.
  */
@@ -154,36 +158,35 @@ dm_target_linear_sync(dm_table_entry_t *
 	return VOP_IOCTL(tlc->pdev->pdev_vnode,  DIOCCACHESYNC, &cmd,
 	    FREAD|FWRITE, kauth_cred_get());	
 }
+
 /*
  * Destroy target specific data. Decrement table pdevs.
  */
 int
 dm_target_linear_destroy(dm_table_entry_t * table_en)
 {
-	dm_target_linear_config_t *tlc;
 
 	/*
 	 * Destroy function is called for every target even if it
 	 * doesn't have target_config.
 	 */
-
 	if (table_en->target_config == NULL)
-		return 0;
+		goto out;
 
-	tlc = table_en->target_config;
+	dm_target_linear_config_t *tlc = table_en->target_config;
+	table_en->target_config = NULL;
 
 	/* Decrement pdev ref counter if 0 remove it */
 	dm_pdev_decr(tlc->pdev);
 
+	kmem_free(tlc, sizeof(*tlc));
+
+out:
 	/* Unbusy target so we can unload it */
 	dm_target_unbusy(table_en->target);
-
-	kmem_free(table_en->target_config, sizeof(dm_target_linear_config_t));
-
-	table_en->target_config = NULL;
-
 	return 0;
 }
+
 /* Add this target pdev dependencies to prop_array_t */
 int
 dm_target_linear_deps(dm_table_entry_t * table_en, prop_array_t prop_array)
@@ -200,6 +203,7 @@ dm_target_linear_deps(dm_table_entry_t *
 
 	return 0;
 }
+
 /*
  * Register upcall device.
  * Linear target doesn't need any upcall devices but other targets like
@@ -210,6 +214,7 @@ dm_target_linear_upcall(dm_table_entry_t
 {
 	return 0;
 }
+
 /*
  * Query physical block size of this target
  * For a linear target this is just the sector size of the underlying device
@@ -230,6 +235,7 @@ dm_target_linear_secsize(dm_table_entry_
 
 	return 0;
 }
+
 /*
  * Transform char s to uint64_t offset number.
  */

Index: src/sys/dev/dm/dm_target_snapshot.c
diff -u src/sys/dev/dm/dm_target_snapshot.c:1.18 src/sys/dev/dm/dm_target_snapshot.c:1.19
--- src/sys/dev/dm/dm_target_snapshot.c:1.18	Sun Jun  4 04:54:38 2017
+++ src/sys/dev/dm/dm_target_snapshot.c	Fri Jan  5 09:22:05 2018
@@ -1,4 +1,4 @@
-/*        $NetBSD: dm_target_snapshot.c,v 1.18 2017/06/04 08:54:38 mbalmer Exp $      */
+/*        $NetBSD: dm_target_snapshot.c,v 1.19 2018/01/05 14:22:05 christos Exp $      */
 
 /*
  * Copyright (c) 2008 The NetBSD Foundation, Inc.
@@ -28,6 +28,8 @@
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  */
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: dm_target_snapshot.c,v 1.19 2018/01/05 14:22:05 christos Exp $");
 
 /*
  * 1. Suspend my_data to temporarily stop any I/O while the snapshot is being
@@ -248,6 +250,7 @@ dm_target_snapshot_init(dm_dev_t * dmv, 
 
 	return 0;
 }
+
 /*
  * Status routine is called to get params string, which is target
  * specific. When dm_table_status_ioctl is called with flag
@@ -296,6 +299,7 @@ dm_target_snapshot_status(void *target_c
 
 	return params;
 }
+
 /* Strategy routine called from dm_strategy. */
 int
 dm_target_snapshot_strategy(dm_table_entry_t * table_en, struct buf * bp)
@@ -310,39 +314,37 @@ dm_target_snapshot_strategy(dm_table_ent
 
 	return 0;
 }
+
 /* Doesn't do anything here. */
 int
 dm_target_snapshot_destroy(dm_table_entry_t * table_en)
 {
-	dm_target_snapshot_config_t *tsc;
 
 	/*
 	 * Destroy function is called for every target even if it
 	 * doesn't have target_config.
 	 */
-
 	if (table_en->target_config == NULL)
-		return 0;
+		goto out;
 
 	printf("Snapshot target destroy function called\n");
 
-	tsc = table_en->target_config;
+	dm_target_snapshot_config_t *tsc = table_en->target_config;
+	table_en->target_config = NULL;
 
 	/* Decrement pdev ref counter if 0 remove it */
 	dm_pdev_decr(tsc->tsc_snap_dev);
-
 	if (tsc->tsc_persistent_dev)
 		dm_pdev_decr(tsc->tsc_cow_dev);
 
+	kmem_free(tsc, sizeof(*tsc));
+out:
 	/* Unbusy target so we can unload it */
 	dm_target_unbusy(table_en->target);
 
-	kmem_free(table_en->target_config, sizeof(dm_target_snapshot_config_t));
-
-	table_en->target_config = NULL;
-
 	return 0;
 }
+
 /* Add this target dependencies to prop_array_t */
 int
 dm_target_snapshot_deps(dm_table_entry_t * table_en,
@@ -365,6 +367,7 @@ dm_target_snapshot_deps(dm_table_entry_t
 	}
 	return 0;
 }
+
 /* Upcall is used to inform other depended devices about IO. */
 int
 dm_target_snapshot_upcall(dm_table_entry_t * table_en, struct buf * bp)
@@ -377,6 +380,7 @@ dm_target_snapshot_upcall(dm_table_entry
 
 	return 0;
 }
+
 /*
  * dm target snapshot origin routines.
  *
@@ -419,6 +423,7 @@ dm_target_snapshot_orig_init(dm_dev_t * 
 
 	return 0;
 }
+
 /*
  * Status routine is called to get params string, which is target
  * specific. When dm_table_status_ioctl is called with flag
@@ -452,6 +457,7 @@ dm_target_snapshot_orig_status(void *tar
 
 	return params;
 }
+
 /* Strategy routine called from dm_strategy. */
 int
 dm_target_snapshot_orig_strategy(dm_table_entry_t * table_en, struct buf * bp)
@@ -466,6 +472,7 @@ dm_target_snapshot_orig_strategy(dm_tabl
 
 	return 0;
 }
+
 /*
  * Sync underlying disk caches.
  */
@@ -479,13 +486,14 @@ dm_target_snapshot_orig_sync(dm_table_en
 
 	cmd = 1;
 
-	return VOP_IOCTL(tsoc->tsoc_real_dev->pdev_vnode,  DIOCCACHESYNC, &cmd, FREAD|FWRITE, kauth_cred_get());
+	return VOP_IOCTL(tsoc->tsoc_real_dev->pdev_vnode,  DIOCCACHESYNC,
+	    &cmd, FREAD|FWRITE, kauth_cred_get());
 }
+
 /* Decrement pdev and free allocated space. */
 int
 dm_target_snapshot_orig_destroy(dm_table_entry_t * table_en)
 {
-	dm_target_snapshot_origin_config_t *tsoc;
 
 	/*
 	 * Destroy function is called for every target even if it
@@ -493,22 +501,22 @@ dm_target_snapshot_orig_destroy(dm_table
 	 */
 
 	if (table_en->target_config == NULL)
-		return 0;
+		goto out;
 
-	tsoc = table_en->target_config;
+	dm_target_snapshot_origin_config_t *tsoc = table_en->target_config;
+	table_en->target_config = NULL;
 
 	/* Decrement pdev ref counter if 0 remove it */
 	dm_pdev_decr(tsoc->tsoc_real_dev);
 
+	kmem_free(tsoc, sizeof(*tsoc));
+out:
 	/* Unbusy target so we can unload it */
 	dm_target_unbusy(table_en->target);
 
-	kmem_free(table_en->target_config, sizeof(dm_target_snapshot_origin_config_t));
-
-	table_en->target_config = NULL;
-
 	return 0;
 }
+
 /*
  * Get target deps and add them to prop_array_t.
  */
@@ -537,6 +545,7 @@ dm_target_snapshot_orig_deps(dm_table_en
 
 	return 0;
 }
+
 /* Unsupported for this target. */
 int
 dm_target_snapshot_orig_upcall(dm_table_entry_t * table_en, struct buf * bp)

Reply via email to