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 | |
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 | ||
37 | struct acs_file_data { | |
38 | struct vsl_iovec iov[IO_VECTOR_LIMIT]; | |
39 | }; | |
40 | ||
41 | static 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 | ||
98 | out: | |
99 | if (rc < 0) | |
100 | io_u->error = rc; | |
101 | ||
102 | return rc; | |
103 | } | |
104 | ||
105 | static 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 | ||
120 | out: | |
121 | return rc; | |
122 | ||
123 | error: | |
124 | f->fd = -1; | |
125 | f->file_data = NULL; | |
126 | if (d) | |
127 | free(d); | |
128 | ||
129 | goto out; | |
130 | } | |
131 | ||
132 | static 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 | ||
142 | static 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 | ||
154 | static 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 | ||
160 | static 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 | ||
168 | static void fio_init fio_fusion_aw_init(void) | |
169 | { | |
170 | register_ioengine(&ioengine); | |
171 | } | |
172 | ||
173 | static void fio_exit fio_fusion_aw_exit(void) | |
174 | { | |
175 | unregister_ioengine(&ioengine); | |
176 | } |