init.c revision fca7035863bd570270376a0c06776e5549ff813e
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 <sys/ipc.h>
12#include <sys/shm.h>
13#include <sys/types.h>
14#include <sys/stat.h>
15
16#include "fio.h"
17#include "parse.h"
18#include "smalloc.h"
19#include "filehash.h"
20#include "verify.h"
21#include "profile.h"
22
23#include "lib/getopt.h"
24
25static char fio_version_string[] = "fio 1.55";
26
27#define FIO_RANDSEED		(0xb1899bedUL)
28
29static char **ini_file;
30static int max_jobs = FIO_MAX_JOBS;
31static int dump_cmdline;
32
33static struct thread_data def_thread;
34struct thread_data *threads = NULL;
35
36int exitall_on_terminate = 0;
37int terse_output = 0;
38int eta_print;
39unsigned long long mlock_size = 0;
40FILE *f_out = NULL;
41FILE *f_err = NULL;
42char **job_sections = NULL;
43int nr_job_sections = 0;
44char *exec_profile = NULL;
45int warnings_fatal = 0;
46
47int write_bw_log = 0;
48int read_only = 0;
49
50static int def_timeout;
51static int write_lat_log;
52
53static int prev_group_jobs;
54
55unsigned long fio_debug = 0;
56unsigned int fio_debug_jobno = -1;
57unsigned int *fio_debug_jobp = NULL;
58
59static char cmd_optstr[256];
60
61/*
62 * Command line options. These will contain the above, plus a few
63 * extra that only pertain to fio itself and not jobs.
64 */
65static struct option l_opts[FIO_NR_OPTIONS] = {
66	{
67		.name		= (char *) "output",
68		.has_arg	= required_argument,
69		.val		= 'o',
70	},
71	{
72		.name		= (char *) "timeout",
73		.has_arg	= required_argument,
74		.val		= 't',
75	},
76	{
77		.name		= (char *) "latency-log",
78		.has_arg	= required_argument,
79		.val		= 'l',
80	},
81	{
82		.name		= (char *) "bandwidth-log",
83		.has_arg	= required_argument,
84		.val		= 'b',
85	},
86	{
87		.name		= (char *) "minimal",
88		.has_arg	= optional_argument,
89		.val		= 'm',
90	},
91	{
92		.name		= (char *) "version",
93		.has_arg	= no_argument,
94		.val		= 'v',
95	},
96	{
97		.name		= (char *) "help",
98		.has_arg	= no_argument,
99		.val		= 'h',
100	},
101	{
102		.name		= (char *) "cmdhelp",
103		.has_arg	= optional_argument,
104		.val		= 'c',
105	},
106	{
107		.name		= (char *) "showcmd",
108		.has_arg	= no_argument,
109		.val		= 's',
110	},
111	{
112		.name		= (char *) "readonly",
113		.has_arg	= no_argument,
114		.val		= 'r',
115	},
116	{
117		.name		= (char *) "eta",
118		.has_arg	= required_argument,
119		.val		= 'e',
120	},
121	{
122		.name		= (char *) "debug",
123		.has_arg	= required_argument,
124		.val		= 'd',
125	},
126	{
127		.name		= (char *) "section",
128		.has_arg	= required_argument,
129		.val		= 'x',
130	},
131	{
132		.name		= (char *) "alloc-size",
133		.has_arg	= required_argument,
134		.val		= 'a',
135	},
136	{
137		.name		= (char *) "profile",
138		.has_arg	= required_argument,
139		.val		= 'p',
140	},
141	{
142		.name		= (char *) "warnings-fatal",
143		.has_arg	= no_argument,
144		.val		= 'w',
145	},
146	{
147		.name		= (char *) "max-jobs",
148		.has_arg	= required_argument,
149		.val		= 'j',
150	},
151	{
152		.name		= NULL,
153	},
154};
155
156FILE *get_f_out()
157{
158	return f_out;
159}
160
161FILE *get_f_err()
162{
163	return f_err;
164}
165
166/*
167 * Return a free job structure.
168 */
169static struct thread_data *get_new_job(int global, struct thread_data *parent)
170{
171	struct thread_data *td;
172
173	if (global)
174		return &def_thread;
175	if (thread_number >= max_jobs) {
176		log_err("error: maximum number of jobs (%d) reached.\n",
177				max_jobs);
178		return NULL;
179	}
180
181	td = &threads[thread_number++];
182	*td = *parent;
183
184	td->o.uid = td->o.gid = -1U;
185
186	dup_files(td, parent);
187	options_mem_dupe(td);
188
189	profile_add_hooks(td);
190
191	td->thread_number = thread_number;
192	return td;
193}
194
195static void put_job(struct thread_data *td)
196{
197	if (td == &def_thread)
198		return;
199
200	profile_td_exit(td);
201
202	if (td->error)
203		log_info("fio: %s\n", td->verror);
204
205	memset(&threads[td->thread_number - 1], 0, sizeof(*td));
206	thread_number--;
207}
208
209static int __setup_rate(struct thread_data *td, enum fio_ddir ddir)
210{
211	unsigned int bs = td->o.min_bs[ddir];
212	unsigned long long bytes_per_sec;
213
214	assert(ddir_rw(ddir));
215
216	if (td->o.rate[ddir])
217		bytes_per_sec = td->o.rate[ddir];
218	else
219		bytes_per_sec = td->o.rate_iops[ddir] * bs;
220
221	if (!bytes_per_sec) {
222		log_err("rate lower than supported\n");
223		return -1;
224	}
225
226	td->rate_nsec_cycle[ddir] = 1000000000ULL / bytes_per_sec;
227	td->rate_pending_usleep[ddir] = 0;
228	return 0;
229}
230
231static int setup_rate(struct thread_data *td)
232{
233	int ret = 0;
234
235	if (td->o.rate[DDIR_READ] || td->o.rate_iops[DDIR_READ])
236		ret = __setup_rate(td, DDIR_READ);
237	if (td->o.rate[DDIR_WRITE] || td->o.rate_iops[DDIR_WRITE])
238		ret |= __setup_rate(td, DDIR_WRITE);
239
240	return ret;
241}
242
243static int fixed_block_size(struct thread_options *o)
244{
245	return o->min_bs[DDIR_READ] == o->max_bs[DDIR_READ] &&
246		o->min_bs[DDIR_WRITE] == o->max_bs[DDIR_WRITE] &&
247		o->min_bs[DDIR_READ] == o->min_bs[DDIR_WRITE];
248}
249
250/*
251 * Lazy way of fixing up options that depend on each other. We could also
252 * define option callback handlers, but this is easier.
253 */
254static int fixup_options(struct thread_data *td)
255{
256	struct thread_options *o = &td->o;
257	int ret = 0;
258
259#ifndef FIO_HAVE_PSHARED_MUTEX
260	if (!o->use_thread) {
261		log_info("fio: this platform does not support process shared"
262			 " mutexes, forcing use of threads. Use the 'thread'"
263			 " option to get rid of this warning.\n");
264		o->use_thread = 1;
265		ret = warnings_fatal;
266	}
267#endif
268
269	if (o->write_iolog_file && o->read_iolog_file) {
270		log_err("fio: read iolog overrides write_iolog\n");
271		free(o->write_iolog_file);
272		o->write_iolog_file = NULL;
273		ret = warnings_fatal;
274	}
275
276	/*
277	 * only really works for sequential io for now, and with 1 file
278	 */
279	if (o->zone_size && td_random(td) && o->open_files == 1)
280		o->zone_size = 0;
281
282	/*
283	 * Reads can do overwrites, we always need to pre-create the file
284	 */
285	if (td_read(td) || td_rw(td))
286		o->overwrite = 1;
287
288	if (!o->min_bs[DDIR_READ])
289		o->min_bs[DDIR_READ] = o->bs[DDIR_READ];
290	if (!o->max_bs[DDIR_READ])
291		o->max_bs[DDIR_READ] = o->bs[DDIR_READ];
292	if (!o->min_bs[DDIR_WRITE])
293		o->min_bs[DDIR_WRITE] = o->bs[DDIR_WRITE];
294	if (!o->max_bs[DDIR_WRITE])
295		o->max_bs[DDIR_WRITE] = o->bs[DDIR_WRITE];
296
297	o->rw_min_bs = min(o->min_bs[DDIR_READ], o->min_bs[DDIR_WRITE]);
298
299	/*
300	 * For random IO, allow blockalign offset other than min_bs.
301	 */
302	if (!o->ba[DDIR_READ] || !td_random(td))
303		o->ba[DDIR_READ] = o->min_bs[DDIR_READ];
304	if (!o->ba[DDIR_WRITE] || !td_random(td))
305		o->ba[DDIR_WRITE] = o->min_bs[DDIR_WRITE];
306
307	if ((o->ba[DDIR_READ] != o->min_bs[DDIR_READ] ||
308	    o->ba[DDIR_WRITE] != o->min_bs[DDIR_WRITE]) &&
309	    !o->norandommap) {
310		log_err("fio: Any use of blockalign= turns off randommap\n");
311		o->norandommap = 1;
312		ret = warnings_fatal;
313	}
314
315	if (!o->file_size_high)
316		o->file_size_high = o->file_size_low;
317
318	if (o->norandommap && o->verify != VERIFY_NONE
319	    && !fixed_block_size(o))  {
320		log_err("fio: norandommap given for variable block sizes, "
321			"verify disabled\n");
322		o->verify = VERIFY_NONE;
323		ret = warnings_fatal;
324	}
325	if (o->bs_unaligned && (o->odirect || td->io_ops->flags & FIO_RAWIO))
326		log_err("fio: bs_unaligned may not work with raw io\n");
327
328	/*
329	 * thinktime_spin must be less than thinktime
330	 */
331	if (o->thinktime_spin > o->thinktime)
332		o->thinktime_spin = o->thinktime;
333
334	/*
335	 * The low water mark cannot be bigger than the iodepth
336	 */
337	if (o->iodepth_low > o->iodepth || !o->iodepth_low) {
338		/*
339		 * syslet work around - if the workload is sequential,
340		 * we want to let the queue drain all the way down to
341		 * avoid seeking between async threads
342		 */
343		if (!strcmp(td->io_ops->name, "syslet-rw") && !td_random(td))
344			o->iodepth_low = 1;
345		else
346			o->iodepth_low = o->iodepth;
347	}
348
349	/*
350	 * If batch number isn't set, default to the same as iodepth
351	 */
352	if (o->iodepth_batch > o->iodepth || !o->iodepth_batch)
353		o->iodepth_batch = o->iodepth;
354
355	if (o->nr_files > td->files_index)
356		o->nr_files = td->files_index;
357
358	if (o->open_files > o->nr_files || !o->open_files)
359		o->open_files = o->nr_files;
360
361	if (((o->rate[0] + o->rate[1]) && (o->rate_iops[0] + o->rate_iops[1]))||
362	    ((o->ratemin[0] + o->ratemin[1]) && (o->rate_iops_min[0] +
363		o->rate_iops_min[1]))) {
364		log_err("fio: rate and rate_iops are mutually exclusive\n");
365		ret = 1;
366	}
367	if ((o->rate[0] < o->ratemin[0]) || (o->rate[1] < o->ratemin[1]) ||
368	    (o->rate_iops[0] < o->rate_iops_min[0]) ||
369	    (o->rate_iops[1] < o->rate_iops_min[1])) {
370		log_err("fio: minimum rate exceeds rate\n");
371		ret = 1;
372	}
373
374	if (!o->timeout && o->time_based) {
375		log_err("fio: time_based requires a runtime/timeout setting\n");
376		o->time_based = 0;
377		ret = warnings_fatal;
378	}
379
380	if (o->fill_device && !o->size)
381		o->size = -1ULL;
382
383	if (o->verify != VERIFY_NONE) {
384		if (td_write(td) && o->do_verify && o->numjobs > 1) {
385			log_info("Multiple writers may overwrite blocks that "
386				"belong to other jobs. This can cause "
387				"verification failures.\n");
388			ret = warnings_fatal;
389		}
390
391		o->refill_buffers = 1;
392		if (o->max_bs[DDIR_WRITE] != o->min_bs[DDIR_WRITE] &&
393		    !o->verify_interval)
394			o->verify_interval = o->min_bs[DDIR_WRITE];
395	}
396
397	if (o->pre_read) {
398		o->invalidate_cache = 0;
399		if (td->io_ops->flags & FIO_PIPEIO) {
400			log_info("fio: cannot pre-read files with an IO engine"
401				 " that isn't seekable. Pre-read disabled.\n");
402			ret = warnings_fatal;
403		}
404	}
405
406#ifndef FIO_HAVE_FDATASYNC
407	if (o->fdatasync_blocks) {
408		log_info("fio: this platform does not support fdatasync()"
409			 " falling back to using fsync().  Use the 'fsync'"
410			 " option instead of 'fdatasync' to get rid of"
411			 " this warning\n");
412		o->fsync_blocks = o->fdatasync_blocks;
413		o->fdatasync_blocks = 0;
414		ret = warnings_fatal;
415	}
416#endif
417
418	return ret;
419}
420
421/*
422 * This function leaks the buffer
423 */
424static char *to_kmg(unsigned int val)
425{
426	char *buf = malloc(32);
427	char post[] = { 0, 'K', 'M', 'G', 'P', 'E', 0 };
428	char *p = post;
429
430	do {
431		if (val & 1023)
432			break;
433
434		val >>= 10;
435		p++;
436	} while (*p);
437
438	snprintf(buf, 31, "%u%c", val, *p);
439	return buf;
440}
441
442/* External engines are specified by "external:name.o") */
443static const char *get_engine_name(const char *str)
444{
445	char *p = strstr(str, ":");
446
447	if (!p)
448		return str;
449
450	p++;
451	strip_blank_front(&p);
452	strip_blank_end(p);
453	return p;
454}
455
456static int exists_and_not_file(const char *filename)
457{
458	struct stat sb;
459
460	if (lstat(filename, &sb) == -1)
461		return 0;
462
463	/* \\.\ is the device namespace in Windows, where every file
464	 * is a device node */
465	if (S_ISREG(sb.st_mode) && strncmp(filename, "\\\\.\\", 4) != 0)
466		return 0;
467
468	return 1;
469}
470
471static void td_fill_rand_seeds_os(struct thread_data *td)
472{
473	os_random_seed(td->rand_seeds[0], &td->bsrange_state);
474	os_random_seed(td->rand_seeds[1], &td->verify_state);
475	os_random_seed(td->rand_seeds[2], &td->rwmix_state);
476
477	if (td->o.file_service_type == FIO_FSERVICE_RANDOM)
478		os_random_seed(td->rand_seeds[3], &td->next_file_state);
479
480	os_random_seed(td->rand_seeds[5], &td->file_size_state);
481	os_random_seed(td->rand_seeds[6], &td->trim_state);
482
483	if (!td_random(td))
484		return;
485
486	if (td->o.rand_repeatable)
487		td->rand_seeds[4] = FIO_RANDSEED * td->thread_number;
488
489	os_random_seed(td->rand_seeds[4], &td->random_state);
490}
491
492static void td_fill_rand_seeds_internal(struct thread_data *td)
493{
494	init_rand_seed(&td->__bsrange_state, td->rand_seeds[0]);
495	init_rand_seed(&td->__verify_state, td->rand_seeds[1]);
496	init_rand_seed(&td->__rwmix_state, td->rand_seeds[2]);
497
498	if (td->o.file_service_type == FIO_FSERVICE_RANDOM)
499		init_rand_seed(&td->__next_file_state, td->rand_seeds[3]);
500
501	init_rand_seed(&td->__file_size_state, td->rand_seeds[5]);
502	init_rand_seed(&td->__trim_state, td->rand_seeds[6]);
503
504	if (!td_random(td))
505		return;
506
507	if (td->o.rand_repeatable)
508		td->rand_seeds[4] = FIO_RANDSEED * td->thread_number;
509
510	init_rand_seed(&td->__random_state, td->rand_seeds[4]);
511}
512
513void td_fill_rand_seeds(struct thread_data *td)
514{
515	if (td->o.use_os_rand)
516		td_fill_rand_seeds_os(td);
517	else
518		td_fill_rand_seeds_internal(td);
519}
520
521/*
522 * Initialize the various random states we need (random io, block size ranges,
523 * read/write mix, etc).
524 */
525static int init_random_state(struct thread_data *td)
526{
527	int fd;
528
529	fd = open("/dev/urandom", O_RDONLY);
530	if (fd == -1) {
531		td_verror(td, errno, "open");
532		return 1;
533	}
534
535	if (read(fd, td->rand_seeds, sizeof(td->rand_seeds)) <
536	    (int) sizeof(td->rand_seeds)) {
537		td_verror(td, EIO, "read");
538		close(fd);
539		return 1;
540	}
541
542	close(fd);
543	td_fill_rand_seeds(td);
544	return 0;
545}
546
547/*
548 * Adds a job to the list of things todo. Sanitizes the various options
549 * to make sure we don't have conflicts, and initializes various
550 * members of td.
551 */
552static int add_job(struct thread_data *td, const char *jobname, int job_add_num)
553{
554	const char *ddir_str[] = { NULL, "read", "write", "rw", NULL,
555				   "randread", "randwrite", "randrw" };
556	unsigned int i;
557	const char *engine;
558	char fname[PATH_MAX];
559	int numjobs, file_alloced;
560
561	/*
562	 * the def_thread is just for options, it's not a real job
563	 */
564	if (td == &def_thread)
565		return 0;
566
567	/*
568	 * if we are just dumping the output command line, don't add the job
569	 */
570	if (dump_cmdline) {
571		put_job(td);
572		return 0;
573	}
574
575	if (profile_td_init(td))
576		goto err;
577
578	engine = get_engine_name(td->o.ioengine);
579	td->io_ops = load_ioengine(td, engine);
580	if (!td->io_ops) {
581		log_err("fio: failed to load engine %s\n", engine);
582		goto err;
583	}
584
585	if (td->o.use_thread)
586		nr_thread++;
587	else
588		nr_process++;
589
590	if (td->o.odirect)
591		td->io_ops->flags |= FIO_RAWIO;
592
593	file_alloced = 0;
594	if (!td->o.filename && !td->files_index && !td->o.read_iolog_file) {
595		file_alloced = 1;
596
597		if (td->o.nr_files == 1 && exists_and_not_file(jobname))
598			add_file(td, jobname);
599		else {
600			for (i = 0; i < td->o.nr_files; i++) {
601				sprintf(fname, "%s.%d.%d", jobname,
602							td->thread_number, i);
603				add_file(td, fname);
604			}
605		}
606	}
607
608	if (fixup_options(td))
609		goto err;
610
611	if (td->io_ops->flags & FIO_DISKLESSIO) {
612		struct fio_file *f;
613
614		for_each_file(td, f, i)
615			f->real_file_size = -1ULL;
616	}
617
618	td->mutex = fio_mutex_init(0);
619
620	td->ts.clat_stat[0].min_val = td->ts.clat_stat[1].min_val = ULONG_MAX;
621	td->ts.slat_stat[0].min_val = td->ts.slat_stat[1].min_val = ULONG_MAX;
622	td->ts.lat_stat[0].min_val = td->ts.lat_stat[1].min_val = ULONG_MAX;
623	td->ts.bw_stat[0].min_val = td->ts.bw_stat[1].min_val = ULONG_MAX;
624	td->ddir_seq_nr = td->o.ddir_seq_nr;
625
626	if ((td->o.stonewall || td->o.new_group) && prev_group_jobs) {
627		prev_group_jobs = 0;
628		groupid++;
629	}
630
631	td->groupid = groupid;
632	prev_group_jobs++;
633
634	if (init_random_state(td))
635		goto err;
636
637	if (setup_rate(td))
638		goto err;
639
640	if (td->o.write_lat_log) {
641		setup_log(&td->ts.lat_log);
642		setup_log(&td->ts.slat_log);
643		setup_log(&td->ts.clat_log);
644	}
645	if (td->o.write_bw_log)
646		setup_log(&td->ts.bw_log);
647
648	if (!td->o.name)
649		td->o.name = strdup(jobname);
650
651	if (!terse_output) {
652		if (!job_add_num) {
653			if (!strcmp(td->io_ops->name, "cpuio")) {
654				log_info("%s: ioengine=cpu, cpuload=%u,"
655					 " cpucycle=%u\n", td->o.name,
656							td->o.cpuload,
657							td->o.cpucycle);
658			} else {
659				char *c1, *c2, *c3, *c4;
660
661				c1 = to_kmg(td->o.min_bs[DDIR_READ]);
662				c2 = to_kmg(td->o.max_bs[DDIR_READ]);
663				c3 = to_kmg(td->o.min_bs[DDIR_WRITE]);
664				c4 = to_kmg(td->o.max_bs[DDIR_WRITE]);
665
666				log_info("%s: (g=%d): rw=%s, bs=%s-%s/%s-%s,"
667					 " ioengine=%s, iodepth=%u\n",
668						td->o.name, td->groupid,
669						ddir_str[td->o.td_ddir],
670						c1, c2, c3, c4,
671						td->io_ops->name,
672						td->o.iodepth);
673
674				free(c1);
675				free(c2);
676				free(c3);
677				free(c4);
678			}
679		} else if (job_add_num == 1)
680			log_info("...\n");
681	}
682
683	/*
684	 * recurse add identical jobs, clear numjobs and stonewall options
685	 * as they don't apply to sub-jobs
686	 */
687	numjobs = td->o.numjobs;
688	while (--numjobs) {
689		struct thread_data *td_new = get_new_job(0, td);
690
691		if (!td_new)
692			goto err;
693
694		td_new->o.numjobs = 1;
695		td_new->o.stonewall = 0;
696		td_new->o.new_group = 0;
697
698		if (file_alloced) {
699			td_new->o.filename = NULL;
700			td_new->files_index = 0;
701			td_new->files_size = 0;
702			td_new->files = NULL;
703		}
704
705		job_add_num = numjobs - 1;
706
707		if (add_job(td_new, jobname, job_add_num))
708			goto err;
709	}
710
711	return 0;
712err:
713	put_job(td);
714	return -1;
715}
716
717/*
718 * Parse as if 'o' was a command line
719 */
720void add_job_opts(const char **o)
721{
722	struct thread_data *td, *td_parent;
723	int i, in_global = 1;
724	char jobname[32];
725
726	i = 0;
727	td_parent = td = NULL;
728	while (o[i]) {
729		if (!strncmp(o[i], "name", 4)) {
730			in_global = 0;
731			if (td)
732				add_job(td, jobname, 0);
733			td = NULL;
734			sprintf(jobname, "%s", o[i] + 5);
735		}
736		if (in_global && !td_parent)
737			td_parent = get_new_job(1, &def_thread);
738		else if (!in_global && !td) {
739			if (!td_parent)
740				td_parent = &def_thread;
741			td = get_new_job(0, td_parent);
742		}
743		if (in_global)
744			fio_options_parse(td_parent, (char **) &o[i], 1);
745		else
746			fio_options_parse(td, (char **) &o[i], 1);
747		i++;
748	}
749
750	if (td)
751		add_job(td, jobname, 0);
752}
753
754static int skip_this_section(const char *name)
755{
756	int i;
757
758	if (!nr_job_sections)
759		return 0;
760	if (!strncmp(name, "global", 6))
761		return 0;
762
763	for (i = 0; i < nr_job_sections; i++)
764		if (!strcmp(job_sections[i], name))
765			return 0;
766
767	return 1;
768}
769
770static int is_empty_or_comment(char *line)
771{
772	unsigned int i;
773
774	for (i = 0; i < strlen(line); i++) {
775		if (line[i] == ';')
776			return 1;
777		if (line[i] == '#')
778			return 1;
779		if (!isspace(line[i]) && !iscntrl(line[i]))
780			return 0;
781	}
782
783	return 1;
784}
785
786/*
787 * This is our [ini] type file parser.
788 */
789static int parse_jobs_ini(char *file, int stonewall_flag)
790{
791	unsigned int global;
792	struct thread_data *td;
793	char *string, *name;
794	FILE *f;
795	char *p;
796	int ret = 0, stonewall;
797	int first_sect = 1;
798	int skip_fgets = 0;
799	int inside_skip = 0;
800	char **opts;
801	int i, alloc_opts, num_opts;
802
803	if (!strcmp(file, "-"))
804		f = stdin;
805	else
806		f = fopen(file, "r");
807
808	if (!f) {
809		perror("fopen job file");
810		return 1;
811	}
812
813	string = malloc(4096);
814
815	/*
816	 * it's really 256 + small bit, 280 should suffice
817	 */
818	name = malloc(280);
819	memset(name, 0, 280);
820
821	alloc_opts = 8;
822	opts = malloc(sizeof(char *) * alloc_opts);
823	num_opts = 0;
824
825	stonewall = stonewall_flag;
826	do {
827		/*
828		 * if skip_fgets is set, we already have loaded a line we
829		 * haven't handled.
830		 */
831		if (!skip_fgets) {
832			p = fgets(string, 4095, f);
833			if (!p)
834				break;
835		}
836
837		skip_fgets = 0;
838		strip_blank_front(&p);
839		strip_blank_end(p);
840
841		if (is_empty_or_comment(p))
842			continue;
843		if (sscanf(p, "[%255[^\n]]", name) != 1) {
844			if (inside_skip)
845				continue;
846			log_err("fio: option <%s> outside of [] job section\n",
847									p);
848			break;
849		}
850
851		name[strlen(name) - 1] = '\0';
852
853		if (skip_this_section(name)) {
854			inside_skip = 1;
855			continue;
856		} else
857			inside_skip = 0;
858
859		global = !strncmp(name, "global", 6);
860
861		if (dump_cmdline) {
862			if (first_sect)
863				log_info("fio ");
864			if (!global)
865				log_info("--name=%s ", name);
866			first_sect = 0;
867		}
868
869		td = get_new_job(global, &def_thread);
870		if (!td) {
871			ret = 1;
872			break;
873		}
874
875		/*
876		 * Seperate multiple job files by a stonewall
877		 */
878		if (!global && stonewall) {
879			td->o.stonewall = stonewall;
880			stonewall = 0;
881		}
882
883		num_opts = 0;
884		memset(opts, 0, alloc_opts * sizeof(char *));
885
886		while ((p = fgets(string, 4096, f)) != NULL) {
887			if (is_empty_or_comment(p))
888				continue;
889
890			strip_blank_front(&p);
891
892			/*
893			 * new section, break out and make sure we don't
894			 * fgets() a new line at the top.
895			 */
896			if (p[0] == '[') {
897				skip_fgets = 1;
898				break;
899			}
900
901			strip_blank_end(p);
902
903			if (num_opts == alloc_opts) {
904				alloc_opts <<= 1;
905				opts = realloc(opts,
906						alloc_opts * sizeof(char *));
907			}
908
909			opts[num_opts] = strdup(p);
910			num_opts++;
911		}
912
913		ret = fio_options_parse(td, opts, num_opts);
914		if (!ret) {
915			if (dump_cmdline)
916				for (i = 0; i < num_opts; i++)
917					log_info("--%s ", opts[i]);
918
919			ret = add_job(td, name, 0);
920		} else {
921			log_err("fio: job %s dropped\n", name);
922			put_job(td);
923		}
924
925		for (i = 0; i < num_opts; i++)
926			free(opts[i]);
927		num_opts = 0;
928	} while (!ret);
929
930	if (dump_cmdline)
931		log_info("\n");
932
933	for (i = 0; i < num_opts; i++)
934		free(opts[i]);
935
936	free(string);
937	free(name);
938	free(opts);
939	if (f != stdin)
940		fclose(f);
941	return ret;
942}
943
944static int fill_def_thread(void)
945{
946	memset(&def_thread, 0, sizeof(def_thread));
947
948	fio_getaffinity(getpid(), &def_thread.o.cpumask);
949
950	/*
951	 * fill default options
952	 */
953	fio_fill_default_options(&def_thread);
954
955	def_thread.o.timeout = def_timeout;
956	return 0;
957}
958
959static void free_shm(void)
960{
961	struct shmid_ds sbuf;
962
963	if (threads) {
964		void *tp = threads;
965
966		threads = NULL;
967		file_hash_exit();
968		fio_debug_jobp = NULL;
969		shmdt(tp);
970		shmctl(shm_id, IPC_RMID, &sbuf);
971	}
972
973	scleanup();
974}
975
976/*
977 * The thread area is shared between the main process and the job
978 * threads/processes. So setup a shared memory segment that will hold
979 * all the job info. We use the end of the region for keeping track of
980 * open files across jobs, for file sharing.
981 */
982static int setup_thread_area(void)
983{
984	void *hash;
985
986	/*
987	 * 1024 is too much on some machines, scale max_jobs if
988	 * we get a failure that looks like too large a shm segment
989	 */
990	do {
991		size_t size = max_jobs * sizeof(struct thread_data);
992
993		size += file_hash_size;
994		size += sizeof(unsigned int);
995
996		shm_id = shmget(0, size, IPC_CREAT | 0600);
997		if (shm_id != -1)
998			break;
999		if (errno != EINVAL) {
1000			perror("shmget");
1001			break;
1002		}
1003
1004		max_jobs >>= 1;
1005	} while (max_jobs);
1006
1007	if (shm_id == -1)
1008		return 1;
1009
1010	threads = shmat(shm_id, NULL, 0);
1011	if (threads == (void *) -1) {
1012		perror("shmat");
1013		return 1;
1014	}
1015
1016	memset(threads, 0, max_jobs * sizeof(struct thread_data));
1017	hash = (void *) threads + max_jobs * sizeof(struct thread_data);
1018	fio_debug_jobp = (void *) hash + file_hash_size;
1019	*fio_debug_jobp = -1;
1020	file_hash_init(hash);
1021	atexit(free_shm);
1022	return 0;
1023}
1024
1025static void usage(const char *name)
1026{
1027	printf("%s [options] [job options] <job file(s)>\n", name);
1028	printf("\t--debug=options\tEnable debug logging\n");
1029	printf("\t--output\tWrite output to file\n");
1030	printf("\t--timeout\tRuntime in seconds\n");
1031	printf("\t--latency-log\tGenerate per-job latency logs\n");
1032	printf("\t--bandwidth-log\tGenerate per-job bandwidth logs\n");
1033	printf("\t--minimal\tMinimal (terse) output\n");
1034	printf("\t--version\tPrint version info and exit\n");
1035	printf("\t--help\t\tPrint this page\n");
1036	printf("\t--cmdhelp=cmd\tPrint command help, \"all\" for all of"
1037		" them\n");
1038	printf("\t--showcmd\tTurn a job file into command line options\n");
1039	printf("\t--eta=when\tWhen ETA estimate should be printed\n");
1040	printf("\t          \tMay be \"always\", \"never\" or \"auto\"\n");
1041	printf("\t--readonly\tTurn on safety read-only checks, preventing"
1042		" writes\n");
1043	printf("\t--section=name\tOnly run specified section in job file\n");
1044	printf("\t--alloc-size=kb\tSet smalloc pool to this size in kb"
1045		" (def 1024)\n");
1046	printf("\t--warnings-fatal Fio parser warnings are fatal\n");
1047	printf("\t--max-jobs\tMaximum number of threads/processes to support\n");
1048	printf("\nFio was written by Jens Axboe <jens.axboe@oracle.com>");
1049	printf("\n                   Jens Axboe <jaxboe@fusionio.com>\n");
1050}
1051
1052#ifdef FIO_INC_DEBUG
1053struct debug_level debug_levels[] = {
1054	{ .name = "process",	.shift = FD_PROCESS, },
1055	{ .name = "file",	.shift = FD_FILE, },
1056	{ .name = "io",		.shift = FD_IO, },
1057	{ .name = "mem",	.shift = FD_MEM, },
1058	{ .name = "blktrace",	.shift = FD_BLKTRACE },
1059	{ .name = "verify",	.shift = FD_VERIFY },
1060	{ .name = "random",	.shift = FD_RANDOM },
1061	{ .name = "parse",	.shift = FD_PARSE },
1062	{ .name = "diskutil",	.shift = FD_DISKUTIL },
1063	{ .name = "job",	.shift = FD_JOB },
1064	{ .name = "mutex",	.shift = FD_MUTEX },
1065	{ .name	= "profile",	.shift = FD_PROFILE },
1066	{ .name = "time",	.shift = FD_TIME },
1067	{ .name = NULL, },
1068};
1069
1070static int set_debug(const char *string)
1071{
1072	struct debug_level *dl;
1073	char *p = (char *) string;
1074	char *opt;
1075	int i;
1076
1077	if (!strcmp(string, "?") || !strcmp(string, "help")) {
1078		log_info("fio: dumping debug options:");
1079		for (i = 0; debug_levels[i].name; i++) {
1080			dl = &debug_levels[i];
1081			log_info("%s,", dl->name);
1082		}
1083		log_info("all\n");
1084		return 1;
1085	}
1086
1087	while ((opt = strsep(&p, ",")) != NULL) {
1088		int found = 0;
1089
1090		if (!strncmp(opt, "all", 3)) {
1091			log_info("fio: set all debug options\n");
1092			fio_debug = ~0UL;
1093			continue;
1094		}
1095
1096		for (i = 0; debug_levels[i].name; i++) {
1097			dl = &debug_levels[i];
1098			found = !strncmp(opt, dl->name, strlen(dl->name));
1099			if (!found)
1100				continue;
1101
1102			if (dl->shift == FD_JOB) {
1103				opt = strchr(opt, ':');
1104				if (!opt) {
1105					log_err("fio: missing job number\n");
1106					break;
1107				}
1108				opt++;
1109				fio_debug_jobno = atoi(opt);
1110				log_info("fio: set debug jobno %d\n",
1111							fio_debug_jobno);
1112			} else {
1113				log_info("fio: set debug option %s\n", opt);
1114				fio_debug |= (1UL << dl->shift);
1115			}
1116			break;
1117		}
1118
1119		if (!found)
1120			log_err("fio: debug mask %s not found\n", opt);
1121	}
1122	return 0;
1123}
1124#else
1125static int set_debug(const char *string)
1126{
1127	log_err("fio: debug tracing not included in build\n");
1128	return 1;
1129}
1130#endif
1131
1132static void fio_options_fill_optstring(void)
1133{
1134	char *ostr = cmd_optstr;
1135	int i, c;
1136
1137	c = i = 0;
1138	while (l_opts[i].name) {
1139		ostr[c++] = l_opts[i].val;
1140		if (l_opts[i].has_arg == required_argument)
1141			ostr[c++] = ':';
1142		else if (l_opts[i].has_arg == optional_argument) {
1143			ostr[c++] = ':';
1144			ostr[c++] = ':';
1145		}
1146		i++;
1147	}
1148	ostr[c] = '\0';
1149}
1150
1151static int parse_cmd_line(int argc, char *argv[])
1152{
1153	struct thread_data *td = NULL;
1154	int c, ini_idx = 0, lidx, ret = 0, do_exit = 0, exit_val = 0;
1155	char *ostr = cmd_optstr;
1156
1157	while ((c = getopt_long_only(argc, argv, ostr, l_opts, &lidx)) != -1) {
1158		switch (c) {
1159		case 'a':
1160			smalloc_pool_size = atoi(optarg);
1161			break;
1162		case 't':
1163			def_timeout = atoi(optarg);
1164			break;
1165		case 'l':
1166			write_lat_log = 1;
1167			break;
1168		case 'b':
1169			write_bw_log = 1;
1170			break;
1171		case 'o':
1172			f_out = fopen(optarg, "w+");
1173			if (!f_out) {
1174				perror("fopen output");
1175				exit(1);
1176			}
1177			f_err = f_out;
1178			break;
1179		case 'm':
1180			terse_output = 1;
1181			break;
1182		case 'h':
1183			usage(argv[0]);
1184			exit(0);
1185		case 'c':
1186			exit(fio_show_option_help(optarg));
1187		case 's':
1188			dump_cmdline = 1;
1189			break;
1190		case 'r':
1191			read_only = 1;
1192			break;
1193		case 'v':
1194			log_info("%s\n", fio_version_string);
1195			exit(0);
1196		case 'e':
1197			if (!strcmp("always", optarg))
1198				eta_print = FIO_ETA_ALWAYS;
1199			else if (!strcmp("never", optarg))
1200				eta_print = FIO_ETA_NEVER;
1201			break;
1202		case 'd':
1203			if (set_debug(optarg))
1204				do_exit++;
1205			break;
1206		case 'x': {
1207			size_t new_size;
1208
1209			if (!strcmp(optarg, "global")) {
1210				log_err("fio: can't use global as only "
1211					"section\n");
1212				do_exit++;
1213				exit_val = 1;
1214				break;
1215			}
1216			new_size = (nr_job_sections + 1) * sizeof(char *);
1217			job_sections = realloc(job_sections, new_size);
1218			job_sections[nr_job_sections] = strdup(optarg);
1219			nr_job_sections++;
1220			break;
1221			}
1222		case 'p':
1223			exec_profile = strdup(optarg);
1224			break;
1225		case FIO_GETOPT_JOB: {
1226			const char *opt = l_opts[lidx].name;
1227			char *val = optarg;
1228
1229			if (!strncmp(opt, "name", 4) && td) {
1230				ret = add_job(td, td->o.name ?: "fio", 0);
1231				if (ret)
1232					return 0;
1233				td = NULL;
1234			}
1235			if (!td) {
1236				int is_section = !strncmp(opt, "name", 4);
1237				int global = 0;
1238
1239				if (!is_section || !strncmp(val, "global", 6))
1240					global = 1;
1241
1242				if (is_section && skip_this_section(val))
1243					continue;
1244
1245				td = get_new_job(global, &def_thread);
1246				if (!td)
1247					return 0;
1248			}
1249
1250			ret = fio_cmd_option_parse(td, opt, val);
1251			break;
1252		}
1253		case 'w':
1254			warnings_fatal = 1;
1255			break;
1256		case 'j':
1257			max_jobs = atoi(optarg);
1258			if (!max_jobs || max_jobs > REAL_MAX_JOBS) {
1259				log_err("fio: invalid max jobs: %d\n", max_jobs);
1260				do_exit++;
1261				exit_val = 1;
1262			}
1263			break;
1264		default:
1265			do_exit++;
1266			exit_val = 1;
1267			break;
1268		}
1269	}
1270
1271	if (do_exit)
1272		exit(exit_val);
1273
1274	if (td) {
1275		if (!ret)
1276			ret = add_job(td, td->o.name ?: "fio", 0);
1277	}
1278
1279	while (optind < argc) {
1280		ini_idx++;
1281		ini_file = realloc(ini_file, ini_idx * sizeof(char *));
1282		ini_file[ini_idx - 1] = strdup(argv[optind]);
1283		optind++;
1284	}
1285
1286	return ini_idx;
1287}
1288
1289int parse_options(int argc, char *argv[])
1290{
1291	int job_files, i;
1292
1293	f_out = stdout;
1294	f_err = stderr;
1295
1296	fio_options_fill_optstring();
1297	fio_options_dup_and_init(l_opts);
1298
1299	if (setup_thread_area())
1300		return 1;
1301	if (fill_def_thread())
1302		return 1;
1303
1304	job_files = parse_cmd_line(argc, argv);
1305
1306	for (i = 0; i < job_files; i++) {
1307		if (fill_def_thread())
1308			return 1;
1309		if (parse_jobs_ini(ini_file[i], i))
1310			return 1;
1311		free(ini_file[i]);
1312	}
1313
1314	free(ini_file);
1315	options_mem_free(&def_thread);
1316
1317	if (!thread_number) {
1318		if (dump_cmdline)
1319			return 0;
1320		if (exec_profile)
1321			return 0;
1322
1323		log_err("No jobs(s) defined\n\n");
1324		usage(argv[0]);
1325		return 1;
1326	}
1327
1328	if (def_thread.o.gtod_offload) {
1329		fio_gtod_init();
1330		fio_gtod_offload = 1;
1331		fio_gtod_cpu = def_thread.o.gtod_cpu;
1332	}
1333
1334	log_info("%s\n", fio_version_string);
1335	return 0;
1336}
1337