init.c revision 2bb3f0a7e00d3d62943b0bcc8119ab81c157c349
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * This file contains job initialization and setup functions. 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdio.h> 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdlib.h> 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <unistd.h> 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <fcntl.h> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <ctype.h> 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string.h> 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <errno.h> 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/ipc.h> 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/shm.h> 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/types.h> 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/stat.h> 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "fio.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "parse.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "smalloc.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "filehash.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "verify.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "profile.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "server.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "lib/getopt.h" 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "fio_version.h" 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char fio_version_string[] = FIO_VERSION; 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define FIO_RANDSEED (0xb1899bedUL) 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static char **ini_file; 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int max_jobs = FIO_MAX_JOBS; 34static int dump_cmdline; 35static int def_timeout; 36 37static struct thread_data def_thread; 38struct thread_data *threads = NULL; 39 40int exitall_on_terminate = 0; 41int terse_output = 0; 42int eta_print; 43unsigned long long mlock_size = 0; 44FILE *f_out = NULL; 45FILE *f_err = NULL; 46char **job_sections = NULL; 47int nr_job_sections = 0; 48char *exec_profile = NULL; 49int warnings_fatal = 0; 50int terse_version = 3; 51int is_backend = 0; 52int nr_clients = 0; 53int log_syslog = 0; 54 55int write_bw_log = 0; 56int read_only = 0; 57 58static int write_lat_log; 59 60static int prev_group_jobs; 61 62unsigned long fio_debug = 0; 63unsigned int fio_debug_jobno = -1; 64unsigned int *fio_debug_jobp = NULL; 65 66static char cmd_optstr[256]; 67static int did_arg; 68 69const fio_fp64_t def_percentile_list[FIO_IO_U_LIST_MAX_LEN] = { 70 { .u.f = 1.00 }, 71 { .u.f = 5.00 }, 72 { .u.f = 10.00 }, 73 { .u.f = 20.00 }, 74 { .u.f = 30.00 }, 75 { .u.f = 40.00 }, 76 { .u.f = 50.00 }, 77 { .u.f = 60.00 }, 78 { .u.f = 70.00 }, 79 { .u.f = 80.00 }, 80 { .u.f = 90.00 }, 81 { .u.f = 95.00 }, 82 { .u.f = 99.00 }, 83 { .u.f = 99.50 }, 84 { .u.f = 99.90 }, 85 { .u.f = 99.95 }, 86 { .u.f = 99.99 }, 87}; 88 89#define FIO_CLIENT_FLAG (1 << 16) 90 91/* 92 * Command line options. These will contain the above, plus a few 93 * extra that only pertain to fio itself and not jobs. 94 */ 95static struct option l_opts[FIO_NR_OPTIONS] = { 96 { 97 .name = (char *) "output", 98 .has_arg = required_argument, 99 .val = 'o' | FIO_CLIENT_FLAG, 100 }, 101 { 102 .name = (char *) "timeout", 103 .has_arg = required_argument, 104 .val = 't' | FIO_CLIENT_FLAG, 105 }, 106 { 107 .name = (char *) "latency-log", 108 .has_arg = required_argument, 109 .val = 'l' | FIO_CLIENT_FLAG, 110 }, 111 { 112 .name = (char *) "bandwidth-log", 113 .has_arg = required_argument, 114 .val = 'b' | FIO_CLIENT_FLAG, 115 }, 116 { 117 .name = (char *) "minimal", 118 .has_arg = optional_argument, 119 .val = 'm' | FIO_CLIENT_FLAG, 120 }, 121 { 122 .name = (char *) "version", 123 .has_arg = no_argument, 124 .val = 'v' | FIO_CLIENT_FLAG, 125 }, 126 { 127 .name = (char *) "help", 128 .has_arg = no_argument, 129 .val = 'h' | FIO_CLIENT_FLAG, 130 }, 131 { 132 .name = (char *) "cmdhelp", 133 .has_arg = optional_argument, 134 .val = 'c' | FIO_CLIENT_FLAG, 135 }, 136 { 137 .name = (char *) "enghelp", 138 .has_arg = optional_argument, 139 .val = 'i' | FIO_CLIENT_FLAG, 140 }, 141 { 142 .name = (char *) "showcmd", 143 .has_arg = no_argument, 144 .val = 's' | FIO_CLIENT_FLAG, 145 }, 146 { 147 .name = (char *) "readonly", 148 .has_arg = no_argument, 149 .val = 'r' | FIO_CLIENT_FLAG, 150 }, 151 { 152 .name = (char *) "eta", 153 .has_arg = required_argument, 154 .val = 'e' | FIO_CLIENT_FLAG, 155 }, 156 { 157 .name = (char *) "debug", 158 .has_arg = required_argument, 159 .val = 'd' | FIO_CLIENT_FLAG, 160 }, 161 { 162 .name = (char *) "section", 163 .has_arg = required_argument, 164 .val = 'x' | FIO_CLIENT_FLAG, 165 }, 166 { 167 .name = (char *) "alloc-size", 168 .has_arg = required_argument, 169 .val = 'a' | FIO_CLIENT_FLAG, 170 }, 171 { 172 .name = (char *) "profile", 173 .has_arg = required_argument, 174 .val = 'p' | FIO_CLIENT_FLAG, 175 }, 176 { 177 .name = (char *) "warnings-fatal", 178 .has_arg = no_argument, 179 .val = 'w' | FIO_CLIENT_FLAG, 180 }, 181 { 182 .name = (char *) "max-jobs", 183 .has_arg = required_argument, 184 .val = 'j' | FIO_CLIENT_FLAG, 185 }, 186 { 187 .name = (char *) "terse-version", 188 .has_arg = required_argument, 189 .val = 'V' | FIO_CLIENT_FLAG, 190 }, 191 { 192 .name = (char *) "server", 193 .has_arg = optional_argument, 194 .val = 'S', 195 }, 196 { .name = (char *) "daemonize", 197 .has_arg = required_argument, 198 .val = 'D', 199 }, 200 { 201 .name = (char *) "client", 202 .has_arg = required_argument, 203 .val = 'C', 204 }, 205 { 206 .name = NULL, 207 }, 208}; 209 210void free_threads_shm(void) 211{ 212 struct shmid_ds sbuf; 213 214 if (threads) { 215 void *tp = threads; 216 217 threads = NULL; 218 shmdt(tp); 219 shmctl(shm_id, IPC_RMID, &sbuf); 220 shm_id = -1; 221 } 222} 223 224void free_shm(void) 225{ 226 if (threads) { 227 file_hash_exit(); 228 flow_exit(); 229 fio_debug_jobp = NULL; 230 free_threads_shm(); 231 } 232 233 scleanup(); 234} 235 236/* 237 * The thread area is shared between the main process and the job 238 * threads/processes. So setup a shared memory segment that will hold 239 * all the job info. We use the end of the region for keeping track of 240 * open files across jobs, for file sharing. 241 */ 242static int setup_thread_area(void) 243{ 244 void *hash; 245 246 if (threads) 247 return 0; 248 249 /* 250 * 1024 is too much on some machines, scale max_jobs if 251 * we get a failure that looks like too large a shm segment 252 */ 253 do { 254 size_t size = max_jobs * sizeof(struct thread_data); 255 256 size += file_hash_size; 257 size += sizeof(unsigned int); 258 259 shm_id = shmget(0, size, IPC_CREAT | 0600); 260 if (shm_id != -1) 261 break; 262 if (errno != EINVAL && errno != ENOMEM) { 263 perror("shmget"); 264 break; 265 } 266 267 max_jobs >>= 1; 268 } while (max_jobs); 269 270 if (shm_id == -1) 271 return 1; 272 273 threads = shmat(shm_id, NULL, 0); 274 if (threads == (void *) -1) { 275 perror("shmat"); 276 return 1; 277 } 278 279 memset(threads, 0, max_jobs * sizeof(struct thread_data)); 280 hash = (void *) threads + max_jobs * sizeof(struct thread_data); 281 fio_debug_jobp = (void *) hash + file_hash_size; 282 *fio_debug_jobp = -1; 283 file_hash_init(hash); 284 285 flow_init(); 286 287 return 0; 288} 289 290/* 291 * Return a free job structure. 292 */ 293static struct thread_data *get_new_job(int global, struct thread_data *parent, 294 int preserve_eo) 295{ 296 struct thread_data *td; 297 298 if (global) 299 return &def_thread; 300 if (setup_thread_area()) { 301 log_err("error: failed to setup shm segment\n"); 302 return NULL; 303 } 304 if (thread_number >= max_jobs) { 305 log_err("error: maximum number of jobs (%d) reached.\n", 306 max_jobs); 307 return NULL; 308 } 309 310 td = &threads[thread_number++]; 311 *td = *parent; 312 313 td->io_ops = NULL; 314 if (!preserve_eo) 315 td->eo = NULL; 316 317 td->o.uid = td->o.gid = -1U; 318 319 dup_files(td, parent); 320 fio_options_mem_dupe(td); 321 322 profile_add_hooks(td); 323 324 td->thread_number = thread_number; 325 return td; 326} 327 328static void put_job(struct thread_data *td) 329{ 330 if (td == &def_thread) 331 return; 332 333 profile_td_exit(td); 334 flow_exit_job(td); 335 336 if (td->error) 337 log_info("fio: %s\n", td->verror); 338 339 fio_options_free(td); 340 if (td->io_ops) 341 free_ioengine(td); 342 343 memset(&threads[td->thread_number - 1], 0, sizeof(*td)); 344 thread_number--; 345} 346 347static int __setup_rate(struct thread_data *td, enum fio_ddir ddir) 348{ 349 unsigned int bs = td->o.min_bs[ddir]; 350 351 assert(ddir_rw(ddir)); 352 353 if (td->o.rate[ddir]) 354 td->rate_bps[ddir] = td->o.rate[ddir]; 355 else 356 td->rate_bps[ddir] = td->o.rate_iops[ddir] * bs; 357 358 if (!td->rate_bps[ddir]) { 359 log_err("rate lower than supported\n"); 360 return -1; 361 } 362 363 td->rate_pending_usleep[ddir] = 0; 364 return 0; 365} 366 367static int setup_rate(struct thread_data *td) 368{ 369 int ret = 0; 370 371 if (td->o.rate[DDIR_READ] || td->o.rate_iops[DDIR_READ]) 372 ret = __setup_rate(td, DDIR_READ); 373 if (td->o.rate[DDIR_WRITE] || td->o.rate_iops[DDIR_WRITE]) 374 ret |= __setup_rate(td, DDIR_WRITE); 375 376 return ret; 377} 378 379static int fixed_block_size(struct thread_options *o) 380{ 381 return o->min_bs[DDIR_READ] == o->max_bs[DDIR_READ] && 382 o->min_bs[DDIR_WRITE] == o->max_bs[DDIR_WRITE] && 383 o->min_bs[DDIR_READ] == o->min_bs[DDIR_WRITE]; 384} 385 386/* 387 * Lazy way of fixing up options that depend on each other. We could also 388 * define option callback handlers, but this is easier. 389 */ 390static int fixup_options(struct thread_data *td) 391{ 392 struct thread_options *o = &td->o; 393 int ret = 0; 394 395#ifndef FIO_HAVE_PSHARED_MUTEX 396 if (!o->use_thread) { 397 log_info("fio: this platform does not support process shared" 398 " mutexes, forcing use of threads. Use the 'thread'" 399 " option to get rid of this warning.\n"); 400 o->use_thread = 1; 401 ret = warnings_fatal; 402 } 403#endif 404 405 if (o->write_iolog_file && o->read_iolog_file) { 406 log_err("fio: read iolog overrides write_iolog\n"); 407 free(o->write_iolog_file); 408 o->write_iolog_file = NULL; 409 ret = warnings_fatal; 410 } 411 412 /* 413 * only really works with 1 file 414 */ 415 if (o->zone_size && o->open_files == 1) 416 o->zone_size = 0; 417 418 /* 419 * If zone_range isn't specified, backward compatibility dictates it 420 * should be made equal to zone_size. 421 */ 422 if (o->zone_size && !o->zone_range) 423 o->zone_range = o->zone_size; 424 425 /* 426 * Reads can do overwrites, we always need to pre-create the file 427 */ 428 if (td_read(td) || td_rw(td)) 429 o->overwrite = 1; 430 431 if (!o->min_bs[DDIR_READ]) 432 o->min_bs[DDIR_READ] = o->bs[DDIR_READ]; 433 if (!o->max_bs[DDIR_READ]) 434 o->max_bs[DDIR_READ] = o->bs[DDIR_READ]; 435 if (!o->min_bs[DDIR_WRITE]) 436 o->min_bs[DDIR_WRITE] = o->bs[DDIR_WRITE]; 437 if (!o->max_bs[DDIR_WRITE]) 438 o->max_bs[DDIR_WRITE] = o->bs[DDIR_WRITE]; 439 440 o->rw_min_bs = min(o->min_bs[DDIR_READ], o->min_bs[DDIR_WRITE]); 441 442 /* 443 * For random IO, allow blockalign offset other than min_bs. 444 */ 445 if (!o->ba[DDIR_READ] || !td_random(td)) 446 o->ba[DDIR_READ] = o->min_bs[DDIR_READ]; 447 if (!o->ba[DDIR_WRITE] || !td_random(td)) 448 o->ba[DDIR_WRITE] = o->min_bs[DDIR_WRITE]; 449 450 if ((o->ba[DDIR_READ] != o->min_bs[DDIR_READ] || 451 o->ba[DDIR_WRITE] != o->min_bs[DDIR_WRITE]) && 452 !o->norandommap) { 453 log_err("fio: Any use of blockalign= turns off randommap\n"); 454 o->norandommap = 1; 455 ret = warnings_fatal; 456 } 457 458 if (!o->file_size_high) 459 o->file_size_high = o->file_size_low; 460 461 if (o->norandommap && o->verify != VERIFY_NONE 462 && !fixed_block_size(o)) { 463 log_err("fio: norandommap given for variable block sizes, " 464 "verify disabled\n"); 465 o->verify = VERIFY_NONE; 466 ret = warnings_fatal; 467 } 468 if (o->bs_unaligned && (o->odirect || td->io_ops->flags & FIO_RAWIO)) 469 log_err("fio: bs_unaligned may not work with raw io\n"); 470 471 /* 472 * thinktime_spin must be less than thinktime 473 */ 474 if (o->thinktime_spin > o->thinktime) 475 o->thinktime_spin = o->thinktime; 476 477 /* 478 * The low water mark cannot be bigger than the iodepth 479 */ 480 if (o->iodepth_low > o->iodepth || !o->iodepth_low) { 481 /* 482 * syslet work around - if the workload is sequential, 483 * we want to let the queue drain all the way down to 484 * avoid seeking between async threads 485 */ 486 if (!strcmp(td->io_ops->name, "syslet-rw") && !td_random(td)) 487 o->iodepth_low = 1; 488 else 489 o->iodepth_low = o->iodepth; 490 } 491 492 /* 493 * If batch number isn't set, default to the same as iodepth 494 */ 495 if (o->iodepth_batch > o->iodepth || !o->iodepth_batch) 496 o->iodepth_batch = o->iodepth; 497 498 if (o->nr_files > td->files_index) 499 o->nr_files = td->files_index; 500 501 if (o->open_files > o->nr_files || !o->open_files) 502 o->open_files = o->nr_files; 503 504 if (((o->rate[0] + o->rate[1]) && (o->rate_iops[0] + o->rate_iops[1]))|| 505 ((o->ratemin[0] + o->ratemin[1]) && (o->rate_iops_min[0] + 506 o->rate_iops_min[1]))) { 507 log_err("fio: rate and rate_iops are mutually exclusive\n"); 508 ret = 1; 509 } 510 if ((o->rate[0] < o->ratemin[0]) || (o->rate[1] < o->ratemin[1]) || 511 (o->rate_iops[0] < o->rate_iops_min[0]) || 512 (o->rate_iops[1] < o->rate_iops_min[1])) { 513 log_err("fio: minimum rate exceeds rate\n"); 514 ret = 1; 515 } 516 517 if (!o->timeout && o->time_based) { 518 log_err("fio: time_based requires a runtime/timeout setting\n"); 519 o->time_based = 0; 520 ret = warnings_fatal; 521 } 522 523 if (o->fill_device && !o->size) 524 o->size = -1ULL; 525 526 if (o->verify != VERIFY_NONE) { 527 if (td_write(td) && o->do_verify && o->numjobs > 1) { 528 log_info("Multiple writers may overwrite blocks that " 529 "belong to other jobs. This can cause " 530 "verification failures.\n"); 531 ret = warnings_fatal; 532 } 533 534 o->refill_buffers = 1; 535 if (o->max_bs[DDIR_WRITE] != o->min_bs[DDIR_WRITE] && 536 !o->verify_interval) 537 o->verify_interval = o->min_bs[DDIR_WRITE]; 538 } 539 540 if (o->pre_read) { 541 o->invalidate_cache = 0; 542 if (td->io_ops->flags & FIO_PIPEIO) { 543 log_info("fio: cannot pre-read files with an IO engine" 544 " that isn't seekable. Pre-read disabled.\n"); 545 ret = warnings_fatal; 546 } 547 } 548 549#ifndef FIO_HAVE_FDATASYNC 550 if (o->fdatasync_blocks) { 551 log_info("fio: this platform does not support fdatasync()" 552 " falling back to using fsync(). Use the 'fsync'" 553 " option instead of 'fdatasync' to get rid of" 554 " this warning\n"); 555 o->fsync_blocks = o->fdatasync_blocks; 556 o->fdatasync_blocks = 0; 557 ret = warnings_fatal; 558 } 559#endif 560 561#ifdef WIN32 562 /* 563 * Windows doesn't support O_DIRECT or O_SYNC with the _open interface, 564 * so fail if we're passed those flags 565 */ 566 if ((td->io_ops->flags & FIO_SYNCIO) && (td->o.odirect || td->o.sync_io)) { 567 log_err("fio: Windows does not support direct or non-buffered io with" 568 " the synchronous ioengines. Use the 'windowsaio' ioengine" 569 " with 'direct=1' and 'iodepth=1' instead.\n"); 570 ret = 1; 571 } 572#endif 573 574 /* 575 * For fully compressible data, just zero them at init time. 576 * It's faster than repeatedly filling it. 577 */ 578 if (td->o.compress_percentage == 100) { 579 td->o.zero_buffers = 1; 580 td->o.compress_percentage = 0; 581 } 582 583 return ret; 584} 585 586/* 587 * This function leaks the buffer 588 */ 589char *fio_uint_to_kmg(unsigned int val) 590{ 591 char *buf = malloc(32); 592 char post[] = { 0, 'K', 'M', 'G', 'P', 'E', 0 }; 593 char *p = post; 594 595 do { 596 if (val & 1023) 597 break; 598 599 val >>= 10; 600 p++; 601 } while (*p); 602 603 snprintf(buf, 31, "%u%c", val, *p); 604 return buf; 605} 606 607/* External engines are specified by "external:name.o") */ 608static const char *get_engine_name(const char *str) 609{ 610 char *p = strstr(str, ":"); 611 612 if (!p) 613 return str; 614 615 p++; 616 strip_blank_front(&p); 617 strip_blank_end(p); 618 return p; 619} 620 621static int exists_and_not_file(const char *filename) 622{ 623 struct stat sb; 624 625 if (lstat(filename, &sb) == -1) 626 return 0; 627 628 /* \\.\ is the device namespace in Windows, where every file 629 * is a device node */ 630 if (S_ISREG(sb.st_mode) && strncmp(filename, "\\\\.\\", 4) != 0) 631 return 0; 632 633 return 1; 634} 635 636static void td_fill_rand_seeds_os(struct thread_data *td) 637{ 638 os_random_seed(td->rand_seeds[0], &td->bsrange_state); 639 os_random_seed(td->rand_seeds[1], &td->verify_state); 640 os_random_seed(td->rand_seeds[2], &td->rwmix_state); 641 642 if (td->o.file_service_type == FIO_FSERVICE_RANDOM) 643 os_random_seed(td->rand_seeds[3], &td->next_file_state); 644 645 os_random_seed(td->rand_seeds[5], &td->file_size_state); 646 os_random_seed(td->rand_seeds[6], &td->trim_state); 647 648 if (!td_random(td)) 649 return; 650 651 if (td->o.rand_repeatable) 652 td->rand_seeds[4] = FIO_RANDSEED * td->thread_number; 653 654 os_random_seed(td->rand_seeds[4], &td->random_state); 655} 656 657static void td_fill_rand_seeds_internal(struct thread_data *td) 658{ 659 init_rand_seed(&td->__bsrange_state, td->rand_seeds[0]); 660 init_rand_seed(&td->__verify_state, td->rand_seeds[1]); 661 init_rand_seed(&td->__rwmix_state, td->rand_seeds[2]); 662 663 if (td->o.file_service_type == FIO_FSERVICE_RANDOM) 664 init_rand_seed(&td->__next_file_state, td->rand_seeds[3]); 665 666 init_rand_seed(&td->__file_size_state, td->rand_seeds[5]); 667 init_rand_seed(&td->__trim_state, td->rand_seeds[6]); 668 669 if (!td_random(td)) 670 return; 671 672 if (td->o.rand_repeatable) 673 td->rand_seeds[4] = FIO_RANDSEED * td->thread_number; 674 675 init_rand_seed(&td->__random_state, td->rand_seeds[4]); 676} 677 678void td_fill_rand_seeds(struct thread_data *td) 679{ 680 if (td->o.use_os_rand) 681 td_fill_rand_seeds_os(td); 682 else 683 td_fill_rand_seeds_internal(td); 684 685 init_rand_seed(&td->buf_state, td->rand_seeds[7]); 686} 687 688 689/* 690 * Initializes the ioengine configured for a job, if it has not been done so 691 * already. 692 */ 693int ioengine_load(struct thread_data *td) 694{ 695 const char *engine; 696 697 /* 698 * Engine has already been loaded. 699 */ 700 if (td->io_ops) 701 return 0; 702 703 engine = get_engine_name(td->o.ioengine); 704 td->io_ops = load_ioengine(td, engine); 705 if (!td->io_ops) { 706 log_err("fio: failed to load engine %s\n", engine); 707 return 1; 708 } 709 710 if (td->io_ops->option_struct_size && td->io_ops->options) { 711 /* 712 * In cases where td->eo is set, clone it for a child thread. 713 * This requires that the parent thread has the same ioengine, 714 * but that requirement must be enforced by the code which 715 * cloned the thread. 716 */ 717 void *origeo = td->eo; 718 /* 719 * Otherwise use the default thread options. 720 */ 721 if (!origeo && td != &def_thread && def_thread.eo && 722 def_thread.io_ops->options == td->io_ops->options) 723 origeo = def_thread.eo; 724 725 options_init(td->io_ops->options); 726 td->eo = malloc(td->io_ops->option_struct_size); 727 /* 728 * Use the default thread as an option template if this uses the 729 * same options structure and there are non-default options 730 * used. 731 */ 732 if (origeo) { 733 memcpy(td->eo, origeo, td->io_ops->option_struct_size); 734 options_mem_dupe(td->eo, td->io_ops->options); 735 } else { 736 memset(td->eo, 0, td->io_ops->option_struct_size); 737 fill_default_options(td->eo, td->io_ops->options); 738 } 739 *(struct thread_data **)td->eo = td; 740 } 741 742 return 0; 743} 744 745/* 746 * Adds a job to the list of things todo. Sanitizes the various options 747 * to make sure we don't have conflicts, and initializes various 748 * members of td. 749 */ 750static int add_job(struct thread_data *td, const char *jobname, int job_add_num, 751 int recursed, int client_type) 752{ 753 unsigned int i; 754 char fname[PATH_MAX]; 755 int numjobs, file_alloced; 756 757 /* 758 * the def_thread is just for options, it's not a real job 759 */ 760 if (td == &def_thread) 761 return 0; 762 763 /* 764 * if we are just dumping the output command line, don't add the job 765 */ 766 if (dump_cmdline) { 767 put_job(td); 768 return 0; 769 } 770 771 td->client_type = client_type; 772 773 if (profile_td_init(td)) 774 goto err; 775 776 if (ioengine_load(td)) 777 goto err; 778 779 if (td->o.odirect) 780 td->io_ops->flags |= FIO_RAWIO; 781 782 file_alloced = 0; 783 if (!td->o.filename && !td->files_index && !td->o.read_iolog_file) { 784 file_alloced = 1; 785 786 if (td->o.nr_files == 1 && exists_and_not_file(jobname)) 787 add_file(td, jobname); 788 else { 789 for (i = 0; i < td->o.nr_files; i++) { 790 sprintf(fname, "%s.%d.%d", jobname, 791 td->thread_number, i); 792 add_file(td, fname); 793 } 794 } 795 } 796 797 if (fixup_options(td)) 798 goto err; 799 800 flow_init_job(td); 801 802 /* 803 * IO engines only need this for option callbacks, and the address may 804 * change in subprocesses. 805 */ 806 if (td->eo) 807 *(struct thread_data **)td->eo = NULL; 808 809 if (td->io_ops->flags & FIO_DISKLESSIO) { 810 struct fio_file *f; 811 812 for_each_file(td, f, i) 813 f->real_file_size = -1ULL; 814 } 815 816 td->mutex = fio_mutex_init(0); 817 818 td->ts.clat_percentiles = td->o.clat_percentiles; 819 if (td->o.overwrite_plist) 820 memcpy(td->ts.percentile_list, td->o.percentile_list, sizeof(td->o.percentile_list)); 821 else 822 memcpy(td->ts.percentile_list, def_percentile_list, sizeof(def_percentile_list)); 823 824 td->ts.clat_stat[0].min_val = td->ts.clat_stat[1].min_val = ULONG_MAX; 825 td->ts.slat_stat[0].min_val = td->ts.slat_stat[1].min_val = ULONG_MAX; 826 td->ts.lat_stat[0].min_val = td->ts.lat_stat[1].min_val = ULONG_MAX; 827 td->ts.bw_stat[0].min_val = td->ts.bw_stat[1].min_val = ULONG_MAX; 828 td->ddir_seq_nr = td->o.ddir_seq_nr; 829 830 if ((td->o.stonewall || td->o.new_group) && prev_group_jobs) { 831 prev_group_jobs = 0; 832 groupid++; 833 } 834 835 td->groupid = groupid; 836 prev_group_jobs++; 837 838 if (init_random_state(td, td->rand_seeds, sizeof(td->rand_seeds))) { 839 td_verror(td, errno, "init_random_state"); 840 goto err; 841 } 842 843 if (setup_rate(td)) 844 goto err; 845 846 if (td->o.write_lat_log) { 847 setup_log(&td->lat_log, td->o.log_avg_msec, IO_LOG_TYPE_LAT); 848 setup_log(&td->slat_log, td->o.log_avg_msec, IO_LOG_TYPE_SLAT); 849 setup_log(&td->clat_log, td->o.log_avg_msec, IO_LOG_TYPE_CLAT); 850 } 851 if (td->o.write_bw_log) 852 setup_log(&td->bw_log, td->o.log_avg_msec, IO_LOG_TYPE_BW); 853 if (td->o.write_iops_log) 854 setup_log(&td->iops_log, td->o.log_avg_msec, IO_LOG_TYPE_IOPS); 855 856 if (!td->o.name) 857 td->o.name = strdup(jobname); 858 859 if (!terse_output) { 860 if (!job_add_num) { 861 if (is_backend && !recursed) 862 fio_server_send_add_job(td); 863 864 if (!(td->io_ops->flags & FIO_NOIO)) { 865 char *c1, *c2, *c3, *c4; 866 867 c1 = fio_uint_to_kmg(td->o.min_bs[DDIR_READ]); 868 c2 = fio_uint_to_kmg(td->o.max_bs[DDIR_READ]); 869 c3 = fio_uint_to_kmg(td->o.min_bs[DDIR_WRITE]); 870 c4 = fio_uint_to_kmg(td->o.max_bs[DDIR_WRITE]); 871 872 log_info("%s: (g=%d): rw=%s, bs=%s-%s/%s-%s," 873 " ioengine=%s, iodepth=%u\n", 874 td->o.name, td->groupid, 875 ddir_str(td->o.td_ddir), 876 c1, c2, c3, c4, 877 td->io_ops->name, 878 td->o.iodepth); 879 880 free(c1); 881 free(c2); 882 free(c3); 883 free(c4); 884 } 885 } else if (job_add_num == 1) 886 log_info("...\n"); 887 } 888 889 /* 890 * recurse add identical jobs, clear numjobs and stonewall options 891 * as they don't apply to sub-jobs 892 */ 893 numjobs = td->o.numjobs; 894 while (--numjobs) { 895 struct thread_data *td_new = get_new_job(0, td, 1); 896 897 if (!td_new) 898 goto err; 899 900 td_new->o.numjobs = 1; 901 td_new->o.stonewall = 0; 902 td_new->o.new_group = 0; 903 904 if (file_alloced) { 905 td_new->o.filename = NULL; 906 td_new->files_index = 0; 907 td_new->files_size = 0; 908 td_new->files = NULL; 909 } 910 911 job_add_num = numjobs - 1; 912 913 if (add_job(td_new, jobname, job_add_num, 1, client_type)) 914 goto err; 915 } 916 917 return 0; 918err: 919 put_job(td); 920 return -1; 921} 922 923/* 924 * Parse as if 'o' was a command line 925 */ 926void add_job_opts(const char **o, int client_type) 927{ 928 struct thread_data *td, *td_parent; 929 int i, in_global = 1; 930 char jobname[32]; 931 932 i = 0; 933 td_parent = td = NULL; 934 while (o[i]) { 935 if (!strncmp(o[i], "name", 4)) { 936 in_global = 0; 937 if (td) 938 add_job(td, jobname, 0, 0, client_type); 939 td = NULL; 940 sprintf(jobname, "%s", o[i] + 5); 941 } 942 if (in_global && !td_parent) 943 td_parent = get_new_job(1, &def_thread, 0); 944 else if (!in_global && !td) { 945 if (!td_parent) 946 td_parent = &def_thread; 947 td = get_new_job(0, td_parent, 0); 948 } 949 if (in_global) 950 fio_options_parse(td_parent, (char **) &o[i], 1); 951 else 952 fio_options_parse(td, (char **) &o[i], 1); 953 i++; 954 } 955 956 if (td) 957 add_job(td, jobname, 0, 0, client_type); 958} 959 960static int skip_this_section(const char *name) 961{ 962 int i; 963 964 if (!nr_job_sections) 965 return 0; 966 if (!strncmp(name, "global", 6)) 967 return 0; 968 969 for (i = 0; i < nr_job_sections; i++) 970 if (!strcmp(job_sections[i], name)) 971 return 0; 972 973 return 1; 974} 975 976static int is_empty_or_comment(char *line) 977{ 978 unsigned int i; 979 980 for (i = 0; i < strlen(line); i++) { 981 if (line[i] == ';') 982 return 1; 983 if (line[i] == '#') 984 return 1; 985 if (!isspace((int) line[i]) && !iscntrl((int) line[i])) 986 return 0; 987 } 988 989 return 1; 990} 991 992/* 993 * This is our [ini] type file parser. 994 */ 995int parse_jobs_ini(char *file, int is_buf, int stonewall_flag, int type) 996{ 997 unsigned int global; 998 struct thread_data *td; 999 char *string, *name; 1000 FILE *f; 1001 char *p; 1002 int ret = 0, stonewall; 1003 int first_sect = 1; 1004 int skip_fgets = 0; 1005 int inside_skip = 0; 1006 char **opts; 1007 int i, alloc_opts, num_opts; 1008 1009 if (is_buf) 1010 f = NULL; 1011 else { 1012 if (!strcmp(file, "-")) 1013 f = stdin; 1014 else 1015 f = fopen(file, "r"); 1016 1017 if (!f) { 1018 perror("fopen job file"); 1019 return 1; 1020 } 1021 } 1022 1023 string = malloc(4096); 1024 1025 /* 1026 * it's really 256 + small bit, 280 should suffice 1027 */ 1028 name = malloc(280); 1029 memset(name, 0, 280); 1030 1031 alloc_opts = 8; 1032 opts = malloc(sizeof(char *) * alloc_opts); 1033 num_opts = 0; 1034 1035 stonewall = stonewall_flag; 1036 do { 1037 /* 1038 * if skip_fgets is set, we already have loaded a line we 1039 * haven't handled. 1040 */ 1041 if (!skip_fgets) { 1042 if (is_buf) 1043 p = strsep(&file, "\n"); 1044 else 1045 p = fgets(string, 4096, f); 1046 if (!p) 1047 break; 1048 } 1049 1050 skip_fgets = 0; 1051 strip_blank_front(&p); 1052 strip_blank_end(p); 1053 1054 if (is_empty_or_comment(p)) 1055 continue; 1056 if (sscanf(p, "[%255[^\n]]", name) != 1) { 1057 if (inside_skip) 1058 continue; 1059 log_err("fio: option <%s> outside of [] job section\n", 1060 p); 1061 break; 1062 } 1063 1064 name[strlen(name) - 1] = '\0'; 1065 1066 if (skip_this_section(name)) { 1067 inside_skip = 1; 1068 continue; 1069 } else 1070 inside_skip = 0; 1071 1072 global = !strncmp(name, "global", 6); 1073 1074 if (dump_cmdline) { 1075 if (first_sect) 1076 log_info("fio "); 1077 if (!global) 1078 log_info("--name=%s ", name); 1079 first_sect = 0; 1080 } 1081 1082 td = get_new_job(global, &def_thread, 0); 1083 if (!td) { 1084 ret = 1; 1085 break; 1086 } 1087 1088 /* 1089 * Seperate multiple job files by a stonewall 1090 */ 1091 if (!global && stonewall) { 1092 td->o.stonewall = stonewall; 1093 stonewall = 0; 1094 } 1095 1096 num_opts = 0; 1097 memset(opts, 0, alloc_opts * sizeof(char *)); 1098 1099 while (1) { 1100 if (is_buf) 1101 p = strsep(&file, "\n"); 1102 else 1103 p = fgets(string, 4096, f); 1104 if (!p) 1105 break; 1106 1107 if (is_empty_or_comment(p)) 1108 continue; 1109 1110 strip_blank_front(&p); 1111 1112 /* 1113 * new section, break out and make sure we don't 1114 * fgets() a new line at the top. 1115 */ 1116 if (p[0] == '[') { 1117 skip_fgets = 1; 1118 break; 1119 } 1120 1121 strip_blank_end(p); 1122 1123 if (num_opts == alloc_opts) { 1124 alloc_opts <<= 1; 1125 opts = realloc(opts, 1126 alloc_opts * sizeof(char *)); 1127 } 1128 1129 opts[num_opts] = strdup(p); 1130 num_opts++; 1131 } 1132 1133 ret = fio_options_parse(td, opts, num_opts); 1134 if (!ret) { 1135 if (dump_cmdline) 1136 for (i = 0; i < num_opts; i++) 1137 log_info("--%s ", opts[i]); 1138 1139 ret = add_job(td, name, 0, 0, type); 1140 } else { 1141 log_err("fio: job %s dropped\n", name); 1142 put_job(td); 1143 } 1144 1145 for (i = 0; i < num_opts; i++) 1146 free(opts[i]); 1147 num_opts = 0; 1148 } while (!ret); 1149 1150 if (dump_cmdline) 1151 log_info("\n"); 1152 1153 i = 0; 1154 while (i < nr_job_sections) { 1155 free(job_sections[i]); 1156 i++; 1157 } 1158 1159 for (i = 0; i < num_opts; i++) 1160 free(opts[i]); 1161 1162 free(string); 1163 free(name); 1164 free(opts); 1165 if (!is_buf && f != stdin) 1166 fclose(f); 1167 return ret; 1168} 1169 1170static int fill_def_thread(void) 1171{ 1172 memset(&def_thread, 0, sizeof(def_thread)); 1173 1174 fio_getaffinity(getpid(), &def_thread.o.cpumask); 1175 def_thread.o.timeout = def_timeout; 1176 1177 /* 1178 * fill default options 1179 */ 1180 fio_fill_default_options(&def_thread); 1181 return 0; 1182} 1183 1184static void usage(const char *name) 1185{ 1186 printf("%s\n", fio_version_string); 1187 printf("%s [options] [job options] <job file(s)>\n", name); 1188 printf(" --debug=options\tEnable debug logging. May be one/more of:\n" 1189 "\t\t\tprocess,file,io,mem,blktrace,verify,random,parse,\n" 1190 "\t\t\tdiskutil,job,mutex,profile,time,net\n"); 1191 printf(" --output\t\tWrite output to file\n"); 1192 printf(" --timeout\t\tRuntime in seconds\n"); 1193 printf(" --latency-log\t\tGenerate per-job latency logs\n"); 1194 printf(" --bandwidth-log\tGenerate per-job bandwidth logs\n"); 1195 printf(" --minimal\t\tMinimal (terse) output\n"); 1196 printf(" --version\t\tPrint version info and exit\n"); 1197 printf(" --terse-version=x\tSet terse version output format to 'x'\n"); 1198 printf(" --help\t\tPrint this page\n"); 1199 printf(" --cmdhelp=cmd\t\tPrint command help, \"all\" for all of" 1200 " them\n"); 1201 printf(" --enghelp=engine\tPrint ioengine help, or list" 1202 " available ioengines\n"); 1203 printf(" --enghelp=engine,cmd\tPrint help for an ioengine" 1204 " cmd\n"); 1205 printf(" --showcmd\t\tTurn a job file into command line options\n"); 1206 printf(" --eta=when\t\tWhen ETA estimate should be printed\n"); 1207 printf(" \t\tMay be \"always\", \"never\" or \"auto\"\n"); 1208 printf(" --readonly\t\tTurn on safety read-only checks, preventing" 1209 " writes\n"); 1210 printf(" --section=name\tOnly run specified section in job file\n"); 1211 printf(" --alloc-size=kb\tSet smalloc pool to this size in kb" 1212 " (def 1024)\n"); 1213 printf(" --warnings-fatal\tFio parser warnings are fatal\n"); 1214 printf(" --max-jobs=nr\t\tMaximum number of threads/processes to support\n"); 1215 printf(" --server=args\t\tStart a backend fio server\n"); 1216 printf(" --daemonize=pidfile\tBackground fio server, write pid to file\n"); 1217 printf(" --client=hostname\tTalk to remote backend fio server at hostname\n"); 1218 printf("\nFio was written by Jens Axboe <jens.axboe@oracle.com>"); 1219 printf("\n Jens Axboe <jaxboe@fusionio.com>\n"); 1220} 1221 1222#ifdef FIO_INC_DEBUG 1223struct debug_level debug_levels[] = { 1224 { .name = "process", 1225 .help = "Process creation/exit logging", 1226 .shift = FD_PROCESS, 1227 }, 1228 { .name = "file", 1229 .help = "File related action logging", 1230 .shift = FD_FILE, 1231 }, 1232 { .name = "io", 1233 .help = "IO and IO engine action logging (offsets, queue, completions, etc)", 1234 .shift = FD_IO, 1235 }, 1236 { .name = "mem", 1237 .help = "Memory allocation/freeing logging", 1238 .shift = FD_MEM, 1239 }, 1240 { .name = "blktrace", 1241 .help = "blktrace action logging", 1242 .shift = FD_BLKTRACE, 1243 }, 1244 { .name = "verify", 1245 .help = "IO verification action logging", 1246 .shift = FD_VERIFY, 1247 }, 1248 { .name = "random", 1249 .help = "Random generation logging", 1250 .shift = FD_RANDOM, 1251 }, 1252 { .name = "parse", 1253 .help = "Parser logging", 1254 .shift = FD_PARSE, 1255 }, 1256 { .name = "diskutil", 1257 .help = "Disk utility logging actions", 1258 .shift = FD_DISKUTIL, 1259 }, 1260 { .name = "job", 1261 .help = "Logging related to creating/destroying jobs", 1262 .shift = FD_JOB, 1263 }, 1264 { .name = "mutex", 1265 .help = "Mutex logging", 1266 .shift = FD_MUTEX 1267 }, 1268 { .name = "profile", 1269 .help = "Logging related to profiles", 1270 .shift = FD_PROFILE, 1271 }, 1272 { .name = "time", 1273 .help = "Logging related to time keeping functions", 1274 .shift = FD_TIME, 1275 }, 1276 { .name = "net", 1277 .help = "Network logging", 1278 .shift = FD_NET, 1279 }, 1280 { .name = NULL, }, 1281}; 1282 1283static int set_debug(const char *string) 1284{ 1285 struct debug_level *dl; 1286 char *p = (char *) string; 1287 char *opt; 1288 int i; 1289 1290 if (!strcmp(string, "?") || !strcmp(string, "help")) { 1291 log_info("fio: dumping debug options:"); 1292 for (i = 0; debug_levels[i].name; i++) { 1293 dl = &debug_levels[i]; 1294 log_info("%s,", dl->name); 1295 } 1296 log_info("all\n"); 1297 return 1; 1298 } 1299 1300 while ((opt = strsep(&p, ",")) != NULL) { 1301 int found = 0; 1302 1303 if (!strncmp(opt, "all", 3)) { 1304 log_info("fio: set all debug options\n"); 1305 fio_debug = ~0UL; 1306 continue; 1307 } 1308 1309 for (i = 0; debug_levels[i].name; i++) { 1310 dl = &debug_levels[i]; 1311 found = !strncmp(opt, dl->name, strlen(dl->name)); 1312 if (!found) 1313 continue; 1314 1315 if (dl->shift == FD_JOB) { 1316 opt = strchr(opt, ':'); 1317 if (!opt) { 1318 log_err("fio: missing job number\n"); 1319 break; 1320 } 1321 opt++; 1322 fio_debug_jobno = atoi(opt); 1323 log_info("fio: set debug jobno %d\n", 1324 fio_debug_jobno); 1325 } else { 1326 log_info("fio: set debug option %s\n", opt); 1327 fio_debug |= (1UL << dl->shift); 1328 } 1329 break; 1330 } 1331 1332 if (!found) 1333 log_err("fio: debug mask %s not found\n", opt); 1334 } 1335 return 0; 1336} 1337#else 1338static int set_debug(const char *string) 1339{ 1340 log_err("fio: debug tracing not included in build\n"); 1341 return 1; 1342} 1343#endif 1344 1345static void fio_options_fill_optstring(void) 1346{ 1347 char *ostr = cmd_optstr; 1348 int i, c; 1349 1350 c = i = 0; 1351 while (l_opts[i].name) { 1352 ostr[c++] = l_opts[i].val; 1353 if (l_opts[i].has_arg == required_argument) 1354 ostr[c++] = ':'; 1355 else if (l_opts[i].has_arg == optional_argument) { 1356 ostr[c++] = ':'; 1357 ostr[c++] = ':'; 1358 } 1359 i++; 1360 } 1361 ostr[c] = '\0'; 1362} 1363 1364static int client_flag_set(char c) 1365{ 1366 int i; 1367 1368 i = 0; 1369 while (l_opts[i].name) { 1370 int val = l_opts[i].val; 1371 1372 if (c == (val & 0xff)) 1373 return (val & FIO_CLIENT_FLAG); 1374 1375 i++; 1376 } 1377 1378 return 0; 1379} 1380 1381void parse_cmd_client(void *client, char *opt) 1382{ 1383 fio_client_add_cmd_option(client, opt); 1384} 1385 1386int parse_cmd_line(int argc, char *argv[], int client_type) 1387{ 1388 struct thread_data *td = NULL; 1389 int c, ini_idx = 0, lidx, ret = 0, do_exit = 0, exit_val = 0; 1390 char *ostr = cmd_optstr; 1391 void *pid_file = NULL; 1392 void *cur_client = NULL; 1393 int backend = 0; 1394 1395 /* 1396 * Reset optind handling, since we may call this multiple times 1397 * for the backend. 1398 */ 1399 optind = 1; 1400 1401 while ((c = getopt_long_only(argc, argv, ostr, l_opts, &lidx)) != -1) { 1402 did_arg = 1; 1403 1404 if ((c & FIO_CLIENT_FLAG) || client_flag_set(c)) { 1405 parse_cmd_client(cur_client, argv[optind - 1]); 1406 c &= ~FIO_CLIENT_FLAG; 1407 } 1408 1409 switch (c) { 1410 case 'a': 1411 smalloc_pool_size = atoi(optarg); 1412 break; 1413 case 't': 1414 def_timeout = atoi(optarg); 1415 break; 1416 case 'l': 1417 write_lat_log = 1; 1418 break; 1419 case 'b': 1420 write_bw_log = 1; 1421 break; 1422 case 'o': 1423 f_out = fopen(optarg, "w+"); 1424 if (!f_out) { 1425 perror("fopen output"); 1426 exit(1); 1427 } 1428 f_err = f_out; 1429 break; 1430 case 'm': 1431 terse_output = 1; 1432 break; 1433 case 'h': 1434 if (!cur_client) { 1435 usage(argv[0]); 1436 do_exit++; 1437 } 1438 break; 1439 case 'c': 1440 if (!cur_client) { 1441 fio_show_option_help(optarg); 1442 do_exit++; 1443 } 1444 break; 1445 case 'i': 1446 if (!cur_client) { 1447 fio_show_ioengine_help(optarg); 1448 do_exit++; 1449 } 1450 break; 1451 case 's': 1452 dump_cmdline = 1; 1453 break; 1454 case 'r': 1455 read_only = 1; 1456 break; 1457 case 'v': 1458 if (!cur_client) { 1459 log_info("%s\n", fio_version_string); 1460 do_exit++; 1461 } 1462 break; 1463 case 'V': 1464 terse_version = atoi(optarg); 1465 if (!(terse_version == 2 || terse_version == 3)) { 1466 log_err("fio: bad terse version format\n"); 1467 exit_val = 1; 1468 do_exit++; 1469 } 1470 break; 1471 case 'e': 1472 if (!strcmp("always", optarg)) 1473 eta_print = FIO_ETA_ALWAYS; 1474 else if (!strcmp("never", optarg)) 1475 eta_print = FIO_ETA_NEVER; 1476 break; 1477 case 'd': 1478 if (set_debug(optarg)) 1479 do_exit++; 1480 break; 1481 case 'x': { 1482 size_t new_size; 1483 1484 if (!strcmp(optarg, "global")) { 1485 log_err("fio: can't use global as only " 1486 "section\n"); 1487 do_exit++; 1488 exit_val = 1; 1489 break; 1490 } 1491 new_size = (nr_job_sections + 1) * sizeof(char *); 1492 job_sections = realloc(job_sections, new_size); 1493 job_sections[nr_job_sections] = strdup(optarg); 1494 nr_job_sections++; 1495 break; 1496 } 1497 case 'p': 1498 exec_profile = strdup(optarg); 1499 break; 1500 case FIO_GETOPT_JOB: { 1501 const char *opt = l_opts[lidx].name; 1502 char *val = optarg; 1503 1504 if (!strncmp(opt, "name", 4) && td) { 1505 ret = add_job(td, td->o.name ?: "fio", 0, 0, client_type); 1506 if (ret) 1507 return 0; 1508 td = NULL; 1509 } 1510 if (!td) { 1511 int is_section = !strncmp(opt, "name", 4); 1512 int global = 0; 1513 1514 if (!is_section || !strncmp(val, "global", 6)) 1515 global = 1; 1516 1517 if (is_section && skip_this_section(val)) 1518 continue; 1519 1520 td = get_new_job(global, &def_thread, 1); 1521 if (!td || ioengine_load(td)) 1522 return 0; 1523 fio_options_set_ioengine_opts(l_opts, td); 1524 } 1525 1526 ret = fio_cmd_option_parse(td, opt, val); 1527 1528 if (!ret && !strcmp(opt, "ioengine")) { 1529 free_ioengine(td); 1530 if (ioengine_load(td)) 1531 return 0; 1532 fio_options_set_ioengine_opts(l_opts, td); 1533 } 1534 break; 1535 } 1536 case FIO_GETOPT_IOENGINE: { 1537 const char *opt = l_opts[lidx].name; 1538 char *val = optarg; 1539 opt = l_opts[lidx].name; 1540 val = optarg; 1541 ret = fio_cmd_ioengine_option_parse(td, opt, val); 1542 break; 1543 } 1544 case 'w': 1545 warnings_fatal = 1; 1546 break; 1547 case 'j': 1548 max_jobs = atoi(optarg); 1549 if (!max_jobs || max_jobs > REAL_MAX_JOBS) { 1550 log_err("fio: invalid max jobs: %d\n", max_jobs); 1551 do_exit++; 1552 exit_val = 1; 1553 } 1554 break; 1555 case 'S': 1556 if (nr_clients) { 1557 log_err("fio: can't be both client and server\n"); 1558 do_exit++; 1559 exit_val = 1; 1560 break; 1561 } 1562 if (optarg) 1563 fio_server_set_arg(optarg); 1564 is_backend = 1; 1565 backend = 1; 1566 break; 1567 case 'D': 1568 pid_file = strdup(optarg); 1569 break; 1570 case 'C': 1571 if (is_backend) { 1572 log_err("fio: can't be both client and server\n"); 1573 do_exit++; 1574 exit_val = 1; 1575 break; 1576 } 1577 if (fio_client_add(&fio_client_ops, optarg, &cur_client)) { 1578 log_err("fio: failed adding client %s\n", optarg); 1579 do_exit++; 1580 exit_val = 1; 1581 break; 1582 } 1583 break; 1584 default: 1585 do_exit++; 1586 exit_val = 1; 1587 break; 1588 } 1589 if (do_exit) 1590 break; 1591 } 1592 1593 if (do_exit) { 1594 if (exit_val && !(is_backend || nr_clients)) 1595 exit(exit_val); 1596 } 1597 1598 if (nr_clients && fio_clients_connect()) { 1599 do_exit++; 1600 exit_val = 1; 1601 return -1; 1602 } 1603 1604 if (is_backend && backend) 1605 return fio_start_server(pid_file); 1606 1607 if (td) { 1608 if (!ret) 1609 ret = add_job(td, td->o.name ?: "fio", 0, 0, client_type); 1610 } 1611 1612 while (!ret && optind < argc) { 1613 ini_idx++; 1614 ini_file = realloc(ini_file, ini_idx * sizeof(char *)); 1615 ini_file[ini_idx - 1] = strdup(argv[optind]); 1616 optind++; 1617 } 1618 1619 return ini_idx; 1620} 1621 1622int fio_init_options(void) 1623{ 1624 f_out = stdout; 1625 f_err = stderr; 1626 1627 fio_options_fill_optstring(); 1628 fio_options_dup_and_init(l_opts); 1629 1630 atexit(free_shm); 1631 1632 if (fill_def_thread()) 1633 return 1; 1634 1635 return 0; 1636} 1637 1638extern int fio_check_options(struct thread_options *); 1639 1640int parse_options(int argc, char *argv[]) 1641{ 1642 const int type = FIO_CLIENT_TYPE_CLI; 1643 int job_files, i; 1644 1645 if (fio_init_options()) 1646 return 1; 1647 if (fio_test_cconv(&def_thread.o)) 1648 log_err("fio: failed internal cconv test\n"); 1649 1650 job_files = parse_cmd_line(argc, argv, type); 1651 1652 if (job_files > 0) { 1653 for (i = 0; i < job_files; i++) { 1654 if (fill_def_thread()) 1655 return 1; 1656 if (nr_clients) { 1657 if (fio_clients_send_ini(ini_file[i])) 1658 return 1; 1659 free(ini_file[i]); 1660 } else if (!is_backend) { 1661 if (parse_jobs_ini(ini_file[i], 0, i, type)) 1662 return 1; 1663 free(ini_file[i]); 1664 } 1665 } 1666 } 1667 1668 free(ini_file); 1669 fio_options_free(&def_thread); 1670 1671 if (!thread_number) { 1672 if (dump_cmdline) 1673 return 0; 1674 if (exec_profile) 1675 return 0; 1676 if (is_backend || nr_clients) 1677 return 0; 1678 if (did_arg) 1679 return 0; 1680 1681 log_err("No jobs(s) defined\n\n"); 1682 1683 if (!did_arg) { 1684 usage(argv[0]); 1685 return 1; 1686 } 1687 1688 return 0; 1689 } 1690 1691 if (def_thread.o.gtod_offload) { 1692 fio_gtod_init(); 1693 fio_gtod_offload = 1; 1694 fio_gtod_cpu = def_thread.o.gtod_cpu; 1695 } 1696 1697 if (!terse_output) 1698 log_info("%s\n", fio_version_string); 1699 1700 return 0; 1701} 1702 1703void options_default_fill(struct thread_options *o) 1704{ 1705 memcpy(o, &def_thread.o, sizeof(*o)); 1706} 1707