Commit | Line | Data |
---|---|---|
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 | |
15a6f166 | 9 | * Software Foundation; under version 2 of the License. |
6ef63580 SK |
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 | } |