Fix rand_seed mismatches in verify phase
authorPuthikorn Voravootivat <puthik@chromium.org>
Wed, 5 Feb 2014 17:17:11 +0000 (10:17 -0700)
committerJens Axboe <axboe@kernel.dk>
Wed, 5 Feb 2014 17:17:11 +0000 (10:17 -0700)
In verify phase, the rand_seed generated on replay does not match
the written rand_seed.

Multiple problems are causing this:
1. In verify phase fio does not set io_u->rand_seed to compare with
   hdr->rand_seed
2. In randrw scenario, fio log is stored in red-black tree in "sorted by LBA"
   order.  Thus, it is imposible to replay the written order, or rather
   generate the seeds again in the same order.
3. In write phase, the code currently will generate rand_seed, write data
   and log rand_seed. When queuedepth > 1, it's possible the writes complete
   in a different order than rand_seed was generated.  Thus when replaying
   the log, the generated rand_seed might not match what was written.
4. verify_backlog option will start verification before all the data has been
   written and it make rand_seed replay code broken with current design.

Proposed fixes:
1. Use of existing verify_state to generate verify header.
   (and assumes this was the original intention of verify_state). And also
   adds code to replay rand_seed in verify phase.
2. If verifysort option is not enabled, store the write log in a list instead
   of the red-black tree. Otherwise, don't attempt to verify the rand_seed
   in the header.
3. In write phase,  generate rand_seed, log rand_seed, write data. I.e. log
   IO transactions in the order generated, not completed.
4. Don't verify rand_seed when verify_backlog is enabled.

Signed-off-by: Puthikorn Voravootivat <puthik@chromium.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
backend.c
io_u.c
iolog.c
verify.c

