vlr_subscr: use osmo_use_count

Depends: Ife31e6798b4e728a23913179e346552a7dd338c0 (libosmocore)
Change-Id: Ib06d030e8464abe415ff597d462ed40eeddef475
diff --git a/src/libmsc/ctrl_commands.c b/src/libmsc/ctrl_commands.c
index e37cc94..87e9afd 100644
--- a/src/libmsc/ctrl_commands.c
+++ b/src/libmsc/ctrl_commands.c
@@ -29,6 +29,8 @@
 
 #include <stdbool.h>
 
+#define VSUB_USE_CTRL "CTRL"
+
 static struct gsm_network *msc_ctrl_net = NULL;
 
 static int get_subscriber_list(struct ctrl_cmd *cmd, void *d)
@@ -73,7 +75,7 @@
 		return CTRL_CMD_ERROR;
 	}
 
-	vsub = vlr_subscr_find_by_imsi(msc_ctrl_net->vlr, cmd->value);
+	vsub = vlr_subscr_find_by_imsi(msc_ctrl_net->vlr, cmd->value, VSUB_USE_CTRL);
 	if (!vsub) {
 		LOGP(DCTRL, LOGL_ERROR, "Attempt to expire unknown subscriber IMSI=%s\n", cmd->value);
 		cmd->reply = "IMSI unknown";
@@ -85,11 +87,11 @@
 	if (vlr_subscr_expire(vsub))
 		LOGP(DCTRL, LOGL_NOTICE, "VLR released subscriber %s\n", vlr_subscr_name(vsub));
 
-	if (vsub->use_count > 1)
+	if (osmo_use_count_total(&vsub->use_count) > 1)
 		LOGP(DCTRL, LOGL_NOTICE, "Subscriber %s is still in use, should be released soon\n",
 		     vlr_subscr_name(vsub));
 
-	vlr_subscr_put(vsub);
+	vlr_subscr_put(vsub, VSUB_USE_CTRL);
 
 	return CTRL_CMD_REPLY;
 }
diff --git a/src/libmsc/db.c b/src/libmsc/db.c
index b5e7ad8..0384320 100644
--- a/src/libmsc/db.c
+++ b/src/libmsc/db.c
@@ -769,7 +769,7 @@
 	daddr = dbi_result_get_string(result, "dest_addr");
 	if (daddr)
 		OSMO_STRLCPY_ARRAY(sms->dst.addr, daddr);
-	sms->receiver = vlr_subscr_find_by_msisdn(net->vlr, sms->dst.addr);
+	sms->receiver = vlr_subscr_find_by_msisdn(net->vlr, sms->dst.addr, VSUB_USE_SMS_RECEIVER);
 
 	sms->src.npi = dbi_result_get_ulonglong(result, "src_npi");
 	sms->src.ton = dbi_result_get_ulonglong(result, "src_ton");
diff --git a/src/libmsc/gsm_04_08.c b/src/libmsc/gsm_04_08.c
index 09744db..4be42e9 100644
--- a/src/libmsc/gsm_04_08.c
+++ b/src/libmsc/gsm_04_08.c
@@ -878,10 +878,10 @@
 	switch (mi_type) {
 	case GSM_MI_TYPE_TMSI:
 		vsub = vlr_subscr_find_by_tmsi(network->vlr,
-					       tmsi_from_string(mi_string));
+					       tmsi_from_string(mi_string), __func__);
 		break;
 	case GSM_MI_TYPE_IMSI:
-		vsub = vlr_subscr_find_by_imsi(network->vlr, mi_string);
+		vsub = vlr_subscr_find_by_imsi(network->vlr, mi_string, __func__);
 		break;
 	case GSM_MI_TYPE_IMEI:
 	case GSM_MI_TYPE_IMEISV:
@@ -909,7 +909,7 @@
 
 		vlr_subscr_rx_imsi_detach(vsub);
 		osmo_signal_dispatch(SS_SUBSCR, S_SUBSCR_DETACHED, vsub);
-		vlr_subscr_put(vsub);
+		vlr_subscr_put(vsub, __func__);
 	}
 
 	ran_conn_close(conn, 0);
@@ -1768,8 +1768,8 @@
 /* VLR informs us that the subscriber data has somehow been modified */
 static void msc_vlr_subscr_update(struct vlr_subscr *subscr)
 {
-	LOGVSUBP(LOGL_NOTICE, subscr, "VLR: update for IMSI=%s (MSISDN=%s, used=%d)\n",
-		 subscr->imsi, subscr->msisdn, subscr->use_count);
+	LOGVSUBP(LOGL_NOTICE, subscr, "VLR: update for IMSI=%s (MSISDN=%s)\n",
+		 subscr->imsi, subscr->msisdn);
 	ran_conn_update_id_for_vsub(subscr);
 }
 
@@ -1806,7 +1806,8 @@
 		}
 	}
 
-	conn->vsub = vlr_subscr_get(vsub);
+	vlr_subscr_get(vsub, VSUB_USE_CONN);
+	conn->vsub = vsub;
 	OSMO_ASSERT(conn->vsub);
 	conn->vsub->cs.attached_via_ran = conn->via_ran;
 
diff --git a/src/libmsc/gsm_04_08_cc.c b/src/libmsc/gsm_04_08_cc.c
index 98c2aa3..532472e 100644
--- a/src/libmsc/gsm_04_08_cc.c
+++ b/src/libmsc/gsm_04_08_cc.c
@@ -1897,9 +1897,9 @@
 		/* New transaction due to setup, find subscriber */
 		if (data->called.number[0])
 			vsub = vlr_subscr_find_by_msisdn(net->vlr,
-							 data->called.number);
+							 data->called.number, __func__);
 		else
-			vsub = vlr_subscr_find_by_imsi(net->vlr, data->imsi);
+			vsub = vlr_subscr_find_by_imsi(net->vlr, data->imsi, __func__);
 
 		/* update the subscriber we deal with */
 		log_set_context(LOG_CTX_VLR_SUBSCR, vsub);
@@ -1921,7 +1921,7 @@
 				"Received '%s' from MNCC with "
 				"detached subscriber %s\n", data->called.number,
 				get_mncc_name(msg_type), vlr_subscr_name(vsub));
-			vlr_subscr_put(vsub);
+			vlr_subscr_put(vsub, __func__);
 			/* Temporarily out of order */
 			return mncc_release_ind(net, NULL, data->callref,
 						GSM48_CAUSE_LOC_PRN_S_LU,
@@ -1932,7 +1932,7 @@
 				    TRANS_ID_UNASSIGNED, data->callref);
 		if (!trans) {
 			LOGP(DCC, LOGL_ERROR, "No memory for trans.\n");
-			vlr_subscr_put(vsub);
+			vlr_subscr_put(vsub, __func__);
 			/* Ressource unavailable */
 			mncc_release_ind(net, NULL, data->callref,
 					 GSM48_CAUSE_LOC_PRN_S_LU,
@@ -1957,7 +1957,7 @@
 					"started for lac %d.\n",
 					data->called.number,
 					get_mncc_name(msg_type), vsub->cgi.lai.lac);
-				vlr_subscr_put(vsub);
+				vlr_subscr_put(vsub, __func__);
 				trans_free(trans);
 				return 0;
 			}
