[sr-dev] git:tirpi/cfg_framework_multivalue: cfg framework: group instances can be deleted + bugfix

Miklos Tirpak miklos at iptel.org
Tue Sep 14 16:46:30 CEST 2010


Module: sip-router
Branch: tirpi/cfg_framework_multivalue
Commit: 8e1d174cc6ddcbdb573e2f6435ed2086d5b1c5ac
URL:    http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=8e1d174cc6ddcbdb573e2f6435ed2086d5b1c5ac

Author: Miklos Tirpak <miklos at iptel.org>
Committer: Miklos Tirpak <miklos at iptel.org>
Date:   Thu Sep  9 16:21:41 2010 +0200

cfg framework: group instances can be deleted + bugfix

- cfg_del_group_inst() is added which can be used to delete
the group instances apart from the default one.
- cfg_find_group_inst() used a wrong offset for shifting.
- The copies of the default variable needs to be updated even if the variable
is atomic.

---

 cfg/cfg_ctx.c    |  108 +++++++++++++++++++++++++++++++++++++++++++++++++----
 cfg/cfg_ctx.h    |    3 +
 cfg/cfg_struct.c |   43 +++++++++++++++++++++-
 cfg/cfg_struct.h |    7 +++
 4 files changed, 151 insertions(+), 10 deletions(-)

