"Fossies" - the Fresh Open Source Software Archive

Member "stress-ng-0.09.56/stress-hdd.c" (15 Mar 2019, 18069 Bytes) of package /linux/privat/stress-ng-0.09.56.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "stress-hdd.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 0.09.54_vs_0.09.55.

    1 /*
    2  * Copyright (C) 2013-2019 Canonical, Ltd.
    3  *
    4  * This program is free software; you can redistribute it and/or
    5  * modify it under the terms of the GNU General Public License
    6  * as published by the Free Software Foundation; either version 2
    7  * of the License, or (at your option) any later version.
    8  *
    9  * This program is distributed in the hope that it will be useful,
   10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   12  * GNU General Public License for more details.
   13  *
   14  * You should have received a copy of the GNU General Public License
   15  * along with this program; if not, write to the Free Software
   16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
   17  *
   18  * This code is a complete clean re-write of the stress tool by
   19  * Colin Ian King <colin.king@canonical.com> and attempts to be
   20  * backwardly compatible with the stress tool by Amos Waterland
   21  * <apw@rossby.metr.ou.edu> but has more stress tests and more
   22  * functionality.
   23  *
   24  */
   25 #include "stress-ng.h"
   26 
   27 #define BUF_ALIGNMENT       (4096)
   28 #define HDD_IO_VEC_MAX      (16)        /* Must be power of 2 */
   29 
   30 /* Write and read stress modes */
   31 #define HDD_OPT_WR_SEQ      (0x00000001)
   32 #define HDD_OPT_WR_RND      (0x00000002)
   33 #define HDD_OPT_RD_SEQ      (0x00000010)
   34 #define HDD_OPT_RD_RND      (0x00000020)
   35 #define HDD_OPT_WR_MASK     (0x00000003)
   36 #define HDD_OPT_RD_MASK     (0x00000030)
   37 
   38 /* POSIX fadvise modes */
   39 #define HDD_OPT_FADV_NORMAL (0x00000100)
   40 #define HDD_OPT_FADV_SEQ    (0x00000200)
   41 #define HDD_OPT_FADV_RND    (0x00000400)
   42 #define HDD_OPT_FADV_NOREUSE    (0x00000800)
   43 #define HDD_OPT_FADV_WILLNEED   (0x00001000)
   44 #define HDD_OPT_FADV_DONTNEED   (0x00002000)
   45 #define HDD_OPT_FADV_MASK   (0x00003f00)
   46 
   47 /* Open O_* modes */
   48 #define HDD_OPT_O_SYNC      (0x00010000)
   49 #define HDD_OPT_O_DSYNC     (0x00020000)
   50 #define HDD_OPT_O_DIRECT    (0x00040000)
   51 #define HDD_OPT_O_NOATIME   (0x00080000)
   52 #define HDD_OPT_O_MASK      (0x000f0000)
   53 
   54 /* Other modes */
   55 #define HDD_OPT_IOVEC       (0x00100000)
   56 #define HDD_OPT_UTIMES      (0x00200000)
   57 #define HDD_OPT_FSYNC       (0x00400000)
   58 #define HDD_OPT_FDATASYNC   (0x00800000)
   59 #define HDD_OPT_SYNCFS      (0x01000000)
   60 
   61 typedef struct {
   62     const char *opt;    /* User option */
   63     const int flag;     /* HDD_OPT_ flag */
   64     const int exclude;  /* Excluded HDD_OPT_ flags */
   65     const int advice;   /* posix_fadvise value */
   66     const int oflag;    /* open O_* flags */
   67 } hdd_opts_t;
   68 
   69 static const hdd_opts_t hdd_opts[] = {
   70 #if defined(O_SYNC)
   71     { "sync",   HDD_OPT_O_SYNC, 0, 0, O_SYNC },
   72 #endif
   73 #if defined(O_DSYNC)
   74     { "dsync",  HDD_OPT_O_DSYNC, 0, 0, O_DSYNC },
   75 #endif
   76 #if defined(O_DIRECT)
   77     { "direct", HDD_OPT_O_DIRECT, 0, 0, O_DIRECT },
   78 #endif
   79 #if defined(O_NOATIME)
   80     { "noatime",    HDD_OPT_O_NOATIME, 0, 0, O_NOATIME },
   81 #endif
   82 #if defined(HAVE_POSIX_FADVISE) && defined(POSIX_FADV_NORMAL)
   83     { "wr-seq", HDD_OPT_WR_SEQ, HDD_OPT_WR_RND, 0, 0 },
   84     { "wr-rnd", HDD_OPT_WR_RND, HDD_OPT_WR_SEQ, 0, 0 },
   85     { "rd-seq", HDD_OPT_RD_SEQ, HDD_OPT_RD_RND, 0, 0 },
   86     { "rd-rnd", HDD_OPT_RD_RND, HDD_OPT_RD_SEQ, 0, 0 },
   87     { "fadv-normal",HDD_OPT_FADV_NORMAL,
   88         (HDD_OPT_FADV_SEQ | HDD_OPT_FADV_RND |
   89          HDD_OPT_FADV_NOREUSE | HDD_OPT_FADV_WILLNEED |
   90          HDD_OPT_FADV_DONTNEED),
   91         POSIX_FADV_NORMAL, 0 },
   92 #endif
   93 #if defined(HAVE_POSIX_FADVISE) && defined(POSIX_FADV_SEQ)
   94     { "fadv-seq",   HDD_OPT_FADV_SEQ,
   95         (HDD_OPT_FADV_NORMAL | HDD_OPT_FADV_RND),
   96         POSIX_FADV_SEQUENTIAL, 0 },
   97 #endif
   98 #if defined(HAVE_POSIX_FADVISE) && defined(POSIX_FADV_RANDOM)
   99     { "fadv-rnd",   HDD_OPT_FADV_RND,
  100         (HDD_OPT_FADV_NORMAL | HDD_OPT_FADV_SEQ),
  101         POSIX_FADV_RANDOM, 0 },
  102 #endif
  103 #if defined(HAVE_POSIX_FADVISE) && defined(POSIX_FADV_NOREUSE)
  104     { "fadv-noreuse", HDD_OPT_FADV_NOREUSE,
  105         HDD_OPT_FADV_NORMAL,
  106         POSIX_FADV_NOREUSE, 0 },
  107 #endif
  108 #if defined(HAVE_POSIX_FADVISE) && defined(POSIX_FADV_WILLNEED)
  109     { "fadv-willneed", HDD_OPT_FADV_WILLNEED,
  110         (HDD_OPT_FADV_NORMAL | HDD_OPT_FADV_DONTNEED),
  111         POSIX_FADV_WILLNEED, 0 },
  112 #endif
  113 #if defined(HAVE_POSIX_FADVISE) && defined(POSIX_FADV_DONTNEED)
  114     { "fadv-dontneed", HDD_OPT_FADV_DONTNEED,
  115         (HDD_OPT_FADV_NORMAL | HDD_OPT_FADV_WILLNEED),
  116         POSIX_FADV_DONTNEED, 0 },
  117 #endif
  118 #if defined(HAVE_FSYNC)
  119     { "fsync",  HDD_OPT_FSYNC, 0, 0, 0 },
  120 #endif
  121 #if defined(HAVE_FDATASYNC)
  122     { "fdatasync",  HDD_OPT_FDATASYNC, 0, 0, 0 },
  123 #endif
  124     { "iovec",  HDD_OPT_IOVEC, 0, 0, 0 },
  125 #if defined(HAVE_SYNCFS)
  126     { "syncfs", HDD_OPT_SYNCFS, 0, 0, 0 },
  127 #endif
  128     { "utimes", HDD_OPT_UTIMES, 0, 0, 0 },
  129 };
  130 
  131 int stress_set_hdd_bytes(const char *opt)
  132 {
  133     uint64_t hdd_bytes;
  134 
  135     hdd_bytes = get_uint64_byte_filesystem(opt, 1);
  136     check_range_bytes("hdd-bytes", hdd_bytes,
  137         MIN_HDD_BYTES, MAX_HDD_BYTES);
  138     return set_setting("hdd-bytes", TYPE_ID_UINT64, &hdd_bytes);
  139 }
  140 
  141 int stress_set_hdd_write_size(const char *opt)
  142 {
  143     uint64_t hdd_write_size;
  144 
  145     hdd_write_size = get_uint64_byte(opt);
  146     check_range_bytes("hdd-write-size", hdd_write_size,
  147         MIN_HDD_WRITE_SIZE, MAX_HDD_WRITE_SIZE);
  148     return set_setting("hdd-write-size", TYPE_ID_UINT64, &hdd_write_size);
  149 }
  150 
  151 /*
  152  *  stress_hdd_write()
  153  *  write with writev or write depending on mode
  154  */
  155 static ssize_t stress_hdd_write(
  156     const int fd,
  157     uint8_t *buf,
  158     const size_t count,
  159     const uint64_t hdd_write_size,
  160     const int hdd_flags)
  161 {
  162     ssize_t ret;
  163 
  164 #if defined(HAVE_FUTIMES)
  165     if (hdd_flags & HDD_OPT_UTIMES)
  166         (void)futimes(fd, NULL);
  167 #endif
  168 
  169     if (hdd_flags & HDD_OPT_IOVEC) {
  170         struct iovec iov[HDD_IO_VEC_MAX];
  171         size_t i;
  172         uint8_t *data = buf;
  173         const uint64_t sz = hdd_write_size / HDD_IO_VEC_MAX;
  174 
  175         for (i = 0; i < HDD_IO_VEC_MAX; i++) {
  176             iov[i].iov_base = (void *)data;
  177             iov[i].iov_len = (size_t)sz;
  178 
  179             data += sz;
  180         }
  181         ret = writev(fd, iov, HDD_IO_VEC_MAX);
  182     } else {
  183         ret = write(fd, buf, count);
  184     }
  185 
  186 #if defined(HAVE_FSYNC)
  187     if (hdd_flags & HDD_OPT_FSYNC)
  188         (void)shim_fsync(fd);
  189 #endif
  190 #if defined(HAVE_FDATASYNC)
  191     if (hdd_flags & HDD_OPT_FDATASYNC)
  192         (void)shim_fdatasync(fd);
  193 #endif
  194 #if defined(HAVE_SYNCFS)
  195     if (hdd_flags & HDD_OPT_SYNCFS)
  196         (void)syncfs(fd);
  197 #endif
  198 
  199     return ret;
  200 }
  201 
  202 /*
  203  *  stress_hdd_read()
  204  *  read with readv or read depending on mode
  205  */
  206 static ssize_t stress_hdd_read(
  207     const int fd,
  208     uint8_t *buf,
  209     const size_t count,
  210     const uint64_t hdd_write_size,
  211     const int hdd_flags)
  212 {
  213 #if defined(HAVE_FUTIMES)
  214     if (hdd_flags & HDD_OPT_UTIMES)
  215         (void)futimes(fd, NULL);
  216 #endif
  217 
  218     if (hdd_flags & HDD_OPT_IOVEC) {
  219         struct iovec iov[HDD_IO_VEC_MAX];
  220         size_t i;
  221         uint8_t *data = buf;
  222         const uint64_t sz = hdd_write_size / HDD_IO_VEC_MAX;
  223 
  224         for (i = 0; i < HDD_IO_VEC_MAX; i++) {
  225             iov[i].iov_base = (void *)data;
  226             iov[i].iov_len = (size_t)sz;
  227 
  228             data += sz;
  229         }
  230         return readv(fd, iov, HDD_IO_VEC_MAX);
  231     } else {
  232         return read(fd, buf, count);
  233     }
  234 }
  235 
  236 
  237 /*
  238  *  stress_set_hdd_opts
  239  *  parse --hdd-opts option(s) list
  240  */
  241 int stress_set_hdd_opts(const char *opts)
  242 {
  243     char *str, *ptr, *token;
  244     int hdd_flags = 0;
  245     int hdd_oflags = 0;
  246     bool opts_set = false;
  247 
  248     str = stress_const_optdup(opts);
  249     if (!str)
  250         return -1;
  251 
  252     for (ptr = str; (token = strtok(ptr, ",")) != NULL; ptr = NULL) {
  253         size_t i;
  254         bool opt_ok = false;
  255 
  256         for (i = 0; i < SIZEOF_ARRAY(hdd_opts); i++) {
  257             if (!strcmp(token, hdd_opts[i].opt)) {
  258                 int exclude = hdd_flags & hdd_opts[i].exclude;
  259                 if (exclude) {
  260                     int j;
  261 
  262                     for (j = 0; hdd_opts[j].opt; j++) {
  263                         if ((exclude & hdd_opts[j].flag) == exclude) {
  264                             (void)fprintf(stderr,
  265                                 "hdd-opt option '%s' is not "
  266                                 "compatible with option '%s'\n",
  267                                 token,
  268                                 hdd_opts[j].opt);
  269                             break;
  270                         }
  271                     }
  272                     free(str);
  273                     return -1;
  274                 }
  275                 hdd_flags  |= hdd_opts[i].flag;
  276                 hdd_oflags |= hdd_opts[i].oflag;
  277                 opt_ok = true;
  278                 opts_set = true;
  279             }
  280         }
  281         if (!opt_ok) {
  282             (void)fprintf(stderr, "hdd-opt option '%s' not known, options are:", token);
  283             for (i = 0; i < SIZEOF_ARRAY(hdd_opts); i++)
  284                 (void)fprintf(stderr, "%s %s",
  285                     i == 0 ? "" : ",", hdd_opts[i].opt);
  286             (void)fprintf(stderr, "\n");
  287             free(str);
  288             return -1;
  289         }
  290     }
  291 
  292     set_setting("hdd-flags", TYPE_ID_INT, &hdd_flags);
  293     set_setting("hdd-oflags", TYPE_ID_INT, &hdd_oflags);
  294     set_setting("hdd-opts-set", TYPE_ID_BOOL, &opts_set);
  295     free(str);
  296 
  297     return 0;
  298 }
  299 
  300 /*
  301  *  stress_hdd_advise()
  302  *  set posix_fadvise options
  303  */
  304 static int stress_hdd_advise(const args_t *args, const int fd, const int flags)
  305 {
  306 #if (defined(POSIX_FADV_SEQ) || defined(POSIX_FADV_RANDOM) || \
  307     defined(POSIX_FADV_NOREUSE) || defined(POSIX_FADV_WILLNEED) || \
  308     defined(POSIX_FADV_DONTNEED)) && defined(HAVE_POSIX_FADVISE)
  309     size_t i;
  310 
  311     if (!(flags & HDD_OPT_FADV_MASK))
  312         return 0;
  313 
  314     for (i = 0; i < SIZEOF_ARRAY(hdd_opts); i++) {
  315         if (hdd_opts[i].flag & flags) {
  316             if (posix_fadvise(fd, 0, 0, hdd_opts[i].advice) < 0) {
  317                 pr_fail_err("posix_fadvise");
  318                 return -1;
  319             }
  320         }
  321     }
  322 #else
  323     (void)args;
  324     (void)fd;
  325     (void)flags;
  326 #endif
  327     return 0;
  328 }
  329 /*
  330  *  stress_hdd
  331  *  stress I/O via writes
  332  */
  333 static int stress_hdd(const args_t *args)
  334 {
  335     uint8_t *buf = NULL;
  336     void *alloc_buf;
  337     uint64_t i, min_size, remainder;
  338     int rc = EXIT_FAILURE;
  339     ssize_t ret;
  340     char filename[PATH_MAX];
  341     size_t opt_index = 0;
  342     uint64_t hdd_bytes = DEFAULT_HDD_BYTES;
  343     uint64_t hdd_write_size = DEFAULT_HDD_WRITE_SIZE;
  344     int hdd_flags = 0, hdd_oflags = 0;
  345     int flags, fadvise_flags;
  346     bool opts_set = false;
  347 
  348     (void)get_setting("hdd-flags", &hdd_flags);
  349     (void)get_setting("hdd-oflags", &hdd_oflags);
  350     (void)get_setting("hdd-opts-set", &opts_set);
  351 
  352     flags = O_CREAT | O_RDWR | O_TRUNC | hdd_oflags;
  353     fadvise_flags = hdd_flags & HDD_OPT_FADV_MASK;
  354 
  355     if (!get_setting("hdd-bytes", &hdd_bytes)) {
  356         if (g_opt_flags & OPT_FLAGS_MAXIMIZE)
  357             hdd_bytes = MAX_HDD_BYTES;
  358         if (g_opt_flags & OPT_FLAGS_MINIMIZE)
  359             hdd_bytes = MIN_HDD_BYTES;
  360     }
  361 
  362     hdd_bytes /= args->num_instances;
  363     if (hdd_bytes < MIN_HDD_WRITE_SIZE)
  364         hdd_bytes = MIN_HDD_WRITE_SIZE;
  365 
  366     if (!get_setting("hdd-write-size", &hdd_write_size)) {
  367         if (g_opt_flags & OPT_FLAGS_MAXIMIZE)
  368             hdd_write_size = MAX_HDD_WRITE_SIZE;
  369         if (g_opt_flags & OPT_FLAGS_MINIMIZE)
  370             hdd_write_size = MIN_HDD_WRITE_SIZE;
  371     }
  372 
  373     if (hdd_flags & HDD_OPT_O_DIRECT) {
  374         min_size = (hdd_flags & HDD_OPT_IOVEC) ?
  375             HDD_IO_VEC_MAX * BUF_ALIGNMENT : MIN_HDD_WRITE_SIZE;
  376     } else {
  377         min_size = (hdd_flags & HDD_OPT_IOVEC) ?
  378             HDD_IO_VEC_MAX * MIN_HDD_WRITE_SIZE : MIN_HDD_WRITE_SIZE;
  379     }
  380     /* Ensure I/O size is not too small */
  381     if (hdd_write_size < min_size) {
  382         hdd_write_size = min_size;
  383         pr_inf("%s: increasing read/write size to %"
  384             PRIu64 " bytes\n", args->name, hdd_write_size);
  385     }
  386 
  387     /* Ensure we get same sized iovec I/O sizes */
  388     remainder = hdd_write_size % HDD_IO_VEC_MAX;
  389     if ((hdd_flags & HDD_OPT_IOVEC) && (remainder != 0)) {
  390         hdd_write_size += HDD_IO_VEC_MAX - remainder;
  391         pr_inf("%s: increasing read/write size to %"
  392             PRIu64 " bytes in iovec mode\n",
  393             args->name, hdd_write_size);
  394     }
  395 
  396     /* Ensure complete file size is not less than the I/O size */
  397     if (hdd_bytes < hdd_write_size) {
  398         hdd_bytes = hdd_write_size;
  399         pr_inf("%s: increasing file size to write size of %"
  400             PRIu64 " bytes\n",
  401             args->name, hdd_bytes);
  402     }
  403 
  404 
  405     ret = stress_temp_dir_mk_args(args);
  406     if (ret < 0)
  407         return exit_status(-ret);
  408 
  409     /* Must have some write option */
  410     if ((hdd_flags & HDD_OPT_WR_MASK) == 0)
  411         hdd_flags |= HDD_OPT_WR_SEQ;
  412     /* Must have some read option */
  413     if ((hdd_flags & HDD_OPT_RD_MASK) == 0)
  414         hdd_flags |= HDD_OPT_RD_SEQ;
  415 
  416 #if defined(HAVE_POSIX_MEMALIGN)
  417     ret = posix_memalign((void **)&alloc_buf, BUF_ALIGNMENT, (size_t)hdd_write_size);
  418     if (ret || !alloc_buf) {
  419         rc = exit_status(errno);
  420         pr_err("%s: cannot allocate buffer\n", args->name);
  421         (void)stress_temp_dir_rm_args(args);
  422         return rc;
  423     }
  424     buf = alloc_buf;
  425 #else
  426     /* Work around lack of posix_memalign */
  427     alloc_buf = malloc((size_t)hdd_write_size + BUF_ALIGNMENT);
  428     if (!alloc_buf) {
  429         pr_err("%s: cannot allocate buffer\n", args->name);
  430         (void)stress_temp_dir_rm_args(args);
  431         return rc;
  432     }
  433     buf = (uint8_t *)stress_align_address(alloc_buf, BUF_ALIGNMENT);
  434 #endif
  435 
  436     stress_strnrnd((char *)buf, hdd_write_size);
  437 
  438     (void)stress_temp_filename_args(args,
  439         filename, sizeof(filename), mwc32());
  440     do {
  441         int fd;
  442         struct stat statbuf;
  443         uint64_t hdd_read_size;
  444 
  445         /*
  446          * aggressive option with no other option enables
  447          * the "work through all the options" mode
  448          */
  449         if (!opts_set && (g_opt_flags & OPT_FLAGS_AGGRESSIVE)) {
  450             opt_index = (opt_index + 1) % SIZEOF_ARRAY(hdd_opts);
  451 
  452             hdd_flags  = hdd_opts[opt_index].flag;
  453             hdd_oflags = hdd_opts[opt_index].oflag;
  454             if ((hdd_flags & HDD_OPT_WR_MASK) == 0)
  455                 hdd_flags |= HDD_OPT_WR_SEQ;
  456             if ((hdd_flags & HDD_OPT_RD_MASK) == 0)
  457                 hdd_flags |= HDD_OPT_RD_SEQ;
  458         }
  459 
  460         if ((fd = open(filename, flags, S_IRUSR | S_IWUSR)) < 0) {
  461             if ((errno == ENOSPC) || (errno == ENOMEM))
  462                 continue;   /* Retry */
  463             pr_fail_err("open");
  464             goto finish;
  465         }
  466 
  467         /* Exercise ftruncate or truncate */
  468         if (mwc1()) {
  469             if (ftruncate(fd, (off_t)0) < 0) {
  470                 pr_fail_err("ftruncate");
  471                 (void)close(fd);
  472                 goto finish;
  473             }
  474         } else {
  475             if (truncate(filename, (off_t)0) < 0) {
  476                 pr_fail_err("truncate");
  477                 (void)close(fd);
  478                 goto finish;
  479             }
  480         }
  481         (void)unlink(filename);
  482 
  483         if (!keep_stressing()) {
  484             (void)close(fd);
  485             goto yielded;
  486         }
  487 
  488         if (stress_hdd_advise(args, fd, fadvise_flags) < 0) {
  489             (void)close(fd);
  490             goto finish;
  491         }
  492 
  493         /* Random Write */
  494         if (hdd_flags & HDD_OPT_WR_RND) {
  495             for (i = 0; i < hdd_bytes; i += hdd_write_size) {
  496                 size_t j;
  497 
  498                 off_t offset = (i == 0) ?
  499                     hdd_bytes :
  500                     (mwc64() % hdd_bytes) & ~511;
  501 
  502                 if (lseek(fd, offset, SEEK_SET) < 0) {
  503                     pr_fail_err("lseek");
  504                     (void)close(fd);
  505                     goto finish;
  506                 }
  507 rnd_wr_retry:
  508                 if (!keep_stressing()) {
  509                     (void)close(fd);
  510                     goto yielded;
  511                 }
  512 
  513                 for (j = 0; j < hdd_write_size; j++)
  514                     buf[j] = (offset + j) & 0xff;
  515 
  516                 ret = stress_hdd_write(fd, buf, (size_t)hdd_write_size,
  517                     hdd_write_size, hdd_flags);
  518                 if (ret <= 0) {
  519                     if ((errno == EAGAIN) || (errno == EINTR))
  520                         goto rnd_wr_retry;
  521                     if (errno == ENOSPC)
  522                         break;
  523                     if (errno) {
  524                         pr_fail_err("write");
  525                         (void)close(fd);
  526                         goto finish;
  527                     }
  528                     continue;
  529                 }
  530                 inc_counter(args);
  531             }
  532         }
  533         /* Sequential Write */
  534         if (hdd_flags & HDD_OPT_WR_SEQ) {
  535             for (i = 0; i < hdd_bytes; i += hdd_write_size) {
  536                 size_t j;
  537 seq_wr_retry:
  538                 if (!keep_stressing()) {
  539                     (void)close(fd);
  540                     goto yielded;
  541                 }
  542 
  543                 for (j = 0; j < hdd_write_size; j += 512)
  544                     buf[j] = (i + j) & 0xff;
  545                 ret = stress_hdd_write(fd, buf, (size_t)hdd_write_size,
  546                     hdd_write_size, hdd_flags);
  547                 if (ret <= 0) {
  548                     if ((errno == EAGAIN) || (errno == EINTR))
  549                         goto seq_wr_retry;
  550                     if (errno == ENOSPC)
  551                         break;
  552                     if (errno) {
  553                         pr_fail_err("write");
  554                         (void)close(fd);
  555                         goto finish;
  556                     }
  557                     continue;
  558                 }
  559                 inc_counter(args);
  560             }
  561         }
  562 
  563         if (fstat(fd, &statbuf) < 0) {
  564             pr_fail_err("fstat");
  565             (void)close(fd);
  566             continue;
  567         }
  568         /* Round to write size to get no partial reads */
  569         hdd_read_size = (uint64_t)statbuf.st_size -
  570             (statbuf.st_size % hdd_write_size);
  571 
  572         /* Sequential Read */
  573         if (hdd_flags & HDD_OPT_RD_SEQ) {
  574             uint64_t misreads = 0;
  575             uint64_t baddata = 0;
  576 
  577             if (lseek(fd, 0, SEEK_SET) < 0) {
  578                 pr_fail_err("lseek");
  579                 (void)close(fd);
  580                 goto finish;
  581             }
  582             for (i = 0; i < hdd_read_size; i += hdd_write_size) {
  583 seq_rd_retry:
  584                 if (!keep_stressing()) {
  585                     (void)close(fd);
  586                     goto yielded;
  587                 }
  588 
  589                 ret = stress_hdd_read(fd, buf, (size_t)hdd_write_size,
  590                     hdd_write_size, hdd_flags);
  591                 if (ret <= 0) {
  592                     if ((errno == EAGAIN) || (errno == EINTR))
  593                         goto seq_rd_retry;
  594                     if (errno) {
  595                         pr_fail_err("read");
  596                         (void)close(fd);
  597                         goto finish;
  598                     }
  599                     continue;
  600                 }
  601                 if (ret != (ssize_t)hdd_write_size)
  602                     misreads++;
  603 
  604                 if (g_opt_flags & OPT_FLAGS_VERIFY) {
  605                     size_t j;
  606 
  607                     for (j = 0; j < hdd_write_size; j += 512) {
  608                         uint8_t v = (i + j) & 0xff;
  609                         if (hdd_flags & HDD_OPT_WR_SEQ) {
  610                             /* Write seq has written to all of the file, so it should always be OK */
  611                             if (buf[0] != v)
  612                                 baddata++;
  613                         } else {
  614                             /* Write rnd has written to some of the file, so data either zero or OK */
  615                             if (buf[0] != 0 && buf[0] != v)
  616                                 baddata++;
  617                         }
  618                     }
  619                 }
  620                 inc_counter(args);
  621             }
  622             if (misreads)
  623                 pr_dbg("%s: %" PRIu64
  624                     " incomplete sequential reads\n",
  625                     args->name, misreads);
  626             if (baddata)
  627                 pr_fail("%s: incorrect data found %"
  628                     PRIu64 " times\n", args->name, baddata);
  629         }
  630         /* Random Read */
  631         if (hdd_flags & HDD_OPT_RD_RND) {
  632             uint64_t misreads = 0;
  633             uint64_t baddata = 0;
  634 
  635             for (i = 0; i < hdd_read_size; i += hdd_write_size) {
  636                 off_t offset = (hdd_bytes > hdd_write_size) ?
  637                     (mwc64() % (hdd_bytes - hdd_write_size)) & ~511 : 0;
  638 
  639                 if (lseek(fd, offset, SEEK_SET) < 0) {
  640                     pr_fail_err("lseek");
  641                     (void)close(fd);
  642                     goto finish;
  643                 }
  644 rnd_rd_retry:
  645                 if (!keep_stressing()) {
  646                     (void)close(fd);
  647                     goto yielded;
  648                 }
  649                 ret = stress_hdd_read(fd, buf, (size_t)hdd_write_size,
  650                     hdd_write_size, hdd_flags);
  651                 if (ret <= 0) {
  652                     if ((errno == EAGAIN) || (errno == EINTR))
  653                         goto rnd_rd_retry;
  654                     if (errno) {
  655                         pr_fail_err("read");
  656                         (void)close(fd);
  657                         goto finish;
  658                     }
  659                     continue;
  660                 }
  661                 if (ret != (ssize_t)hdd_write_size)
  662                     misreads++;
  663 
  664                 if (g_opt_flags & OPT_FLAGS_VERIFY) {
  665                     size_t j;
  666 
  667                     for (j = 0; j < hdd_write_size; j += 512) {
  668                         uint8_t v = (i + j) & 0xff;
  669                         if (hdd_flags & HDD_OPT_WR_SEQ) {
  670                             /* Write seq has written to all of the file, so it should always be OK */
  671                             if (buf[0] != v)
  672                                 baddata++;
  673                         } else {
  674                             /* Write rnd has written to some of the file, so data either zero or OK */
  675                             if (buf[0] != 0 && buf[0] != v)
  676                                 baddata++;
  677                         }
  678                     }
  679                 }
  680                 inc_counter(args);
  681             }
  682             if (misreads)
  683                 pr_dbg("%s: %" PRIu64
  684                     " incomplete random reads\n",
  685                     args->name, misreads);
  686         }
  687         (void)close(fd);
  688 
  689     } while (keep_stressing());
  690 
  691 yielded:
  692     rc = EXIT_SUCCESS;
  693 finish:
  694     free(alloc_buf);
  695     (void)stress_temp_dir_rm_args(args);
  696     return rc;
  697 }
  698 
  699 stressor_info_t stress_hdd_info = {
  700     .stressor = stress_hdd,
  701     .class = CLASS_IO | CLASS_OS
  702 };