diff --git a/net/bluetooth/msft.c b/net/bluetooth/msft.c
index 9612c5d1b..1f79e7980 100644
--- a/net/bluetooth/msft.c
+++ b/net/bluetooth/msft.c
@@ -132,10 +132,45 @@ struct msft_data {
 	__u8 filter_enabled;
 	/* To synchronize add/remove address filter and monitor device event.*/
 	struct mutex filter_lock;
+	struct kref	kref;
 };
 
+static void msft_data_free(struct kref *kref);
+
+static struct msft_data *msft_data_hold_unless_zero(struct msft_data *msft)
+{
+	if (!msft)
+		return NULL;
+
+	BT_DBG("msft %p orig refcnt %u", msft, kref_read(&msft->kref));
+	
+	if (!kref_get_unless_zero(&msft->kref))
+		return NULL;
+
+	return msft;
+}
+
+static void msft_data_put(struct msft_data *msft)
+{
+	BT_DBG("msft %p orig refcnt %u", msft, kref_read(&msft->kref));
+
+	kref_put(&msft->kref, msft_data_free);
+}
+
+static void msft_data_free(struct kref *kref)
+{
+	struct msft_data *msft = container_of(kref, struct msft_data, kref);
+
+	BT_DBG("msft %p", msft);
+
+	kfree(msft->evt_prefix);
+	mutex_destroy(&msft->filter_lock);
+	kfree(msft);
+}
+
 bool msft_monitor_supported(struct hci_dev *hdev)
 {
+	/* msft_get_features() holds and put hdev->msft_data */
 	return !!(msft_get_features(hdev) & MSFT_FEATURE_MASK_LE_ADV_MONITOR);
 }
 
@@ -449,12 +484,17 @@ static int msft_remove_monitor_sync(struct hci_dev *hdev,
 /* This function requires the caller holds hci_req_sync_lock */
 int msft_suspend_sync(struct hci_dev *hdev)
 {
-	struct msft_data *msft = hdev->msft_data;
+	struct msft_data *msft;
 	struct adv_monitor *monitor;
 	int handle = 0;
 
-	if (!msft || !msft_monitor_supported(hdev))
+	msft = msft_data_hold_unless_zero(hdev->msft_data);
+	if (!msft)
 		return 0;
+	if (!msft_monitor_supported(hdev)) {
+		msft_data_put(msft);
+		return 0;
+	}
 
 	msft->suspending = true;
 
@@ -471,6 +511,7 @@ int msft_suspend_sync(struct hci_dev *hdev)
 	/* All monitors have been removed */
 	msft->suspending = false;
 
+	msft_data_put(msft);
 	return 0;
 }
 
@@ -608,11 +649,17 @@ static void reregister_monitor(struct hci_dev *hdev)
 /* This function requires the caller holds hci_req_sync_lock */
 int msft_resume_sync(struct hci_dev *hdev)
 {
-	struct msft_data *msft = hdev->msft_data;
+	struct msft_data *msft;
 
-	if (!msft || !msft_monitor_supported(hdev))
+	msft = msft_data_hold_unless_zero(hdev->msft_data);
+	if (!msft)
 		return 0;
 
+	if (!msft_monitor_supported(hdev)) {
+		msft_data_put(msft);
+		return 0;
+	}
+
 	hci_dev_lock(hdev);
 
 	/* Clear already tracked devices on resume. Once the monitors are
@@ -625,17 +672,19 @@ int msft_resume_sync(struct hci_dev *hdev)
 
 	reregister_monitor(hdev);
 
+	msft_data_put(msft);
 	return 0;
 }
 
 /* This function requires the caller holds hci_req_sync_lock */
 void msft_do_open(struct hci_dev *hdev)
 {
-	struct msft_data *msft = hdev->msft_data;
+	struct msft_data *msft;
 
 	if (hdev->msft_opcode == HCI_OP_NOP)
 		return;
 
+	msft = msft_data_hold_unless_zero(hdev->msft_data);
 	if (!msft) {
 		bt_dev_err(hdev, "MSFT extension not registered");
 		return;
@@ -650,8 +699,7 @@ void msft_do_open(struct hci_dev *hdev)
 	msft->features = 0;
 
 	if (!read_supported_features(hdev, msft)) {
-		hdev->msft_data = NULL;
-		kfree(msft);
+		msft_data_put(msft);
 		return;
 	}
 
@@ -663,15 +711,17 @@ void msft_do_open(struct hci_dev *hdev)
 		 */
 		reregister_monitor(hdev);
 	}
+	msft_data_put(msft);
 }
 
 void msft_do_close(struct hci_dev *hdev)
 {
-	struct msft_data *msft = hdev->msft_data;
+	struct msft_data *msft;
 	struct msft_monitor_advertisement_handle_data *handle_data, *tmp;
 	struct msft_monitor_addr_filter_data *address_filter, *n;
 	struct adv_monitor *monitor;
 
+	msft = msft_data_hold_unless_zero(hdev->msft_data);
 	if (!msft)
 		return;
 
@@ -705,6 +755,8 @@ void msft_do_close(struct hci_dev *hdev)
 	hdev->advmon_pend_notify = false;
 	msft_monitor_device_del(hdev, 0, NULL, 0, true);
 
+	msft_data_put(msft);
+
 	hci_dev_unlock(hdev);
 }
 
@@ -767,6 +819,7 @@ void msft_register(struct hci_dev *hdev)
 	INIT_LIST_HEAD(&msft->address_filters);
 	hdev->msft_data = msft;
 	mutex_init(&msft->filter_lock);
+	kref_init(&msft->kref);
 }
 
 void msft_unregister(struct hci_dev *hdev)
@@ -779,10 +832,7 @@ void msft_unregister(struct hci_dev *hdev)
 	bt_dev_dbg(hdev, "Unregister MSFT extension");
 
 	hdev->msft_data = NULL;
-
-	kfree(msft->evt_prefix);
-	mutex_destroy(&msft->filter_lock);
-	kfree(msft);
+	msft_data_put(msft);
 }
 
 /* This function requires the caller holds hdev->lock */
