fusion-aw-sync: fixup GPL disclaimer
[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 #ifdef FIO_HAVE_FUSION_AW
26
27 #include <vsl_dp_experimental/vectored_write.h>
28
29 /* Fix sector size to 512 bytes independent of actual sector size, just like
30  * the linux kernel. */
31 #define SECTOR_SHIFT    9
32 #define SECTOR_SIZE    (1U<<SECTOR_SHIFT)
33
34 struct acs_file_data {
35         struct vsl_iovec iov[IO_VECTOR_LIMIT];
36 };
37
38 static int queue(struct thread_data *td, struct io_u *io_u)
39 {
40         int rc;
41         int iov_index;
42         off_t offset;
43         char *xfer_buf;
44         size_t xfer_buflen;
45         struct acs_file_data *d = io_u->file->file_data;
46
47         if (io_u->ddir != DDIR_WRITE) {
48                 td_vmsg(td, -EIO, "only writes supported", "io_u->ddir");
49                 rc = -EIO;
50                 goto out;
51         }
52         if (io_u->xfer_buflen > IO_SIZE_MAX) {
53                 td_vmsg(td, -EIO, "data too big", "io_u->xfer_buflen");
54                 rc = -EIO;
55                 goto out;
56         }
57         if (io_u->xfer_buflen & (SECTOR_SIZE - 1)) {
58                 td_vmsg(td, -EIO, "unaligned data size", "io_u->xfer_buflen");
59                 rc = -EIO;
60                 goto out;
61         }
62
63         /* Chop up the write into minimal number of iovec's necessary */
64         iov_index = 0;
65         offset = io_u->offset;
66         xfer_buf = io_u->xfer_buf;
67         xfer_buflen = io_u->xfer_buflen;
68         while (xfer_buflen) {
69                 struct vsl_iovec *iov = &d->iov[iov_index++];
70
71                 iov->iov_len = xfer_buflen > IO_VECTOR_MAX_SIZE ?
72                     IO_VECTOR_MAX_SIZE : xfer_buflen;
73                 iov->iov_base = (uint64_t) xfer_buf;
74                 iov->sector = offset >> SECTOR_SHIFT;
75                 iov->iov_flag = VSL_IOV_WRITE;
76
77                 offset += iov->iov_len;
78                 xfer_buf += iov->iov_len;
79                 xfer_buflen -= iov->iov_len;
80         }
81         assert(xfer_buflen == 0);
82         assert(iov_index <= IO_VECTOR_LIMIT);
83
84         rc = vsl_vectored_write(io_u->file->fd, d->iov, iov_index, O_ATOMIC);
85         if (rc == -1) {
86                 td_verror(td, -errno, "vsl_vectored_write");
87                 rc = -EIO;
88                 goto out;
89         } else {
90                 io_u->error = 0;
91                 io_u->file->file_pos = io_u->offset + rc;
92                 rc = FIO_Q_COMPLETED;
93         }
94
95 out:
96         if (rc < 0)
97                 io_u->error = rc;
98
99         return rc;
100 }
101
102 static int open_file(struct thread_data *td, struct fio_file *f)
103 {
104         int rc;
105         struct acs_file_data *d = NULL;
106
107         d = malloc(sizeof(*d));
108         if (!d) {
109                 td_verror(td, -ENOMEM, "malloc");
110                 rc = -ENOMEM;
111                 goto error;
112         }
113         f->file_data = d;
114
115         rc = generic_open_file(td, f);
116
117 out:
118         return rc;
119
120 error:
121         f->fd = -1;
122         f->file_data = NULL;
123         if (d)
124                 free(d);
125
126         goto out;
127 }
128
129 static int close_file(struct thread_data *td, struct fio_file *f)
130 {
131         if (f->file_data) {
132                 free(f->file_data);
133                 f->file_data = NULL;
134         }
135
136         return generic_close_file(td, f);
137 }
138
139 static struct ioengine_ops ioengine = {
140         .name = "fusion-aw-sync",
141         .version = FIO_IOOPS_VERSION,
142         .queue = queue,
143         .open_file = open_file,
144         .close_file = close_file,
145         .get_file_size = generic_get_file_size,
146         .flags = FIO_SYNCIO | FIO_RAWIO | FIO_MEMALIGN
147 };
148
149 #else /* !FUSION_HAVE_FUSION_AW */
150
151 static int fio_fusion_aw_eng_init(struct thread_data fio_unused *td)
152 {
153         log_err("fio: fusion atomic write engine not available\n");
154         return 1;
155 }
156
157 static struct ioengine_ops ioengine = {
158         .name           = "fusion-aw-sync",
159         .version        = FIO_IOOPS_VERSION,
160         .init           = fio_fusion_aw_eng_init,
161 };
162
163 #endif /* FUSION_HAVE_FUSION_AW */
164
165 static void fio_init fio_fusion_aw_init(void)
166 {
167         register_ioengine(&ioengine);
168 }
169
170 static void fio_exit fio_fusion_aw_exit(void)
171 {
172         unregister_ioengine(&ioengine);
173 }