Wire up fusion-aw-sync engine
[fio.git] / engines / fusion-aw.c
CommitLineData
6ef63580
SK
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. You may obtain a copy
10 * of the source code for DirectFS by sending a request to Fusion-io, Inc.,
11 * 2855 E. Cottonwood Parkway, Suite 100, Salt Lake City, UT 84121; Attention:
12 * Legal Department.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License version
17 * 2 for more details.
18 *
19 * You should have received a copy of the GNU General Public License Version 2
20 * along with this program; if not see <http://www.gnu.org/licenses/>
21 */
22
23#include <stdlib.h>
24#include <stdint.h>
25
26#include "../fio.h"
27
28#ifdef FIO_HAVE_FUSION_AW
29
30#include <vsl_dp_experimental/vectored_write.h>
31
32/* Fix sector size to 512 bytes independent of actual sector size, just like
33 * the linux kernel. */
34#define SECTOR_SHIFT 9
35#define SECTOR_SIZE (1U<<SECTOR_SHIFT)
36
37struct acs_file_data {
38 struct vsl_iovec iov[IO_VECTOR_LIMIT];
39};
40
41static int queue(struct thread_data *td, struct io_u *io_u)
42{
43 int rc;
44 int iov_index;
45 off_t offset;
46 char *xfer_buf;
47 size_t xfer_buflen;
48 struct acs_file_data *d = io_u->file->file_data;
49
50 if (io_u->ddir != DDIR_WRITE) {
51 td_vmsg(td, -EIO, "only writes supported", "io_u->ddir");
52 rc = -EIO;
53 goto out;
54 }
55 if (io_u->xfer_buflen > IO_SIZE_MAX) {
56 td_vmsg(td, -EIO, "data too big", "io_u->xfer_buflen");
57 rc = -EIO;
58 goto out;
59 }
60 if (io_u->xfer_buflen & (SECTOR_SIZE - 1)) {
61 td_vmsg(td, -EIO, "unaligned data size", "io_u->xfer_buflen");
62 rc = -EIO;
63 goto out;
64 }
65
66 /* Chop up the write into minimal number of iovec's necessary */
67 iov_index = 0;
68 offset = io_u->offset;
69 xfer_buf = io_u->xfer_buf;
70 xfer_buflen = io_u->xfer_buflen;
71 while (xfer_buflen) {
72 struct vsl_iovec *iov = &d->iov[iov_index++];
73
74 iov->iov_len = xfer_buflen > IO_VECTOR_MAX_SIZE ?
75 IO_VECTOR_MAX_SIZE : xfer_buflen;
76 iov->iov_base = (uint64_t) xfer_buf;
77 iov->sector = offset >> SECTOR_SHIFT;
78 iov->iov_flag = VSL_IOV_WRITE;
79
80 offset += iov->iov_len;
81 xfer_buf += iov->iov_len;
82 xfer_buflen -= iov->iov_len;
83 }
84 assert(xfer_buflen == 0);
85 assert(iov_index <= IO_VECTOR_LIMIT);
86
87 rc = vsl_vectored_write(io_u->file->fd, d->iov, iov_index, O_ATOMIC);
88 if (rc == -1) {
89 td_verror(td, -errno, "vsl_vectored_write");
90 rc = -EIO;
91 goto out;
92 } else {
93 io_u->error = 0;
94 io_u->file->file_pos = io_u->offset + rc;
95 rc = FIO_Q_COMPLETED;
96 }
97
98out:
99 if (rc < 0)
100 io_u->error = rc;
101
102 return rc;
103}
104
105static int open_file(struct thread_data *td, struct fio_file *f)
106{
107 int rc;
108 struct acs_file_data *d = NULL;
109
110 d = malloc(sizeof(*d));
111 if (!d) {
112 td_verror(td, -ENOMEM, "malloc");
113 rc = -ENOMEM;
114 goto error;
115 }
116 f->file_data = d;
117
118 rc = generic_open_file(td, f);
119
120out:
121 return rc;
122
123error:
124 f->fd = -1;
125 f->file_data = NULL;
126 if (d)
127 free(d);
128
129 goto out;
130}
131
132static int close_file(struct thread_data *td, struct fio_file *f)
133{
134 if (f->file_data) {
135 free(f->file_data);
136 f->file_data = NULL;
137 }
138
139 return generic_close_file(td, f);
140}
141
142static struct ioengine_ops ioengine = {
143 .name = "fusion-aw-sync",
144 .version = FIO_IOOPS_VERSION,
145 .queue = queue,
146 .open_file = open_file,
147 .close_file = close_file,
148 .get_file_size = generic_get_file_size,
149 .flags = FIO_SYNCIO | FIO_RAWIO | FIO_MEMALIGN
150};
151
152#else /* !FUSION_HAVE_FUSION_AW */
153
154static int fio_fusion_aw_eng_init(struct thread_data fio_unused *td)
155{
156 log_err("fio: fusion atomic write engine not available\n");
157 return 1;
158}
159
160static struct ioengine_ops ioengine = {
161 .name = "fusion-aw-sync",
162 .version = FIO_IOOPS_VERSION,
163 .init = fio_fusion_aw_eng_init,
164};
165
166#endif /* FUSION_HAVE_FUSION_AW */
167
168static void fio_init fio_fusion_aw_init(void)
169{
170 register_ioengine(&ioengine);
171}
172
173static void fio_exit fio_fusion_aw_exit(void)
174{
175 unregister_ioengine(&ioengine);
176}