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