+static int get_next_seq_offset(struct thread_data *td, struct fio_file *f,
+ enum fio_ddir ddir, uint64_t *offset)
+{
+ assert(ddir_rw(ddir));
+
+ if (f->last_pos >= f->io_size + get_start_offset(td) && td->o.time_based)
+ f->last_pos = f->last_pos - f->io_size;
+
+ if (f->last_pos < f->real_file_size) {
+ uint64_t pos;
+
+ if (f->last_pos == f->file_offset && td->o.ddir_seq_add < 0)
+ f->last_pos = f->real_file_size;
+
+ pos = f->last_pos - f->file_offset;
+ if (pos)
+ pos += td->o.ddir_seq_add;
+
+ *offset = pos;
+ return 0;
+ }
+
+ return 1;
+}
+
+static int get_next_block(struct thread_data *td, struct io_u *io_u,
+ enum fio_ddir ddir, int rw_seq,
+ unsigned int *is_random)
+{
+ struct fio_file *f = io_u->file;
+ uint64_t b, offset;
+ int ret;
+
+ assert(ddir_rw(ddir));
+
+ b = offset = -1ULL;
+
+ if (rw_seq) {
+ if (td_random(td)) {
+ if (should_do_random(td, ddir)) {
+ ret = get_next_rand_block(td, f, ddir, &b);
+ *is_random = 1;
+ } else {
+ *is_random = 0;
+ io_u->flags |= IO_U_F_BUSY_OK;
+ ret = get_next_seq_offset(td, f, ddir, &offset);
+ if (ret)
+ ret = get_next_rand_block(td, f, ddir, &b);
+ }
+ } else {
+ *is_random = 0;
+ ret = get_next_seq_offset(td, f, ddir, &offset);
+ }
+ } else {
+ io_u->flags |= IO_U_F_BUSY_OK;
+ *is_random = 0;
+
+ if (td->o.rw_seq == RW_SEQ_SEQ) {
+ ret = get_next_seq_offset(td, f, ddir, &offset);
+ if (ret) {
+ ret = get_next_rand_block(td, f, ddir, &b);
+ *is_random = 0;
+ }
+ } else if (td->o.rw_seq == RW_SEQ_IDENT) {
+ if (f->last_start != -1ULL)
+ offset = f->last_start - f->file_offset;
+ else
+ offset = 0;
+ ret = 0;
+ } else {
+ log_err("fio: unknown rw_seq=%d\n", td->o.rw_seq);
+ ret = 1;
+ }
+ }
+
+ if (!ret) {
+ if (offset != -1ULL)
+ io_u->offset = offset;
+ else if (b != -1ULL)
+ io_u->offset = b * td->o.ba[ddir];
+ else {
+ log_err("fio: bug in offset generation: offset=%llu, b=%llu\n", (unsigned long long) offset, (unsigned long long) b);
+ ret = 1;
+ }
+ }
+
+ return ret;