@@ -1973,18 +1973,18 @@
 							SGSAP_SERV_IND_CS_CALL);
 			if (!trans->paging_request) {
 				LOGP(DCC, LOGL_ERROR, "Failed to allocate paging token.\n");
-				vlr_subscr_put(vsub);
+				vlr_subscr_put(vsub, __func__);
 				trans_free(trans);
 				return 0;
 			}
-			vlr_subscr_put(vsub);
+			vlr_subscr_put(vsub, __func__);
 			return 0;
 		}
 
 		/* Assign conn */
 		trans->conn = ran_conn_get(conn, RAN_CONN_USE_TRANS_CC);
 		trans->dlci = 0x00; /* SAPI=0, not SACCH */
-		vlr_subscr_put(vsub);
+		vlr_subscr_put(vsub, __func__);
 	} else {
 		/* update the subscriber we deal with */
 		log_set_context(LOG_CTX_VLR_SUBSCR, trans->vsub);
diff --git a/src/libmsc/gsm_04_11.c b/src/libmsc/gsm_04_11.c
index ccb2610..37d0333 100644
--- a/src/libmsc/gsm_04_11.c
+++ b/src/libmsc/gsm_04_11.c
@@ -71,7 +71,7 @@
 {
 	/* drop references to subscriber structure */
 	if (sms->receiver)
-		vlr_subscr_put(sms->receiver);
+		vlr_subscr_put(sms->receiver, VSUB_USE_SMS_RECEIVER);
 #ifdef BUILD_SMPP
 	if (sms->smpp.esme)
 		smpp_esme_put(sms->smpp.esme);
@@ -89,7 +89,8 @@
 	if (!sms)
 		return NULL;
 
-	sms->receiver = vlr_subscr_get(receiver);
+	vlr_subscr_get(receiver, VSUB_USE_SMS_RECEIVER);
+	sms->receiver = receiver;
 	OSMO_STRLCPY_ARRAY(sms->text, text);
 
 	OSMO_STRLCPY_ARRAY(sms->src.addr, sender_msisdn);
@@ -441,8 +442,7 @@
 #endif
 
 	/* determine gsms->receiver based on dialled number */
-	gsms->receiver = vlr_subscr_find_by_msisdn(conn->network->vlr,
-						   gsms->dst.addr);
+	gsms->receiver = vlr_subscr_find_by_msisdn(conn->network->vlr, gsms->dst.addr, VSUB_USE_SMS_RECEIVER);
 	if (!gsms->receiver) {
 #ifdef BUILD_SMPP
 		/* Avoid a second look-up */
diff --git a/src/libmsc/gsm_subscriber.c b/src/libmsc/gsm_subscriber.c
index c4faa94..97b58b2 100644
--- a/src/libmsc/gsm_subscriber.c
+++ b/src/libmsc/gsm_subscriber.c
@@ -50,6 +50,8 @@
 #include <osmocom/msc/a_iface.h>
 #include <osmocom/msc/sgs_iface.h>
 
+#define VSUB_USE_PAGING "Paging"
+
 void subscr_paging_cancel(struct vlr_subscr *vsub, enum gsm_paging_event event)
 {
 	subscr_paging_dispatch(GSM_HOOK_RR_PAGING, event, NULL, NULL, vsub);
@@ -106,7 +108,7 @@
 
 	/* balanced with the moment we start paging */
 	vsub->cs.is_paging = false;
-	vlr_subscr_put(vsub);
+	vlr_subscr_put(vsub, VSUB_USE_PAGING);
 	return 0;
 }
 
@@ -168,7 +170,7 @@
 			return NULL;
 		}
 		/* reduced on the first paging callback */
-		vlr_subscr_get(vsub);
+		vlr_subscr_get(vsub, VSUB_USE_PAGING);
 		vsub->cs.is_paging = true;
 		osmo_timer_setup(&vsub->cs.paging_response_timer, paging_response_timer_cb, vsub);
 		osmo_timer_schedule(&vsub->cs.paging_response_timer, net->paging_response_timer, 0);
diff --git a/src/libmsc/msc_vty.c b/src/libmsc/msc_vty.c
index a79f451..9bc8f3a 100644
--- a/src/libmsc/msc_vty.c
+++ b/src/libmsc/msc_vty.c
@@ -68,6 +68,8 @@
 	1,
 };
 
+#define VSUB_USE_VTY "VTY"
+
 #define NETWORK_STR "Configure the GSM network\n"
 #define CODE_CMD_STR "Code commands\n"
 #define NAME_CMD_STR "Name Commands\n"
@@ -671,6 +673,7 @@
 	struct gsm_trans *trans;
 	int reqs;
 	struct llist_head *entry;
+	char buf[128];
 
 	if (strlen(vsub->name))
 		vty_out(vty, "    Name: '%s'%s", vsub->name, VTY_NEWLINE);
@@ -755,7 +758,7 @@
 	else
 		vty_out(vty, "    SGs-MME: (none)%s", VTY_NEWLINE);
 
-	vty_out(vty, "    Use count: %u%s", vsub->use_count, VTY_NEWLINE);
+	vty_out(vty, "    Use: %s%s", osmo_use_count_name_buf(buf, sizeof(buf), &vsub->use_count), VTY_NEWLINE);
 
 	/* Connection */
 	if (vsub->msc_conn_ref) {
@@ -882,11 +885,11 @@
 					       const char *id)
 {
 	if (!strcmp(type, "extension") || !strcmp(type, "msisdn"))
-		return vlr_subscr_find_by_msisdn(gsmnet->vlr, id);
+		return vlr_subscr_find_by_msisdn(gsmnet->vlr, id, VSUB_USE_VTY);
 	else if (!strcmp(type, "imsi") || !strcmp(type, "id"))
-		return vlr_subscr_find_by_imsi(gsmnet->vlr, id);
+		return vlr_subscr_find_by_imsi(gsmnet->vlr, id, VSUB_USE_VTY);
 	else if (!strcmp(type, "tmsi"))
-		return vlr_subscr_find_by_tmsi(gsmnet->vlr, atoi(id));
+		return vlr_subscr_find_by_tmsi(gsmnet->vlr, atoi(id), VSUB_USE_VTY);
 
 	return NULL;
 }
@@ -916,7 +919,7 @@
 	/* In the vty output to the user, exclude this local use count added by vlr_subscr_get() in get_vsub_by_argv().
 	 * This works, because: for get_vsub_by_argv() to succeed, there *must* have been at least one use count before
 	 * this, and since this is not multi-threaded, this vlr_subscr_put() cannot possibly reach a count of 0. */
-	vlr_subscr_put(vsub);
+	vlr_subscr_put(vsub, VSUB_USE_VTY);
 
 	subscr_dump_full_vty(vty, vsub);
 
@@ -955,7 +958,7 @@
 	if (sms)
 		gsm411_send_sms(gsmnet, sms->receiver, sms);
 
-	vlr_subscr_put(vsub);
+	vlr_subscr_put(vsub, VSUB_USE_VTY);
 
 	return CMD_SUCCESS;
 }
@@ -979,7 +982,7 @@
 
 	db_sms_delete_by_msisdn(vsub->msisdn);
 
-	vlr_subscr_put(vsub);
+	vlr_subscr_put(vsub, VSUB_USE_VTY);
 
 	return CMD_SUCCESS;
 }
@@ -1011,7 +1014,7 @@
 			goto err;
 		}
 		sender_msisdn = sender->msisdn;
-		vlr_subscr_put(sender);
+		vlr_subscr_put(sender, VSUB_USE_VTY);
 	}
 
 	str = argv_concat(argv, argc, 4);
