restart:
list_for_each(entry, &td->io_u_busylist) {
struct io_u *io_u = list_entry(entry, struct io_u, list);
+ int err;
if (io_u->seen)
continue;
- if (aio_error(&io_u->aiocb) != EINPROGRESS) {
- pd->aio_events[r++] = io_u;
- io_u->seen = 1;
+ err = aio_error(&io_u->aiocb);
+ switch (err) {
+ default:
+ io_u->error = err;
+ case ECANCELED:
+ case 0:
+ pd->aio_events[r++] = io_u;
+ io_u->seen = 1;
+ break;
+ case EINPROGRESS:
+ break;
}
if (r >= max)
ret = aio_write(aiocb);
if (ret)
- return errno;
-
- return 0;
+ io_u->error = errno;
+
+ return io_u->error;
}
static void fio_posixaio_cleanup(struct thread_data *td)
else
ret = write(td->fd, io_u->buf, io_u->buflen);
- if (ret < 0)
- return errno;
+ if (ret != io_u->buflen) {
+ if (ret > 0) {
+ io_u->resid = io_u->buflen - ret;
+ io_u->error = ENODATA;
+ } else
+ io_u->error = errno;
+ }
- sd->last_io_u = io_u;
- return 0;
+ if (!io_u->error)
+ sd->last_io_u = io_u;
+
+ return io_u->error;
}
static void fio_syncio_cleanup(struct thread_data *td)
* not really direct, but should drop the pages from the cache
*/
if (td->odirect) {
- msync(td->mmap + real_off, io_u->buflen, MS_SYNC);
- madvise(td->mmap + real_off, io_u->buflen, MADV_DONTNEED);
+ if (msync(td->mmap + real_off, io_u->buflen, MS_SYNC) < 0)
+ io_u->error = errno;
+ if (madvise(td->mmap + real_off, io_u->buflen, MADV_DONTNEED) < 0)
+ io_u->error = errno;
}
- sd->last_io_u = io_u;
- return 0;
+ if (!io_u->error)
+ sd->last_io_u = io_u;
+
+ return io_u->error;
}
static int fio_mmapio_sync(struct thread_data *td)
return NULL;
io_u = list_entry(td->io_u_freelist.next, struct io_u, list);
+ io_u->error = 0;
+ io_u->resid = 0;
list_del(&io_u->list);
list_add(&io_u->list, &td->io_u_busylist);
td->cur_depth++;
#define iocb_time(iocb) ((unsigned long) (iocb)->data)
-static int ios_completed(struct thread_data *td, int nr)
+static int ios_completed(struct thread_data *td, int nr, int *err)
{
unsigned long msec;
struct io_u *io_u;
struct timeval e;
int i, bytes_done;
+ if (err)
+ *err = 0;
+
gettimeofday(&e, NULL);
for (i = 0, bytes_done = 0; i < nr; i++) {
io_u = td->io_event(td, i);
- td->io_blocks++;
- td->io_bytes += io_u->buflen;
- td->this_io_bytes += io_u->buflen;
+ if (!io_u->error) {
+ td->io_blocks++;
+ td->io_bytes += (io_u->buflen - io_u->resid);
+ td->this_io_bytes += (io_u->buflen - io_u->resid);
+
+ msec = mtime_since(&io_u->issue_time, &e);
- msec = mtime_since(&io_u->issue_time, &e);
+ add_clat_sample(td, msec);
+ add_bw_sample(td);
- add_clat_sample(td, msec);
- add_bw_sample(td);
+ if (td_write(td))
+ log_io_piece(td, io_u);
- if (td_write(td))
- log_io_piece(td, io_u);
+ bytes_done += (io_u->buflen - io_u->resid);
+ } else if (err)
+ *err = io_u->error;
- bytes_done += io_u->buflen;
put_io_u(td, io_u);
}
*/
r = io_u_getevents(td, 0, td->cur_depth, &ts);
if (r > 0)
- ios_completed(td, r);
+ ios_completed(td, r, NULL);
/*
* now cancel remaining active events
if (td->cur_depth) {
r = io_u_getevents(td, td->cur_depth, td->cur_depth, NULL);
if (r > 0)
- ios_completed(td, r);
+ ios_completed(td, r, NULL);
}
}
}
v_io_u = td->io_event(td, 0);
+ if (v_io_u->error) {
+ td_verror(td, v_io_u->error);
+ put_io_u(td, v_io_u);
+ v_io_u = NULL;
+ break;
+ }
td->cur_off = v_io_u->offset + v_io_u->buflen;
while (td->this_io_bytes < td->io_size) {
struct timespec ts = { .tv_sec = 0, .tv_nsec = 0};
struct timespec *timeout;
- int ret, min_evts = 0;
+ int ret, min_evts = 0, err;
struct io_u *io_u;
unsigned int bytes_done;
} else if (!ret)
continue;
- bytes_done = ios_completed(td, ret);
+ bytes_done = ios_completed(td, ret, &err);
+ if (err) {
+ td_verror(td, err);
+ break;
+ }
/*
* the rate is batched for now, it should work for batches
static void clear_io_state(struct thread_data *td)
{
- if (td->io_engine & FIO_SYNCIO)
+ if (td->io_engine == FIO_SYNCIO)
lseek(td->fd, SEEK_SET, 0);
td->cur_off = 0;