msc: Add per subscriber keep_in_ram flag

Currently the keep_subscr flag in gsm_subscriber_group refers to a
whole group of subscribers which makes it difficult to really delete
single entries if the flag is set.

This patch adds a keep_in_ram field to gsm_subscriber which allows for
keeping subscriber objects in RAM while deleting others.

Note that really deleting an entry requires that both flags
(subscr_group->keep_subscr and subscr->keep_in_ram) are set to 0. So
only the latter should be used if a specification requires the
deletion of a subscriber entry.

Sponsored-by: On-Waves ehf
diff --git a/openbsc/include/openbsc/gsm_subscriber.h b/openbsc/include/openbsc/gsm_subscriber.h
index eaf4028..46fc87f 100644
--- a/openbsc/include/openbsc/gsm_subscriber.h
+++ b/openbsc/include/openbsc/gsm_subscriber.h
@@ -49,6 +49,9 @@
 	int authorized;
 	time_t expire_lu;
 
+	/* Don't delete subscribers even if group->keep_subscr is not set */
+	int keep_in_ram;
+
 	/* Temporary field which is not stored in the DB/HLR */
 	uint32_t flags;
 
diff --git a/openbsc/src/libcommon/gsm_subscriber_base.c b/openbsc/src/libcommon/gsm_subscriber_base.c
index 3d01ca2..3c56101 100644
--- a/openbsc/src/libcommon/gsm_subscriber_base.c
+++ b/openbsc/src/libcommon/gsm_subscriber_base.c
@@ -91,7 +91,9 @@
 	subscr->use_count--;
 	DEBUGP(DREF, "subscr %s usage decreased usage to: %d\n",
 			subscr->extension, subscr->use_count);
-	if (subscr->use_count <= 0 && !subscr->group->keep_subscr)
+	if (subscr->use_count <= 0 &&
+	    !((subscr->group && subscr->group->keep_subscr) ||
+	      subscr->keep_in_ram))
 		subscr_free(subscr);
 	return NULL;
 }
diff --git a/openbsc/tests/subscr/subscr_test.c b/openbsc/tests/subscr/subscr_test.c
index 277fc88..2a5d0e1 100644
--- a/openbsc/tests/subscr/subscr_test.c
+++ b/openbsc/tests/subscr/subscr_test.c
@@ -83,6 +83,22 @@
 	subscr_purge_inactive(&dummy_sgrp);
 
 	OSMO_ASSERT(llist_empty(&active_subscribers));
+
+	/* Test force_no_keep */
+
+	dummy_sgrp.keep_subscr = 0;
+
+	subscr = subscr_get_or_create(&dummy_sgrp, imsi);
+	OSMO_ASSERT(subscr);
+	subscr->keep_in_ram = 1;
+
+	OSMO_ASSERT(!llist_empty(&active_subscribers));
+	OSMO_ASSERT(subscr->use_count == 1);
+
+	subscr->keep_in_ram = 0;
+
+	subscr_put(subscr);
+	OSMO_ASSERT(llist_empty(&active_subscribers));
 }
 
 int main()