@@ -1068,10 +1118,11 @@ static void msft_monitor_device_evt(struct hci_dev *hdev, struct sk_buff *skb)
 
 void msft_vendor_evt(struct hci_dev *hdev, void *data, struct sk_buff *skb)
 {
-	struct msft_data *msft = hdev->msft_data;
+	struct msft_data *msft;
 	u8 *evt_prefix;
 	u8 *evt;
 
+	msft = msft_data_hold_unless_zero(hdev->msft_data);
 	if (!msft)
 		return;
 
@@ -1081,21 +1132,21 @@ void msft_vendor_evt(struct hci_dev *hdev, void *data, struct sk_buff *skb)
 	if (msft->evt_prefix_len > 0) {
 		evt_prefix = msft_skb_pull(hdev, skb, 0, msft->evt_prefix_len);
 		if (!evt_prefix)
-			return;
+			goto done;
 
 		if (memcmp(evt_prefix, msft->evt_prefix, msft->evt_prefix_len))
-			return;
+			goto done;
 	}
 
 	/* Every event starts at least with an event code and the rest of
 	 * the data is variable and depends on the event code.
 	 */
 	if (skb->len < 1)
-		return;
+		goto done;
 
 	evt = msft_skb_pull(hdev, skb, 0, sizeof(*evt));
 	if (!evt)
-		return;
+		goto done;
 
 	hci_dev_lock(hdev);
 
@@ -1112,13 +1163,24 @@ void msft_vendor_evt(struct hci_dev *hdev, void *data, struct sk_buff *skb)
 	}
 
 	hci_dev_unlock(hdev);
+
+done:
+	msft_data_put(msft);
 }
 
 __u64 msft_get_features(struct hci_dev *hdev)
 {
-	struct msft_data *msft = hdev->msft_data;
+	struct msft_data *msft;
+	unsigned long long features;
+
+	msft = msft_data_hold_unless_zero(hdev->msft_data);
+	if (!msft)
+		return 0;
+
+	features = msft->features;
 
-	return msft ? msft->features : 0;
+	msft_data_put(msft);
+	return features;
 }
 
 static void msft_le_set_advertisement_filter_enable_cb(struct hci_dev *hdev,
@@ -1152,37 +1214,48 @@ static void msft_le_set_advertisement_filter_enable_cb(struct hci_dev *hdev,
 /* This function requires the caller holds hci_req_sync_lock */
 int msft_add_monitor_pattern(struct hci_dev *hdev, struct adv_monitor *monitor)
 {
-	struct msft_data *msft = hdev->msft_data;
+	struct msft_data *msft;
+	int err;
 
+	msft = msft_data_hold_unless_zero(hdev->msft_data);
 	if (!msft)
 		return -EOPNOTSUPP;
 
-	if (msft->resuming || msft->suspending)
+	if (msft->resuming || msft->suspending) {
+		msft_data_put(msft);
 		return -EBUSY;
+	}
 
-	return msft_add_monitor_sync(hdev, monitor);
+	err = msft_add_monitor_sync(hdev, monitor);
+	msft_data_put(msft);
+	return err;
 }
 
 /* This function requires the caller holds hci_req_sync_lock */
 int msft_remove_monitor(struct hci_dev *hdev, struct adv_monitor *monitor)
 {
-	struct msft_data *msft = hdev->msft_data;
+	struct msft_data *msft;
+	int err;
 
+	msft = msft_data_hold_unless_zero(hdev->msft_data);
 	if (!msft)
 		return -EOPNOTSUPP;
 
 	if (msft->resuming || msft->suspending)
 		return -EBUSY;
 
-	return msft_remove_monitor_sync(hdev, monitor);
+	err = msft_remove_monitor_sync(hdev, monitor);
+	msft_data_put(msft);
+	return err;
 }
 
 int msft_set_filter_enable(struct hci_dev *hdev, bool enable)
 {
 	struct msft_cp_le_set_advertisement_filter_enable cp;
-	struct msft_data *msft = hdev->msft_data;
+	struct msft_data *msft;
 	int err;
 
+	msft = msft_data_hold_unless_zero(hdev->msft_data);
 	if (!msft)
 		return -EOPNOTSUPP;
 
@@ -1193,6 +1266,7 @@ int msft_set_filter_enable(struct hci_dev *hdev, bool enable)
 
 	msft_le_set_advertisement_filter_enable_cb(hdev, &cp, err);
 
+	msft_data_put(msft);
 	return 0;
 }
 