@@ -1020,7 +1023,7 @@
 
 err:
 	if (vsub)
-		vlr_subscr_put(vsub);
+		vlr_subscr_put(vsub, VSUB_USE_VTY);
 
 	return rc;
 }
@@ -1053,7 +1056,7 @@
 			goto err;
 		}
 		sender_msisdn = sender->msisdn;
-		vlr_subscr_put(sender);
+		vlr_subscr_put(sender, VSUB_USE_VTY);
 	}
 
 	str = argv_concat(argv, argc, 4);
@@ -1062,7 +1065,7 @@
 
 err:
 	if (vsub)
-		vlr_subscr_put(vsub);
+		vlr_subscr_put(vsub, VSUB_USE_VTY);
 
 	return rc;
 }
@@ -1161,7 +1164,7 @@
 		break;
 	}
 
-	vlr_subscr_put(vsub);
+	vlr_subscr_put(vsub, VSUB_USE_VTY);
 	return rc ? CMD_WARNING : CMD_SUCCESS;
 }
 
@@ -1197,7 +1200,7 @@
 		break;
 	}
 
-	vlr_subscr_put(vsub);
+	vlr_subscr_put(vsub, VSUB_USE_VTY);
 	return rc ? CMD_WARNING : CMD_SUCCESS;
 }
 
@@ -1224,7 +1227,7 @@
 	level = atoi(argv[2]);
 	text = argv_concat(argv, argc, 3);
 	if (!text) {
-		vlr_subscr_put(vsub);
+		vlr_subscr_put(vsub, VSUB_USE_VTY);
 		return CMD_WARNING;
 	}
 
@@ -1232,7 +1235,7 @@
 	if (!conn) {
 		vty_out(vty, "%% An active connection is required for %s %s%s",
 			argv[0], argv[1], VTY_NEWLINE);
-		vlr_subscr_put(vsub);
+		vlr_subscr_put(vsub, VSUB_USE_VTY);
 		talloc_free(text);
 		return CMD_WARNING;
 	}
@@ -1242,7 +1245,7 @@
 	 * we use dummy GSM 04.07 transaction ID. */
 	msc_send_ussd_release_complete(conn, 0x00);
 
-	vlr_subscr_put(vsub);
+	vlr_subscr_put(vsub, VSUB_USE_VTY);
 	talloc_free(text);
 	return CMD_SUCCESS;
 }
@@ -1267,7 +1270,7 @@
 	else
 		vty_out(vty, "%% paging subscriber failed%s", VTY_NEWLINE);
 
-	vlr_subscr_put(vsub);
+	vlr_subscr_put(vsub, VSUB_USE_VTY);
 	return req ? CMD_SUCCESS : CMD_WARNING;
 }
 
@@ -1323,7 +1326,7 @@
 	if (!conn) {
 		vty_out(vty, "%% An active connection is required for %s %s%s",
 			argv[0], argv[1], VTY_NEWLINE);
-		vlr_subscr_put(vsub);
+		vlr_subscr_put(vsub, VSUB_USE_VTY);
 		return CMD_WARNING;
 	}
 
@@ -1351,7 +1354,7 @@
 	if (!conn) {
 		vty_out(vty, "%% An active connection is required for %s %s%s",
 			argv[0], argv[1], VTY_NEWLINE);
-		vlr_subscr_put(vsub);
+		vlr_subscr_put(vsub, VSUB_USE_VTY);
 		return CMD_WARNING;
 	}
 
@@ -1378,12 +1381,12 @@
 		vty_out(vty, "%% VLR released subscriber %s%s",
 			vlr_subscr_name(vsub), VTY_NEWLINE);
 
-	if (vsub->use_count > 1)
+	if (osmo_use_count_total(&vsub->use_count) > 1)
 		vty_out(vty, "%% Subscriber %s is still in use,"
 			" should be released soon%s",
 			vlr_subscr_name(vsub), VTY_NEWLINE);
 
-	vlr_subscr_put(vsub);
+	vlr_subscr_put(vsub, VSUB_USE_VTY);
 	return CMD_SUCCESS;
 }
 
@@ -1575,7 +1578,7 @@
 	if (!tgt)
 		return CMD_WARNING;
 
-	vlr_subscr = vlr_subscr_find_by_imsi(gsmnet->vlr, imsi);
+	vlr_subscr = vlr_subscr_find_by_imsi(gsmnet->vlr, imsi, VSUB_USE_VTY);
 
 	if (!vlr_subscr) {
 		vty_out(vty, "%%no subscriber with IMSI(%s)%s",
@@ -1584,6 +1587,7 @@
 	}
 
 	log_set_filter_vlr_subscr(tgt, vlr_subscr);
+	vlr_subscr_put(vlr_subscr, VSUB_USE_VTY);
 	return CMD_SUCCESS;
 }
 
diff --git a/src/libmsc/ran_conn.c b/src/libmsc/ran_conn.c
index e54e542..8ad183e 100644
--- a/src/libmsc/ran_conn.c
+++ b/src/libmsc/ran_conn.c
@@ -552,7 +552,7 @@
 		DEBUGP(DRLL, "%s: Freeing RAN connection\n", vlr_subscr_name(conn->vsub));
 		conn->vsub->lu_fsm = NULL;
 		conn->vsub->msc_conn_ref = NULL;
-		vlr_subscr_put(conn->vsub);
+		vlr_subscr_put(conn->vsub, VSUB_USE_CONN);
 		conn->vsub = NULL;
 	} else
 		DEBUGP(DRLL, "Freeing RAN connection with NULL subscriber\n");
diff --git a/src/libmsc/sgs_iface.c b/src/libmsc/sgs_iface.c
index f64b191..eed107a 100644
--- a/src/libmsc/sgs_iface.c
+++ b/src/libmsc/sgs_iface.c
@@ -98,6 +98,7 @@
 		return NULL;
 	}
 
+	vlr_subscr_get(vsub, VSUB_USE_CONN);
 	conn->vsub = vsub;
 	conn->vsub->cs.attached_via_ran = conn->via_ran;
 
@@ -264,7 +265,7 @@
 	uint8_t msg_type = msg->data[0];
 
 	/* Subscriber must be known by the VLR */
-	vsub = vlr_subscr_find_by_imsi(gsm_network->vlr, imsi);
+	vsub = vlr_subscr_find_by_imsi(gsm_network->vlr, imsi, __func__);
 	if (!vsub) {
 		LOGSGC(sgc, LOGL_NOTICE, "SGsAP Message %s with unknown IMSI (%s), releasing\n",
 		       sgsap_msg_type_name(msg_type), imsi);
@@ -279,11 +280,11 @@
 		       vlr_subscr_name(vsub), sgsap_msg_type_name(msg_type));
 		resp = gsm29118_create_release_req(vsub->imsi, SGSAP_SGS_CAUSE_IMSI_DET_EPS_NONEPS);
 		sgs_tx(sgc, resp);
-		vlr_subscr_put(vsub);
+		vlr_subscr_put(vsub, __func__);
 		return false;
 	}
 
-	vlr_subscr_put(vsub);
+	vlr_subscr_put(vsub, __func__);
 	return true;
 }
 
