Browse code

cfg framework: cfg_set_now() supports the group instances

cfg_set_now() can write the variables within both
the default and the additional group instances.
If the additional variable is not explicitely set, then
the default value overwrites it.

Note: the group instance must exist before cfg_set_now() is called,
it is not created dynamicaly.

The function does not work yet before the config is shmized.

Miklos Tirpak authored on 07/09/2010 15:09:07
Showing 7 changed files
... ...
@@ -61,6 +61,7 @@ int cfg_declare(char *group_name, cfg_def_t *def, void *values, int def_size,
61 61
 	for (i=0, size=0; i<num; i++) {
62 62
 		mapping[i].def = &(def[i]);
63 63
 		mapping[i].name_len = strlen(def[i].name);
64
+		mapping[i].pos = i;
64 65
 		/* record all the types for sanity checks */
65 66
 		types|=1 << CFG_VAR_MASK(def[i].type);
66 67
 
... ...
@@ -239,6 +239,63 @@ error:
239 239
 		} \
240 240
 	} while(0)
241 241
 
242
+/* returns the size of the variable */
243
+static int cfg_var_size(cfg_mapping_t *var)
244
+{
245
+	switch (CFG_VAR_TYPE(var)) {
246
+
247
+	case CFG_VAR_INT:
248
+		return sizeof(int);
249
+
250
+	case CFG_VAR_STRING:
251
+		return sizeof(char *);
252
+
253
+	case CFG_VAR_STR:
254
+		return sizeof(str);
255
+
256
+	case CFG_VAR_POINTER:
257
+		return sizeof(void *);
258
+
259
+	default:
260
+		LOG(L_CRIT, "BUG: cfg_var_size(): unknown type: %u\n",
261
+			CFG_VAR_TYPE(var));
262
+		return 0;
263
+	}
264
+}
265
+
266
+/* Update the varibales of the array within the meta structure
267
+ * with the new default value.
268
+ * The array is cloned before a change if clone is set to 1.
269
+ */
270
+static int cfg_update_defaults(cfg_group_meta_t	*meta,
271
+				cfg_group_t *group, cfg_mapping_t *var, char *new_val,
272
+				int clone)
273
+{
274
+	int	i, clone_done=0;
275
+	cfg_group_inst_t *array, *ginst;
276
+
277
+	array = meta->array;
278
+	for (i = 0; i < meta->num; i++) {
279
+		ginst = (cfg_group_inst_t *)((char *)array
280
+			+ (sizeof(cfg_group_meta_t) + group->size - 1) * i);
281
+
282
+		if (!CFG_VAR_TEST(ginst, var)) {
283
+			/* The variable uses the default value, it needs to be rewritten. */
284
+			if (clone && !clone_done) {
285
+				/* The array needs to be cloned before the modification */
286
+				if (!(array = cfg_clone_array(meta, group)))
287
+					return -1;
288
+				ginst = translate_pointer(array, meta->array, ginst);
289
+				/* re-link the array to the meta-data */
290
+				meta->array = array;
291
+				clone_done = 1;
292
+			}
293
+			memcpy(ginst->vars + var->offset, new_val, cfg_var_size(var)); 
294
+		}
295
+	}
296
+	return 0;
297
+}
298
+
242 299
 /* sets the value of a variable without the need of commit
243 300
  *
244 301
  * return value:
... ...
@@ -246,7 +303,7 @@ error:
246 246
  *  -1: error
247 247
  *   1: variable has not been found
248 248
  */
