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