fusion-aw: make configure and compile actually work
[fio.git] / engines / fusion-aw.c
1 /*
2  * Custom fio(1) engine that submits synchronous atomic writes to file.
3  *
4  * Copyright (C) 2012 Fusion-io, Inc.
5  * Author: Santhosh Kumar Koundinya.
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by the Free
9  * Software Foundation; under version 2 of the License.
10  *
11  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License version
14  * 2 for more details.
15  *
16  * You should have received a copy of the GNU General Public License Version 2
17  * along with this program; if not see <http://www.gnu.org/licenses/>
18  */
19
20 #include <stdlib.h>
21 #include <stdint.h>
22
23 #include "../fio.h"
24
25 #include <nvm/vectored_write.h>
26
27 /* Fix sector size to 512 bytes independent of actual sector size, just like
28  * the linux kernel. */
29 #define SECTOR_SHIFT    9
30 #define SECTOR_SIZE    (1U<<SECTOR_SHIFT)
31
32 struct acs_engine_data {
33         struct vsl_iovec iov[IO_VECTOR_LIMIT];
34 };
35
36 static int queue(struct thread_data *td, struct io_u *io_u)
37 {
38         int rc;
39         int iov_index;
40         off_t offset;
41         char *xfer_buf;
42         size_t xfer_buflen;
43         struct acs_engine_data *d =
44                 (struct acs_engine_data *) io_u->file->engine_data;
45
46         if (io_u->ddir != DDIR_WRITE) {
47                 td_vmsg(td, -EIO, "only writes supported", "io_u->ddir");
48                 rc = -EIO;
49                 goto out;
50         }
51         if (io_u->xfer_buflen > IO_SIZE_MAX) {
52                 td_vmsg(td, -EIO, "data too big", "io_u->xfer_buflen");
53                 rc = -EIO;
54                 goto out;
55         }
56         if (io_u->xfer_buflen & (SECTOR_SIZE - 1)) {
57                 td_vmsg(td, -EIO, "unaligned data size", "io_u->xfer_buflen");
58                 rc = -EIO;
59                 goto out;
60         }
61
62         /* Chop up the write into minimal number of iovec's necessary */
63         iov_index = 0;
64         offset = io_u->offset;
65         xfer_buf = io_u->xfer_buf;
66         xfer_buflen = io_u->xfer_buflen;
67         while (xfer_buflen) {
68                 struct vsl_iovec *iov = &d->iov[iov_index++];
69
70                 iov->iov_len = xfer_buflen > IO_VECTOR_MAX_SIZE ?
71                     IO_VECTOR_MAX_SIZE : xfer_buflen;
72                 iov->iov_base = (uint64_t) xfer_buf;
73                 iov->sector = offset >> SECTOR_SHIFT;
74                 iov->iov_flag = VSL_IOV_WRITE;
75
76                 offset += iov->iov_len;
77                 xfer_buf += iov->iov_len;
78                 xfer_buflen -= iov->iov_len;
79         }
80         assert(xfer_buflen == 0);
81         assert(iov_index <= IO_VECTOR_LIMIT);
82
83         rc = vsl_vectored_write(io_u->file->fd, d->iov, iov_index, O_ATOMIC);
84         if (rc == -1) {
85                 td_verror(td, -errno, "vsl_vectored_write");
86                 rc = -EIO;
87                 goto out;
88         } else {
89                 io_u->error = 0;
90                 rc = FIO_Q_COMPLETED;
91         }
92
93 out:
94         if (rc < 0)
95                 io_u->error = rc;
96
97         return rc;
98 }
99
100 static int open_file(struct thread_data *td, struct fio_file *f)
101 {
102         int rc;
103         struct acs_engine_data *d = NULL;
104
105         d = malloc(sizeof(*d));
106         if (!d) {
107                 td_verror(td, -ENOMEM, "malloc");
108                 rc = -ENOMEM;
109                 goto error;
110         }
111         f->engine_data = (uintptr_t) d;
112
113         rc = generic_open_file(td, f);
114
115 out:
116         return rc;
117
118 error:
119         f->fd = -1;
120         f->engine_data = 0;
121         if (d)
122                 free(d);
123
124         goto out;
125 }
126
127 static int close_file(struct thread_data *td, struct fio_file *f)
128 {
129         if (f->engine_data) {
130                 free((void *) f->engine_data);
131                 f->engine_data = 0;
132         }
133
134         return generic_close_file(td, f);
135 }
136
137 static struct ioengine_ops ioengine = {
138         .name = "fusion-aw-sync",
139         .version = FIO_IOOPS_VERSION,
140         .queue = queue,
141         .open_file = open_file,
142         .close_file = close_file,
143         .get_file_size = generic_get_file_size,
144         .flags = FIO_SYNCIO | FIO_RAWIO | FIO_MEMALIGN
145 };
146
147 static void fio_init fio_fusion_aw_init(void)
148 {
149         register_ioengine(&ioengine);
150 }
151
152 static void fio_exit fio_fusion_aw_exit(void)
153 {
154         unregister_ioengine(&ioengine);
155 }