1/*
2 *   Copyright (c) International Business Machines Corp., 2001-2004
3 *
4 *   This program is free software;  you can redistribute it and/or modify
5 *   it under the terms of the GNU General Public License as published by
6 *   the Free Software Foundation; either version 2 of the License, or
7 *   (at your option) any later version.
8 *
9 *   This program is distributed in the hope that it will be useful,
10 *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
11 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
12 *   the GNU General Public License for more details.
13 *
14 *   You should have received a copy of the GNU General Public License
15 *   along with this program;  if not, write to the Free Software
16 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18#include <stdio.h>
19#include <string.h>
20#include <assert.h>
21#include <inttypes.h>
22#include <ctype.h>
23
24#include "ffsb.h"
25#include "parser.h"
26#include "ffsb_tg.h"
27#include "ffsb_stats.h"
28#include "util.h"
29#include "list.h"
30
31#define BUFSIZE 1024
32
33config_options_t global_options[] = GLOBAL_OPTIONS;
34config_options_t tg_options[] = THREADGROUP_OPTIONS;
35config_options_t fs_options[] = FILESYSTEM_OPTIONS;
36config_options_t stats_options[] = STATS_OPTIONS;
37container_desc_t container_desc[] = CONTAINER_DESC;
38
39/* strips out whitespace and comments, returns NULL on eof */
40void parseerror(char *msg)
41{
42	fprintf(stderr, "Error parsing %s\n", msg);
43	exit(1);
44}
45
46static char *get_next_line(FILE * f)
47{
48	static char buf[BUFSIZE];
49	char *ret, *tmp;
50	int flag = 1;
51	while (flag) {
52		ret = fgets(buf, BUFSIZE, f);
53		if (ret == NULL)
54			return NULL;
55		ret = buf;
56		while (isspace(*ret))
57			ret++;
58
59		if ((*ret == COMMENT_CHAR) || (*ret == '\0'))
60			continue;
61
62		tmp = ret;
63		while (*tmp != '\0') {
64			if (*tmp == COMMENT_CHAR) {
65				*tmp = '\0';
66				break;
67			}
68			tmp++;
69		}
70		flag = 0;
71	}
72	return ret;
73}
74
75static char *strip_space(char *buf)
76{
77	int len;
78	char *tmp, *tmp2;
79	int flag = 1;
80
81	len = strnlen(buf, BUFSIZE);
82	tmp = malloc(sizeof(char) * len);
83	memset(tmp, 0, sizeof(char) * len);
84	tmp2 = tmp;
85	while (flag) {
86		if (!isspace(*buf)) {
87			*tmp = *buf;
88			tmp++;
89		}
90		buf++;
91		if (*buf != '\0')
92			continue;
93		flag = 0;
94	}
95	return tmp2;
96}
97
98static uint64_t size64_convert(char *buf)
99{
100	size_t buf_size = strlen(buf);
101	char unit[3] = { 0 };
102	char search_str[256];
103	uint64_t size;
104	uint64_t multiplier = 1;
105	int i;
106
107	if (buf_size == 1)
108		goto out;
109
110	strcpy(unit, buf + (buf_size - 2));
111	for (i = 0; i < 2; i++) {
112		if (isdigit(unit[i]))
113			goto try_single;
114		unit[i] = toupper(unit[i]);
115	}
116	goto do_multiplier;
117
118try_single:
119	memcpy(unit, "\0", 3);
120	strcpy(unit, buf + (buf_size - 1));
121	if (isdigit(unit[0])) {
122		unit[0] = 0;
123		goto out;
124	}
125	unit[0] = toupper(unit[0]);
126
127do_multiplier:
128	if (!strcmp("KB", unit) || !strcmp("K", unit))
129		multiplier = 1024;
130	if (!strcmp("MB", unit) || !strcmp("M", unit))
131		multiplier = 1048576;
132	if (!strcmp("GB", unit) || !strcmp("G", unit))
133		multiplier = 1073741824;
134	if (multiplier == 1) {
135		unit[0] = 0;
136		multiplier = 0;
137	}
138out:
139	sprintf(search_str, "%%llu%s", unit);
140	if (1 == sscanf(buf, search_str, &size))
141		return size * multiplier;
142	return 0;
143}
144
145static uint64_t *get_opt64(char *buf, char string[])
146{
147	char search_str[256];
148	char *line = strip_space(buf);
149	uint64_t temp;
150	uint64_t *ret;
151
152	sprintf(search_str, "%s=%%llu\\n", string);
153	if (1 == sscanf(line, search_str, &temp)) {
154		ret = malloc(sizeof(uint64_t));
155		*ret = temp;
156		return ret;
157	}
158	free(line);
159	return NULL;
160}
161
162static uint32_t *get_opt32(char *buf, char string[])
163{
164	uint32_t *ret;
165	uint64_t *res;
166	res = get_opt64(buf, string);
167	if (res) {
168		ret = malloc(sizeof(uint32_t));
169		*ret = *res;
170		free(res);
171		return ret;
172	}
173	return NULL;
174}
175
176static uint8_t *get_optbool(char *buf, char string[])
177{
178	uint8_t *ret;
179	uint64_t *res;
180	res = get_opt64(buf, string);
181	if (res) {
182		if ((int)*res < 0 || (int)*res > 1) {
183			printf("Error in: %s", buf);
184			printf("%llu not boolean\n", (long long unsigned)*res);
185			exit(1);
186		}
187		ret = malloc(sizeof(uint8_t));
188		*ret = *res;
189		free(res);
190		return ret;
191	}
192	return NULL;
193}
194
195static char *get_optstr(char *buf, char string[])
196{
197	char search_str[256];
198	char *line = strip_space(buf);
199	char *ret_buf;
200	char temp[BUFSIZE];
201	int len;
202
203	len = strnlen(string, BUFSIZE);
204	sprintf(search_str, "%s=%%%ds\\n", string, BUFSIZE - len - 1);
205	if (1 == sscanf(line, search_str, &temp)) {
206		len = strnlen(temp, 4096);
207		ret_buf = malloc(len);
208		strncpy(ret_buf, temp, len);
209		return ret_buf;
210	}
211	free(line);
212	return NULL;
213}
214
215static double *get_optdouble(char *buf, char string[])
216{
217	char search_str[256];
218	char *line = strip_space(buf);
219	double temp;
220	double *ret;
221
222	sprintf(search_str, "%s=%%lf\\n", string);
223	if (1 == sscanf(line, search_str, &temp)) {
224		ret = malloc(sizeof(double));
225		*ret = temp;
226		return ret;
227	}
228	free(line);
229	return NULL;
230}
231
232static range_t *get_optrange(char *buf, char string[])
233{
234	char search_str[256];
235	double a, b;
236	range_t *ret;
237
238	sprintf(search_str, "%s %%lf %%lf\\n", string);
239	if (2 == sscanf(buf, search_str, &a, &b)) {
240		ret = malloc(sizeof(struct range));
241		ret->a = a;
242		ret->b = b;
243		return ret;
244	}
245	return NULL;
246}
247
248static size_weight_t *get_optsizeweight(char *buf, char string[])
249{
250	char search_str[256];
251	char size[256];
252	int weight;
253	size_weight_t *ret;
254
255	sprintf(search_str, "%s %%s %%d\\n", string);
256	if (2 == sscanf(buf, search_str, &size, &weight)) {
257		ret = malloc(sizeof(struct size_weight));
258		ret->size = size64_convert(size);
259		ret->weight = weight;
260		return ret;
261	}
262	return NULL;
263}
264
265static uint64_t *get_optsize64(char *buf, char string[])
266{
267	char search_str[256];
268	char *line = strip_space(buf);
269	char temp[256];
270	uint64_t size;
271	uint64_t *ret = NULL;
272
273	sprintf(search_str, "%s=%%s\\n", string);
274	if (1 == sscanf(line, search_str, &temp)) {
275		ret = malloc(sizeof(uint64_t));
276		*ret = size64_convert(temp);
277	}
278	free(line);
279	return ret;
280}
281
282static uint32_t *get_optsize32(char *buf, char string[])
283{
284	uint32_t *ret;
285	uint64_t *res;
286	res = get_optsize64(buf, string);
287	if (res) {
288		ret = malloc(sizeof(uint32_t));
289		*ret = *res;
290		free(res);
291		return ret;
292	}
293	return NULL;
294}
295
296static uint64_t *get_deprecated(char *buf, char string[])
297{
298	char search_str[256];
299	char temp[BUFSIZE];
300	int len;
301
302	len = strnlen(string, BUFSIZE);
303	sprintf(search_str, "%s%%%ds\\n", string, BUFSIZE - len - 1);
304	if (1 == sscanf(buf, search_str, &temp))
305		printf("WARNING: The \"%s\" option is deprecated!!!\n", string);
306
307	return NULL;
308}
309
310static container_t *init_container(void)
311{
312	container_t *container;
313	container = malloc(sizeof(container_t));
314	container->config = NULL;
315	container->type = 0;
316	container->next = NULL;
317	return container;
318}
319
320static int set_option(char *buf, config_options_t * options)
321{
322	void *value;
323
324	while (options->name) {
325		switch (options->type) {
326		case TYPE_WEIGHT:
327		case TYPE_U32:
328			value = get_opt32(buf, options->name);
329			if (value)
330				goto out;
331			break;
332		case TYPE_U64:
333			value = get_opt64(buf, options->name);
334			if (value)
335				goto out;
336			break;
337		case TYPE_STRING:
338			value = get_optstr(buf, options->name);
339			if (value)
340				goto out;
341			break;
342		case TYPE_BOOLEAN:
343			value = get_optbool(buf, options->name);
344			if (value)
345				goto out;
346			break;
347		case TYPE_DOUBLE:
348			value = get_optdouble(buf, options->name);
349			if (value)
350				goto out;
351			break;
352		case TYPE_RANGE:
353			value = get_optrange(buf, options->name);
354			if (value)
355				goto out;
356			break;
357		case TYPE_SIZEWEIGHT:
358			value = get_optsizeweight(buf, options->name);
359			if (value)
360				goto out;
361			break;
362		case TYPE_DEPRECATED:
363			value = get_deprecated(buf, options->name);
364			if (value)
365				goto out;
366			break;
367		case TYPE_SIZE32:
368			value = get_optsize32(buf, options->name);
369			if (value)
370				goto out;
371			break;
372		case TYPE_SIZE64:
373			value = get_optsize64(buf, options->name);
374			if (value)
375				goto out;
376			break;
377		default:
378			printf("Unknown type\n");
379			break;
380		}
381		options++;
382	}
383	return 0;
384
385out:
386	if (options->storage_type == STORE_SINGLE)
387		options->value = value;
388	if (options->storage_type == STORE_LIST) {
389		if (!options->value) {
390			value_list_t *lhead;
391			lhead = malloc(sizeof(struct value_list));
392			INIT_LIST_HEAD(&lhead->list);
393			options->value = lhead;
394		}
395		value_list_t *tmp_list, *tmp_list2;
396		tmp_list = malloc(sizeof(struct value_list));
397		INIT_LIST_HEAD(&tmp_list->list);
398		tmp_list->value = value;
399		tmp_list2 = (struct value_list *)options->value;
400		list_add(&(tmp_list->list), &(tmp_list2->list));
401	}
402
403	return 1;
404}
405
406void insert_container(container_t * container, container_t * new_container)
407{
408	while (container->next)
409		container = container->next;
410	container->next = new_container;
411}
412
413container_t *search_group(char *, FILE *);
414
415container_t *handle_container(char *buf, FILE * f, uint32_t type,
416			      config_options_t * options)
417{
418	container_desc_t *desc = container_desc;
419	container_t *ret_container;
420	container_t *tmp_container, *tmp2_container;
421	container_t *child = NULL;
422	int is_option;
423
424	while (desc->name)
425		if (desc->type == type)
426			break;
427		else
428			desc++;
429
430	if (!desc->name)
431		return NULL;
432
433	buf = get_next_line(f);
434	while (buf) {
435		is_option = set_option(buf, options);
436		tmp_container = search_group(buf, f);
437		if (tmp_container) {
438			if (tmp_container->type == END) {
439				free(tmp_container);
440				break;
441			} else {
442				if (child == NULL)
443					child = tmp_container;
444				else {
445					tmp2_container = child;
446					while (tmp2_container->next)
447						tmp2_container =
448						    tmp2_container->next;
449					tmp2_container->next = tmp_container;
450				}
451
452			}
453		}
454		if (!is_option && !tmp_container) {
455			printf("ERROR!!! Unknow option: %s", buf);
456			exit(1);
457		}
458		buf = get_next_line(f);
459	}
460	ret_container = init_container();
461	ret_container->config = options;
462	ret_container->type = type;
463	if (child)
464		ret_container->child = child;
465
466	return ret_container;
467}
468
469container_t *search_group(char *buf, FILE * f)
470{
471	char temp[BUFSIZE];
472	char *ptr;
473	config_options_t *options;
474	container_desc_t *desc = container_desc;
475	container_t *ret_container;
476
477	if (1 == sscanf(buf, "[%s]\n", (char *)&temp))
478		while (desc->name) {
479			ptr = strstr(buf, desc->name);
480			if (ptr)
481				switch (desc->type) {
482				case FILESYSTEM:
483					options = malloc(sizeof(fs_options));
484					memcpy(options, fs_options,
485					       sizeof(fs_options));
486					return handle_container(buf, f,
487								desc->type,
488								options);
489					break;
490				case THREAD_GROUP:
491					options = malloc(sizeof(tg_options));
492					memcpy(options, tg_options,
493					       sizeof(tg_options));
494					return handle_container(buf, f,
495								desc->type,
496								options);
497					break;
498				case STATS:
499					options = malloc(sizeof(stats_options));
500					memcpy(options, stats_options,
501					       sizeof(stats_options));
502					return handle_container(buf, f,
503								desc->type,
504								options);
505					break;
506				case END:
507					ret_container = init_container();
508					ret_container->type = END;
509					return ret_container;
510					break;
511				}
512			desc++;
513		}
514	return NULL;
515}
516
517void *get_value(config_options_t * config, char *name)
518{
519	while (config->name) {
520		if (!strcmp(config->name, name)) {
521			if (config->value)
522				return config->value;
523			else
524				return NULL;
525		}
526		config++;
527	}
528	return 0;
529}
530
531char *get_config_str(config_options_t * config, char *name)
532{
533	return get_value(config, name);
534}
535
536uint32_t get_config_u32(config_options_t * config, char *name)
537{
538	void *value = get_value(config, name);
539	if (value)
540		return *(uint32_t *) value;
541	return 0;
542}
543
544uint8_t get_config_bool(config_options_t * config, char *name)
545{
546	void *value = get_value(config, name);
547	if (value)
548		return *(uint8_t *) value;
549	return 0;
550}
551
552uint64_t get_config_u64(config_options_t * config, char *name)
553{
554	void *value = get_value(config, name);
555	if (value)
556		return *(uint64_t *) value;
557	return 0;
558}
559
560double get_config_double(config_options_t * config, char *name)
561{
562	void *value = get_value(config, name);
563	if (value)
564		return *(double *)value;
565	return 0;
566}
567
568static profile_config_t *parse(FILE * f)
569{
570	char *buf;
571	profile_config_t *profile_conf;
572	container_t *tmp_container;
573
574	profile_conf = malloc(sizeof(profile_config_t));
575	profile_conf->global = malloc(sizeof(global_options));
576	memcpy(profile_conf->global, global_options, sizeof(global_options));
577	profile_conf->fs_container = NULL;
578	profile_conf->tg_container = NULL;
579	int is_option;
580	buf = get_next_line(f);
581
582	while (buf) {
583		is_option = set_option(buf, profile_conf->global);
584		tmp_container = search_group(buf, f);
585		if (tmp_container)
586			switch (tmp_container->type) {
587			case FILESYSTEM:
588				if (profile_conf->fs_container == NULL)
589					profile_conf->fs_container =
590					    tmp_container;
591				else
592					insert_container(profile_conf->
593							 fs_container,
594							 tmp_container);
595				break;
596			case THREAD_GROUP:
597				if (profile_conf->tg_container == NULL)
598					profile_conf->tg_container =
599					    tmp_container;
600				else
601					insert_container(profile_conf->
602							 tg_container,
603							 tmp_container);
604				break;
605			default:
606				break;
607			}
608		if (!is_option && !tmp_container) {
609			printf("ERROR!!! Unknow option: %s", buf);
610			exit(1);
611		}
612		buf = get_next_line(f);
613	}
614	return profile_conf;
615}
616
617void set_weight(ffsb_tg_t * tg, config_options_t * config)
618{
619	char *op;
620	int len;
621	config_options_t *tmp_config = config;
622
623	while (tmp_config->name) {
624		if (tmp_config->type == TYPE_WEIGHT) {
625			len = strlen(tmp_config->name);
626			op = malloc(sizeof(char) * len - 6);
627			memset(op, 0, sizeof(char) * len - 6);
628			strncpy(op, tmp_config->name, len - 7);
629			tg_set_op_weight(tg, op,
630					 get_config_u32(config,
631							tmp_config->name));
632			free(op);
633		}
634		tmp_config++;
635	}
636}
637
638int get_weight_total(ffsb_tg_t * tg)
639{
640	char *op;
641	int len;
642	int total = 0;
643	config_options_t *tmp_config = tg_options;
644
645	while (tmp_config->name) {
646		if (tmp_config->type == TYPE_WEIGHT) {
647			len = strlen(tmp_config->name);
648			op = malloc(sizeof(char) * len - 6);
649			memset(op, 0, sizeof(char) * len - 6);
650			strncpy(op, tmp_config->name, len - 7);
651			total += tg_get_op_weight(tg, op);
652			free(op);
653		}
654		tmp_config++;
655	}
656	return total;
657}
658
659/* !!! hackish verification function, we should somehow roll this into the */
660/* op descriptions/struct themselves at some point with a callback verify */
661/* op requirements: */
662/* require tg->read_blocksize:  read, readall */
663/* require tg->write_blocksize: write, create, append, rewritefsync */
664/* */
665
666static int verify_tg(ffsb_tg_t * tg)
667{
668	uint32_t read_weight = tg_get_op_weight(tg, "read");
669	uint32_t readall_weight = tg_get_op_weight(tg, "readall");
670	uint32_t write_weight = tg_get_op_weight(tg, "write");
671	uint32_t create_weight = tg_get_op_weight(tg, "create");
672	uint32_t append_weight = tg_get_op_weight(tg, "append");
673	uint32_t createdir_weight = tg_get_op_weight(tg, "createdir");
674	uint32_t delete_weight = tg_get_op_weight(tg, "delete");
675	uint32_t writeall_weight = tg_get_op_weight(tg, "writeall");
676	uint32_t writeall_fsync_weight = tg_get_op_weight(tg, "writeall_fsync");
677
678	uint32_t sum_weight = get_weight_total(tg);
679
680	uint32_t read_blocksize = tg_get_read_blocksize(tg);
681	uint32_t write_blocksize = tg_get_write_blocksize(tg);
682
683	int read_random = tg_get_read_random(tg);
684	int read_skip = tg_get_read_skip(tg);
685	uint32_t read_skipsize = tg_get_read_skipsize(tg);
686
687	if (sum_weight == 0) {
688		printf("Error: A threadgroup must have at least one weighted "
689		       "operation\n");
690		return 1;
691	}
692
693	if ((read_weight || readall_weight) && !(read_blocksize)) {
694		printf("Error: read and readall operations require a "
695		       "read_blocksize\n");
696		return 1;
697	}
698
699	if ((write_weight || create_weight || append_weight || writeall_weight
700	     || writeall_fsync_weight) && !(write_blocksize)) {
701		printf("Error: write, writeall, create, append"
702		       "operations require a write_blocksize\n");
703		return 1;
704	}
705
706	if (read_random && read_skip) {
707		printf("Error: read_random and read_skip are mutually "
708		       "exclusive\n");
709		return 1;
710	}
711
712	if (read_skip && !(read_skipsize)) {
713		printf("Error: read_skip specified but read_skipsize is "
714		       "zero\n");
715		return 1;
716	}
717
718	return 0;
719}
720
721static unsigned get_num_containers(container_t * container)
722{
723	int numtg = 0;
724	while (container) {
725		numtg++;
726		container = container->next;
727	}
728	return numtg;
729}
730
731static unsigned get_num_threadgroups(profile_config_t * profile_conf)
732{
733	return get_num_containers(profile_conf->tg_container);
734}
735
736static unsigned get_num_filesystems(profile_config_t * profile_conf)
737{
738	return get_num_containers(profile_conf->fs_container);
739}
740
741static int get_num_totalthreads(profile_config_t * profile_conf)
742{
743	int num_threads = 0;
744	container_t *tg = profile_conf->tg_container;
745	config_options_t *tg_config;
746
747	while (tg) {
748		tg_config = tg->config;
749		while (tg_config->name) {
750			if (!strcmp(tg_config->name, "num_threads"))
751				num_threads += *(uint32_t *) tg_config->value;
752			tg_config++;
753		}
754		if (tg->next)
755			tg = tg->next;
756		else
757			break;
758	}
759
760	return num_threads;
761}
762
763container_t *get_container(container_t * head_cont, int pos)
764{
765	int count = 0;
766	while (head_cont) {
767		if (count == pos)
768			return head_cont;
769		head_cont = head_cont->next;
770		count++;
771	}
772	return NULL;
773}
774
775config_options_t *get_fs_config(ffsb_config_t * fc, int pos)
776{
777	container_t *tmp_cont;
778
779	assert(pos < fc->num_filesys);
780	tmp_cont = get_container(fc->profile_conf->fs_container, pos);
781	if (tmp_cont)
782		return tmp_cont->config;
783	return NULL;
784}
785
786container_t *get_fs_container(ffsb_config_t * fc, int pos)
787{
788	assert(pos < fc->num_filesys);
789	return get_container(fc->profile_conf->fs_container, pos);
790}
791
792config_options_t *get_tg_config(ffsb_config_t * fc, int pos)
793{
794	container_t *tmp_cont;
795
796	assert(pos < fc->num_threadgroups);
797	tmp_cont = get_container(fc->profile_conf->tg_container, pos);
798	if (tmp_cont)
799		return tmp_cont->config;
800	return NULL;
801}
802
803container_t *get_tg_container(ffsb_config_t * fc, int pos)
804{
805	assert(pos < fc->num_threadgroups);
806	return get_container(fc->profile_conf->tg_container, pos);
807}
808
809static void init_threadgroup(ffsb_config_t * fc, config_options_t * config,
810			     ffsb_tg_t * tg, int tg_num)
811{
812	int num_threads;
813	memset(tg, 0, sizeof(ffsb_tg_t));
814
815	num_threads = get_config_u32(config, "num_threads");
816
817	init_ffsb_tg(tg, num_threads, tg_num);
818
819	if (get_config_str(config, "bindfs")) {
820		int i;
821		config_options_t *tmp_config;
822		for (i = 0; i < fc->num_filesys; i++) {
823			tmp_config = get_fs_config(fc, i);
824			if (!strcmp(get_config_str(config, "bindfs"),
825				    get_config_str(tmp_config, "location")))
826				break;
827		}
828		if (strcmp(get_config_str(config, "bindfs"),
829			   get_config_str(tmp_config, "location"))) {
830			printf("Bind fs failed:  Base fs \"%s\" not found\n",
831			       get_config_str(config, "bindfs"));
832			exit(1);
833		}
834		printf("%d\n", i);
835		tg->bindfs = i;
836	}
837
838	tg->read_random = get_config_bool(config, "read_random");
839	tg->read_size = get_config_u64(config, "read_size");
840	tg->read_skip = get_config_bool(config, "read_skip");
841	tg->read_skipsize = get_config_u32(config, "read_skipsize");
842
843	tg->write_random = get_config_bool(config, "write_random");
844	tg->write_size = get_config_u64(config, "write_size");
845	tg->fsync_file = get_config_bool(config, "fsync_file");
846
847	tg->wait_time = get_config_u32(config, "op_delay");
848
849	tg_set_read_blocksize(tg, get_config_u32(config, "read_blocksize"));
850	tg_set_write_blocksize(tg, get_config_u32(config, "write_blocksize"));
851
852	set_weight(tg, config);
853
854	if (verify_tg(tg)) {
855		printf("threadgroup %d verification failed\n", tg_num);
856		exit(1);
857	}
858}
859
860static void init_filesys(ffsb_config_t * fc, int num)
861{
862	config_options_t *config = get_fs_config(fc, num);
863	profile_config_t *profile_conf = fc->profile_conf;
864	ffsb_fs_t *fs = &fc->filesystems[num];
865	value_list_t *tmp_list, *list_head;
866
867	memset(fs, 0, sizeof(ffsb_fs_t));
868
869	fs->basedir = get_config_str(config, "location");
870
871	if (get_config_str(config, "clone")) {
872		int i;
873		config_options_t *tmp_config;
874		for (i = 0; i < fc->num_filesys; i++) {
875			tmp_config = get_fs_config(fc, i);
876			if (!strcmp(get_config_str(config, "clone"),
877				    get_config_str(tmp_config, "location")))
878				break;
879		}
880		if (strcmp(get_config_str(config, "clone"),
881			   get_config_str(tmp_config, "location"))) {
882			printf("Clone fs failed:  Base fs \"%s\" not found\n",
883			       get_config_str(config, "clone"));
884			exit(1);
885		}
886		config = tmp_config;
887	}
888
889	fs->num_dirs = get_config_u32(config, "num_dirs");
890	fs->num_start_files = get_config_u32(config, "num_files");
891	fs->minfilesize = get_config_u64(config, "min_filesize");
892	fs->maxfilesize = get_config_u64(config, "max_filesize");
893	fs->desired_fsutil = get_config_double(config, "desired_util");
894	fs->init_fsutil = get_config_double(config, "init_util");
895	fs->init_size = get_config_u64(config, "init_size");
896
897	fs->flags = 0;
898	if (get_config_bool(config, "reuse"))
899		fs->flags |= FFSB_FS_REUSE_FS;
900
901	if (get_config_bool(profile_conf->global, "directio"))
902		 fs->flags |= FFSB_FS_DIRECTIO | FFSB_FS_ALIGNIO4K;
903
904	if (get_config_bool(profile_conf->global, "bufferio"))
905		 fs->flags |= FFSB_FS_LIBCIO;
906
907	if (get_config_bool(profile_conf->global, "alignio"))
908		 fs->flags |= FFSB_FS_ALIGNIO4K;
909
910	if (get_config_bool(config, "agefs")) {
911		container_t *age_cont = get_fs_container(fc, num);
912		if (!age_cont->child) {
913			printf("No age threaggroup in profile");
914			exit(1);
915		}
916
917		age_cont = age_cont->child;
918		ffsb_tg_t *age_tg = ffsb_malloc(sizeof(ffsb_tg_t));
919		init_threadgroup(fc, age_cont->config, age_tg, 0);
920		fs->aging_tg = age_tg;
921		fs->age_fs = 1;
922	}
923
924	if (get_config_u32(config, "create_blocksize"))
925		fs->create_blocksize = get_config_u32(config,
926						      "create_blocksize");
927	else
928		fs->create_blocksize = FFSB_FS_DEFAULT_CREATE_BLOCKSIZE;
929
930	if (get_config_u32(config, "age_blocksize"))
931		fs->age_blocksize = get_config_u32(config, "age_blocksize");
932	else
933		fs->age_blocksize = FFSB_FS_DEFAULT_AGE_BLOCKSIZE;
934
935	list_head = (value_list_t *) get_value(config, "size_weight");
936	if (list_head) {
937		int count = 0;
938		size_weight_t *sizew;
939		list_for_each_entry(tmp_list, &list_head->list, list)
940		    count++;
941
942		fs->num_weights = count;
943		fs->size_weights =
944		    malloc(sizeof(size_weight_t) * fs->num_weights);
945
946		count = 0;
947		list_for_each_entry(tmp_list, &list_head->list, list) {
948			sizew = (size_weight_t *) tmp_list->value;
949			fs->size_weights[count].size = sizew->size;
950			fs->size_weights[count].weight = sizew->weight;
951			fs->sum_weights += sizew->weight;
952			count++;
953		}
954	}
955}
956
957static void init_tg_stats(ffsb_config_t * fc, int num)
958{
959	config_options_t *config;
960	container_t *tmp_cont;
961	value_list_t *tmp_list, *list_head;
962	syscall_t sys;
963	ffsb_statsc_t fsc = { 0, };
964	char *sys_name;
965	range_t *bucket_range;
966	uint32_t min, max;
967
968	tmp_cont = get_tg_container(fc, num);
969	if (tmp_cont->child) {
970		if (tmp_cont->type == STATS) {
971			config = tmp_cont->config;
972			if (get_config_bool(config, "enable_stats")) {
973
974				list_head =
975				    (value_list_t *) get_value(config,
976							       "ignore");
977				if (list_head)
978					list_for_each_entry(tmp_list,
979							    &list_head->list,
980							    list) {
981					sys_name = (char *)tmp_list->value;
982					ffsb_stats_str2syscall(sys_name, &sys);
983					ffsb_statsc_ignore_sys(&fsc, sys);
984					}
985
986				list_head =
987				    (value_list_t *) get_value(config,
988							       "msec_range");
989				if (list_head
990				    && get_config_bool(config, "enable_range"))
991					list_for_each_entry(tmp_list,
992							    &list_head->list,
993							    list) {
994					bucket_range =
995					    (range_t *) tmp_list->value;
996					min =
997					    (uint32_t) (bucket_range->a *
998							1000.0f);
999					max =
1000					    (uint32_t) (bucket_range->b *
1001							1000.0f);
1002					ffsb_statsc_addbucket(&fsc, min, max);
1003					}
1004
1005				tg_set_statsc(&fc->groups[num], &fsc);
1006			}
1007		}
1008	}
1009}
1010
1011static void init_config(ffsb_config_t * fc, profile_config_t * profile_conf)
1012{
1013	config_options_t *config;
1014	container_t *tmp_cont;
1015	int i;
1016
1017	fc->time = get_config_u32(profile_conf->global, "time");
1018	fc->num_filesys = get_num_filesystems(profile_conf);
1019	fc->num_threadgroups = get_num_threadgroups(profile_conf);
1020	fc->num_totalthreads = get_num_totalthreads(profile_conf);
1021	fc->profile_conf = profile_conf;
1022	fc->callout = get_config_str(profile_conf->global, "callout");
1023
1024	fc->filesystems = ffsb_malloc(sizeof(ffsb_fs_t) * fc->num_filesys);
1025	for (i = 0; i < fc->num_filesys; i++)
1026		init_filesys(fc, i);
1027
1028	fc->groups = ffsb_malloc(sizeof(ffsb_tg_t) * fc->num_threadgroups);
1029	for (i = 0; i < fc->num_threadgroups; i++) {
1030		config = get_tg_config(fc, i);
1031		init_threadgroup(fc, config, &fc->groups[i], i);
1032		init_tg_stats(fc, i);
1033	}
1034}
1035
1036void ffsb_parse_newconfig(ffsb_config_t * fc, char *filename)
1037{
1038	FILE *f;
1039
1040	profile_config_t *profile_conf;
1041
1042	f = fopen(filename, "r");
1043	if (f == NULL) {
1044		perror(filename);
1045		exit(1);
1046	}
1047	profile_conf = parse(f);
1048	fclose(f);
1049
1050	init_config(fc, profile_conf);
1051}
1052