-
Notifications
You must be signed in to change notification settings - Fork 15
/
Copy pathdt.c
executable file
·10562 lines (10031 loc) · 326 KB
/
dt.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/****************************************************************************
* *
* COPYRIGHT (c) 1988 - 2023 *
* This Software Provided *
* By *
* Robin's Nest Software Inc. *
* *
* Permission to use, copy, modify, distribute and sell this software and *
* its documentation for any purpose and without fee is hereby granted, *
* provided that the above copyright notice appear in all copies and that *
* both that copyright notice and this permission notice appear in the *
* supporting documentation, and that the name of the author not be used *
* in advertising or publicity pertaining to distribution of the software *
* without specific, written prior permission. *
* *
* THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, *
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN *
* NO EVENT SHALL HE BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL *
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR *
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS *
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF *
* THIS SOFTWARE. *
* *
****************************************************************************/
/*
* Module: dt.c
* Author: Robin T. Miller
*
* Description:
* Main line code for generic data test program 'dt'.
*
* Modification History:
*
* September 21th, 2023 by Robin T. Miller
* When specifying retryable errors, honor user specified error limit.
*
* August 18th, 2023 by Robin T. Miller
* When a thread is hung, report total statistics before cancelling
* the thread. These hangs often occur when all storage connections are lost
* and the outstanding I/O is *not* completing (NFS mounts or iSCSI LUN, etc).
*
* November 15th, 2021 by Robin T. Miller
* Add support for dtapp, hammer, and sio I/O behaviors.
*
* June 16th, 2021 by Robin T. Miller
* Add support for separate SCSI trigger device.
*
* June 14th, 2021 by Robin T. Miller
* Add support for "limit=random" to automatically setup random limits.
*
* May 24th, 2021 by Robin T. Miller
* When reporting the no-progress record number with read-after-write
* enabled, do not include both reads and writes, so the record is accurate.
*
* March 21st, 2021 by Robin T. Miller
* Add support for forcing FALSE data corruptions for debugging.
*
* March 8th, 2021 by Robin T. Miller
* When creating log directories in setup_log_directory(), create the
* last subdirectory (as required). For user specified log directory, expand
* format control strings prior to creating the directory (logdir= option).
*
* February 11th, 2021 by Robin T. Miller
* Create master log creation function for use by other tool parsers.
*
* October 28th, 2020 by Robin T. Miller
* Add support for comma separated workload[s]= option.
*
* October 27th, 2020 by Robin T. Miller
* When "trigger=" is specified, no parameters, then remove triggers.
* This empty check is consistent with other options, like prefix=, etc.
*
* October 21st, 2020 by Robin T. Miller
* Add array=string option, esp. for external trigger scripts.
* Add --trigger= and --workload= parsing for I/O behavior options.
*
* September 24th, 2020 by Robin T. Miller
* Updated signal handler to avoid exiting with FAILURE on SIGINT (2) or
* SIGTERM (15), esp. for the latter since automation often sends this signal
* to kill tools. SIGINT and SIGTERM will now exit with SUCCESS.
*
* August 5th, 2020 by Robin T. Miller
* Add support for starting slice offset.
*
* July 8th, 2020 by Robin T. Miller
* When looking up alternate tool I/O behavior names, do string compare
* with length, to avoid issues with Windows ".exe" file extension.
*
* May 11th, 2020 by Robin T. MIller
* Add options for date and time field separator used when formatting
* the log prefix format strings (e.g. "%ymd", "%hms").
*
* May 7th, 2020 by Robin T. Miller
* Apply special step option handling to both disks and files, by setting
* up and ending offset so I/O loops break reaching this offset.
*
* April 8th, 2020 by Robin T. Miller
* Add flag for output position, so zero offset is handled properly.
* Note: This allows copying to a different offset from input file!
*
* March 31st, 2020 by Robin T. Miller
* Add "showvflags=hex" option to show block tag verify flags set.
*
* March 19th, 2020 by Robin T. Miller
* When selecting 100% reads (readp=100), switch output file to input file.
* This helps with automation desiring to do read verify only w/of= option!
*
* March 7th, 2020 by Robin T. Miller
* Remove a file position sanity check no longer valid with updates made
* in FindCapacity() with new logic associated with the file position option.
*
* February 12th, 2020 by Robin T. Miller
* For Unix systems, increase the open file resource limit, now that low
* limits are imposed on newer Linux distros, to avoid false failures!
*
* February 11th, 2020 by Robin T. Miller
* Added "showfslba" and "showfsmap" commands to show the file system map,
* for the file specified, assuming we can acquire FS extents to map physical LBAs.
*
* Decamber 6th, 2019 by Robin T. Miller
* When re-enabling stats via "enable=stats", ensure all the stat flags
* reset when disabled, get enabled once again, esp. since these are sticky.
* FYI: Found script issue where stats were disabled, but not easily re-enabled!
*
* November 21st, 2019 by Robin T. Miller
* Add a retry data corruption limit option (retryDC_limit=value).
* The normal retry limit is used for retrying errors (60 by default).
* Added separate retry data corruption delay option (retryDC_delay).
* Fix "dir=/var/tmp of=dt-%user-%uuid.data" expansion by updating the
* base name properly in format_device_name() function. (see comments there).
*
* November 20th, 2019 by Robin T. Miller
* In setup_thread_names(), with multiple threads create a unique directory
* for each thread under the top level directory. Previously, when the top level
* directory was a mount point, a new top level directory was created with "-jNtN"
* so subsequent files and subdirectories were not created under the mount point.
* So, now instead of say /var/tmp/dtdir-j1t1, it's now /var/tmp/dtdir/j1t1.
*
* October 6th, 2019 by Robin T. Miller
* Change the default dispose mode setting to keep on error.
*
* July 27th, 2019 by Robin T. Miller
* Change the delete error log file default to be true.
* For those running multiple processes, beware of this change!
*
* June 14th, 2019 by Robin T. Miller
* Fix bug in do_datatest_validate() where the pattern buffer was reset
* causing pattern=incr and pattern=string not work (only 1st 4 bytes used).
*
* June 6th, 2019 by Robin T. Miller
* Add logdir= option to prepend to job/log file paths.
*
* May 27th, 2019 by Robin T. Miller
* Add support for capacity percentage for thin provisioned LUNs,
* to help avoid exceeding backend storage for over-provisioned volumes.
*
* May 20th, 2019 by Robin T. Miller
* Add support for appending a default file name to a directory.
*
* May 21st, 2018 by Robin T. Miller
* Fix bug introduced with mounted files system check in copy mode.
* Only the input file has an output file dinfo pointer, so add this check.
* Failure to have this check results in a "Segmentation fault (core dumped)".
*
* April 12th, 2018 by Robin T. Miller
* For Linux file systems with direct I/O, get the disk block size.
* This disk block size is required for later sanity checks for direct I/O.
* Failure to enforce DIO I/O sizes leads to EINVAL errors, misleading for
* everyone (including this author). This occurs on disks with 4k sectors!
*
* March 1st, 2018 by Robin T. Miller
* Add mounted file system check when writing to /dev/ disk devices.
* Note: This is *not* full proof, since LVM devices are not handled, and
* will not detect /dev/sd* when DM-MP /dev/mapper partitions are mounted.
* But that said, this is better than what we did before.
* FYI: This is Linux only right now, since I no longer have other OS's.
*
* January 21st, 2017 by Robin T. Miller
* For Windows, parse <cr><lf> properly for continuation lines.
* Allows comments on continuation lines, including leading spaces.
*
* December 21st, 2016 by Robin T. Miller
* Fix bug in MakeArgList() while parsing quoted strings, due to how
* strcpy() copies overlapping strings. Must use our own copy loop!
*
* December 13th, 2016 by Robin T. Miller
* Ensure the trailing log header and exit status go to the correct
* output stream, stdout vs. stderr, for scripts separating these two.
*
* November 4th, 2016 by Robin T. Miller
* Add enable/disable options for controlling job statistics.
* Added support to control the total statistics separately.
* Note: Pass/Total/Job statistics are controlled seperately,
* making it easier to customize the type of statistics desired.
*
* September 17th, 2016 by Robin T. Miller
* Fix parsing of quoted text in MakeArgList().
* Bug was terminaing with a NULL, rather than processing more
* text in the string. What was I thinking? ;(
*
* February 2nd, 2016 by Robin T. Miller
* When dumping history, do so for multiple devices.
*
* January 7th, 2016 by Robin T. Miller
* Implement the log append flag, we were always overwriting logs.
* December 18th, 2015 by Robin T. Miller
* Remove interactive check in main loop, which previously automatically
* waited for jobs. Robin thought this was a convenience, but can/is misleading.
*
* December 16th, 2015 by Robin T. Miller
* Expand variables in conditional part of ${var:${VAR}} parsing.
* Add support for ${var:?Error text} when variable is not defined.
* Save the workload name, so we can use %workload format string.
*
* December 12th, 2015 by Robin T. Miller
* When using read percentage, initialize the file once as required.
* Added enable/disable-{fill_always,fill_once} to initialize files
* prior to writing. This is useful for read percentage and debugging.
*
* December 11th, 2015 by Robin T. Miller
* When direct I/O is enabled, automatically enable FS align flag.
* Most file systems require aligned file offsets with direct I/O.
*
* November 21th, 2015 by Robin T. Miller
* Added support for read/write and sequential/random percentages.
*
* November 19th, 2015 by Robin T. Miller
* Added higher resolution timer (gettimeofday) for start/pass/end times.
*
* November 17th, 2015 by Robin T. Miller
* When emitting prompt status, use the master thread exit status rather than
* the global exit status. This avoids incorrect status when threads fail, rather
* than the last command status and/or jobs waited upon.
* Note: These changes are specifically for pipe and client modes.
*
* October 6th, 2015 by Robin T. Miller
* Add support for variable data limit options:
* min_limit=value max_limit=value incr_limit=value
* Similar to variable block sizes, except without an increment,
* the data limit will default to variable.
*
* June 14th, 2015 by Robin T. Miller
* Fix bug in cleanup_device() preventing freeing data buffers.
* Move dt pattern initialize to do_datatest_initialize(), and perform
* this *after* cloning the master to avoid wasted memory which is significant
* with IOT pattern with large block sizes and/or large pattern files.
*
* June 13th, 2015 by Robin T. Miller
* Update docopy() and domirror() to avoid pattern buffer setup.
*
* June 9th, 2015 by Robin T. Miller
* Added support for block tags (btags).
*
* April 21st, 2015 by Robin T. Miller
* Add support for an optional error file via errfile=filename option.
* When specified, this file is open'ed in append mode for writing all errors.
*
* March 9th, 2015 by Robin T. Miller
* Add additional check when checking for directory exists, to ensure
* the root failure (e.g. "permission denied") gets reported, and also to
* avoid trying to create the directory since this is misleading to folks.
*
* March 7th, 2015 by Robin T. Miller
* Add checks for iodir=vary and iotype=vary, when parsing additional
* iodir/iotype parameters. Do not overwrite random I/O flag, if vary enabled.
* Previously, iodir=vary with iotype=sequential, reset the random I/O flag,
* which in the case of slices, prevented the random limit from being setup!
*
* January 29th, 2015 by Robin T. Miller
* Allow empty pattern options to undue thier affect, to allow this
* method to overide previous pattern options. Reverts to their defaults.
*
* December 19th, 2014 by Robin T. Miller
* Fixed a problem in the dt I/O loop where a runtime=-1 was setting
* the end runtime (incorrectly), causing dt threads to exit after 1 second.
* The other I/O behaviors are correct, as are the other dt threads.
*
* November 19th, 2014 by Robin T. Miller
* Update make_options_string() to do a better job quoting options
* containing whitespace, now used for defining workloads and dt command
* line for logging.
*
* November 4th, 2014 by Robin T. Miller
* Made debug flags persistent ("sticky") for client/server mode.
*
* October 18th, 2014 by Robin T. Miller
* Add support for maxdatap= option for direct disks.
*
* October 10th, 2014 by Robin T. Miller
* Added support for iomode=mirror.
* Created common functions for doio() and domirror().
*
* October 1st, 2014 by Robin T. Miller
* Modify I/O loops to honor the error limit regardless of the operation.
* Previously, the error limit was not honored for open or delete failures.
*
* September 25th, 2014 by Robin T. Miller
* Note; For NFS, unbuffered I/O is enabled to avoid false corruptions.
* Added warning for file systems, when the free space is less than the
* data limit required for dir(s) and file(s) specified.
*
* September 7th, 2014 by Robin T. Miller
* Invoke pthread_detach() for threads we wish to detach. This is required
* for Windows, since to mimic POSIX detached threaads, the thread handle must
* be closed. Previously on Windows, detached threads were leaking handles.
*
* July 14th, 2014 by Robin T. Miller
* Add support for SCSI I/O.
*
* June 2nd, 2014 by Robin T. Miller
* When alarm is specified *without* a keepalive time, then enable
* keepalives, which restores compatablity with older dt's.
*
* May 29th, 2014 by Robin T. Miller
* Fix bug when the runtime is -1 (infinite), the alarm value was set
* to this value which caused the monitoring thread to wait forever, thus
* things serviced by this thread never executed (noprog's, keepalives, etc).
*
* April 9th, 2014 by Robin T. Miller
* Converted Printf/Fprint's to Eprintf/Wprintf for errors and warning.
*
* April 2nd, 2014 by Robin T. Miller
* When specifying procs=value, retain backwards compatability by creating
* unique file names, otherwise we run the risk of breaking someone's scripts!
* FYI: procs=1 is equivalent to "threads=1 enable=funique".
*
* March 31st, 2014 by Robin T. Miller
* Allow ${VAR:string} format, when expanding environment variables.
* Where "string" gets used when ${VAR} is *not* defined!
*
* January 27th, 2014 by Robin T. Miller
* Moved validation checks *after* common device setup, required so the
* file system information is setup (required for validation checks like XFS).
*
* January 22nd, 2014 by Robin T. Miller
* If the error limit was set by a noprog exit status, ensure the thread
* status is set to FAILURE, so the onerr=abort option will stop other threads.
*
* January 14th, 2014 by Robin T. Miller
* If spt commands fail, execute triggers specified (if any).
* In particular, dumping ras trace buffers could be very helpful!
*
* June 20th, 2013 by Robin T Miller
* Mostly a rewrite for multithreaded IO, so starting with new history!
*/
#include "dt.h"
#include <ctype.h>
#include <fcntl.h>
#include <math.h>
#include <signal.h>
#if !defined(WIN32)
# if !defined(_QNX_SOURCE)
# if !defined(sun)
# include <sys/ioctl.h>
# endif /* !defined(sun) */
# include <sys/file.h>
# include <sys/param.h>
# include <sys/resource.h>
# if defined(sun) || defined(_OSF_SOURCE)
# include <sys/mman.h>
# endif /* defined(sun) || defined(_OSF_SOURCE) */
# endif /* !defined(_QNX_SOURCE) */
#include <sys/wait.h>
#endif /* !defined(WIN32) */
#if defined(DEC)
# include <sys/utsname.h>
#endif /* defined(DEC) */
#if defined(HP_UX)
# include <sys/scsi.h>
# if !defined(SCSI_MAX_Q_DEPTH)
# define SCSI_MAX_Q_DEPTH 255
# endif
#endif /* defined(HP_UX) */
//#define MEMORY_DEBUG 1
/* To enabled: % export MALLOC_TRACE=mcheck.data */
#if defined(MEMORY_DEBUG)
# if defined(__linux__)
# include <mcheck.h>
# endif /* defined(__linux__) */
#endif /* defined(MEMORY_DEBUG) */
pthread_attr_t detached_thread_attrs;
pthread_attr_t *tdattrp = &detached_thread_attrs;
pthread_attr_t joinable_thread_attrs;
pthread_attr_t *tjattrp = &joinable_thread_attrs;
pthread_mutex_t print_lock; /* Printing lock (sync output). */
pthread_t ParentThread; /* The parents' thread. */
pthread_t iotuneThread; /* The IO tuning thread. */
pthread_t MonitorThread; /* The monitoring thread. */
#if defined(WIN32)
os_tid_t ParentThreadId; /* The parents' thread ID. */
os_tid_t iotuneThreadId; /* The IO tuning thread ID. */
os_tid_t MonitorThreadId; /* The monitoring thread ID. */
#else /* !defined(WIN32) */
# define ParentThreadId ParentThread
# define iotuneThreadId iotuneThread
# define MonitorThreadId MonitorThread
#endif /* defined(WIN32) */
extern iobehavior_funcs_t dtapp_iobehavior_funcs;
extern iobehavior_funcs_t hammer_iobehavior_funcs;
extern iobehavior_funcs_t sio_iobehavior_funcs;
iobehavior_funcs_t *iobehavior_funcs_table[] = {
&dtapp_iobehavior_funcs,
&hammer_iobehavior_funcs,
&sio_iobehavior_funcs,
NULL
};
iobehavior_funcs_t *find_iobehavior(dinfo_t *dip, char *name);
/*
* File Lock Modes:
*/
static lock_mode_t lock_full[] = {
{ 1, 80 }, /* FULL LOCK 80% */
{ 81, 100 }, /* PARTIAL LOCK 20% */
};
static lock_mode_t lock_mixed[] = {
{ 1, 50 }, /* FULL LOCK 50% */
{ 51, 100 }, /* PARTIAL LOCK 50% */
};
static lock_mode_t lock_partial[] = {
{ 1, 20 }, /* FULL LOCK 20% */
{ 21, 100 }, /* PARTIAL LOCK 80% */
};
volatile unsigned int monitor_interval;
/*
* Forward References:
*/
int ProcessStartupFile(dinfo_t *dip);
int ProcessStartupScripts(dinfo_t *dip);
int initiate_devs(dinfo_t *dip);
int initiate_job(dinfo_t *dip, job_id_t *job_id);
void catch_signals(dinfo_t *dip);
void ignore_signals(dinfo_t *dip);
void *docopy(void *arg);
void *domirror(void *arg);
void *doio(void *arg);
/*
* Utility Functions:
*/
void do_sleeps(dinfo_t *dip);
hbool_t is_stop_on_file(dinfo_t *dip);
int stop_job_on_stop_file(dinfo_t *mdip, job_info_t *job);
int make_stderr_buffered(dinfo_t *dip);
int create_unique_thread_log(dinfo_t *dip);
void report_pass_statistics(dinfo_t *dip);
int setup_base_name(dinfo_t *dip, char *file);
int finish_test(dinfo_t *dip, int exit_code, hbool_t do_cleanup);
double do_iops(dinfo_t *dip);
void *do_monitoring(void *arg);
int do_monitor_processing(dinfo_t *mdip, dinfo_t *dip);
int SetThreadCancelType(dinfo_t *dip, int cancel_type);
char *decodeCancelType(int cancel_type);
int init_pthread_attributes(dinfo_t *dip);
int setup_thread_attributes(dinfo_t *dip, pthread_attr_t *tattrp, hbool_t joinable_flag);
int StartMonitorThread(dinfo_t *dip, unsigned int interval);
char *expand_word(dinfo_t *dip, char **from, size_t bufsiz, int *status);
int parse_args(dinfo_t *dip, int argc, char **argv);
char *concatenate_args(dinfo_t *dip, int argc, char **argv, int arg_index);
void show_expression(dinfo_t *dip, large_t value);
int parse_job_args(dinfo_t *dip, char *string, job_id_t *job_id, char **job_tag, hbool_t errors);
int parse_connection_args(dinfo_t *dip, char **string, char **host, uint32_t *port, hbool_t errors);
void SignalHandler(int signal_number);
void finish_exiting(dinfo_t *dip, int status);
int create_detached_thread(dinfo_t *dip, void *(*func)(void *));
void *do_stop_all_job_threads(void *arg);
int start_iotuning(dinfo_t *dip);
void *do_iotune_file(void *arg);
void *do_triggers(void *arg);
void terminate_job(dinfo_t *dip);
void report_times(dinfo_t *dip, time_t initiated_time, time_t current_time);
void save_cmdline(dinfo_t *dip);
void EmitStatus(dinfo_t *dip);
void cleanup_EOL(char *string);
void display_command(dinfo_t *dip, char *command, hbool_t prompt);
int ParseWorkload(dinfo_t *dip, char *workload);
static dinfo_t *init_device_information(void);
void init_device_defaults(dinfo_t *dip);
int do_show_fsmap(dinfo_t *dip);
int do_precopy_setup(dinfo_t *idip, dinfo_t *odip);
int do_common_copy_setup(dinfo_t *idip, dinfo_t *odip);
int do_common_validate(dinfo_t *dip);
int do_datatest_validate(dinfo_t *dip);
large_t do_maxdata_percentage(dinfo_t *dip, large_t data_bytes, int data_percentage);
/*
* Variable Declarations:
*/
vbool_t CmdInterruptedFlag; /* User interrupted command. */
hbool_t debug_flag = False; /* Enable debug output flag. */
hbool_t mDebugFlag = False; /* Memory related debug flag. */
hbool_t pDebugFlag = False; /* Process related debug flag. */
hbool_t tDebugFlag = False; /* Thread related debug flag. */
int exit_status = SUCCESS; /* Normal success exit status. */
#define UNIX_INIT_PROCESS 1 /* The process ID of init!(Unix)*/
pid_t parent_process_id; /* Our parent process ID. (Unix)*/
/* No longer used, can probably go! (left for parser) */
int term_wait_retries = 0; /* Termination wait retries. */
hbool_t sighup_flag = True; /* Hangup signal control. */
vbool_t terminating_flag = False; /* Program terminating flag. */
hbool_t terminate_on_signals = False; /* Terminate on signals. */
int page_size = 0; /* Define number of bytes/page. */
/* Note: No longer used, but must retain backwards compatibility! */
unsigned int cancel_delay = DEFAULT_CANCEL_DELAY;
/* Time to delay before cancel. */
unsigned int kill_delay = DEFAULT_KILL_DELAY;
/* Delay after threads stopped. */
clock_t hertz;
char *cmdname; /* Pointer to our program name. */
char *dtpath; /* Path to our dt executable. */
FILE *efp; /* Default error data stream. */
FILE *ofp; /* Default output data stream. */
char *error_log; /* The error log file name. */
FILE *error_logfp; /* The error log file pointer. */
char *master_log; /* The master log file name. */
FILE *master_logfp; /* The master log file pointer. */
dinfo_t *master_dinfo; /* The parents' information. */
dinfo_t *iotune_dinfo; /* The I/O device information. */
char *reread_file; /* Optional re-read file name. */
char *tools_directory; /* The default tools directory. */
hbool_t DeleteErrorLogFlag = True; /* Controls error log deleting. */
hbool_t ExitFlag = False; /* In pipe mode, exit flag. */
hbool_t InteractiveFlag = False; /* Stay in interactive mode. */
hbool_t StdinIsAtty; /* Standard input isatty flag. */
hbool_t StdoutIsAtty; /* Standard output isatty flag. */
hbool_t StderrIsAtty; /* Standard error isatty flag. */
hbool_t PipeModeFlag = False; /* The pipe mode control flag. */
uint32_t PipeDelay = 250; /* Pipe mode delay value. */
int max_open_files = 0; /* The maximum open files. */
/*
* Default alarm message is per pass statistics, user can override.
*/
/* Note: To remain backwards compatable, I am not changing the default. */
#if defined(Nimble)
char *keepalive0 = "%d Stats: mode %i, blocks %l, %m Mbytes,"
" MB/sec: %mbps, IO/sec: %iops, pass %p/%P,"
" elapsed %t";
char *keepalive1 = "%d Stats: mode %i, blocks %L, %M Mbytes,"
" MB/sec: %mbps, IO/sec: %iops, pass %p/%P,"
" elapsed %T";
/* Default keepalive messages. */
#else /* !defined(Nimble) */
char *keepalive0 = "%d Stats: mode %i, blocks %l, %m Mbytes, pass %p/%P,"
" elapsed %t";
char *keepalive1 = "%d Stats: mode %i, blocks %L, %M Mbytes, pass %p/%P,"
" elapsed %T";
/* Default keepalive messages. */
#endif /* defined(Nimble) */
/*
* When stats is set to brief, these message strings get used:
* Remember: The stats type is automatically prepended: "End of TYPE"
*/
char *pass_msg = "pass %p/%P, %l blocks, %m Mbytes, %c records,"
" errors %e/%E, elapsed %t";
char *pass_dir_msg =
"pass %p/%P, %l blocks, %m Mbytes, %c records,"
" errors %e/%E, iodir=%iodir, elapsed %t";
char *pass_type_msg =
"pass %p/%P, %l blocks, %m Mbytes, %c records,"
" errors %e/%E, iotype=%iotype, elapsed %t";
/* Per pass keepalive message. */
char *totals_msg = "%d Totals: %L blocks, %M Mbytes,"
" errors %e/%E, passes %p/%P, elapsed %T";
/* Totals keepalive message. */
/*
* Data patterns used for multiple passes.
*/
u_int32 data_patterns[] = {
DEFAULT_PATTERN,
0x00ff00ffU,
0x0f0f0f0fU,
0xc6dec6deU,
0x6db6db6dU,
0x55555555U,
0xaaaaaaaaU, /* Complement of previous data pattern. */
0x33333333U, /* Continuous worst case pattern (media defects) */
0x26673333U, /* Frequency burst worst case pattern #1. */
0x66673326U, /* Frequency burst worst case pattern #2. */
0x71c7c71cU, /* Dibit worst case data pattern. */
0x00000000U,
0xffffffffU,
};
int npatterns = sizeof(data_patterns) / sizeof(u_int32);
/*
* This table is indexed by the operation type (enum optype):
*/
optiming_t optiming_table[] =
{
/* Operation Type Control Flag Name */
{ NONE_OP, False, NULL },
{ OPEN_OP, True, "open" },
{ CLOSE_OP, True, "close" },
{ READ_OP, True, "read" },
{ WRITE_OP, True, "write" },
{ IOCTL_OP, True, "ioctl" },
{ FSYNC_OP, True, "fsync" },
{ MSYNC_OP, True, "msync" },
{ AIOWAIT_OP, True, "aiowait" },
{ MKDIR_OP, True, "mkdir" },
{ RMDIR_OP, True, "rmdir" },
{ DELETE_OP, True, "unlink" },
{ TRUNCATE_OP, True, "truncate" },
{ RENAME_OP, True, "rename" },
{ LOCK_OP, True, "lock" },
{ UNLOCK_OP, True, "unlock" },
{ GETATTR_OP, True, "stat" },
{ SEEK_OP, True, "seek" },
{ SPARSE_OP, True, "sparse" },
{ TRIM_OP, True, "trim" },
{ VINFO_OP, True, "vinfo" },
{ VPATH_OP, True, "vpath" },
{ MMAP_OP, True, "mmap" },
{ MUNMAP_OP, True, "munmap" },
{ CANCEL_OP, True, "cancel" },
{ RESUME_OP, True, "resume" },
{ SUSPEND_OP, True, "suspend" },
{ TERMINATE_OP, True, "terminate"},
{ OTHER_OP, True, "other" }
};
char *miscompare_op = "miscompare";
int
HandleExit(dinfo_t *dip, int status)
{
/* Note: This may change, but don't wish to miss any errors! */
if (status == FAILURE) exit_status = status;
/*
* Commands like "help" or "version" will cause scripts to exit,
* but we don't wish to continue on fatal errors, so...
*/
if (InteractiveFlag || PipeModeFlag || dip->script_level) {
if (dip->script_level && (status == FAILURE)) {
finish_exiting(dip, status);
}
} else {
finish_exiting(dip, status);
}
return(status);
}
/*
* The mainline sets this up, need common for logging anywhere!
*/
void
log_header(dinfo_t *dip, hbool_t error_flag)
{
/*
* Write the command line for future reference.
*/
Lprintf(dip, "Command Line:\n\n %c ", getuid() ? '%' : '#');
Lprintf(dip, "%s\n", dip->di_cmd_line);
Lprintf(dip, "\n --> %s <--\n\n", version_str);
if (error_flag == True) {
eLflush(dip);
} else {
Lflush(dip);
}
return;
}
void
save_cmdline(dinfo_t *dip)
{
char buffer[LOG_BUFSIZE];
char *options;
if (dip->di_cmd_line) {
FreeStr(dip, dip->di_cmd_line);
dip->di_cmd_line = NULL;
}
options = make_options_string(dip, dip->argc, dip->argv, True);
if (options == NULL) return;
/* Include the dt path with the options. */
(void)sprintf(buffer, "%s %s", dtpath, options);
dip->di_cmd_line = strdup(buffer);
FreeStr(dip, options);
return;
}
int
ProcessStartupFile(dinfo_t *dip)
{
int status;
do {
terminating_flag = False;
CmdInterruptedFlag = False;
if ( (status = dtGetCommandLine(dip)) != SUCCESS) {
continue; /* EOF or FAILURE! */
}
if (dip->argc <= 0) continue;
/*
* Parse the arguments.
*/
if ( (status = parse_args(dip, dip->argc, dip->argv)) != SUCCESS) {
continue;
}
/* Note: The startup file should set flags or define workloads only. */
/* Note: We may expand and lift this restriction later (as required). */
} while ( !CmdInterruptedFlag && !terminating_flag && (status == SUCCESS) );
/* Reprime for parsing command line arguments. */
if (dip->cmdbufptr) {
FreeStr(dip, dip->cmdbufptr);
dip->cmdbufptr = NULL;
}
if (dip->argv) {
Free(dip, dip->argv);
dip->argv = NULL;
}
if (status == END_OF_FILE) status = SUCCESS;
return(status);
}
int
ProcessStartupScripts(dinfo_t *dip)
{
char filename[PATH_BUFFER_SIZE];
char *script_name;
char *home_dir;
int status = WARNING;
/*
* Script Order: (both are optional)
* 1) user defined script
* 2) normal startip script
* This allows #1 to override #2!
*/
if ((script_name = getenv(STARTUP_ENVNAME)) == NULL) {
script_name = STARTUP_SCRIPT;
if ((home_dir = getenv("HOME")) == NULL) {
return(status);
}
(void)sprintf(filename, "%s%c%s", home_dir, dip->di_dir_sep, script_name);
script_name = filename;
}
if ( os_file_exists(script_name) == False ) {
return(status);
}
status = OpenScriptFile(dip, script_name);
if (status == SUCCESS) {
status = ProcessStartupFile(dip);
}
return(status);
}
iobehavior_funcs_t *
find_iobehavior(dinfo_t *dip, char *name)
{
iobehavior_funcs_t **iobtp = &iobehavior_funcs_table[0];
iobehavior_funcs_t *iobf;
while ( iobf = *iobtp++ ) {
/* Switched to compare with length due to Windows .exe! */
if ( EQL(iobf->iob_name, name, strlen(iobf->iob_name)) ) {
return(iobf);
}
/* We now support a tool to dt mapping function. */
if ( iobf->iob_maptodt_name && EQL(iobf->iob_maptodt_name, name, strlen(iobf->iob_maptodt_name)) ) {
return(iobf);
}
}
return(NULL);
}
/*
* main() - Start of data transfer program.
*/
int
main(int argc, char **argv)
{
char *tmp;
dinfo_t *dip = NULL;
int pstatus, status;
hbool_t FirstTime = True;
hbool_t maptodt = False;
iobehavior_funcs_t *iobf = NULL;
#if defined(__unix)
struct rlimit rlim, *prlim = &rlim;
#endif /* defined(__unix) */
efp = stderr;
ofp = stdout;
/* Note: For Windows we need to check both path separators! (Cygwin) */
/* Also Note: Newer Windows appear to accept both separaters! really? */
tmp = strrchr(argv[0], POSIX_DIRSEP);
#if defined(WIN32)
if (tmp == NULL) {
tmp = strrchr(argv[0], DIRSEP); /* Native directory separator. */
}
#endif /* defined(WIN32) */
cmdname = tmp ? &(tmp[1]) : argv[0];
dip = master_dinfo = init_device_information();
dip->di_stdin_flag = False;
dip->di_stdout_flag = False;
dtpath = argv[0];
dip->di_process_id = os_getpid();
parent_process_id = os_getppid();
argc--; argv++; /* Skip our program name. */
page_size = getpagesize();
#if defined(__unix)
hertz = sysconf(_SC_CLK_TCK);
//max_open_files = sysconf(_SC_OPEN_MAX);
status = getrlimit(RLIMIT_NOFILE, prlim);
if (status == SUCCESS) {
max_open_files = prlim->rlim_cur;
}
if ((max_open_files < DEFAULT_MAX_OPEN_FILES) || getenv(MAXFILES_ENVNAME)) {
char *p;
if (p = getenv(MAXFILES_ENVNAME)) {
int maxfiles = number(dip, p, ANY_RADIX, &status, False);
if (status == SUCCESS) {
max_open_files = maxfiles;
}
} else {
max_open_files = DEFAULT_MAX_OPEN_FILES;
}
if (max_open_files > prlim->rlim_cur) {
if ( getuid() ) {
prlim->rlim_cur = prlim->rlim_max; /* non-root to hard limit! */
max_open_files = prlim->rlim_max;
} else {
prlim->rlim_cur = max_open_files; /* Try to set to higher limit. */
}
/* Note: This may fail, esp. for non-root users! */
status = setrlimit(RLIMIT_NOFILE, prlim);
}
}
#elif defined(WIN32x)
/* TODO: Don't think this is necessary now! */
/*
* Convert the pseudo handle into a real handle by duplicating!
*/
if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
GetCurrentProcess(), &ParentThread, 0, True, DUPLICATE_SAME_ACCESS)) {
wPerror(dip, "DuplicateHandle() failed");
}
#endif /* defined(WIN32) */
/* TODO: More cleanup! */
#if defined(OSFMK) || defined(__QNXNTO__) || defined(WIN32)
hertz = CLK_TCK; /* Actually a libc function. */
#endif /* defined(OSFMK) || defined(__QNX_NTO__) defined(WIN32) */
CmdInterruptedFlag = False;
StdinIsAtty = isatty(fileno(stdin));
StdoutIsAtty = isatty(fileno(stdout));
StderrIsAtty = isatty(fileno(stderr));
if (StdoutIsAtty == True) {
dip->di_logheader_flag = False;
dip->di_logtrailer_flag = False;
} else {
dip->di_logtrailer_flag = True;
}
(void)make_stderr_buffered(dip);
(void)init_pthread_attributes(dip);
(void)initialize_jobs_data(dip);
initialize_workloads_data();
status = ProcessStartupScripts(dip);
//if (tools_directory = NULL) {
// tools_directory = strdup(TOOLS_DIR);
//}
if (argc == 0) {
/* This must be done *after* processing startup files. */
InteractiveFlag = True;
}
catch_signals(dip);
if (dip->di_debug_flag || dip->di_pDebugFlag || dip->di_tDebugFlag) {
Printf(dip, "Parent process ID is %d, Thread ID is "OS_TID_FMT"\n",
dip->di_process_id, ParentThreadId);
}
dip->argc = argc;
dip->argv = argv;
/*
* Try to find the I/O behavior based on the program name.
* Note: The purpose of this is to link tool to dt and map!
*/
iobf = find_iobehavior(dip, cmdname);
/* Note: This check is necessary until we have dt I/O functions! */
if ( (iobf == NULL) && NEL("dt", cmdname, 2) ) {
Printf(dip, "Sorry, we don't know any I/O behavior named '%s'!\n", cmdname);
exit(FAILURE);
}
/* Handle special I/O tool mapping (if supported). */
if (iobf) {
int status = SUCCESS;
/* Special name to map tool options to dt options. */
if (iobf->iob_maptodt_name) {
maptodt = (EQS(cmdname, iobf->iob_maptodt_name)) ? True : False;
}
/* Map the tool options, if mapping is supported. */
if ( (maptodt == True) && iobf->iob_dtmap_options ) {
status = (*iobf->iob_dtmap_options)(dip, argc, argv);
exit(status); /* Only display the mapped options! */
} else if (iobf->iob_map_options) {
status = (*iobf->iob_map_options)(dip, argc, argv);
}
if (status == FAILURE) exit(status);
InteractiveFlag = False;
}
do {
dip = master_dinfo;
if (FirstTime) {
/* Parse command line options first! */
FirstTime = False;
#if defined(MEMORY_DEBUG) && defined(__linux__)
mtrace();
#endif /* defined(MEMORY_DEBUG) && defined(__linux__) */
} else {
terminating_flag = False;
CmdInterruptedFlag = False;
cleanup_device(dip, True);
init_device_defaults(dip);
if ( (pstatus = dtGetCommandLine(dip)) != SUCCESS) {
if (pstatus == END_OF_FILE) {
ExitFlag = True;
} else if (pstatus == FAILURE) {
dip->di_exit_status = exit_status = status = pstatus;
dip->di_exit_status = HandleExit(dip, pstatus);
}
continue;
}
}
if (dip->argc <= 0) continue;
/*
* Parse the arguments.
*/
if ( (pstatus = parse_args(dip, dip->argc, dip->argv)) != SUCCESS) {
dip->di_exit_status = HandleExit(dip, pstatus);
continue;
}
/* For elapsed time, initialze the start time. */
dip->di_start_time = times(&dip->di_stimes);
gettimeofday(&dip->di_start_timer, NULL);
#if 0
/*
* In interactive mode, check for any background jobs finishing.
* In non-interactive mode, we expect folks to wait for jobs!
* Note: This can be misleading to interactive users, remove?
*/
if ( (InteractiveFlag == True) && (dip->script_level == 0) ) {
status = jobs_finished(dip);
if (status == FAILURE) {
dip->di_exit_status = exit_status = status;
}
}
#endif /* 0 */