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