Home | History | Annotate | Download | only in engines
      1 /*
      2  * Native Solaris async IO engine
      3  *
      4  */
      5 #include <stdio.h>
      6 #include <stdlib.h>
      7 #include <unistd.h>
      8 #include <signal.h>
      9 #include <errno.h>
     10 
     11 #include "../fio.h"
     12 
     13 #include <sys/asynch.h>
     14 
     15 struct solarisaio_data {
     16 	struct io_u **aio_events;
     17 	unsigned int aio_pending;
     18 	unsigned int nr;
     19 	unsigned int max_depth;
     20 };
     21 
     22 static int fio_solarisaio_cancel(struct thread_data fio_unused *td,
     23 			       struct io_u *io_u)
     24 {
     25 	return aiocancel(&io_u->resultp);
     26 }
     27 
     28 static int fio_solarisaio_prep(struct thread_data fio_unused *td,
     29 			    struct io_u *io_u)
     30 {
     31 	struct solarisaio_data *sd = td->io_ops_data;
     32 
     33 	io_u->resultp.aio_return = AIO_INPROGRESS;
     34 	io_u->engine_data = sd;
     35 	return 0;
     36 }
     37 
     38 static void wait_for_event(struct timeval *tv)
     39 {
     40 	struct solarisaio_data *sd;
     41 	struct io_u *io_u;
     42 	aio_result_t *res;
     43 
     44 	res = aiowait(tv);
     45 	if (res == (aio_result_t *) -1) {
     46 		int err = errno;
     47 
     48 		if (err != EINVAL) {
     49 			log_err("fio: solarisaio got %d in aiowait\n", err);
     50 			exit(err);
     51 		}
     52 		return;
     53 	} else if (!res)
     54 		return;
     55 
     56 	io_u = container_of(res, struct io_u, resultp);
     57 	sd = io_u->engine_data;
     58 
     59 	if (io_u->resultp.aio_return >= 0) {
     60 		io_u->resid = io_u->xfer_buflen - io_u->resultp.aio_return;
     61 		io_u->error = 0;
     62 	} else
     63 		io_u->error = io_u->resultp.aio_errno;
     64 
     65 	/*
     66 	 * For SIGIO, we need a write barrier between the two, so that
     67 	 * the ->aio_pending store is seen after the ->aio_events store
     68 	 */
     69 	sd->aio_events[sd->aio_pending] = io_u;
     70 	write_barrier();
     71 	sd->aio_pending++;
     72 	sd->nr--;
     73 }
     74 
     75 static int fio_solarisaio_getevents(struct thread_data *td, unsigned int min,
     76 				    unsigned int max, const struct timespec *t)
     77 {
     78 	struct solarisaio_data *sd = td->io_ops_data;
     79 	struct timeval tv;
     80 	int ret;
     81 
     82 	if (!min || !t) {
     83 		tv.tv_sec = 0;
     84 		tv.tv_usec = 0;
     85 	} else {
     86 		tv.tv_sec = t->tv_sec;
     87 		tv.tv_usec = t->tv_nsec / 1000;
     88 	}
     89 
     90 	while (sd->aio_pending < min)
     91 		wait_for_event(&tv);
     92 
     93 	/*
     94 	 * should be OK without locking, as int operations should be atomic
     95 	 */
     96 	ret = sd->aio_pending;
     97 	sd->aio_pending -= ret;
     98 	return ret;
     99 }
    100 
    101 static struct io_u *fio_solarisaio_event(struct thread_data *td, int event)
    102 {
    103 	struct solarisaio_data *sd = td->io_ops_data;
    104 
    105 	return sd->aio_events[event];
    106 }
    107 
    108 static int fio_solarisaio_queue(struct thread_data fio_unused *td,
    109 			      struct io_u *io_u)
    110 {
    111 	struct solarisaio_data *sd = td->io_ops_data;
    112 	struct fio_file *f = io_u->file;
    113 	off_t off;
    114 	int ret;
    115 
    116 	fio_ro_check(td, io_u);
    117 
    118 	if (io_u->ddir == DDIR_SYNC) {
    119 		if (sd->nr)
    120 			return FIO_Q_BUSY;
    121 		if (fsync(f->fd) < 0)
    122 			io_u->error = errno;
    123 
    124 		return FIO_Q_COMPLETED;
    125 	}
    126 
    127 	if (io_u->ddir == DDIR_DATASYNC) {
    128 		if (sd->nr)
    129 			return FIO_Q_BUSY;
    130 		if (fdatasync(f->fd) < 0)
    131 			io_u->error = errno;
    132 
    133 		return FIO_Q_COMPLETED;
    134 	}
    135 
    136 	if (sd->nr == sd->max_depth)
    137 		return FIO_Q_BUSY;
    138 
    139 	off = io_u->offset;
    140 	if (io_u->ddir == DDIR_READ)
    141 		ret = aioread(f->fd, io_u->xfer_buf, io_u->xfer_buflen, off,
    142 					SEEK_SET, &io_u->resultp);
    143 	else
    144 		ret = aiowrite(f->fd, io_u->xfer_buf, io_u->xfer_buflen, off,
    145 					SEEK_SET, &io_u->resultp);
    146 	if (ret) {
    147 		io_u->error = errno;
    148 		td_verror(td, io_u->error, "xfer");
    149 		return FIO_Q_COMPLETED;
    150 	}
    151 
    152 	sd->nr++;
    153 	return FIO_Q_QUEUED;
    154 }
    155 
    156 static void fio_solarisaio_cleanup(struct thread_data *td)
    157 {
    158 	struct solarisaio_data *sd = td->io_ops_data;
    159 
    160 	if (sd) {
    161 		free(sd->aio_events);
    162 		free(sd);
    163 	}
    164 }
    165 
    166 /*
    167  * Set USE_SIGNAL_COMPLETIONS to use SIGIO as completion events.
    168  */
    169 #ifdef USE_SIGNAL_COMPLETIONS
    170 static void fio_solarisaio_sigio(int sig)
    171 {
    172 	wait_for_event(NULL);
    173 }
    174 
    175 static void fio_solarisaio_init_sigio(void)
    176 {
    177 	struct sigaction act;
    178 
    179 	memset(&act, 0, sizeof(act));
    180 	act.sa_handler = fio_solarisaio_sigio;
    181 	act.sa_flags = SA_RESTART;
    182 	sigaction(SIGIO, &act, NULL);
    183 }
    184 #endif
    185 
    186 static int fio_solarisaio_init(struct thread_data *td)
    187 {
    188 	struct solarisaio_data *sd = malloc(sizeof(*sd));
    189 	unsigned int max_depth;
    190 
    191 	max_depth = td->o.iodepth;
    192 	if (max_depth > MAXASYNCHIO) {
    193 		max_depth = MAXASYNCHIO;
    194 		log_info("fio: lower depth to %d due to OS constraints\n",
    195 							max_depth);
    196 	}
    197 
    198 	memset(sd, 0, sizeof(*sd));
    199 	sd->aio_events = malloc(max_depth * sizeof(struct io_u *));
    200 	memset(sd->aio_events, 0, max_depth * sizeof(struct io_u *));
    201 	sd->max_depth = max_depth;
    202 
    203 #ifdef USE_SIGNAL_COMPLETIONS
    204 	fio_solarisaio_init_sigio();
    205 #endif
    206 
    207 	td->io_ops_data = sd;
    208 	return 0;
    209 }
    210 
    211 static struct ioengine_ops ioengine = {
    212 	.name		= "solarisaio",
    213 	.version	= FIO_IOOPS_VERSION,
    214 	.init		= fio_solarisaio_init,
    215 	.prep		= fio_solarisaio_prep,
    216 	.queue		= fio_solarisaio_queue,
    217 	.cancel		= fio_solarisaio_cancel,
    218 	.getevents	= fio_solarisaio_getevents,
    219 	.event		= fio_solarisaio_event,
    220 	.cleanup	= fio_solarisaio_cleanup,
    221 	.open_file	= generic_open_file,
    222 	.close_file	= generic_close_file,
    223 	.get_file_size	= generic_get_file_size,
    224 };
    225 
    226 static void fio_init fio_solarisaio_register(void)
    227 {
    228 	register_ioengine(&ioengine);
    229 }
    230 
    231 static void fio_exit fio_solarisaio_unregister(void)
    232 {
    233 	unregister_ioengine(&ioengine);
    234 }
    235