+static int binject_open_ctl(struct thread_data *td)
+{
+ int fd;
+
+ fd = open("/dev/binject-ctl", O_RDWR);
+ if (fd < 0)
+ td_verror(td, errno, "open binject-ctl");
+
+ return fd;
+}
+
+static void binject_unmap_dev(struct thread_data *td, struct binject_file *bf)
+{
+ struct b_ioctl_cmd bic;
+ int fdb;
+
+ if (bf->fd >= 0) {
+ close(bf->fd);
+ bf->fd = -1;
+ }
+
+ fdb = binject_open_ctl(td);
+ if (fdb < 0)
+ return;
+
+ bic.minor = bf->minor;
+
+ if (ioctl(fdb, B_IOCTL_DEL, &bic) < 0)
+ td_verror(td, errno, "binject dev unmap");
+
+ close(fdb);
+}
+
+static int binject_map_dev(struct thread_data *td, struct binject_file *bf,
+ int fd)
+{
+ struct b_ioctl_cmd bic;
+ char name[80];
+ struct stat sb;
+ int fdb, dev_there, loops;
+
+ fdb = binject_open_ctl(td);
+ if (fdb < 0)
+ return 1;
+
+ bic.fd = fd;
+
+ if (ioctl(fdb, B_IOCTL_ADD, &bic) < 0) {
+ td_verror(td, errno, "binject dev map");
+ close(fdb);
+ return 1;
+ }
+
+ bf->minor = bic.minor;
+
+ sprintf(name, "/dev/binject%u", bf->minor);
+
+ /*
+ * Wait for udev to create the node...
+ */
+ dev_there = loops = 0;
+ do {
+ if (!stat(name, &sb)) {
+ dev_there = 1;
+ break;
+ }
+
+ usleep(10000);
+ } while (++loops < 100);
+
+ close(fdb);
+
+ if (!dev_there) {
+ log_err("fio: timed out waiting for binject dev\n");
+ goto err_unmap;
+ }
+
+ bf->fd = open(name, O_RDWR);
+ if (bf->fd < 0) {
+ td_verror(td, errno, "binject dev open");
+err_unmap:
+ binject_unmap_dev(td, bf);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int fio_binject_close_file(struct thread_data *td, struct fio_file *f)
+{
+ struct binject_file *bf = (struct binject_file *) f->engine_data;
+
+ if (bf) {
+ binject_unmap_dev(td, bf);
+ free(bf);
+ f->engine_data = 0;
+ return generic_close_file(td, f);
+ }
+
+ return 0;
+}
+
+static int fio_binject_open_file(struct thread_data *td, struct fio_file *f)
+{
+ struct binject_file *bf;
+ unsigned int bs;
+ int ret;
+
+ ret = generic_open_file(td, f);
+ if (ret)
+ return 1;
+
+ if (f->filetype != FIO_TYPE_BD) {
+ log_err("fio: binject only works with block devices\n");
+ goto err_close;
+ }
+ if (ioctl(f->fd, BLKSSZGET, &bs) < 0) {
+ td_verror(td, errno, "BLKSSZGET");
+ goto err_close;
+ }
+
+ bf = malloc(sizeof(*bf));
+ bf->bs = bs;
+ bf->minor = bf->fd = -1;
+ f->engine_data = (uintptr_t) bf;
+
+ if (binject_map_dev(td, bf, f->fd)) {
+err_close:
+ ret = generic_close_file(td, f);
+ return 1;
+ }
+
+ return 0;
+}
+