changeset 23863:254c33369d8b

13194 null/dangling pointer deref somewhere under dmu_objset_upgrade Portions contributed by: Andy Fiddaman <andy@omniosce.org> Reviewed by: Jason King <jason.king@joyent.com> Reviewed by: Toomas Soome <tsoome@me.com> Reviewed by: Jerry Jelinek <gjelinek@gmail.com> Approved by: Robert Mustacchi <rm@fingolfin.org>
author Arkadiusz Bubała <arkadiusz.bubala@open-e.com>
date Mon, 30 Nov 2020 19:21:29 +0000
parents 352129d46a4b
children bbce4fbe98af
files usr/src/uts/common/fs/zfs/dmu_objset.c usr/src/uts/common/fs/zfs/zfs_ioctl.c usr/src/uts/common/fs/zfs/zfs_vfsops.c
diffstat 3 files changed, 25 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/common/fs/zfs/dmu_objset.c	Fri Dec 04 00:02:13 2020 +0200
+++ b/usr/src/uts/common/fs/zfs/dmu_objset.c	Mon Nov 30 19:21:29 2020 +0000
@@ -28,6 +28,7 @@
  * Copyright (c) 2015, STRATO AG, Inc. All rights reserved.
  * Copyright (c) 2014 Integros [integros.com]
  * Copyright 2017 Nexenta Systems, Inc.
+ * Copyright (c) 2017 Open-E, Inc. All Rights Reserved.
  */
 
 /* Portions Copyright 2010 Robert Milkowski */
@@ -81,6 +82,8 @@
  */
 int dmu_rescan_dnode_threshold = 131072;
 
+static char *upgrade_tag = "upgrade_tag";
+
 static void dmu_objset_find_dp_cb(void *arg);
 
 static void dmu_objset_upgrade(objset_t *os, dmu_objset_upgrade_cb_t cb);
@@ -1484,6 +1487,7 @@
 	os->os_upgrade_exit = B_TRUE;
 	os->os_upgrade_id = 0;
 	mutex_exit(&os->os_upgrade_lock);
+	dsl_dataset_long_rele(dmu_objset_ds(os), upgrade_tag);
 }
 
 static void
@@ -1492,6 +1496,9 @@
 	if (os->os_upgrade_id != 0)
 		return;
 
+	ASSERT(dsl_pool_config_held(dmu_objset_pool(os)));
+	dsl_dataset_long_hold(dmu_objset_ds(os), upgrade_tag);
+
 	mutex_enter(&os->os_upgrade_lock);
 	if (os->os_upgrade_id == 0 && os->os_upgrade_status == 0) {
 		os->os_upgrade_exit = B_FALSE;
@@ -1499,8 +1506,10 @@
 		os->os_upgrade_id = taskq_dispatch(
 		    os->os_spa->spa_upgrade_taskq,
 		    dmu_objset_upgrade_task_cb, os, TQ_SLEEP);
-		if (os->os_upgrade_id == 0)
+		if (os->os_upgrade_id == TASKQID_INVALID) {
+			dsl_dataset_long_rele(dmu_objset_ds(os), upgrade_tag);
 			os->os_upgrade_status = ENOMEM;
+		}
 	}
 	mutex_exit(&os->os_upgrade_lock);
 }
@@ -1511,10 +1520,12 @@
 	mutex_enter(&os->os_upgrade_lock);
 	os->os_upgrade_exit = B_TRUE;
 	if (os->os_upgrade_id != 0) {
+		taskqid_t tid = os->os_upgrade_id;
+
 		os->os_upgrade_id = 0;
 		mutex_exit(&os->os_upgrade_lock);
 
-		taskq_wait(os->os_spa->spa_upgrade_taskq);
+		taskq_wait_id(os->os_spa->spa_upgrade_taskq, tid);
 	} else {
 		mutex_exit(&os->os_upgrade_lock);
 	}
--- a/usr/src/uts/common/fs/zfs/zfs_ioctl.c	Fri Dec 04 00:02:13 2020 +0200
+++ b/usr/src/uts/common/fs/zfs/zfs_ioctl.c	Mon Nov 30 19:21:29 2020 +0000
@@ -5627,9 +5627,6 @@
 	if (error != 0)
 		return (error);
 
-	dsl_dataset_long_hold(dmu_objset_ds(os), FTAG);
-	dsl_pool_rele(dmu_objset_pool(os), FTAG);
-
 	if (dmu_objset_userobjspace_upgradable(os) ||
 	    dmu_objset_projectquota_upgradable(os)) {
 		mutex_enter(&os->os_upgrade_lock);
@@ -5643,11 +5640,14 @@
 			mutex_exit(&os->os_upgrade_lock);
 		}
 
+		dsl_pool_rele(dmu_objset_pool(os), FTAG);
+
 		taskq_wait_id(os->os_spa->spa_upgrade_taskq, os->os_upgrade_id);
 		error = os->os_upgrade_status;
-	}
-
-	dsl_dataset_long_rele(dmu_objset_ds(os), FTAG);
+	} else {
+		dsl_pool_rele(dmu_objset_pool(os), FTAG);
+	}
+
 	dsl_dataset_rele(dmu_objset_ds(os), FTAG);
 
 	return (error);
--- a/usr/src/uts/common/fs/zfs/zfs_vfsops.c	Fri Dec 04 00:02:13 2020 +0200
+++ b/usr/src/uts/common/fs/zfs/zfs_vfsops.c	Mon Nov 30 19:21:29 2020 +0000
@@ -924,8 +924,13 @@
 	int err;
 
 	if (!dmu_objset_userobjspace_present(zfsvfs->z_os)) {
-		if (dmu_objset_userobjspace_upgradable(zfsvfs->z_os))
+		if (dmu_objset_userobjspace_upgradable(zfsvfs->z_os)) {
+			dsl_pool_config_enter(
+			    dmu_objset_pool(zfsvfs->z_os), FTAG);
 			dmu_objset_id_quota_upgrade(zfsvfs->z_os);
+			dsl_pool_config_exit(
+			    dmu_objset_pool(zfsvfs->z_os), FTAG);
+		}
 		return (B_FALSE);
 	}