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 22struct binject_data { 23 struct b_user_cmd *cmds; 24 struct io_u **events; 25 struct pollfd *pfds; 26 int *fd_flags; 27}; 28 29struct binject_file { 30 unsigned int bs; 31 int minor; 32 int fd; 33}; 34 35static 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 51static 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 62static 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 69one_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 93static 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 173static 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 186static 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 216static 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 235static 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 242static 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 253static 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 275static 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"); 322err_unmap: 323 binject_unmap_dev(td, bf); 324 return 1; 325 } 326 327 return 0; 328} 329 330static 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 344static 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)) { 369err_close: 370 ret = generic_close_file(td, f); 371 return 1; 372 } 373 374 return 0; 375} 376 377static 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 390static 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 413static 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 */ 435static 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 441static struct ioengine_ops ioengine = { 442 .name = "binject", 443 .version = FIO_IOOPS_VERSION, 444 .init = fio_binject_init, 445}; 446 447#endif 448 449static void fio_init fio_binject_register(void) 450{ 451 register_ioengine(&ioengine); 452} 453 454static void fio_exit fio_binject_unregister(void) 455{ 456 unregister_ioengine(&ioengine); 457} 458