@@ -316,12 +317,12 @@
 	struct vlr_subscr *vsub;
 
 	if (imsi) {
-		vsub = vlr_subscr_find_by_imsi(gsm_network->vlr, imsi);
+		vsub = vlr_subscr_find_by_imsi(gsm_network->vlr, imsi, __func__);
 		if (!vsub)
 			subscr_string = imsi;
 		else {
 			subscr_string = vlr_subscr_name(vsub);
-			vlr_subscr_put(vsub);
+			vlr_subscr_put(vsub, __func__);
 		}
 	}
 
@@ -556,10 +557,10 @@
 	struct vlr_subscr *vsub;
 
 	/* Check for lingering connections */
-	vsub = vlr_subscr_find_by_imsi(gsm_network->vlr, imsi);
+	vsub = vlr_subscr_find_by_imsi(gsm_network->vlr, imsi, __func__);
 	if (vsub) {
 		subscr_conn_toss(vsub);
-		vlr_subscr_put(vsub);
+		vlr_subscr_put(vsub, __func__);
 	}
 
 	/* Determine MME-Name */
@@ -675,7 +676,7 @@
 		return 0;
 
 	/* Subscriber must be known by the VLR */
-	vsub = vlr_subscr_find_by_imsi(gsm_network->vlr, imsi);
+	vsub = vlr_subscr_find_by_imsi(gsm_network->vlr, imsi, __func__);
 	if (!vsub)
 		return sgs_tx_status(sgc, imsi, SGSAP_SGS_CAUSE_IMSI_UNKNOWN, msg, SGSAP_IE_IMSI);
 
@@ -698,7 +699,7 @@
 		OSMO_ASSERT(false);
 	}
 
-	vlr_subscr_put(vsub);
+	vlr_subscr_put(vsub, __func__);
 	return 0;
 }
 
@@ -739,7 +740,7 @@
 	if (!check_sgs_association(sgc, msg, imsi))
 		return 0;
 
-	vsub = vlr_subscr_find_by_imsi(gsm_network->vlr, imsi);
+	vsub = vlr_subscr_find_by_imsi(gsm_network->vlr, imsi, __func__);
 	/* Note: vsub is already sufficiently verified by check_sgs_association(),
 	 * we must have a vsub at this point! */
 	OSMO_ASSERT(vsub);
@@ -747,13 +748,13 @@
 	/* The Service request is intended as a paging response, if one is
 	 * received while nothing is paging something is very wrong! */
 	if (!vlr_sgs_pag_pend(vsub)) {
-		vlr_subscr_put(vsub);
+		vlr_subscr_put(vsub, __func__);
 		return sgs_tx_status(sgc, imsi, SGSAP_SGS_CAUSE_MSG_INCOMP_STATE, msg, -1);
 	}
 	serv_ind_ie = TLVP_VAL_MINLEN(tp, SGSAP_IE_SERVICE_INDICATOR, 1);
 
 	if (!serv_ind_ie) {
-		vlr_subscr_put(vsub);
+		vlr_subscr_put(vsub, __func__);
 		return sgs_tx_status(sgc, imsi, SGSAP_SGS_CAUSE_MISSING_MAND_IE, msg, SGSAP_IE_SERVICE_INDICATOR);
 	}
 	if (serv_ind_ie[0] == SGSAP_SERV_IND_CS_CALL)
@@ -761,7 +762,7 @@
 	else if (serv_ind_ie[0] == SGSAP_SERV_IND_SMS)
 		serv_ind = serv_ind_ie[0];
 	else {
-		vlr_subscr_put(vsub);
+		vlr_subscr_put(vsub, __func__);
 		return sgs_tx_status(sgc, imsi, SGSAP_SGS_CAUSE_INVALID_MAND_IE, msg, SGSAP_IE_SERVICE_INDICATOR);
 	}
 
@@ -776,17 +777,19 @@
 	 * the connection will be allocated when the MS is appearing on the
 	 * A-Interface. */
 	if (serv_ind == SGSAP_SERV_IND_CS_CALL) {
-		vlr_subscr_put(vsub);
+		vlr_subscr_put(vsub, __func__);
 		return 0;
 	}
 
 	/* Allocate subscriber connection */
 	conn = subscr_conn_allocate_sgs(sgc, vsub, true);
 	if (!conn) {
-		vlr_subscr_put(vsub);
+		vlr_subscr_put(vsub, __func__);
 		return sgs_tx_status(sgc, imsi, SGSAP_SGS_CAUSE_MSG_INCOMP_STATE, msg, -1);
 	}
 
+	/* The conn has added a get() for the vsub, balance above vlr_subscr_find_by_imsi() */
+	vlr_subscr_put(vsub, __func__);
 	return 0;
 }
 
@@ -795,14 +798,13 @@
 {
 	struct dtap_header *dtap;
 	struct ran_conn *conn;
-	bool ran_conn_created = false;
 	const uint8_t *nas_msg_container_ie;
 	struct vlr_subscr *vsub;
 
 	if (!check_sgs_association(sgc, msg, imsi))
 		return 0;
 
-	vsub = vlr_subscr_find_by_imsi(gsm_network->vlr, imsi);
+	vsub = vlr_subscr_find_by_imsi(gsm_network->vlr, imsi, __func__);
 	/* Note: vsub is already sufficiently verified by check_sgs_association(),
 	 * we must have a vsub at this point! */
 	OSMO_ASSERT(vsub);
@@ -811,7 +813,6 @@
 	conn = connection_for_subscr(vsub);
 	if (!conn) {
 		conn = subscr_conn_allocate_sgs(sgc, vsub, false);
-		ran_conn_created = true;
 	} else {
 		if (conn->via_ran != OSMO_RAT_EUTRAN_SGS) {
 			LOGSGC(sgc, LOGL_ERROR,
@@ -821,16 +822,17 @@
 		}
 	}
 
+	/* Balance above vlr_subscr_find_by_imsi() */
+	vlr_subscr_put(vsub, __func__);
+
 	/* If we do not find an existing connection and allocating a new one
 	 * faild, give up and return status. */
 	if (!conn) {
-		vlr_subscr_put(vsub);
 		return sgs_tx_status(sgc, imsi, SGSAP_SGS_CAUSE_MSG_INCOMP_STATE, msg, 0);
 	}
 
 	nas_msg_container_ie = TLVP_VAL_MINLEN(tp, SGSAP_IE_NAS_MSG_CONTAINER, 1);
 	if (!nas_msg_container_ie) {
-		vlr_subscr_put(vsub);
 		return sgs_tx_status(sgc, imsi, SGSAP_SGS_CAUSE_MISSING_MAND_IE, msg, SGSAP_IE_NAS_MSG_CONTAINER);
 	}
 
@@ -842,12 +844,6 @@
 	/* Forward dtap payload into the msc */
 	ran_conn_dtap(conn, msg);
 
-	/* If we did not create the conn right here, we just handle the ref
-	 * counting normally. Otherwise we are in the same role as
-	 * sgs_rx_service_req() and we want that the refcount says incremented
-	 * througout the lifetime of the newly created conn. */
-	if (!ran_conn_created)
-		vlr_subscr_put(vsub);
 	return 0;
 }
 
@@ -860,7 +856,7 @@
 	 * to the 4G network, so we use the SGs interface again for further
 	 * communication with the UE. */
 
-	vsub = vlr_subscr_find_by_imsi(gsm_network->vlr, imsi);
+	vsub = vlr_subscr_find_by_imsi(gsm_network->vlr, imsi, __func__);
 	if (!vsub)
 		return sgs_tx_status(sgc, imsi, SGSAP_SGS_CAUSE_IMSI_UNKNOWN, msg, SGSAP_IE_IMSI);
 
@@ -868,7 +864,7 @@
 	subscr_conn_toss(vsub);
 
 	vsub->cs.attached_via_ran = OSMO_RAT_EUTRAN_SGS;
-	vlr_subscr_put(vsub);
+	vlr_subscr_put(vsub, __func__);
 	return 0;
 }
 