249
-int cfg_set_now(cfg_ctx_t *ctx, str *group_name, str *var_name,
249
+int cfg_set_now(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *var_name,
250 250
 			void *val, unsigned int val_type)
251 251
 {
252 252
 	cfg_group_t	*group;
... ...
@@ -257,6 +314,8 @@ int cfg_set_now(cfg_ctx_t *ctx, str *group_name, str *var_name,
257 257
 	char		*old_string = NULL;
258 258
 	char		**replaced = NULL;
259 259
 	cfg_child_cb_t	*child_cb = NULL;
260
+	cfg_group_inst_t	*group_inst, *new_array = NULL;
261
+	unsigned char		*var_block;
260 262
 
261 263
 	/* verify the context even if we do not need it now
262 264
 	to make sure that a cfg driver has called the function
... ...
@@ -266,6 +325,15 @@ int cfg_set_now(cfg_ctx_t *ctx, str *group_name, str *var_name,
266 266
 		return -1;
267 267
 	}
268 268
 
269
+	if (group_id && !cfg_shmized) {
270
+		/* The config group has not been shmized yet,
271
+		but an additional instance of a variable needs to be added to the group.
272
+		Add this instance to the linked list of variables, they
273
+		will be fixed later. */
274
+		/* TODO */
275
+		return -1;
276
+	}
277
+
269 278
 	/* look-up the group and the variable */
270 279
 	if (cfg_lookup_var(group_name, var_name, &group, &var))
271 280
 		return 1;
... ...
@@ -276,6 +344,19 @@ int cfg_set_now(cfg_ctx_t *ctx, str *group_name, str *var_name,
276 276
 		goto error0;
277 277
 	}
278 278
 
279
+	/* The additional variable instances having per-child process callback
280
+	 * with CFG_CB_ONLY_ONCE flag cannot be rewritten.
281
+	 * The reason is that such variables typically set global parameters
282
+	 * as opposed to per-process variables. Hence, it is not possible to set
283
+	 * the group handle temporary to another block, and then reset it back later. */
284
+	if (group_id
285
+		&& var->def->on_set_child_cb
286
+		&& var->def->type & CFG_CB_ONLY_ONCE
287
+	) {
288
+		LOG(L_ERR, "ERROR: cfg_set_now(): This variable does not support muliple values.\n");
289
+		goto error0;
290
+	}
291
+
279 292
 	/* check whether we have to convert the type */
280 293
 	if (convert_val(val_type, val, CFG_INPUT_TYPE(var), &v))
281 294
 		goto error0;
... ...
@@ -294,7 +375,24 @@ int cfg_set_now(cfg_ctx_t *ctx, str *group_name, str *var_name,
294 294
 		/* Call the fixup function.
295 295
 		There is no need to set a temporary cfg handle,
296 296
 		becaue a single variable is changed */
297
-		if (var->def->on_change_cb(*(group->handle),
297
+		if (!group_id) {
298
+			var_block = *(group->handle);
299
+		} else {
300
+			if (!cfg_local) {
301
+				LOG(L_ERR, "ERROR: cfg_set_now(): Local configuration is missing\n");
302
+				goto error0;
303
+			}
304
+			group_inst = cfg_find_group(CFG_GROUP_META(cfg_local, group),
305
+							group->size,
306
+							*group_id);
307
+			if (!group_inst) {
308
+				LOG(L_ERR, "ERROR: cfg_set_now(): local group instance is not found\n");
309
+				goto error0;
310
+			}
311
+			var_block = group_inst->vars;
312
+		}
313
+
314
+		if (var->def->on_change_cb(var_block,
298 315
 						group_name,
299 316
 						var_name,
300 317
 						&v) < 0) {
... ...
@@ -304,7 +402,10 @@ int cfg_set_now(cfg_ctx_t *ctx, str *group_name, str *var_name,
304 304
 
305 305
 	}
306 306
 
307
-	if (var->def->on_set_child_cb) {
307
+	/* Set the per-child process callback only if the default value is changed.
308
+	 * The callback of other instances will be called when the config is
309
+	 * switched to that instance. */
310
+	if (!group_id && var->def->on_set_child_cb) {
308 311
 		/* get the name of the variable from the internal struct,
309 312
 		because var_name may be freed before the callback needs it */
310 313
 		s.s = group->name;
... ...
@@ -325,16 +426,50 @@ int cfg_set_now(cfg_ctx_t *ctx, str *group_name, str *var_name,
325 325
 		while the new one is prepared */
326 326
 		CFG_WRITER_LOCK();
327 327
 
328
+		if (group_id) {
329
+			group_inst = cfg_find_group(CFG_GROUP_META(*cfg_global, group),
330
+							group->size,
331
+							*group_id);
332
+			if (!group_inst) {
333
+				LOG(L_ERR, "ERROR: cfg_set_now(): global group instance is not found\n");
334
+				goto error0;
335
+			}
336
+			var_block = group_inst->vars;
337
+		} else {
338
+			group_inst = NULL;
339
+			var_block = CFG_GROUP_DATA(*cfg_global, group);
340
+		}
341
+
328 342
 		if (var->def->type & CFG_ATOMIC) {
329 343
 			/* atomic change is allowed, we can rewrite the value
330 344
 			directly in the global config */
331
-			p = (*cfg_global)->vars+group->var_offset+var->offset;
345
+			p = var_block + var->offset;
332 346
 
333 347
 		} else {
334 348
 			/* clone the memory block, and prepare the modification */
335 349
 			if (!(block = cfg_clone_global())) goto error;
336 350
 
337
-			p = block->vars+group->var_offset+var->offset;
351
+			if (group_inst) {
352
+				/* The additional array of the group needs to be also cloned.
353
+				 * When any of the variables within this array is changed, then
354
+				 * the complete config block and this array is replaced. */
355
+				if (!(new_array = cfg_clone_array(CFG_GROUP_META(*cfg_global, group), group)))
356
+					goto error;
357
+				group_inst = translate_pointer(new_array,
358
+					CFG_GROUP_META(*cfg_global, group)->array,
359
+					group_inst);
360
+				var_block = group_inst->vars;
361
+				CFG_GROUP_META(block, group)->array = new_array;
362
+			} else {
363
+				/* The additional array may need to be replaced depending
364
+				 * on whether or not there is any variable in the array set
365
+				 * to the default value which is changed now. If this is the case,
366
+				 * then the array will be replaced later when the variables are
367
+				 * updated.
368
+				 */
369
+				var_block = CFG_GROUP_DATA(block, group);
370
+			}
371
+			p = var_block + var->offset;
338 372
 		}
339 373
 	} else {
340 374
 		/* we are allowed to rewrite the value on-the-fly
... ...
@@ -371,8 +506,23 @@ int cfg_set_now(cfg_ctx_t *ctx, str *group_name, str *var_name,
371 371
 		break;
372 372
 
373 373
 	}
374
+	if (group_inst && !CFG_VAR_TEST_AND_SET(group_inst, var))
375
+		old_string = NULL; /* the string is the same as the default one,
376
+					it cannot be freed */
374 377
 
375 378
 	if (cfg_shmized) {
379
+		if (!group_inst && CFG_GROUP_META(block, group)->array) {
380
+			if (cfg_update_defaults(CFG_GROUP_META(block, group),
381
+						group, var, p,
382
+						((var->def->type & CFG_ATOMIC) == 0)) /* clone if needed */
383
+			) {
384
+				LOG(L_ERR, "ERROR: cfg_set_now(): not enough shm memory\n");
385
+				goto error;
386
+			}
387
+			if (CFG_GROUP_META(block, group)->array != CFG_GROUP_META(*cfg_global, group)->array)
388
+				new_array = CFG_GROUP_META(block, group)->array;
389
+		}
390
+
376 391
 		if (old_string) {
377 392
 			/* prepare the array of the replaced strings,
378 393
 			they will be freed when the old block is freed */
... ...
@@ -430,6 +580,7 @@ int cfg_set_now(cfg_ctx_t *ctx, str *group_name, str *var_name,
430 430
 error:
431 431
 	if (cfg_shmized) CFG_WRITER_UNLOCK();
432 432
 	if (block) cfg_block_free(block);
433
+	if (new_array) shm_free(new_array);
433 434
 	if (child_cb) cfg_child_cb_free(child_cb);
434 435
 
435 436
 error0:
... ...
@@ -443,45 +594,27 @@ error0:
443 443
 }
444 444
 
445 445
 /* wrapper function for cfg_set_now */
446
-int cfg_set_now_int(cfg_ctx_t *ctx, str *group_name, str *var_name, int val)
446
+int cfg_set_now_int(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *var_name,
447
+			int val)
447 448
 {
448
-	return cfg_set_now(ctx, group_name, var_name, (void *)(long)val, CFG_VAR_INT);
449
+	return cfg_set_now(ctx, group_name, group_id, var_name,
450
+				(void *)(long)val, CFG_VAR_INT);
449 451
 }
450 452
 
451 453
 /* wrapper function for cfg_set_now */
452
-int cfg_set_now_string(cfg_ctx_t *ctx, str *group_name, str *var_name, char *val)
454
+int cfg_set_now_string(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *var_name,
455
+			char *val)
453 456
 {
454
-	return cfg_set_now(ctx, group_name, var_name, (void *)val, CFG_VAR_STRING);
457
+	return cfg_set_now(ctx, group_name, group_id, var_name,
458
+				(void *)val, CFG_VAR_STRING);
455 459
 }
456 460
 
457 461
 /* wrapper function for cfg_set_now */
458
-int cfg_set_now_str(cfg_ctx_t *ctx, str *group_name, str *var_name, str *val)
459
-{
460
-	return cfg_set_now(ctx, group_name, var_name, (void *)val, CFG_VAR_STR);
461
-}
462
-
463
-/* returns the size of the variable */
464
-static int cfg_var_size(cfg_mapping_t *var)
462
+int cfg_set_now_str(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *var_name,
463
+			str *val)
465 464
 {
466
-	switch (CFG_VAR_TYPE(var)) {
467
-
468
-	case CFG_VAR_INT:
469
-		return sizeof(int);
470
-
471
-	case CFG_VAR_STRING:
472
-		return sizeof(char *);
473
-
474
-	case CFG_VAR_STR:
475
-		return sizeof(str);
476
-
477
-	case CFG_VAR_POINTER:
478
-		return sizeof(void *);
479
-
480
-	default:
481
-		LOG(L_CRIT, "BUG: cfg_var_size(): unknown type: %u\n",
482
-			CFG_VAR_TYPE(var));
483
-		return 0;
484
-	}
465
+	return cfg_set_now(ctx, group_name, group_id, var_name,
466
+				(void *)val, CFG_VAR_STR);
485 467
 }
486 468
 
487 469
 /* sets the value of a variable but does not commit the change
... ...
@@ -491,7 +624,7 @@ static int cfg_var_size(cfg_mapping_t *var)
491 491
  *  -1: error
492 492
  *   1: variable has not been found
493 493
  */
494
-int cfg_set_delayed(cfg_ctx_t *ctx, str *group_name, str *var_name,
494
+int cfg_set_delayed(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *var_name,
495 495
 			void *val, unsigned int val_type)
496 496
 {
497 497
 	cfg_group_t	*group;
... ...
@@ -506,7 +639,7 @@ int cfg_set_delayed(cfg_ctx_t *ctx, str *group_name, str *var_name,
506 506
 	if (!cfg_shmized)
507 507
 		/* the cfg has not been shmized yet, there is no
508 508
 		point in registering the change and committing it later */
509
-		return cfg_set_now(ctx, group_name, var_name,
509
+		return cfg_set_now(ctx, group_name, group_id, var_name,
510 510
 					val, val_type);
511 511
 
512 512
 	if (!ctx) {
... ...
@@ -683,21 +816,27 @@ error0:
683 683
 }
684 684
 
685 685
 /* wrapper function for cfg_set_delayed */
686
-int cfg_set_delayed_int(cfg_ctx_t *ctx, str *group_name, str *var_name, int val)
686
+int cfg_set_delayed_int(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *var_name,
687
+				int val)
687 688
 {
688
-	return cfg_set_delayed(ctx, group_name, var_name, (void *)(long)val, CFG_VAR_INT);
689
+	return cfg_set_delayed(ctx, group_name, group_id, var_name,
690
+				(void *)(long)val, CFG_VAR_INT);
689 691
 }
690 692
 
691 693
 /* wrapper function for cfg_set_delayed */
692
-int cfg_set_delayed_string(cfg_ctx_t *ctx, str *group_name, str *var_name, char *val)
694
+int cfg_set_delayed_string(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *var_name,
695
+				char *val)
693 696
 {
694
-	return cfg_set_delayed(ctx, group_name, var_name, (void *)val, CFG_VAR_STRING);
697
+	return cfg_set_delayed(ctx, group_name, group_id, var_name,
698
+				(void *)val, CFG_VAR_STRING);
695 699
 }
696 700
 
697 701
 /* wrapper function for cfg_set_delayed */
698
-int cfg_set_delayed_str(cfg_ctx_t *ctx, str *group_name, str *var_name, str *val)
702
+int cfg_set_delayed_str(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *var_name,
703
+				str *val)
699 704
 {
700
-	return cfg_set_delayed(ctx, group_name, var_name, (void *)val, CFG_VAR_STR);
705
+	return cfg_set_delayed(ctx, group_name, group_id, var_name,
706
+				(void *)val, CFG_VAR_STR);
701 707
 }
702 708
 
703 709
 /* commits the previously prepared changes within the context */
... ...
@@ -785,8 +924,7 @@ int cfg_commit(cfg_ctx_t *ctx)
785 785
 		changed;
786 786
 		changed = changed->next
787 787
 	) {
788
-		p = block->vars
789
-			+ changed->group->var_offset
788
+		p = CFG_GROUP_DATA(block, changed->group)
790 789
 			+ changed->var->offset;
791 790
 
792 791
 		if ((CFG_VAR_TYPE(changed->var) == CFG_VAR_STRING)
... ...
@@ -84,18 +84,24 @@ int cfg_register_ctx(cfg_ctx_t **handle, cfg_on_declare on_declare_cb);
84 84
 void cfg_ctx_destroy(void);
85 85
 
86 86
 /*! \brief set the value of a variable without the need of explicit commit */
87
-int cfg_set_now(cfg_ctx_t *ctx, str *group_name, str *var_name,
87
+int cfg_set_now(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *var_name,
88 88
 			void *val, unsigned int val_type);
89
-int cfg_set_now_int(cfg_ctx_t *ctx, str *group_name, str *var_name, int val);
90
-int cfg_set_now_string(cfg_ctx_t *ctx, str *group_name, str *var_name, char *val);
91
-int cfg_set_now_str(cfg_ctx_t *ctx, str *group_name, str *var_name, str *val);
89
+int cfg_set_now_int(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *var_name,
90
+			int val);
91
+int cfg_set_now_string(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *var_name,
92
+			char *val);
93
+int cfg_set_now_str(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *var_name,
94
+			str *val);
92 95
 
93 96
 /* sets the value of a variable but does not commit the change */
94
-int cfg_set_delayed(cfg_ctx_t *ctx, str *group_name, str *var_name,
97
+int cfg_set_delayed(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *var_name,
95 98
 			void *val, unsigned int val_type);
96
-int cfg_set_delayed_int(cfg_ctx_t *ctx, str *group_name, str *var_name, int val);
97
-int cfg_set_delayed_string(cfg_ctx_t *ctx, str *group_name, str *var_name, char *val);
98
-int cfg_set_delayed_str(cfg_ctx_t *ctx, str *group_name, str *var_name, str *val);
99
+int cfg_set_delayed_int(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *var_name,
100
+			int val);
101
+int cfg_set_delayed_string(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *var_name,
102
+			char *val);
103
+int cfg_set_delayed_str(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *var_name,
104
+			str *val);
99 105
 
100 106
 /*! \brief commits the previously prepared changes within the context */
101 107
 int cfg_commit(cfg_ctx_t *ctx);
... ...
@@ -181,6 +181,7 @@ int cfg_script_fixup(cfg_group_t *group, unsigned char *block)
181 181
 
182 182
 		mapping[i].def = &(def[i]);
183 183
 		mapping[i].name_len = script_var->name_len;
184
+		mapping[i].pos = i;
184 185
 
185 186
 		switch (script_var->type) {
186 187
 		case CFG_VAR_INT:
... ...
@@ -29,6 +29,7 @@
29 29
 #define _CFG_SCRIPT_H
30 30
 
31 31
 #include "../str.h"
32
+#include "cfg_struct.h"
32 33
 
33 34
 /* structure used for temporary storing the variables
34 35
  * which are declared in the script */
... ...
@@ -216,19 +216,19 @@ int cfg_shmize(void)
216 216
 			if (cfg_shmize_strings(group)) goto error;
217 217
 
218 218
 			/* copy the values to the new block */
219
-			memcpy(block->vars+group->var_offset, group->vars, group->size);
219
+			memcpy(CFG_GROUP_DATA(block, group), group->vars, group->size);
220 220
 		} else {
221 221
 			/* The group was declared with NULL values,
222 222
 			 * we have to fix it up.
223 223
 			 * The fixup function takes care about the values,
224 224
 			 * it fills up the block */
225
-			if (cfg_script_fixup(group, block->vars+group->var_offset)) goto error;
225
+			if (cfg_script_fixup(group, CFG_GROUP_DATA(block, group))) goto error;
226 226
 
227 227
 			/* Notify the drivers about the new config definition.
228 228
 			 * Temporary set the group handle so that the drivers have a chance to
229 229
 			 * overwrite the default values. The handle must be reset after this
230 230
 			 * because the main process does not have a local configuration. */
231
-			*(group->handle) = block->vars+group->var_offset;
231
+			*(group->handle) = CFG_GROUP_DATA(block, group);
232 232
 			cfg_notify_drivers(group->name, group->name_len,
233 233
 					group->mapping->def);
234 234
 			*(group->handle) = NULL;
... ...
@@ -584,6 +584,48 @@ cfg_block_t *cfg_clone_global(void)
584 584
 	return block;
585 585
 }
586 586
 
587
+/* Clone an array of configuration group instances.
588
+ * WARNING: unsafe, cfg_writer_lock or cfg_global_lock must be held!
589
+ */
590
+cfg_group_inst_t *cfg_clone_array(cfg_group_meta_t *meta, cfg_group_t *group)
591
+{
592
+	cfg_group_inst_t	*new_array;
593
+	int			size;
594
+
595
+	if (!meta->array || !meta->num)
596
+		return NULL;
597
+
598
+	size = (sizeof(cfg_group_inst_t) + group->size - 1) * meta->num;
599
+	new_array = (cfg_group_inst_t *)shm_malloc(size);
600
+	if (!new_array) {
601
+		LOG(L_ERR, "ERROR: cfg_clone_array(): not enough shm memory\n");
602
+		return NULL;
603
+	}
604
+	memcpy(new_array, meta->array, size);
605
+
606
+	return new_array;
607
+}
608
+
609
+/* Find the group instance within the meta-data based on the group_id */
610
+cfg_group_inst_t *cfg_find_group(cfg_group_meta_t *meta, int group_size, unsigned int group_id)
611
+{
612
+	int	i;
613
+	cfg_group_inst_t *ginst;
614
+
615
+	if (!meta)
616
+		return NULL;
617
+
618
+	/* For now, search lineray till the end of the array.
619
+	TODO: improve */
620
+	for (i = 0; i < meta->num; i++) {
621
+		ginst = (cfg_group_inst_t *)((char *)meta->array
622
+			+ (sizeof(cfg_group_meta_t) + group_size - 1) * i);
623
+		if (ginst->id == group_id)
624
+			return ginst;
625
+	}
626
+	return NULL;
627
+}
628
+
587 629
 /* append new callbacks to the end of the child callback list
588 630
  *
589 631
  * WARNING: the function is unsafe, either hold CFG_LOCK(),
... ...
@@ -34,6 +34,7 @@
34 34
 #include "../mem/shm_mem.h"
35 35
 #include "../locking.h"
36 36
 #include "../compiler_opt.h"
37
+#include "../bit_test.h"
37 38
 #include "cfg.h"
38 39
 
39 40
 /*! \brief Maximum number of variables within a configuration group. */
... ...
@@ -42,12 +43,27 @@
42 42
 /*! \brief indicates that the variable has been already shmized */
43 43
 #define cfg_var_shmized	1U
44 44
 
45
+/*! \brief Structure for storing additional values of a variable.
46
+ * When the config is shmzied, these variables are combined in
47
+ * an array.
48
+ */
49
+typedef struct _cfg_add_var {
50
+	unsigned int	type;
51
+	union {
52
+		str	s;
53
+		int	i;
54
+	} val;
55
+	unsigned int	group_id; /*!< Id of the group instance */
56
+	struct _cfg_add_var	*next;
57
+} cfg_add_var_t;
58
+
45 59
 /*! \brief structure used for variable - pointer mapping */
46 60
 typedef struct _cfg_mapping {
47 61
 	cfg_def_t	*def;		/*!< one item of the cfg structure definition */
48 62
 	int		name_len;	/*!< length of def->name */
49 63
 
50 64
 	/* additional information about the cfg variable */
65
+	int		pos;	/*!< position of the variable within the group starting from 0 */
51 66
 	int		offset; /*!< offest within the memory block */
52 67
 	unsigned int	flag;	/*!< flag indicating the state of the variable */
53 68
 } cfg_mapping_t;
... ...
@@ -60,6 +76,9 @@ typedef struct _cfg_group {
60 60
 	char		*vars;		/*!< pointer to the memory block where the values
61 61
 					are stored -- used only before the config is
62 62
 					shmized. */
63
+	cfg_add_var_t	*add_var;	/*!< Additional instances of the variables.
64
+					This linked list is used only before the config is
65
+					shmized. */
63 66
 	int		size;		/*!< size of the memory block that has to be
64 67
 					allocated to store the values */
65 68
 	int		meta_offset;	/*!< offset of the group within the
... ...
@@ -81,6 +100,7 @@ typedef struct _cfg_group {
81 81
 /*! \brief One instance of the cfg group variables which stores
82 82
  * the additional values. These values can overwrite the default values. */
83 83
 typedef struct _cfg_group_inst {
84
+	unsigned int	id;		/*!< identifier of the group instance */
84 85
 	unsigned int	set[CFG_MAX_VAR_NUM/(sizeof(int)*8)];
85 86
 					/*!< Bitmap indicating whether or not a value is explicitely set
86 87
 					within this instance. If the value is not set,
... ...
@@ -147,6 +167,24 @@ extern cfg_child_cb_t	*cfg_child_cb;
147 147
 #define CFG_VAR_TYPE(var)	CFG_VAR_MASK((var)->def->type)
148 148
 #define CFG_INPUT_TYPE(var)	CFG_INPUT_MASK((var)->def->type)
149 149
 
150
+/* get the meta-data of a group from the block */
151
+#define CFG_GROUP_META(block, group) \
152
+	((cfg_group_meta_t *)((block)->vars + (group)->meta_offset))
153
+
154
+/* get the data block of a group from the block */
155
+#define CFG_GROUP_DATA(block, group) \
156
+	((unsigned char *)((block)->vars + (group)->var_offset))
157
+
158
+/* Test whether a variable is explicitely set in the group instance,
159
+ * or it uses the default value */
160
+#define CFG_VAR_TEST(group_inst, var) \
161
+	bit_test((var)->pos % (sizeof(int)*8), (group_inst)->set + (var)->pos/(sizeof(int)*8))
162
+
163
+/* Test whether a variable is explicitely set in the group instance,
164
+ * or it uses the default value, and set the flag. */
165
+#define CFG_VAR_TEST_AND_SET(group_inst, var) \
166
+	bit_test_and_set((var)->pos % (sizeof(int)*8), (group_inst)->set + (var)->pos/(sizeof(int)*8))
167
+
150 168
 /* initiate the cfg framework */
151 169
 int sr_cfg_init(void);
152 170
 
... ...
@@ -266,7 +304,7 @@ static inline void cfg_update_local(int no_cbs)
266 266
 		group;
267 267
 		group = group->next
268 268
 	)
269
-		*(group->handle) = cfg_local->vars + group->var_offset;
269
+		*(group->handle) = CFG_GROUP_DATA(cfg_local, group);
270 270
 
271 271
 	if (unlikely(cfg_child_cb==CFG_NO_CHILD_CBS || no_cbs))
272 272
 		return;
... ...
@@ -328,12 +366,20 @@ cfg_group_t *cfg_lookup_group(char *name, int len);
328 328
 int cfg_lookup_var(str *gname, str *vname,
329 329
 			cfg_group_t **group, cfg_mapping_t **var);
330 330
 
331
-/* clones the global config block */
331
+/* clones the global config block
332
+ * WARNING: unsafe, cfg_writer_lock or cfg_global_lock must be held!
333
+ */
332 334
 cfg_block_t *cfg_clone_global(void);
333 335
 
336
+/* Clone an array of configuration group instances. */
337
+cfg_group_inst_t *cfg_clone_array(cfg_group_meta_t *meta, cfg_group_t *group);
338
+
334 339
 /* clones a string to shared memory */
335 340
 int cfg_clone_str(str *src, str *dst);
336 341
 
342
+/* Find the group instance within the meta-data based on the group_id */
343
+cfg_group_inst_t *cfg_find_group(cfg_group_meta_t *meta, int group_size, unsigned int group_id);
344
+
337 345
 /* append new callbacks to the end of the child callback list
338 346
  *
339 347
  * WARNING: the function is unsafe, either hold CFG_LOCK(),