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