index 93e66325f08569ec23fee63eb020065191d30616..bf9d066e012abc8a44a938fcbf319a68a81d6d64 100644 (file)
--- a/backend.c
+++ b/backend.c
@@ -697,6 +697,13 @@ static uint64_t do_io(struct thread_data *td)
                 */
                if (td->o.verify != VERIFY_NONE && io_u->ddir == DDIR_READ &&
                    ((io_u->flags & IO_U_F_VER_LIST) || !td_rw(td))) {
                 */
                if (td->o.verify != VERIFY_NONE && io_u->ddir == DDIR_READ &&
                    ((io_u->flags & IO_U_F_VER_LIST) || !td_rw(td))) {
+
+                       if (!td->o.verify_pattern_bytes) {
+                               io_u->rand_seed = __rand(&td->__verify_state);
+                               if (sizeof(int) != sizeof(long *))
+                                       io_u->rand_seed *= __rand(&td->__verify_state);
+                       }
+
                        if (td->o.verify_async)
                                io_u->end_io = verify_io_u_async;
                        else
                        if (td->o.verify_async)
                                io_u->end_io = verify_io_u_async;
                        else
@@ -707,6 +714,12 @@ static uint64_t do_io(struct thread_data *td)
                else
                        td_set_runstate(td, TD_RUNNING);
 
                else
                        td_set_runstate(td, TD_RUNNING);
 
+               if (td_write(td) && io_u->ddir == DDIR_WRITE &&
+                   td->o.do_verify &&
+                   td->o.verify != VERIFY_NONE &&
+                   !td->o.experimental_verify)
+                       log_io_piece(td, io_u);
+
                ret = td_io_queue(td, io_u);
                switch (ret) {
                case FIO_Q_COMPLETED:
                ret = td_io_queue(td, io_u);
                switch (ret) {
                case FIO_Q_COMPLETED:
diff --git a/io_u.c b/io_u.c
index 518d884f867565cd70b398281797712d0be84755..f68b2139ef8de06d6946b8e3fbed208dc0691a55 100644 (file)
--- a/io_u.c
+++ b/io_u.c
@@ -1623,12 +1623,6 @@ static void io_completed(struct thread_data *td, struct io_u *io_u,
                                         utime_since_now(&td->start));
                }
 
                                         utime_since_now(&td->start));
                }
 
-               if (td_write(td) && idx == DDIR_WRITE &&
-                   td->o.do_verify &&
-                   td->o.verify != VERIFY_NONE &&
-                   !td->o.experimental_verify)
-                       log_io_piece(td, io_u);
-
                icd->bytes_done[idx] += bytes;
 
                if (io_u->end_io) {
                icd->bytes_done[idx] += bytes;
 
                if (io_u->end_io) {
diff --git a/iolog.c b/iolog.c
index ec29971f6a51dfd2d67dc3e00f0c90a76264c7fc..017b235c217a4e0ce52b298fd958386213001ef0 100644 (file)
--- a/iolog.c
+++ b/iolog.c
@@ -209,7 +209,7 @@ void log_io_piece(struct thread_data *td, struct io_u *io_u)
         * drop the old one, which we rely on the rb insert/lookup for
         * handling.
         */
         * drop the old one, which we rely on the rb insert/lookup for
         * handling.
         */
-       if ((!td_random(td) || !td->o.overwrite) &&
+       if (((!td->o.verifysort) || !td_random(td) || !td->o.overwrite) &&
              (file_randommap(td, ipo->file) || td->o.verify == VERIFY_NONE)) {
                INIT_FLIST_HEAD(&ipo->list);
                flist_add_tail(&ipo->list, &td->io_hist_list);
              (file_randommap(td, ipo->file) || td->o.verify == VERIFY_NONE)) {
                INIT_FLIST_HEAD(&ipo->list);
                flist_add_tail(&ipo->list, &td->io_hist_list);
index 568bae85cd167836e9e756067fecd90ff0fa666e..90cd093add1fbbb13ba2f9d713ce60dc9e4f49e9 100644 (file)
--- a/verify.c
+++ b/verify.c
@@ -72,10 +72,10 @@ void fill_verify_pattern(struct thread_data *td, void *p, unsigned int len,
                if (use_seed)
                        __fill_random_buf(p, len, seed);
                else
                if (use_seed)
                        __fill_random_buf(p, len, seed);
                else
-                       io_u->rand_seed = fill_random_buf(&td->buf_state, p, len);
+                       io_u->rand_seed = fill_random_buf(&td->__verify_state, p, len);
                return;
        }
                return;
        }
-       
+
        if (io_u->buf_filled_len >= len) {
                dprint(FD_VERIFY, "using already filled verify pattern b=%d len=%u\n",
                        td->o.verify_pattern_bytes, len);
        if (io_u->buf_filled_len >= len) {
                dprint(FD_VERIFY, "using already filled verify pattern b=%d len=%u\n",
                        td->o.verify_pattern_bytes, len);
@@ -718,6 +718,13 @@ int verify_io_u(struct thread_data *td, struct io_u *io_u)
                        memswp(p, p + td->o.verify_offset, header_size);
                hdr = p;
 
                        memswp(p, p + td->o.verify_offset, header_size);
                hdr = p;
 
+               /*
+                * Make rand_seed check pass when have verifysort or
+                * verify_backlog.
+                */
+               if (td->o.verifysort || (td->flags & TD_F_VER_BACKLOG))
+                       io_u->rand_seed = hdr->rand_seed;
+
                ret = verify_header(io_u, hdr);
                switch (ret) {
                case 0:
                ret = verify_header(io_u, hdr);
                switch (ret) {
                case 0:
@@ -1056,6 +1063,12 @@ int get_next_verify(struct thread_data *td, struct io_u *io_u)
                remove_trim_entry(td, ipo);
                free(ipo);
                dprint(FD_VERIFY, "get_next_verify: ret io_u %p\n", io_u);
                remove_trim_entry(td, ipo);
                free(ipo);
                dprint(FD_VERIFY, "get_next_verify: ret io_u %p\n", io_u);
+
+               if (!td->o.verify_pattern_bytes) {
+                       io_u->rand_seed = __rand(&td->__verify_state);
+                       if (sizeof(int) != sizeof(long *))
+                               io_u->rand_seed *= __rand(&td->__verify_state);
+               }
                return 0;
        }
 
                return 0;
        }