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