diff --git a/src/libmsc/smpp_openbsc.c b/src/libmsc/smpp_openbsc.c
index 9156445..01c39f9 100644
--- a/src/libmsc/smpp_openbsc.c
+++ b/src/libmsc/smpp_openbsc.c
@@ -48,6 +48,9 @@
 
 #include "smpp_smsc.h"
 
+#define VSUB_USE_SMPP "SMPP"
+#define VSUB_USE_SMPP_CMD "SMPP-cmd"
+
 /*! \brief find vlr_subscr for a given SMPP NPI/TON/Address */
 static struct vlr_subscr *subscr_by_dst(struct gsm_network *net,
 					    uint8_t npi, uint8_t ton,
@@ -57,11 +60,11 @@
 
 	switch (npi) {
 	case NPI_Land_Mobile_E212:
-		vsub = vlr_subscr_find_by_imsi(net->vlr, addr);
+		vsub = vlr_subscr_find_by_imsi(net->vlr, addr, VSUB_USE_SMPP);
 		break;
 	case NPI_ISDN_E163_E164:
 	case NPI_Private:
-		vsub = vlr_subscr_find_by_msisdn(net->vlr, addr);
+		vsub = vlr_subscr_find_by_msisdn(net->vlr, addr, VSUB_USE_SMPP);
 		break;
 	default:
 		LOGP(DSMPP, LOGL_NOTICE, "Unsupported NPI: %u\n", npi);
@@ -117,7 +120,7 @@
 			if (smpp34_submit_tlv_msg_payload(t, submit, &sms_msg,
 							  &sms_msg_len) < 0) {
 				if (dest)
-					vlr_subscr_put(dest);
+					vlr_subscr_put(dest, VSUB_USE_SMPP);
 				return ESME_ROPTPARNOTALLWD;
 			}
 			break;
@@ -136,7 +139,7 @@
 		} else {
 			LOGP(DLSMS, LOGL_ERROR,
 			     "SMPP neither message payload nor valid sm_length.\n");
-			vlr_subscr_put(dest);
+			vlr_subscr_put(dest, VSUB_USE_SMPP);
 			return ESME_RINVPARLEN;
 		}
 	}
@@ -532,7 +535,7 @@
 {
 	osmo_timer_del(&cmd->response_timer);
 	llist_del(&cmd->list);
-	vlr_subscr_put(cmd->vsub);
+	vlr_subscr_put(cmd->vsub, VSUB_USE_SMPP_CMD);
 	talloc_free(cmd);
 }
 
@@ -619,7 +622,8 @@
 	cmd->is_report		= sms->is_report;
 	cmd->gsm411_msg_ref	= sms->gsm411.msg_ref;
 	cmd->gsm411_trans_id	= sms->gsm411.transaction_id;
-	cmd->vsub		= vlr_subscr_get(vsub);
+	vlr_subscr_get(vsub, VSUB_USE_SMPP_CMD);
+	cmd->vsub = vsub;
 
 	/* FIXME: No predefined value for this response_timer as specified by
 	 * SMPP 3.4 specs, section 7.2. Make this configurable? Don't forget
diff --git a/src/libmsc/sms_queue.c b/src/libmsc/sms_queue.c
index 4de30ad..a56814d 100644
--- a/src/libmsc/sms_queue.c
+++ b/src/libmsc/sms_queue.c
@@ -118,14 +118,15 @@
 	if (!pending)
 		return NULL;
 
-	pending->vsub = vlr_subscr_get(sms->receiver);
+	vlr_subscr_get(sms->receiver, VSUB_USE_SMS_PENDING);
+	pending->vsub = sms->receiver;
 	pending->sms_id = sms->id;
 	return pending;
 }
 
 static void sms_pending_free(struct gsm_sms_pending *pending)
 {
-	vlr_subscr_put(pending->vsub);
+	vlr_subscr_put(pending->vsub, VSUB_USE_SMS_PENDING);
 	llist_del(&pending->entry);
 	talloc_free(pending);
 }
@@ -482,12 +483,13 @@
 	case S_SMS_DELIVERED:
 		/* Remember the subscriber and clear the pending entry */
 		network->sms_queue->pending -= 1;
-		vsub = vlr_subscr_get(pending->vsub);
+		vsub = pending->vsub;
+		vlr_subscr_get(vsub, __func__);
 		db_sms_delete_sent_message_by_id(pending->sms_id);
 		sms_pending_free(pending);
 		/* Attempt to send another SMS to this subscriber */
 		sms_send_next(vsub);
-		vlr_subscr_put(vsub);
+		vlr_subscr_put(vsub, __func__);
 		break;
 	case S_SMS_MEM_EXCEEDED:
 		network->sms_queue->pending -= 1;
diff --git a/src/libmsc/transaction.c b/src/libmsc/transaction.c
index 66126e6..b38c152 100644
--- a/src/libmsc/transaction.c
+++ b/src/libmsc/transaction.c
@@ -93,6 +93,11 @@
 	return NULL;
 }
 
