Home | History | Annotate | Download | only in engines
      1 /*
      2  * binject engine
      3  *
      4  * IO engine that uses the Linux binject interface to directly inject
      5  * bio's to block devices.
      6  *
      7  */
      8 #include <stdio.h>
      9 #include <stdlib.h>
     10 #include <unistd.h>
     11 #include <errno.h>
     12 #include <assert.h>
     13 #include <string.h>
     14 #include <sys/poll.h>
     15 #include <sys/types.h>
     16 #include <sys/stat.h>
     17 
     18 #include "../fio.h"
     19 
     20 #ifdef FIO_HAVE_BINJECT
     21 
     22 struct binject_data {
     23 	struct b_user_cmd *cmds;
     24 	struct io_u **events;
     25 	struct pollfd *pfds;
     26 	int *fd_flags;
     27 };
     28 
     29 struct binject_file {
     30 	unsigned int bs;
     31 	int minor;
     32 	int fd;
     33 };
     34 
     35 static void binject_buc_init(struct binject_data *bd, struct io_u *io_u)
     36 {
     37 	struct b_user_cmd *buc = &io_u->buc;
     38 
     39 	memset(buc, 0, sizeof(*buc));
     40 	binject_buc_set_magic(buc);
     41 
     42 	buc->buf = (unsigned long) io_u->xfer_buf;
     43 	buc->len = io_u->xfer_buflen;
     44 	buc->offset = io_u->offset;
     45 	buc->usr_ptr = (unsigned long) io_u;
     46 
     47 	buc->flags = B_FLAG_NOIDLE | B_FLAG_UNPLUG;
     48 	assert(buc->buf);
     49 }
     50 
     51 static int pollin_events(struct pollfd *pfds, int fds)
     52 {
     53 	int i;
     54 
     55 	for (i = 0; i < fds; i++)
     56 		if (pfds[i].revents & POLLIN)
     57 			return 1;
     58 
     59 	return 0;
     60 }
     61 
     62 static unsigned int binject_read_commands(struct thread_data *td, void *p,
     63 					  int left, int *err)
     64 {
     65 	struct binject_file *bf;
     66 	struct fio_file *f;
     67 	int i, ret, events;
     68 
     69 one_more:
     70 	events = 0;
     71 	for_each_file(td, f, i) {
     72 		bf = (struct binject_file *) (uintptr_t) f->engine_data;
     73 		ret = read(bf->fd, p, left * sizeof(struct b_user_cmd));
     74 		if (ret < 0) {
     75 			if (errno == EAGAIN)
     76 				continue;
     77 			*err = -errno;
     78 			td_verror(td, errno, "read");
     79 			break;
     80 		} else if (ret) {
     81 			p += ret;
     82 			events += ret / sizeof(struct b_user_cmd);
     83 		}
     84 	}
     85 
     86 	if (*err || events)
     87 		return events;
     88 
     89 	usleep(1000);
     90 	goto one_more;
     91 }
     92 
     93 static int fio_binject_getevents(struct thread_data *td, unsigned int min,
     94 			      unsigned int max, struct timespec fio_unused *t)
     95 {
     96 	struct binject_data *bd = td->io_ops->data;
     97 	int left = max, ret, r = 0, ev_index = 0;
     98 	void *buf = bd->cmds;
     99 	unsigned int i, events;
    100 	struct fio_file *f;
    101 	struct binject_file *bf;
    102 
    103 	/*
    104 	 * Fill in the file descriptors
    105 	 */
    106 	for_each_file(td, f, i) {
    107 		bf = (struct binject_file *) (uintptr_t) f->engine_data;
    108 
    109 		/*
    110 		 * don't block for min events == 0
    111 		 */
    112 		if (!min)
    113 			bd->fd_flags[i] = fio_set_fd_nonblocking(bf->fd, "binject");
    114 		else
    115 			bd->fd_flags[i] = -1;
    116 
    117 		bd->pfds[i].fd = bf->fd;
    118 		bd->pfds[i].events = POLLIN;
    119 	}
    120 
    121 	while (left) {
    122 		while (!min) {
    123 			ret = poll(bd->pfds, td->o.nr_files, -1);
    124 			if (ret < 0) {
    125 				if (!r)
    126 					r = -errno;
    127 				td_verror(td, errno, "poll");
    128 				break;
    129 			} else if (!ret)
    130 				continue;
    131 
    132 			if (pollin_events(bd->pfds, td->o.nr_files))
    133 				break;
    134 		}
    135 
    136 		if (r < 0)
    137 			break;
    138 
    139 		events = binject_read_commands(td, buf, left, &r);
    140 
    141 		if (r < 0)
    142 			break;
    143 
    144 		left -= events;
    145 		r += events;
    146 
    147 		for (i = 0; i < events; i++) {
    148 			struct b_user_cmd *buc = (struct b_user_cmd *) buf + i;
    149 
    150 			bd->events[ev_index] = (struct io_u *) (unsigned long) buc->usr_ptr;
    151 			ev_index++;
    152 		}
    153 	}
    154 
    155 	if (!min) {
    156 		for_each_file(td, f, i) {
    157 			bf = (struct binject_file *) (uintptr_t) f->engine_data;
    158 
    159 			if (bd->fd_flags[i] == -1)
    160 				continue;
    161 
    162 			if (fcntl(bf->fd, F_SETFL, bd->fd_flags[i]) < 0)
    163 				log_err("fio: binject failed to restore fcntl flags: %s\n", strerror(errno));
    164 		}
    165 	}
    166 
    167 	if (r > 0)
    168 		assert(ev_index == r);
    169 
    170 	return r;
    171 }
    172 
    173 static int fio_binject_doio(struct thread_data *td, struct io_u *io_u)
    174 {
    175 	struct b_user_cmd *buc = &io_u->buc;
    176 	struct binject_file *bf = (struct binject_file *) (uintptr_t) io_u->file->engine_data;
    177 	int ret;
    178 
    179 	ret = write(bf->fd, buc, sizeof(*buc));
    180 	if (ret < 0)
    181 		return ret;
    182 
    183 	return FIO_Q_QUEUED;
    184 }
    185 
    186 static int fio_binject_prep(struct thread_data *td, struct io_u *io_u)
    187 {
    188 	struct binject_data *bd = td->io_ops->data;
    189 	struct b_user_cmd *buc = &io_u->buc;
    190 	struct binject_file *bf = (struct binject_file *) (uintptr_t) io_u->file->engine_data;
    191 
    192 	if (io_u->xfer_buflen & (bf->bs - 1)) {
    193 		log_err("read/write not sector aligned\n");
    194 		return EINVAL;
    195 	}
    196 
    197 	if (io_u->ddir == DDIR_READ) {
    198 		binject_buc_init(bd, io_u);
    199 		buc->type = B_TYPE_READ;
    200 	} else if (io_u->ddir == DDIR_WRITE) {
    201 		binject_buc_init(bd, io_u);
    202 		if (io_u->flags & IO_U_F_BARRIER)
    203 			buc->type = B_TYPE_WRITEBARRIER;
    204 		else
    205 			buc->type = B_TYPE_WRITE;
    206 	} else if (io_u->ddir == DDIR_TRIM) {
    207 		binject_buc_init(bd, io_u);
    208 		buc->type = B_TYPE_DISCARD;
    209 	} else {
    210 		assert(0);
    211 	}
    212 
    213 	return 0;
    214 }
    215 
    216 static int fio_binject_queue(struct thread_data *td, struct io_u *io_u)
    217 {
    218 	int ret;
    219 
    220 	fio_ro_check(td, io_u);
    221 
    222 	ret = fio_binject_doio(td, io_u);
    223 
    224 	if (ret < 0)
    225 		io_u->error = errno;
    226 
    227 	if (io_u->error) {
    228 		td_verror(td, io_u->error, "xfer");
    229 		return FIO_Q_COMPLETED;
    230 	}
    231 
    232 	return ret;
    233 }
    234 
    235 static struct io_u *fio_binject_event(struct thread_data *td, int event)
    236 {
    237 	struct binject_data *bd = td->io_ops->data;
    238 
    239 	return bd->events[event];
    240 }
    241 
    242 static int binject_open_ctl(struct thread_data *td)
    243 {
    244 	int fd;
    245 
    246 	fd = open("/dev/binject-ctl", O_RDWR);
    247 	if (fd < 0)
    248 		td_verror(td, errno, "open binject-ctl");
    249 
    250 	return fd;
    251 }
    252 
    253 static void binject_unmap_dev(struct thread_data *td, struct binject_file *bf)
    254 {
    255 	struct b_ioctl_cmd bic;
    256 	int fdb;
    257 
    258 	if (bf->fd >= 0) {
    259 		close(bf->fd);
    260 		bf->fd = -1;
    261 	}
    262 
    263 	fdb = binject_open_ctl(td);
    264 	if (fdb < 0)
    265 		return;
    266 
    267 	bic.minor = bf->minor;
    268 
    269 	if (ioctl(fdb, B_IOCTL_DEL, &bic) < 0)
    270 		td_verror(td, errno, "binject dev unmap");
    271 
    272 	close(fdb);
    273 }
    274 
    275 static int binject_map_dev(struct thread_data *td, struct binject_file *bf,
    276 			   int fd)
    277 {
    278 	struct b_ioctl_cmd bic;
    279 	char name[80];
    280 	struct stat sb;
    281 	int fdb, dev_there, loops;
    282 
    283 	fdb = binject_open_ctl(td);
    284 	if (fdb < 0)
    285 		return 1;
    286 
    287 	bic.fd = fd;
    288 
    289 	if (ioctl(fdb, B_IOCTL_ADD, &bic) < 0) {
    290 		td_verror(td, errno, "binject dev map");
    291 		close(fdb);
    292 		return 1;
    293 	}
    294 
    295 	bf->minor = bic.minor;
    296 
    297 	sprintf(name, "/dev/binject%u", bf->minor);
    298 
    299 	/*
    300 	 * Wait for udev to create the node...
    301 	 */
    302 	dev_there = loops = 0;
    303 	do {
    304 		if (!stat(name, &sb)) {
    305 			dev_there = 1;
    306 			break;
    307 		}
    308 
    309 		usleep(10000);
    310 	} while (++loops < 100);
    311 
    312 	close(fdb);
    313 
    314 	if (!dev_there) {
    315 		log_err("fio: timed out waiting for binject dev\n");
    316 		goto err_unmap;
    317 	}
    318 
    319 	bf->fd = open(name, O_RDWR);
    320 	if (bf->fd < 0) {
    321 		td_verror(td, errno, "binject dev open");
    322 err_unmap:
    323 		binject_unmap_dev(td, bf);
    324 		return 1;
    325 	}
    326 
    327 	return 0;
    328 }
    329 
    330 static int fio_binject_close_file(struct thread_data *td, struct fio_file *f)
    331 {
    332 	struct binject_file *bf = (struct binject_file *) (uintptr_t) f->engine_data;
    333 
    334 	if (bf) {
    335 		binject_unmap_dev(td, bf);
    336 		free(bf);
    337 		f->engine_data = 0;
    338 		return generic_close_file(td, f);
    339 	}
    340 
    341 	return 0;
    342 }
    343 
    344 static int fio_binject_open_file(struct thread_data *td, struct fio_file *f)
    345 {
    346 	struct binject_file *bf;
    347 	unsigned int bs;
    348 	int ret;
    349 
    350 	ret = generic_open_file(td, f);
    351 	if (ret)
    352 		return 1;
    353 
    354 	if (f->filetype != FIO_TYPE_BD) {
    355 		log_err("fio: binject only works with block devices\n");
    356 		goto err_close;
    357 	}
    358 	if (ioctl(f->fd, BLKSSZGET, &bs) < 0) {
    359 		td_verror(td, errno, "BLKSSZGET");
    360 		goto err_close;
    361 	}
    362 
    363 	bf = malloc(sizeof(*bf));
    364 	bf->bs = bs;
    365 	bf->minor = bf->fd = -1;
    366 	f->engine_data = (uintptr_t) bf;
    367 
    368 	if (binject_map_dev(td, bf, f->fd)) {
    369 err_close:
    370 		ret = generic_close_file(td, f);
    371 		return 1;
    372 	}
    373 
    374 	return 0;
    375 }
    376 
    377 static void fio_binject_cleanup(struct thread_data *td)
    378 {
    379 	struct binject_data *bd = td->io_ops->data;
    380 
    381 	if (bd) {
    382 		free(bd->events);
    383 		free(bd->cmds);
    384 		free(bd->fd_flags);
    385 		free(bd->pfds);
    386 		free(bd);
    387 	}
    388 }
    389 
    390 static int fio_binject_init(struct thread_data *td)
    391 {
    392 	struct binject_data *bd;
    393 
    394 	bd = malloc(sizeof(*bd));
    395 	memset(bd, 0, sizeof(*bd));
    396 
    397 	bd->cmds = malloc(td->o.iodepth * sizeof(struct b_user_cmd));
    398 	memset(bd->cmds, 0, td->o.iodepth * sizeof(struct b_user_cmd));
    399 
    400 	bd->events = malloc(td->o.iodepth * sizeof(struct io_u *));
    401 	memset(bd->events, 0, td->o.iodepth * sizeof(struct io_u *));
    402 
    403 	bd->pfds = malloc(sizeof(struct pollfd) * td->o.nr_files);
    404 	memset(bd->pfds, 0, sizeof(struct pollfd) * td->o.nr_files);
    405 
    406 	bd->fd_flags = malloc(sizeof(int) * td->o.nr_files);
    407 	memset(bd->fd_flags, 0, sizeof(int) * td->o.nr_files);
    408 
    409 	td->io_ops->data = bd;
    410 	return 0;
    411 }
    412 
    413 static struct ioengine_ops ioengine = {
    414 	.name		= "binject",
    415 	.version	= FIO_IOOPS_VERSION,
    416 	.init		= fio_binject_init,
    417 	.prep		= fio_binject_prep,
    418 	.queue		= fio_binject_queue,
    419 	.getevents	= fio_binject_getevents,
    420 	.event		= fio_binject_event,
    421 	.cleanup	= fio_binject_cleanup,
    422 	.open_file	= fio_binject_open_file,
    423 	.close_file	= fio_binject_close_file,
    424 	.get_file_size	= generic_get_file_size,
    425 	.flags		= FIO_RAWIO | FIO_BARRIER | FIO_MEMALIGN,
    426 };
    427 
    428 #else /* FIO_HAVE_BINJECT */
    429 
    430 /*
    431  * When we have a proper configure system in place, we simply wont build
    432  * and install this io engine. For now install a crippled version that
    433  * just complains and fails to load.
    434  */
    435 static int fio_binject_init(struct thread_data fio_unused *td)
    436 {
    437 	log_err("fio: ioengine binject not available\n");
    438 	return 1;
    439 }
    440 
    441 static struct ioengine_ops ioengine = {
    442 	.name		= "binject",
    443 	.version	= FIO_IOOPS_VERSION,
    444 	.init		= fio_binject_init,
    445 };
    446 
    447 #endif
    448 
    449 static void fio_init fio_binject_register(void)
    450 {
    451 	register_ioengine(&ioengine);
    452 }
    453 
    454 static void fio_exit fio_binject_unregister(void)
    455 {
    456 	unregister_ioengine(&ioengine);
    457 }
    458