diff --git a/cfg/cfg_ctx.c b/cfg/cfg_ctx.c
index b0fa851..3ecc69e 100644
--- a/cfg/cfg_ctx.c
+++ b/cfg/cfg_ctx.c
@@ -274,10 +274,11 @@ static int cfg_update_defaults(cfg_group_meta_t	*meta,
 	int	i, clone_done=0;
 	cfg_group_inst_t *array, *ginst;
 
-	array = meta->array;
+	if (!(array = meta->array))
+		return 0;
 	for (i = 0; i < meta->num; i++) {
 		ginst = (cfg_group_inst_t *)((char *)array
-			+ (sizeof(cfg_group_meta_t) + group->size - 1) * i);
+			+ (sizeof(cfg_group_inst_t) + group->size - 1) * i);
 
 		if (!CFG_VAR_TEST(ginst, var)) {
 			/* The variable uses the default value, it needs to be rewritten. */
@@ -514,15 +515,15 @@ int cfg_set_now(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *va
 					it cannot be freed */
 
 	if (cfg_shmized) {
-		if (!group_inst && block && CFG_GROUP_META(block, group)->array) {
-			if (cfg_update_defaults(CFG_GROUP_META(block, group),
+		if (!group_inst) {
+			/* the default value is changed, the copies of this value
+			need to be also updated */
+			if (cfg_update_defaults(CFG_GROUP_META(block ? block : *cfg_global, group),
 						group, var, p,
-						((var->def->type & CFG_ATOMIC) == 0)) /* clone if needed */
-			) {
-				LOG(L_ERR, "ERROR: cfg_set_now(): not enough shm memory\n");
+						block ? 1 : 0) /* clone if needed */
+			)
 				goto error;
-			}
-			if (CFG_GROUP_META(block, group)->array != CFG_GROUP_META(*cfg_global, group)->array)
+			if (block && (CFG_GROUP_META(block, group)->array != CFG_GROUP_META(*cfg_global, group)->array))
 				new_array = CFG_GROUP_META(block, group)->array;
 		}
 
@@ -1338,3 +1339,92 @@ error:
 
 	return -1;
 }
+
+/* Delete an instance of a group */
+int cfg_del_group_inst(cfg_ctx_t *ctx, str *group_name, unsigned int group_id)
+{
+	cfg_group_t	*group;
+	cfg_block_t	*block = NULL;
+	void		**replaced = NULL;
+	cfg_group_inst_t	*new_array = NULL, *group_inst;
+
+	/* verify the context even if we do not need it now
+	to make sure that a cfg driver has called the function
+	(very very weak security) */
+	if (!ctx) {
+		LOG(L_ERR, "ERROR: cfg_del_group_inst(): context is undefined\n");
+		return -1;
+	}
+
+	if (!cfg_shmized) {
+		/* It makes no sense to delete a group instance that has not
+		been created yet */
+		return -1;
+	}
+
+	if (!(group = cfg_lookup_group(group_name->s, group_name->len))) {
+		LOG(L_ERR, "ERROR: cfg_del_group_inst(): group not found\n");
+		return -1;
+	}
+
+	/* make sure that nobody else replaces the global config
+	while the new one is prepared */
+	CFG_WRITER_LOCK();
+	if (!(group_inst = cfg_find_group(CFG_GROUP_META(*cfg_global, group),
+							group->size,
+							group_id))
+	) {
+		LOG(L_DBG, "DEBUG: cfg_del_group_inst(): the group instance does not exist\n");
+		goto error;
+	}
+
+	/* clone the global memory block because the additional array can be
+	replaced only together with the block. */
+	if (!(block = cfg_clone_global()))
+		goto error;
+
+	/* Remove the group instance from the array. */
+	if (cfg_collapse_array(CFG_GROUP_META(*cfg_global, group), group,
+					group_inst,
+					&new_array)
+	)
+		goto error;
+
+	CFG_GROUP_META(block, group)->array = new_array;
+	CFG_GROUP_META(block, group)->num--;
+
+	if (CFG_GROUP_META(*cfg_global, group)->array) {
+		/* prepare the array of the replaced strings,
+		and replaced group instances,
+		they will be freed when the old block is freed */
+		replaced = (void **)shm_malloc(sizeof(void *) * 2);
+		if (!replaced) {
+			LOG(L_ERR, "ERROR: cfg_del_group_inst(): not enough shm memory\n");
+			goto error;
+		}
+		replaced[0] = CFG_GROUP_META(*cfg_global, group)->array;
+		replaced[1] = NULL;
+	}
+	/* replace the global config with the new one */
+	cfg_install_global(block, replaced, NULL, NULL);
+	CFG_WRITER_UNLOCK();
+
+	LOG(L_INFO, "INFO: cfg_del_group_inst(): "
+		"group instance is deleted: %.*s[%u]\n",
+		group_name->len, group_name->s,
+		group_id);
+
+	return 0;
+error:
+	CFG_WRITER_UNLOCK();
+	if (block) cfg_block_free(block);
+	if (new_array) shm_free(new_array);
+	if (replaced) shm_free(replaced);
+
+	LOG(L_ERR, "ERROR: cfg_add_group_inst(): "
+		"Failed to delete the group instance: %.*s[%u]\n",
+		group_name->len, group_name->s,
+		group_id);
+
+	return -1;
+}
diff --git a/cfg/cfg_ctx.h b/cfg/cfg_ctx.h
index 255911e..964e7f5 100644
--- a/cfg/cfg_ctx.h
+++ b/cfg/cfg_ctx.h
@@ -180,4 +180,7 @@ void cfg_diff_release(cfg_ctx_t *ctx);
 /* Add a new instance to an existing group */
 int cfg_add_group_inst(cfg_ctx_t *ctx, str *group_name, unsigned int group_id);
 
+/* Delete an instance of a group */
+int cfg_del_group_inst(cfg_ctx_t *ctx, str *group_name, unsigned int group_id);
+
 #endif /* _CFG_CTX_H */
diff --git a/cfg/cfg_struct.c b/cfg/cfg_struct.c
index 77d7cf5..9d5f008 100644
--- a/cfg/cfg_struct.c
+++ b/cfg/cfg_struct.c
@@ -645,6 +645,47 @@ cfg_group_inst_t *cfg_extend_array(cfg_group_meta_t *meta, cfg_group_t *group,
 	return new_array;
 }
 
+/* Remove an instance from a group array.
+ * inst must point to an instance within meta->array.
+ * *_new_array is set to the newly allocated array. */
+int cfg_collapse_array(cfg_group_meta_t *meta, cfg_group_t *group,
+				cfg_group_inst_t *inst,
+				cfg_group_inst_t **_new_array)
+{
+	cfg_group_inst_t	*new_array, *old_array;
+	int			inst_size, offset;
+
+	if (!meta->num)
+		return -1;
+
+	if (meta->num == 1) {
+		*_new_array = NULL;
+		return 0;
+	}
+
+	inst_size = sizeof(cfg_group_inst_t) + group->size - 1;
+	new_array = (cfg_group_inst_t *)shm_malloc(inst_size * (meta->num - 1));
+	if (!new_array) {
+		LOG(L_ERR, "ERROR: cfg_collapse_array(): not enough shm memory\n");
+		return -1;
+	}
+
+	old_array = meta->array;
+	offset = (char *)inst - (char *)old_array;
+	if (offset)
+		memcpy(	new_array,
+			old_array,
+			offset);
+
+	if (meta->num * inst_size > offset + inst_size)
+		memcpy( (char *)new_array + offset,
+			(char *)old_array + offset + inst_size,
+			(meta->num - 1) * inst_size - offset);
+
+	*_new_array = new_array;
+	return 0;
+}
+
 /* Find the group instance within the meta-data based on the group_id */
 cfg_group_inst_t *cfg_find_group(cfg_group_meta_t *meta, int group_size, unsigned int group_id)
 {
@@ -658,7 +699,7 @@ cfg_group_inst_t *cfg_find_group(cfg_group_meta_t *meta, int group_size, unsigne
 	TODO: improve */
 	for (i = 0; i < meta->num; i++) {
 		ginst = (cfg_group_inst_t *)((char *)meta->array
-			+ (sizeof(cfg_group_meta_t) + group_size - 1) * i);
+			+ (sizeof(cfg_group_inst_t) + group_size - 1) * i);
 		if (ginst->id == group_id)
 			return ginst;
 		else if (ginst->id > group_id)
diff --git a/cfg/cfg_struct.h b/cfg/cfg_struct.h
index 65519e2..5f1fa0a 100644
--- a/cfg/cfg_struct.h
+++ b/cfg/cfg_struct.h
@@ -381,6 +381,13 @@ cfg_group_inst_t *cfg_extend_array(cfg_group_meta_t *meta, cfg_group_t *group,
 				unsigned int group_id,
 				cfg_group_inst_t **new_group);
 
+/* Remove an instance from a group array.
+ * inst must point to an instance within meta->array.
+ * *_new_array is set to the newly allocated array. */
+int cfg_collapse_array(cfg_group_meta_t *meta, cfg_group_t *group,
+				cfg_group_inst_t *inst,
+				cfg_group_inst_t **_new_array);
+
 /* clones a string to shared memory */
 int cfg_clone_str(str *src, str *dst);
 




More information about the sr-dev mailing list