+static const char *trans_vsub_use(uint8_t proto)
+{
+	return get_value_string_or_null(gsm48_pdisc_names, proto) ? : "trans-proto-unknown";
+}
+
 /*! Allocate a new transaction and add it to network list
  *  \param[in] net Netwokr in which we allocate transaction
  *  \param[in] subscr Subscriber for which we allocate transaction
@@ -121,8 +126,8 @@
 	if (!trans)
 		return NULL;
 
-	trans->vsub = vlr_subscr_get(vsub);
-
+	vlr_subscr_get(vsub, trans_vsub_use(protocol));
+	trans->vsub = vsub;
 	trans->protocol = protocol;
 	trans->transaction_id = trans_id;
 	trans->callref = callref;
@@ -165,7 +170,7 @@
 	}
 
 	if (trans->vsub) {
-		vlr_subscr_put(trans->vsub);
+		vlr_subscr_put(trans->vsub, trans_vsub_use(trans->protocol));
 		trans->vsub = NULL;
 	}
 
diff --git a/src/libvlr/vlr.c b/src/libvlr/vlr.c
index cd4209d..1afdbec 100644
--- a/src/libvlr/vlr.c
+++ b/src/libvlr/vlr.c
@@ -119,6 +119,7 @@
 
 struct vlr_subscr *_vlr_subscr_find_by_imsi(struct vlr_instance *vlr,
 					    const char *imsi,
+					    const char *use,
 					    const char *file, int line)
 {
 	struct vlr_subscr *vsub;
@@ -127,14 +128,17 @@
 		return NULL;
 
 	llist_for_each_entry(vsub, &vlr->subscribers, list) {
-		if (vlr_subscr_matches_imsi(vsub, imsi))
-			return _vlr_subscr_get(vsub, file, line);
+		if (vlr_subscr_matches_imsi(vsub, imsi)) {
+			vlr_subscr_get_src(vsub, use, file, line);
+			return vsub;
+		}
 	}
 	return NULL;
 }
 
 struct vlr_subscr *_vlr_subscr_find_by_tmsi(struct vlr_instance *vlr,
 					    uint32_t tmsi,
+					    const char *use,
 					    const char *file, int line)
 {
 	struct vlr_subscr *vsub;
@@ -143,14 +147,17 @@
 		return NULL;
 
 	llist_for_each_entry(vsub, &vlr->subscribers, list) {
-		if (vlr_subscr_matches_tmsi(vsub, tmsi))
-			return _vlr_subscr_get(vsub, file, line);
+		if (vlr_subscr_matches_tmsi(vsub, tmsi)) {
+			vlr_subscr_get_src(vsub, use, file, line);
+			return vsub;
+		}
 	}
 	return NULL;
 }
 
 struct vlr_subscr *_vlr_subscr_find_by_msisdn(struct vlr_instance *vlr,
 					      const char *msisdn,
+					      const char *use,
 					      const char *file, int line)
 {
 	struct vlr_subscr *vsub;
@@ -159,8 +166,10 @@
 		return NULL;
 
 	llist_for_each_entry(vsub, &vlr->subscribers, list) {
-		if (vlr_subscr_matches_msisdn(vsub, msisdn))
-			return _vlr_subscr_get(vsub, file, line);
+		if (vlr_subscr_matches_msisdn(vsub, msisdn)) {
+			vlr_subscr_get_src(vsub, use, file, line);
+			return vsub;
+		}
 	}
 	return NULL;
 }
@@ -217,30 +226,24 @@
 	return vlr_tx_gsup_message(vlr, &gsup_reply);
 }
 
-struct vlr_subscr *_vlr_subscr_get(struct vlr_subscr *sub, const char *file, int line)
+static int vlr_subscr_use_cb(struct osmo_use_count_entry *e, int32_t old_use_count, const char *file, int line)
 {
-	if (!sub)
-		return NULL;
-	OSMO_ASSERT(sub->use_count < INT_MAX);
-	sub->use_count++;
-	LOGPSRC(DREF, LOGL_DEBUG, file, line,
-		"VLR subscr %s usage increases to: %d\n",
-		vlr_subscr_name(sub), sub->use_count);
-	return sub;
-}
+	struct vlr_subscr *vsub = e->use_count->talloc_object;
+	char buf[128];
 
-struct vlr_subscr *_vlr_subscr_put(struct vlr_subscr *sub, const char *file, int line)
-{
-	if (!sub)
-		return NULL;
-	sub->use_count--;
-	LOGPSRC(DREF, sub->use_count >= 0? LOGL_DEBUG : LOGL_ERROR,
-		file, line,
-		"VLR subscr %s usage decreases to: %d\n",
-		vlr_subscr_name(sub), sub->use_count);
-	if (sub->use_count <= 0)
-		vlr_subscr_free(sub);
-	return NULL;
+	if (!e->use)
+		return -EINVAL;
+
+	LOGPSRC(DREF, LOGL_DEBUG, file, line, "VLR subscr %s %s %s: now used by %s\n",
+		vlr_subscr_name(vsub), (e->count - old_use_count) > 0? "+" : "-", e->use,
+		osmo_use_count_name_buf(buf, sizeof(buf), e->use_count));
+
+	if (e->count < 0)
+		return -ERANGE;
+
+	if (osmo_use_count_total(e->use_count) <= 0)
+		vlr_subscr_free(vsub);
+	return 0;
 }
 
 /* Allocate a new subscriber and insert it into list */
@@ -250,9 +253,16 @@
 	int i;
 
 	vsub = talloc_zero(vlr, struct vlr_subscr);
-	vsub->vlr = vlr;
-	vsub->tmsi = GSM_RESERVED_TMSI;
-	vsub->tmsi_new = GSM_RESERVED_TMSI;
+	*vsub = (struct vlr_subscr){
+		.vlr = vlr,
+		.tmsi = GSM_RESERVED_TMSI,
+		.tmsi_new = GSM_RESERVED_TMSI,
+		.use_count = (struct osmo_use_count){
+			.talloc_object = vsub,
+			.use_cb = vlr_subscr_use_cb,
+		},
+	};
+	osmo_use_count_make_static_entries(&vsub->use_count, vsub->use_count_buf, ARRAY_SIZE(vsub->use_count_buf));
 
 	for (i = 0; i < ARRAY_SIZE(vsub->auth_tuples); i++)
 		vsub->auth_tuples[i].key_seq = VLR_KEY_SEQ_INVAL;
@@ -269,11 +279,6 @@
 	return vsub;
 }
 
-struct vlr_subscr *vlr_subscr_alloc(struct vlr_instance *vlr)
-{
-	return vlr_subscr_get(_vlr_subscr_alloc(vlr));
-}
-
 /* Send a GSUP Purge MS request.
  * TODO: this should be sent to the *previous* VLR when this VLR is "taking"
  * this subscriber, not to the HLR? */
@@ -297,12 +302,12 @@
 	if (!vsub)
 		return;
 
-	vlr_subscr_get(vsub);
+	vlr_subscr_get(vsub, __func__);
 	if (vsub->lu_fsm)
 		vlr_loc_update_cancel(vsub->lu_fsm, fsm_cause, gsm48_cause);
 	if (vsub->proc_arq_fsm)
 		vlr_parq_cancel(vsub->proc_arq_fsm, fsm_cause, gsm48_cause);
-	vlr_subscr_put(vsub);
+	vlr_subscr_put(vsub, __func__);
 }
 
 /* Call vlr_subscr_cancel(), then completely drop the entry from the VLR */
@@ -327,6 +332,7 @@
 	struct vlr_instance *vlr = vsub->vlr;
 	uint32_t tmsi;
 	int tried, rc;
+	struct vlr_subscr *other_vsub;
 
 	for (tried = 0; tried < 100; tried++) {
 		rc = osmo_get_rand_id((uint8_t *) &tmsi, sizeof(tmsi));
@@ -349,8 +355,10 @@
 		}
 
 		/* If this TMSI is already in use, try another one. */
-		if (vlr_subscr_find_by_tmsi(vlr, tmsi))
+		if ((other_vsub = vlr_subscr_find_by_tmsi(vlr, tmsi, __func__))) {
+			vlr_subscr_put(other_vsub, __func__);
 			continue;
+		}
 
 		vsub->tmsi_new = tmsi;
 		vsub->vlr->ops.subscr_update(vsub);
