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 | ||
99db6564 | 25 | #include <nvm/vectored_write.h> |
6ef63580 SK |
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 | ||
c11a9ddf | 32 | struct acs_engine_data { |
6ef63580 SK |
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; | |
c11a9ddf JA |
43 | struct acs_engine_data *d = |
44 | (struct acs_engine_data *) io_u->file->engine_data; | |
6ef63580 SK |
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; | |
6ef63580 SK |
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; | |
c11a9ddf | 103 | struct acs_engine_data *d = NULL; |
6ef63580 SK |
104 | |
105 | d = malloc(sizeof(*d)); | |
106 | if (!d) { | |
107 | td_verror(td, -ENOMEM, "malloc"); | |
108 | rc = -ENOMEM; | |
109 | goto error; | |
110 | } | |
c11a9ddf | 111 | f->engine_data = (uintptr_t) d; |
6ef63580 SK |
112 | |
113 | rc = generic_open_file(td, f); | |
114 | ||
115 | out: | |
116 | return rc; | |
117 | ||
118 | error: | |
119 | f->fd = -1; | |
c11a9ddf | 120 | f->engine_data = 0; |
6ef63580 SK |
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 | { | |
c11a9ddf JA |
129 | if (f->engine_data) { |
130 | free((void *) f->engine_data); | |
131 | f->engine_data = 0; | |
6ef63580 SK |
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 | ||
6ef63580 SK |
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 | } |