init.c revision df64119de537aba99c85d1dc80190b354589f8b9
1/*
2 * This file contains the ini and command liner parser. It will create
3 * and initialize the specified jobs.
4 */
5#include <stdio.h>
6#include <stdlib.h>
7#include <unistd.h>
8#include <fcntl.h>
9#include <ctype.h>
10#include <string.h>
11#include <errno.h>
12#include <sys/ipc.h>
13#include <sys/shm.h>
14#include <sys/types.h>
15#include <sys/stat.h>
16
17#include "fio.h"
18
19/*
20 * The default options
21 */
22#define DEF_BS			(4096)
23#define DEF_TIMEOUT		(0)
24#define DEF_RATE_CYCLE		(1000)
25#define DEF_ODIRECT		(1)
26#define DEF_IO_ENGINE		(FIO_SYNCIO)
27#define DEF_IO_ENGINE_NAME	"sync"
28#define DEF_SEQUENTIAL		(1)
29#define DEF_RAND_REPEAT		(1)
30#define DEF_OVERWRITE		(1)
31#define DEF_CREATE		(1)
32#define DEF_INVALIDATE		(1)
33#define DEF_SYNCIO		(0)
34#define DEF_RANDSEED		(0xb1899bedUL)
35#define DEF_BWAVGTIME		(500)
36#define DEF_CREATE_SER		(1)
37#define DEF_CREATE_FSYNC	(1)
38#define DEF_LOOPS		(1)
39#define DEF_VERIFY		(0)
40#define DEF_STONEWALL		(0)
41#define DEF_NUMJOBS		(1)
42#define DEF_USE_THREAD		(0)
43#define DEF_FILE_SIZE		(1024 * 1024 * 1024UL)
44#define DEF_ZONE_SIZE		(0)
45#define DEF_ZONE_SKIP		(0)
46#define DEF_RWMIX_CYCLE		(500)
47#define DEF_RWMIX_READ		(50)
48#define DEF_NICE		(0)
49
50static int def_timeout = DEF_TIMEOUT;
51
52static char fio_version_string[] = "fio 1.5";
53
54static char **ini_file;
55static int max_jobs = MAX_JOBS;
56
57struct thread_data def_thread;
58struct thread_data *threads = NULL;
59
60int rate_quit = 0;
61int write_lat_log = 0;
62int write_bw_log = 0;
63int exitall_on_terminate = 0;
64int terse_output = 0;
65unsigned long long mlock_size = 0;
66FILE *f_out = NULL;
67FILE *f_err = NULL;
68
69/*
70 * Return a free job structure.
71 */
72static struct thread_data *get_new_job(int global, struct thread_data *parent)
73{
74	struct thread_data *td;
75
76	if (global)
77		return &def_thread;
78	if (thread_number >= max_jobs)
79		return NULL;
80
81	td = &threads[thread_number++];
82	*td = *parent;
83	td->name[0] = '\0';
84
85	td->fd = -1;
86	td->thread_number = thread_number;
87	return td;
88}
89
90static void put_job(struct thread_data *td)
91{
92	memset(&threads[td->thread_number - 1], 0, sizeof(*td));
93	thread_number--;
94}
95
96/*
97 * Adds a job to the list of things todo. Sanitizes the various options
98 * to make sure we don't have conflicts, and initializes various
99 * members of td.
100 */
101static int add_job(struct thread_data *td, const char *jobname, int job_add_num)
102{
103	char *ddir_str[] = { "read", "write", "randread", "randwrite",
104			     "rw", NULL, "randrw" };
105	struct stat sb;
106	int numjobs, ddir;
107
108#ifndef FIO_HAVE_LIBAIO
109	if (td->io_engine == FIO_LIBAIO) {
110		log_err("Linux libaio not available\n");
111		return 1;
112	}
113#endif
114#ifndef FIO_HAVE_POSIXAIO
115	if (td->io_engine == FIO_POSIXAIO) {
116		log_err("posix aio not available\n");
117		return 1;
118	}
119#endif
120
121	/*
122	 * the def_thread is just for options, it's not a real job
123	 */
124	if (td == &def_thread)
125		return 0;
126
127	/*
128	 * Set default io engine, if none set
129	 */
130	if (!td->io_ops) {
131		td->io_ops = load_ioengine(td, DEF_IO_ENGINE_NAME);
132		if (!td->io_ops) {
133			log_err("default engine %s not there?\n", DEF_IO_ENGINE_NAME);
134			return 1;
135		}
136	}
137
138	if (td->io_ops->flags & FIO_SYNCIO)
139		td->iodepth = 1;
140	else {
141		if (!td->iodepth)
142			td->iodepth = 1;
143	}
144
145	/*
146	 * only really works for sequential io for now
147	 */
148	if (td->zone_size && !td->sequential)
149		td->zone_size = 0;
150
151	/*
152	 * Reads can do overwrites, we always need to pre-create the file
153	 */
154	if (td_read(td) || td_rw(td))
155		td->overwrite = 1;
156
157	td->filetype = FIO_TYPE_FILE;
158	if (!stat(jobname, &sb)) {
159		if (S_ISBLK(sb.st_mode))
160			td->filetype = FIO_TYPE_BD;
161		else if (S_ISCHR(sb.st_mode))
162			td->filetype = FIO_TYPE_CHAR;
163	}
164
165	if (td->filetype == FIO_TYPE_FILE) {
166		char tmp[PATH_MAX];
167
168		if (td->directory && td->directory[0] != '\0')
169			sprintf(tmp, "%s/%s.%d", td->directory, jobname, td->thread_number);
170		else
171			sprintf(tmp, "%s.%d", jobname, td->thread_number);
172		td->file_name = strdup(tmp);
173	} else
174		td->file_name = strdup(jobname);
175
176	fio_sem_init(&td->mutex, 0);
177
178	td->clat_stat[0].min_val = td->clat_stat[1].min_val = ULONG_MAX;
179	td->slat_stat[0].min_val = td->slat_stat[1].min_val = ULONG_MAX;
180	td->bw_stat[0].min_val = td->bw_stat[1].min_val = ULONG_MAX;
181
182	if (td->min_bs == -1U)
183		td->min_bs = td->bs;
184	if (td->max_bs == -1U)
185		td->max_bs = td->bs;
186	if (td_read(td) && !td_rw(td))
187		td->verify = 0;
188
189	if (td->stonewall && td->thread_number > 1)
190		groupid++;
191
192	td->groupid = groupid;
193
194	if (setup_rate(td))
195		goto err;
196
197	if (write_lat_log) {
198		setup_log(&td->slat_log);
199		setup_log(&td->clat_log);
200	}
201	if (write_bw_log)
202		setup_log(&td->bw_log);
203
204	if (td->name[0] == '\0')
205		snprintf(td->name, sizeof(td->name)-1, "client%d", td->thread_number);
206
207	ddir = td->ddir + (!td->sequential << 1) + (td->iomix << 2);
208
209	if (!terse_output) {
210		if (!job_add_num) {
211			if (td->io_ops->flags & FIO_CPUIO)
212				fprintf(f_out, "%s: ioengine=cpu, cpuload=%u, cpucycle=%u\n", td->name, td->cpuload, td->cpucycle);
213			else
214				fprintf(f_out, "%s: (g=%d): rw=%s, odir=%d, bs=%d-%d, rate=%d, ioengine=%s, iodepth=%d\n", td->name, td->groupid, ddir_str[ddir], td->odirect, td->min_bs, td->max_bs, td->rate, td->io_ops->name, td->iodepth);
215		} else if (job_add_num == 1)
216			fprintf(f_out, "...\n");
217	}
218
219	/*
220	 * recurse add identical jobs, clear numjobs and stonewall options
221	 * as they don't apply to sub-jobs
222	 */
223	numjobs = td->numjobs;
224	while (--numjobs) {
225		struct thread_data *td_new = get_new_job(0, td);
226
227		if (!td_new)
228			goto err;
229
230		td_new->numjobs = 1;
231		td_new->stonewall = 0;
232		job_add_num = numjobs - 1;
233
234		if (add_job(td_new, jobname, job_add_num))
235			goto err;
236	}
237	return 0;
238err:
239	put_job(td);
240	return -1;
241}
242
243/*
244 * Initialize the various random states we need (random io, block size ranges,
245 * read/write mix, etc).
246 */
247int init_random_state(struct thread_data *td)
248{
249	unsigned long seeds[4];
250	int fd, num_maps, blocks;
251
252	fd = open("/dev/urandom", O_RDONLY);
253	if (fd == -1) {
254		td_verror(td, errno);
255		return 1;
256	}
257
258	if (read(fd, seeds, sizeof(seeds)) < (int) sizeof(seeds)) {
259		td_verror(td, EIO);
260		close(fd);
261		return 1;
262	}
263
264	close(fd);
265
266	os_random_seed(seeds[0], &td->bsrange_state);
267	os_random_seed(seeds[1], &td->verify_state);
268	os_random_seed(seeds[2], &td->rwmix_state);
269
270	if (td->sequential)
271		return 0;
272
273	if (td->rand_repeatable)
274		seeds[3] = DEF_RANDSEED;
275
276	blocks = (td->io_size + td->min_bs - 1) / td->min_bs;
277	num_maps = blocks / BLOCKS_PER_MAP;
278	td->file_map = malloc(num_maps * sizeof(long));
279	td->num_maps = num_maps;
280	memset(td->file_map, 0, num_maps * sizeof(long));
281
282	os_random_seed(seeds[3], &td->random_state);
283	return 0;
284}
285
286static void fill_cpu_mask(os_cpu_mask_t cpumask, int cpu)
287{
288#ifdef FIO_HAVE_CPU_AFFINITY
289	unsigned int i;
290
291	CPU_ZERO(&cpumask);
292
293	for (i = 0; i < sizeof(int) * 8; i++) {
294		if ((1 << i) & cpu)
295			CPU_SET(i, &cpumask);
296	}
297#endif
298}
299
300static unsigned long get_mult_time(char c)
301{
302	switch (c) {
303		case 'm':
304		case 'M':
305			return 60;
306		case 'h':
307		case 'H':
308			return 60 * 60;
309		case 'd':
310		case 'D':
311			return 24 * 60 * 60;
312		default:
313			return 1;
314	}
315}
316
317static unsigned long get_mult_bytes(char c)
318{
319	switch (c) {
320		case 'k':
321		case 'K':
322			return 1024;
323		case 'm':
324		case 'M':
325			return 1024 * 1024;
326		case 'g':
327		case 'G':
328			return 1024 * 1024 * 1024;
329		default:
330			return 1;
331	}
332}
333
334/*
335 * convert string after '=' into decimal value, noting any size suffix
336 */
337static int str_to_decimal(char *p, unsigned long long *val, int kilo)
338{
339	char *str;
340	int len;
341
342	str = strchr(p, '=');
343	if (!str)
344		return 1;
345
346	str++;
347	len = strlen(str);
348
349	*val = strtoul(str, NULL, 10);
350	if (*val == ULONG_MAX && errno == ERANGE)
351		return 1;
352
353	if (kilo)
354		*val *= get_mult_bytes(str[len - 1]);
355	else
356		*val *= get_mult_time(str[len - 1]);
357	return 0;
358}
359
360static int check_str_bytes(char *p, char *name, unsigned long long *val)
361{
362	if (strncmp(p, name, strlen(name) - 1))
363		return 1;
364
365	return str_to_decimal(p, val, 1);
366}
367
368static int check_str_time(char *p, char *name, unsigned long long *val)
369{
370	if (strncmp(p, name, strlen(name) - 1))
371		return 1;
372
373	return str_to_decimal(p, val, 0);
374}
375
376static void strip_blank_front(char **p)
377{
378	char *s = *p;
379
380	while (isspace(*s))
381		s++;
382}
383
384static void strip_blank_end(char *p)
385{
386	char *s = p + strlen(p) - 1;
387
388	while (isspace(*s) || iscntrl(*s))
389		s--;
390
391	*(s + 1) = '\0';
392}
393
394typedef int (str_cb_fn)(struct thread_data *, char *);
395
396static int check_str(char *p, char *name, str_cb_fn *cb, struct thread_data *td)
397{
398	char *s;
399
400	if (strncmp(p, name, strlen(name)))
401		return 1;
402
403	s = strstr(p, name);
404	if (!s)
405		return 1;
406
407	s = strchr(s, '=');
408	if (!s)
409		return 1;
410
411	s++;
412	strip_blank_front(&s);
413	return cb(td, s);
414}
415
416static int check_strstore(char *p, char *name, char *dest)
417{
418	char *s;
419
420	if (strncmp(p, name, strlen(name)))
421		return 1;
422
423	s = strstr(p, name);
424	if (!s)
425		return 1;
426
427	s = strchr(p, '=');
428	if (!s)
429		return 1;
430
431	s++;
432	strip_blank_front(&s);
433
434	strcpy(dest, s);
435	return 0;
436}
437
438static int __check_range_bytes(char *str, unsigned long *val)
439{
440	char suffix;
441
442	if (sscanf(str, "%lu%c", val, &suffix) == 2) {
443		*val *= get_mult_bytes(suffix);
444		return 0;
445	}
446
447	if (sscanf(str, "%lu", val) == 1)
448		return 0;
449
450	return 1;
451}
452
453static int check_range_bytes(char *p, char *name, unsigned long *s,
454			     unsigned long *e)
455{
456	char option[128];
457	char *str, *p1, *p2;
458
459	if (strncmp(p, name, strlen(name)))
460		return 1;
461
462	strcpy(option, p);
463	p = option;
464
465	str = strstr(p, name);
466	if (!str)
467		return 1;
468
469	p += strlen(name);
470
471	str = strchr(p, '=');
472	if (!str)
473		return 1;
474
475	/*
476	 * 'p' now holds whatever is after the '=' sign
477	 */
478	p1 = str + 1;
479
480	/*
481	 * terminate p1 at the '-' sign
482	 */
483	p = strchr(p1, '-');
484	if (!p)
485		return 1;
486
487	p2 = p + 1;
488	*p = '\0';
489
490	if (!__check_range_bytes(p1, s) && !__check_range_bytes(p2, e))
491		return 0;
492
493	return 1;
494}
495
496static int check_int(char *p, char *name, unsigned int *val)
497{
498	char *str;
499
500	if (strncmp(p, name, strlen(name)))
501		return 1;
502
503	str = strstr(p, name);
504	if (!str)
505		return 1;
506
507	str = strchr(p, '=');
508	if (!str)
509		return 1;
510
511	str++;
512
513	if (sscanf(str, "%u", val) == 1)
514		return 0;
515
516	return 1;
517}
518
519static int check_strset(char *p, char *name)
520{
521	return strncmp(p, name, strlen(name));
522}
523
524static int is_empty_or_comment(char *line)
525{
526	unsigned int i;
527
528	for (i = 0; i < strlen(line); i++) {
529		if (line[i] == ';')
530			return 1;
531		if (!isspace(line[i]) && !iscntrl(line[i]))
532			return 0;
533	}
534
535	return 1;
536}
537
538static int str_rw_cb(struct thread_data *td, char *mem)
539{
540	if (!strncmp(mem, "read", 4) || !strncmp(mem, "0", 1)) {
541		td->ddir = DDIR_READ;
542		td->sequential = 1;
543		return 0;
544	} else if (!strncmp(mem, "randread", 8)) {
545		td->ddir = DDIR_READ;
546		td->sequential = 0;
547		return 0;
548	} else if (!strncmp(mem, "write", 5) || !strncmp(mem, "1", 1)) {
549		td->ddir = DDIR_WRITE;
550		td->sequential = 1;
551		return 0;
552	} else if (!strncmp(mem, "randwrite", 9)) {
553		td->ddir = DDIR_WRITE;
554		td->sequential = 0;
555		return 0;
556	} else if (!strncmp(mem, "rw", 2)) {
557		td->ddir = 0;
558		td->iomix = 1;
559		td->sequential = 1;
560		return 0;
561	} else if (!strncmp(mem, "randrw", 6)) {
562		td->ddir = 0;
563		td->iomix = 1;
564		td->sequential = 0;
565		return 0;
566	}
567
568	log_err("fio: data direction: read, write, randread, randwrite, rw, randrw\n");
569	return 1;
570}
571
572static int str_verify_cb(struct thread_data *td, char *mem)
573{
574	if (!strncmp(mem, "0", 1)) {
575		td->verify = VERIFY_NONE;
576		return 0;
577	} else if (!strncmp(mem, "md5", 3) || !strncmp(mem, "1", 1)) {
578		td->verify = VERIFY_MD5;
579		return 0;
580	} else if (!strncmp(mem, "crc32", 5)) {
581		td->verify = VERIFY_CRC32;
582		return 0;
583	}
584
585	log_err("fio: verify types: md5, crc32\n");
586	return 1;
587}
588
589static int str_mem_cb(struct thread_data *td, char *mem)
590{
591	if (!strncmp(mem, "malloc", 6)) {
592		td->mem_type = MEM_MALLOC;
593		return 0;
594	} else if (!strncmp(mem, "shm", 3)) {
595		td->mem_type = MEM_SHM;
596		return 0;
597	} else if (!strncmp(mem, "mmap", 4)) {
598		td->mem_type = MEM_MMAP;
599		return 0;
600	}
601
602	log_err("fio: mem type: malloc, shm, mmap\n");
603	return 1;
604}
605
606static int str_ioengine_cb(struct thread_data *td, char *str)
607{
608	td->io_ops = load_ioengine(td, str);
609	if (td->io_ops)
610		return 0;
611
612	log_err("fio: ioengine: { linuxaio, aio, libaio }, posixaio, sync, mmap, sgio, splice, cpu\n");
613	return 1;
614}
615
616/*
617 * This is our [ini] type file parser.
618 */
619int parse_jobs_ini(char *file, int stonewall_flag)
620{
621	unsigned int prioclass, prio, cpu, global, il;
622	unsigned long long ull;
623	unsigned long ul1, ul2;
624	struct thread_data *td;
625	char *string, *name, *tmpbuf;
626	fpos_t off;
627	FILE *f;
628	char *p;
629	int ret = 0, stonewall;
630
631	f = fopen(file, "r");
632	if (!f) {
633		perror("fopen job file");
634		return 1;
635	}
636
637	string = malloc(4096);
638	name = malloc(256);
639	tmpbuf = malloc(4096);
640
641	stonewall = stonewall_flag;
642	while ((p = fgets(string, 4096, f)) != NULL) {
643		if (ret)
644			break;
645		if (is_empty_or_comment(p))
646			continue;
647		if (sscanf(p, "[%s]", name) != 1)
648			continue;
649
650		global = !strncmp(name, "global", 6);
651
652		name[strlen(name) - 1] = '\0';
653
654		td = get_new_job(global, &def_thread);
655		if (!td) {
656			ret = 1;
657			break;
658		}
659
660		/*
661		 * Seperate multiple job files by a stonewall
662		 */
663		if (!global && stonewall) {
664			td->stonewall = stonewall;
665			stonewall = 0;
666		}
667
668		fgetpos(f, &off);
669		while ((p = fgets(string, 4096, f)) != NULL) {
670			if (is_empty_or_comment(p))
671				continue;
672			if (strstr(p, "["))
673				break;
674			strip_blank_front(&p);
675			strip_blank_end(p);
676
677			if (!check_int(p, "prio", &prio)) {
678#ifndef FIO_HAVE_IOPRIO
679				log_err("io priorities not available\n");
680				ret = 1;
681				break;
682#endif
683				td->ioprio |= prio;
684				fgetpos(f, &off);
685				continue;
686			}
687			if (!check_int(p, "prioclass", &prioclass)) {
688#ifndef FIO_HAVE_IOPRIO
689				log_err("io priorities not available\n");
690				ret = 1;
691				break;
692#else
693				td->ioprio |= prioclass << IOPRIO_CLASS_SHIFT;
694				fgetpos(f, &off);
695				continue;
696#endif
697			}
698			if (!check_int(p, "direct", &il)) {
699				td->odirect = il;
700				fgetpos(f, &off);
701				continue;
702			}
703			if (!check_int(p, "rand_repeatable", &il)) {
704				td->rand_repeatable = il;
705				fgetpos(f, &off);
706				continue;
707			}
708			if (!check_int(p, "rate", &td->rate)) {
709				fgetpos(f, &off);
710				continue;
711			}
712			if (!check_int(p, "ratemin", &td->ratemin)) {
713				fgetpos(f, &off);
714				continue;
715			}
716			if (!check_int(p, "ratecycle", &td->ratecycle)) {
717				fgetpos(f, &off);
718				continue;
719			}
720			if (!check_int(p, "cpuload", &td->cpuload)) {
721				fgetpos(f, &off);
722				continue;
723			}
724			if (!check_int(p, "cpuchunks", &td->cpucycle)) {
725				fgetpos(f, &off);
726				continue;
727			}
728			if (!check_int(p, "thinktime", &td->thinktime)) {
729				fgetpos(f, &off);
730				continue;
731			}
732			if (!check_int(p, "cpumask", &cpu)) {
733#ifndef FIO_HAVE_CPU_AFFINITY
734				log_err("cpu affinity not available\n");
735				ret = 1;
736				break;
737#endif
738				fill_cpu_mask(td->cpumask, cpu);
739				fgetpos(f, &off);
740				continue;
741			}
742			if (!check_int(p, "fsync", &td->fsync_blocks)) {
743				fgetpos(f, &off);
744				td->end_fsync = 1;
745				continue;
746			}
747			if (!check_int(p, "startdelay", &td->start_delay)) {
748				fgetpos(f, &off);
749				continue;
750			}
751			if (!check_str_time(p, "timeout", &ull)) {
752				td->timeout = ull;
753				fgetpos(f, &off);
754				continue;
755			}
756			if (!check_int(p, "invalidate", &il)) {
757				td->invalidate_cache = il;
758				fgetpos(f, &off);
759				continue;
760			}
761			if (!check_int(p, "iodepth", &td->iodepth)) {
762				fgetpos(f, &off);
763				continue;
764			}
765			if (!check_int(p, "sync", &il)) {
766				td->sync_io = il;
767				fgetpos(f, &off);
768				continue;
769			}
770			if (!check_int(p, "bwavgtime", &td->bw_avg_time)) {
771				fgetpos(f, &off);
772				continue;
773			}
774			if (!check_int(p, "create_serialize", &il)) {
775				td->create_serialize = il;
776				fgetpos(f, &off);
777				continue;
778			}
779			if (!check_int(p, "create_fsync", &il)) {
780				td->create_fsync = il;
781				fgetpos(f, &off);
782				continue;
783			}
784			if (!check_int(p, "end_fsync", &il)) {
785				td->end_fsync = il;
786				fgetpos(f, &off);
787				continue;
788			}
789			if (!check_int(p, "loops", &td->loops)) {
790				fgetpos(f, &off);
791				continue;
792			}
793			if (!check_int(p, "numjobs", &td->numjobs)) {
794				fgetpos(f, &off);
795				continue;
796			}
797			if (!check_int(p, "overwrite", &il)) {
798				td->overwrite = il;
799				fgetpos(f, &off);
800				continue;
801			}
802			if (!check_int(p, "rwmixcycle", &td->rwmixcycle)) {
803				fgetpos(f, &off);
804				continue;
805			}
806			if (!check_int(p, "rwmixread", &il)) {
807				if (il > 100)
808					il = 100;
809				td->rwmixread = il;
810				fgetpos(f, &off);
811				continue;
812			}
813			if (!check_int(p, "rwmixwrite", &il)) {
814				if (il > 100)
815					il = 100;
816				td->rwmixread = 100 - il;
817				fgetpos(f, &off);
818				continue;
819			}
820			if (!check_int(p, "nice", &td->nice)) {
821				fgetpos(f, &off);
822				continue;
823			}
824			if (!check_range_bytes(p, "bsrange", &ul1, &ul2)) {
825				if (ul1 > ul2) {
826					td->max_bs = ul1;
827					td->min_bs = ul2;
828				} else {
829					td->max_bs = ul2;
830					td->min_bs = ul1;
831				}
832				fgetpos(f, &off);
833				continue;
834			}
835			if (!check_str_bytes(p, "bs", &ull)) {
836				td->bs = ull;
837				fgetpos(f, &off);
838				continue;
839			}
840			if (!check_str_bytes(p, "size", &td->file_size)) {
841				fgetpos(f, &off);
842				continue;
843			}
844			if (!check_str_bytes(p, "offset", &td->file_offset)) {
845				fgetpos(f, &off);
846				continue;
847			}
848			if (!check_str_bytes(p, "zonesize", &td->zone_size)) {
849				fgetpos(f, &off);
850				continue;
851			}
852			if (!check_str_bytes(p, "zoneskip", &td->zone_skip)) {
853				fgetpos(f, &off);
854				continue;
855			}
856			if (!check_str_bytes(p, "lockmem", &mlock_size)) {
857				fgetpos(f, &off);
858				continue;
859			}
860			if (!check_strstore(p, "directory", tmpbuf)) {
861				td->directory = strdup(tmpbuf);
862				fgetpos(f, &off);
863				continue;
864			}
865			if (!check_strstore(p, "name", tmpbuf)) {
866				snprintf(td->name, sizeof(td->name)-1, "%s%d", tmpbuf, td->thread_number);
867				fgetpos(f, &off);
868				continue;
869			}
870			if (!check_str(p, "mem", str_mem_cb, td)) {
871				fgetpos(f, &off);
872				continue;
873			}
874			if (!check_str(p, "verify", str_verify_cb, td)) {
875				fgetpos(f, &off);
876				continue;
877			}
878			if (!check_str(p, "rw", str_rw_cb, td)) {
879				fgetpos(f, &off);
880				continue;
881			}
882			if (!check_str(p, "ioengine", str_ioengine_cb, td)) {
883				fgetpos(f, &off);
884				continue;
885			}
886			if (!check_strset(p, "create")) {
887				td->create_file = 1;
888				fgetpos(f, &off);
889				continue;
890			}
891			if (!check_strset(p, "exitall")) {
892				exitall_on_terminate = 1;
893				fgetpos(f, &off);
894				continue;
895			}
896			if (!check_strset(p, "stonewall")) {
897				td->stonewall = 1;
898				fgetpos(f, &off);
899				continue;
900			}
901			if (!check_strset(p, "thread")) {
902				td->use_thread = 1;
903				fgetpos(f, &off);
904				continue;
905			}
906			if (!check_strstore(p, "iolog", tmpbuf)) {
907				if (td->write_iolog) {
908					log_err("fio: read iolog overrides given write_iolog\n");
909					free(td->iolog_file);
910					td->write_iolog = 0;
911				}
912				td->iolog_file = strdup(tmpbuf);
913				td->read_iolog = 1;
914				fgetpos(f, &off);
915				continue;
916			}
917			if (!check_strstore(p, "write_iolog", tmpbuf)) {
918				if (!td->read_iolog) {
919					td->iolog_file = strdup(tmpbuf);
920					td->write_iolog = 1;
921				} else
922					log_err("fio: read iolog overrides given write_iolog\n");
923				fgetpos(f, &off);
924				continue;
925			}
926			if (!check_strstore(p, "exec_prerun", tmpbuf)) {
927				td->exec_prerun = strdup(tmpbuf);
928				fgetpos(f, &off);
929				continue;
930			}
931			if (!check_strstore(p, "exec_postrun", tmpbuf)) {
932				td->exec_postrun = strdup(tmpbuf);
933				fgetpos(f, &off);
934				continue;
935			}
936			if (!check_strstore(p, "ioscheduler", tmpbuf)) {
937#ifndef FIO_HAVE_IOSCHED_SWITCH
938				log_err("io scheduler switching not available\n");
939				ret = 1;
940				break;
941#else
942				td->ioscheduler = strdup(tmpbuf);
943				fgetpos(f, &off);
944				continue;
945#endif
946			}
947
948			/*
949			 * Don't break here, continue parsing options so we
950			 * dump all the bad ones. Makes trial/error fixups
951			 * easier on the user.
952			 */
953			printf("Client%d: bad option %s\n",td->thread_number,p);
954			ret = 1;
955		}
956
957		if (!ret) {
958			fsetpos(f, &off);
959			ret = add_job(td, name, 0);
960		}
961		if (ret)
962			break;
963	}
964
965	free(string);
966	free(name);
967	free(tmpbuf);
968	fclose(f);
969	return ret;
970}
971
972static int fill_def_thread(void)
973{
974	memset(&def_thread, 0, sizeof(def_thread));
975
976	if (fio_getaffinity(getpid(), &def_thread.cpumask) == -1) {
977		perror("sched_getaffinity");
978		return 1;
979	}
980
981	/*
982	 * fill globals
983	 */
984	def_thread.ddir = DDIR_READ;
985	def_thread.iomix = 0;
986	def_thread.bs = DEF_BS;
987	def_thread.min_bs = -1;
988	def_thread.max_bs = -1;
989	def_thread.odirect = DEF_ODIRECT;
990	def_thread.ratecycle = DEF_RATE_CYCLE;
991	def_thread.sequential = DEF_SEQUENTIAL;
992	def_thread.timeout = def_timeout;
993	def_thread.create_file = DEF_CREATE;
994	def_thread.overwrite = DEF_OVERWRITE;
995	def_thread.invalidate_cache = DEF_INVALIDATE;
996	def_thread.sync_io = DEF_SYNCIO;
997	def_thread.mem_type = MEM_MALLOC;
998	def_thread.bw_avg_time = DEF_BWAVGTIME;
999	def_thread.create_serialize = DEF_CREATE_SER;
1000	def_thread.create_fsync = DEF_CREATE_FSYNC;
1001	def_thread.loops = DEF_LOOPS;
1002	def_thread.verify = DEF_VERIFY;
1003	def_thread.stonewall = DEF_STONEWALL;
1004	def_thread.numjobs = DEF_NUMJOBS;
1005	def_thread.use_thread = DEF_USE_THREAD;
1006	def_thread.rwmixcycle = DEF_RWMIX_CYCLE;
1007	def_thread.rwmixread = DEF_RWMIX_READ;
1008	def_thread.nice = DEF_NICE;
1009	def_thread.rand_repeatable = DEF_RAND_REPEAT;
1010#ifdef FIO_HAVE_DISK_UTIL
1011	def_thread.do_disk_util = 1;
1012#endif
1013
1014	return 0;
1015}
1016
1017static void usage(char *name)
1018{
1019	printf("%s\n", fio_version_string);
1020	printf("\t-o Write output to file\n");
1021	printf("\t-t Runtime in seconds\n");
1022	printf("\t-l Generate per-job latency logs\n");
1023	printf("\t-w Generate per-job bandwidth logs\n");
1024	printf("\t-m Minimal (terse) output\n");
1025	printf("\t-v Print version info and exit\n");
1026}
1027
1028static int parse_cmd_line(int argc, char *argv[])
1029{
1030	int c, idx = 1, ini_idx = 0;
1031
1032	while ((c = getopt(argc, argv, "t:o:lwvhm")) != EOF) {
1033		switch (c) {
1034			case 't':
1035				def_timeout = atoi(optarg);
1036				idx = optind;
1037				break;
1038			case 'l':
1039				write_lat_log = 1;
1040				idx = optind;
1041				break;
1042			case 'w':
1043				write_bw_log = 1;
1044				idx = optind;
1045				break;
1046			case 'o':
1047				f_out = fopen(optarg, "w+");
1048				if (!f_out) {
1049					perror("fopen output");
1050					exit(1);
1051				}
1052				f_err = f_out;
1053				idx = optind;
1054				break;
1055			case 'm':
1056				terse_output = 1;
1057				idx = optind;
1058				break;
1059			case 'h':
1060				usage(argv[0]);
1061				exit(0);
1062			case 'v':
1063				printf("%s\n", fio_version_string);
1064				exit(0);
1065		}
1066	}
1067
1068	while (idx < argc) {
1069		ini_idx++;
1070		ini_file = realloc(ini_file, ini_idx * sizeof(char *));
1071		ini_file[ini_idx - 1] = strdup(argv[idx]);
1072		idx++;
1073	}
1074
1075	if (!f_out) {
1076		f_out = stdout;
1077		f_err = stderr;
1078	}
1079
1080	return ini_idx;
1081}
1082
1083static void free_shm(void)
1084{
1085	struct shmid_ds sbuf;
1086
1087	if (threads) {
1088		shmdt((void *) threads);
1089		threads = NULL;
1090		shmctl(shm_id, IPC_RMID, &sbuf);
1091	}
1092}
1093
1094/*
1095 * The thread area is shared between the main process and the job
1096 * threads/processes. So setup a shared memory segment that will hold
1097 * all the job info.
1098 */
1099static int setup_thread_area(void)
1100{
1101	/*
1102	 * 1024 is too much on some machines, scale max_jobs if
1103	 * we get a failure that looks like too large a shm segment
1104	 */
1105	do {
1106		size_t size = max_jobs * sizeof(struct thread_data);
1107
1108		shm_id = shmget(0, size, IPC_CREAT | 0600);
1109		if (shm_id != -1)
1110			break;
1111		if (errno != EINVAL) {
1112			perror("shmget");
1113			break;
1114		}
1115
1116		max_jobs >>= 1;
1117	} while (max_jobs);
1118
1119	if (shm_id == -1)
1120		return 1;
1121
1122	threads = shmat(shm_id, NULL, 0);
1123	if (threads == (void *) -1) {
1124		perror("shmat");
1125		return 1;
1126	}
1127
1128	atexit(free_shm);
1129	return 0;
1130}
1131
1132int parse_options(int argc, char *argv[])
1133{
1134	int job_files, i;
1135
1136	if (setup_thread_area())
1137		return 1;
1138	if (fill_def_thread())
1139		return 1;
1140
1141	job_files = parse_cmd_line(argc, argv);
1142	if (!job_files) {
1143		log_err("Need job file(s)\n");
1144		usage(argv[0]);
1145		return 1;
1146	}
1147
1148	for (i = 0; i < job_files; i++) {
1149		if (fill_def_thread())
1150			return 1;
1151		if (parse_jobs_ini(ini_file[i], i))
1152			return 1;
1153		free(ini_file[i]);
1154	}
1155
1156	free(ini_file);
1157	return 0;
1158}
1159