@@ -368,21 +376,23 @@
  * \param[out] created  if non-NULL, returns whether a new entry was created. */
 struct vlr_subscr *_vlr_subscr_find_or_create_by_imsi(struct vlr_instance *vlr,
 						      const char *imsi,
+						      const char *use,
 						      bool *created,
 						      const char *file,
 						      int line)
 {
 	struct vlr_subscr *vsub;
-	vsub = _vlr_subscr_find_by_imsi(vlr, imsi, file, line);
+	vsub = _vlr_subscr_find_by_imsi(vlr, imsi, use, file, line);
 	if (vsub) {
 		if (created)
 			*created = false;
 		return vsub;
 	}
 
-	vsub = _vlr_subscr_get(_vlr_subscr_alloc(vlr), file, line);
+	vsub = _vlr_subscr_alloc(vlr);
 	if (!vsub)
 		return NULL;
+	vlr_subscr_get_src(vsub, use, file, line);
 	vlr_subscr_set_imsi(vsub, imsi);
 	LOGP(DVLR, LOGL_INFO, "New subscr, IMSI: %s\n", vsub->imsi);
 	if (created)
@@ -396,21 +406,23 @@
  * \param[out] created  if non-NULL, returns whether a new entry was created. */
 struct vlr_subscr *_vlr_subscr_find_or_create_by_tmsi(struct vlr_instance *vlr,
 						      uint32_t tmsi,
+						      const char *use,
 						      bool *created,
 						      const char *file,
 						      int line)
 {
 	struct vlr_subscr *vsub;
-	vsub = _vlr_subscr_find_by_tmsi(vlr, tmsi, file, line);
+	vsub = _vlr_subscr_find_by_tmsi(vlr, tmsi, use, file, line);
 	if (vsub) {
 		if (created)
 			*created = false;
 		return vsub;
 	}
 
-	vsub = _vlr_subscr_get(_vlr_subscr_alloc(vlr), file, line);
+	vsub = _vlr_subscr_alloc(vlr);
 	if (!vsub)
 		return NULL;
+	vlr_subscr_get_src(vsub, use, file, line);
 	vsub->tmsi = tmsi;
 	LOGP(DVLR, LOGL_INFO, "New subscr, TMSI: 0x%08x\n", vsub->tmsi);
 	if (created)
@@ -1098,7 +1110,7 @@
 		goto msgb_free_and_return;
 	}
 
-	vsub = vlr_subscr_find_by_imsi(vlr, gsup.imsi);
+	vsub = vlr_subscr_find_by_imsi(vlr, gsup.imsi, __func__);
 	if (!vsub) {
 		switch (gsup.message_type) {
 		case OSMO_GSUP_MSGT_PURGE_MS_RESULT:
@@ -1146,7 +1158,7 @@
 		break;
 	}
 
-	vlr_subscr_put(vsub);
+	vlr_subscr_put(vsub, __func__);
 
 msgb_free_and_return:
 	msgb_free(msg);
@@ -1239,7 +1251,7 @@
 	if (vsub->lu_complete) {
 		/* balancing the get from vlr_lu_compl_fsm_success() */
 		vsub->lu_complete = false;
-		vlr_subscr_put(vsub);
+		vlr_subscr_put(vsub, VSUB_USE_ATTACHED);
 
 		return true;
 	}
@@ -1425,16 +1437,18 @@
 			       struct vlr_subscr *vlr_subscr)
 {
 	struct vlr_subscr **fsub = (void*)&target->filter_data[LOG_FLT_VLR_SUBSCR];
+	const char *use = "logfilter";
 
 	/* free the old data */
 	if (*fsub) {
-		vlr_subscr_put(*fsub);
+		vlr_subscr_put(*fsub, use);
 		*fsub = NULL;
 	}
 
 	if (vlr_subscr) {
 		target->filter_map |= (1 << LOG_FLT_VLR_SUBSCR);
-		*fsub = vlr_subscr_get(vlr_subscr);
+		vlr_subscr_get(vlr_subscr, use);
+		*fsub = vlr_subscr;
 	} else
 		target->filter_map &= ~(1 << LOG_FLT_VLR_SUBSCR);
 }
diff --git a/src/libvlr/vlr_access_req_fsm.c b/src/libvlr/vlr_access_req_fsm.c
index 26db42c..3040158 100644
--- a/src/libvlr/vlr_access_req_fsm.c
+++ b/src/libvlr/vlr_access_req_fsm.c
@@ -356,10 +356,10 @@
 	/* Obtain_Identity_VLR */
 	if (!par->by_tmsi) {
 		/* IMSI was included */
-		vsub = vlr_subscr_find_by_imsi(par->vlr, par->imsi);
+		vsub = vlr_subscr_find_by_imsi(par->vlr, par->imsi, __func__);
 	} else {
 		/* TMSI was included */
-		vsub = vlr_subscr_find_by_tmsi(par->vlr, par->tmsi);
+		vsub = vlr_subscr_find_by_tmsi(par->vlr, par->tmsi, __func__);
 	}
 	if (vsub) {
 		log_set_context(LOG_CTX_VLR_SUBSCR, vsub);
@@ -377,7 +377,7 @@
 			proc_arq_fsm_done(fi, GSM48_REJECT_NETWORK_FAILURE);
 		else
 			proc_arq_vlr_fn_post_imsi(fi);
-		vlr_subscr_put(vsub);
+		vlr_subscr_put(vsub, __func__);
 		return;
 	}
 	/* No VSUB could be resolved. What now? */
@@ -412,7 +412,7 @@
 
 	OSMO_ASSERT(event == PR_ARQ_E_ID_IMSI);
 
-	vsub = vlr_subscr_find_by_imsi(vlr, par->imsi);
+	vsub = vlr_subscr_find_by_imsi(vlr, par->imsi, __func__);
 	if (!vsub) {
 		/* Set User Error: Unidentified Subscriber */
 		proc_arq_fsm_done(fi, GSM48_REJECT_IMSI_UNKNOWN_IN_VLR);
@@ -422,7 +422,7 @@
 		proc_arq_fsm_done(fi, GSM48_REJECT_NETWORK_FAILURE);
 	else
 		proc_arq_vlr_fn_post_imsi(fi);
-	vlr_subscr_put(vsub);
+	vlr_subscr_put(vsub, __func__);
 }
 
 /* Authenticate_VLR has completed */
diff --git a/src/libvlr/vlr_lu_fsm.c b/src/libvlr/vlr_lu_fsm.c
index 7ddf455..ecf96fa 100644
--- a/src/libvlr/vlr_lu_fsm.c
+++ b/src/libvlr/vlr_lu_fsm.c
@@ -360,7 +360,7 @@
 	if (!vsub->lu_complete) {
 		vsub->lu_complete = true;
 		/* Balanced by vlr_subscr_expire() */
-		vlr_subscr_get(vsub);
+		vlr_subscr_get(vsub, VSUB_USE_ATTACHED);
 	}
 	_vlr_lu_compl_fsm_done(fi, VLR_FSM_RESULT_SUCCESS, 0);
 	vlr_sgs_fsm_update_id(vsub);
@@ -982,7 +982,7 @@
 		 * someone else's TMSI.
 		 * TODO: Otherwise we can ask for the IMSI and verify that it
 		 * matches the IMSI on record. */
-		vsub = vlr_subscr_find_or_create_by_tmsi(vlr, lfp->tmsi, NULL);
+		vsub = vlr_subscr_find_or_create_by_tmsi(vlr, lfp->tmsi, __func__, NULL);
 
 		if (!vsub) {
 			LOGPFSML(fi, LOGL_ERROR, "VLR subscriber allocation failed\n");
@@ -992,27 +992,27 @@
 
 		vsub->sub_dataconf_by_hlr_ind = false;
 		if (assoc_lfp_with_sub(fi, vsub)) {
-			vlr_subscr_put(vsub);
+			vlr_subscr_put(vsub, __func__);
 			return -1; /* error, fsm failure invoked in assoc_lfp_with_sub() */
 		}
-		vlr_subscr_put(vsub);
+		vlr_subscr_put(vsub, __func__);
 	} else {
 		/* IMSI was used */
-		vsub = vlr_subscr_find_or_create_by_imsi(vlr, lfp->imsi, NULL);
+		vsub = vlr_subscr_find_or_create_by_imsi(vlr, lfp->imsi, __func__, NULL);
 
 		if (!vsub) {
 			LOGPFSML(fi, LOGL_ERROR, "VLR subscriber allocation failed\n");
 			lu_fsm_failure(fi, GSM48_REJECT_SRV_OPT_TMP_OUT_OF_ORDER);
-			vlr_subscr_put(vsub);
+			vlr_subscr_put(vsub, __func__);
 			return -1;
 		}
 
 		vsub->sub_dataconf_by_hlr_ind = false;
 		if (assoc_lfp_with_sub(fi, vsub)) {
-			vlr_subscr_put(vsub);
+			vlr_subscr_put(vsub, __func__);
 			return -1; /* error, fsm failure invoked in assoc_lfp_with_sub() */
 		}
-		vlr_subscr_put(vsub);
+		vlr_subscr_put(vsub, __func__);
 	}
 	return 0;
 }
diff --git a/src/libvlr/vlr_sgs.c b/src/libvlr/vlr_sgs.c
index 06737db..3ee7799 100644
--- a/src/libvlr/vlr_sgs.c
+++ b/src/libvlr/vlr_sgs.c
@@ -80,7 +80,7 @@
 	OSMO_ASSERT(cfg);
 	OSMO_ASSERT(imsi);
 
-	vsub = vlr_subscr_find_or_create_by_imsi(vlr, imsi, NULL);
+	vsub = vlr_subscr_find_or_create_by_imsi(vlr, imsi, VSUB_USE_SGS, NULL);
 	if (!vsub) {
 		LOGP(DSGS, LOGL_ERROR, "VLR subscriber allocation failed\n");
 		return -EINVAL;
@@ -137,7 +137,7 @@
 	struct vlr_subscr *vsub;
 	enum sgs_ue_fsm_event evt;
 
-	vsub = vlr_subscr_find_by_imsi(vlr, imsi);
+	vsub = vlr_subscr_find_by_imsi(vlr, imsi, __func__);
 	if (!vsub)
 		return;
 
@@ -164,12 +164,12 @@
 	}
 
 	osmo_fsm_inst_dispatch(vsub->sgs_fsm, evt, NULL);
-	vlr_subscr_put(vsub);
 
 	/* Detaching from non EPS services essentially means that the
 	 * subscriber is detached from 2G. In any case the VLR will
 	 * get rid of the subscriber. */
 	vlr_subscr_expire(vsub);
+	vlr_subscr_put(vsub, __func__);
 }
 
 /*! Perform an SGs EPS detach.
@@ -180,7 +180,7 @@
 {
 	struct vlr_subscr *vsub;
 	enum sgs_ue_fsm_event evt;
-	vsub = vlr_subscr_find_by_imsi(vlr, imsi);
+	vsub = vlr_subscr_find_by_imsi(vlr, imsi, __func__);
 	if (!vsub)
 		return;
 
@@ -211,7 +211,7 @@
 	if (vsub->expire_lu == VLR_SUBSCRIBER_NO_EXPIRATION)
 		vlr_subscr_enable_expire_lu(vsub);
 
-	vlr_subscr_put(vsub);
+	vlr_subscr_put(vsub, __func__);
 }
 
 /*! Perform an SGs TMSI reallocation complete.
@@ -220,12 +220,12 @@
 void vlr_sgs_tmsi_reall_compl(struct vlr_instance *vlr, const char *imsi)
 {
 	struct vlr_subscr *vsub;
-	vsub = vlr_subscr_find_by_imsi(vlr, imsi);
+	vsub = vlr_subscr_find_by_imsi(vlr, imsi, __func__);
 	if (!vsub)
 		return;
 
 	osmo_fsm_inst_dispatch(vsub->sgs_fsm, SGS_UE_E_RX_TMSI_REALLOC, NULL);
-	vlr_subscr_put(vsub);
+	vlr_subscr_put(vsub, __func__);
 }
 
 /*! Notify that an SGs paging has been rejected by the MME.
@@ -235,7 +235,7 @@
 void vlr_sgs_pag_rej(struct vlr_instance *vlr, const char *imsi, enum sgsap_sgs_cause cause)
 {
 	struct vlr_subscr *vsub;
-	vsub = vlr_subscr_find_by_imsi(vlr, imsi);
+	vsub = vlr_subscr_find_by_imsi(vlr, imsi, __func__);
 	if (!vsub)
 		return;
 
@@ -246,10 +246,10 @@
 	     vlr_subscr_msisdn_or_name(vsub), vlr_sgs_state_timer_name(SGS_STATE_TS5), sgsap_sgs_cause_name(cause));
 
 	osmo_fsm_inst_dispatch(vsub->sgs_fsm, SGS_UE_E_RX_PAGING_FAILURE, &cause);
-	vlr_subscr_put(vsub);
-
 	/* Balance ref count increment from vlr_sgs_pag() */
-	vlr_subscr_put(vsub);
+	vlr_subscr_put(vsub, VSUB_USE_SGS_PAGING);
+
+	vlr_subscr_put(vsub, __func__);
 }
 
 /*! Notify that an SGs paging has been accepted by the MME.
@@ -258,16 +258,16 @@
 void vlr_sgs_pag_ack(struct vlr_instance *vlr, const char *imsi)
 {
 	struct vlr_subscr *vsub;
-	vsub = vlr_subscr_find_by_imsi(vlr, imsi);
+	vsub = vlr_subscr_find_by_imsi(vlr, imsi, __func__);
 	if (!vsub)
 		return;
 
 	/* Stop Ts5 and and consider the paging as successful */
 	osmo_timer_del(&vsub->sgs.Ts5);
-	vlr_subscr_put(vsub);
-
 	/* Balance ref count increment from vlr_sgs_pag() */
-	vlr_subscr_put(vsub);
+	vlr_subscr_put(vsub, VSUB_USE_SGS_PAGING);
+
+	vlr_subscr_put(vsub, __func__);
 }
 
 /*! Notify that the UE has been marked as unreachable by the MME.
@@ -277,7 +277,7 @@
 void vlr_sgs_ue_unr(struct vlr_instance *vlr, const char *imsi, enum sgsap_sgs_cause cause)
 {
 	struct vlr_subscr *vsub;
-	vsub = vlr_subscr_find_by_imsi(vlr, imsi);
+	vsub = vlr_subscr_find_by_imsi(vlr, imsi, __func__);
 	if (!vsub)
 		return;
 
@@ -289,7 +289,7 @@
 	     vlr_subscr_msisdn_or_name(vsub), vlr_sgs_state_timer_name(SGS_STATE_TS5), sgsap_sgs_cause_name(cause));
 
 	osmo_fsm_inst_dispatch(vsub->sgs_fsm, SGS_UE_E_RX_SGSAP_UE_UNREACHABLE, &cause);
-	vlr_subscr_put(vsub);
+	vlr_subscr_put(vsub, __func__);
 }
 
 /* Callback function that is called when an SGs paging request times out */
@@ -306,7 +306,7 @@
 	     vlr_subscr_msisdn_or_name(vsub), vlr_sgs_state_timer_name(SGS_STATE_TS5));
 
 	/* Balance ref count increment from vlr_sgs_pag() */
-	vlr_subscr_put(vsub);
+	vlr_subscr_put(vsub, VSUB_USE_SGS_PAGING);
 
 	return;
 }
@@ -346,7 +346,7 @@
 	/* Ensure that the reference count is increased by one while the
 	 * paging is happening. We will balance this again in vlr_sgs_pag_rej()
 	 * and vlr_sgs_pag_ack(); */
-	vlr_subscr_get(vsub);
+	vlr_subscr_get(vsub, VSUB_USE_SGS_PAGING);
 }
 
 /*! Check if the SGs interface is currently paging