Add missing --cmdhelp type string for FIO_OPT_UNSUPPORTED
[fio.git] / engines / e4defrag.c
CommitLineData
9c25d2e3
DM
1/*
2 * ioe_e4defrag: ioengine for git://git.kernel.dk/fio.git
3 *
4 * IO engine that does regular EXT4_IOC_MOVE_EXT ioctls to simulate
5 * defragment activity
6 *
7 */
8
9#include <sys/types.h>
10#include <sys/stat.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include <unistd.h>
14#include <sys/uio.h>
15#include <errno.h>
16#include <assert.h>
17#include <fcntl.h>
18
19#include "../fio.h"
d220c761 20#include "../optgroup.h"
9c25d2e3
DM
21
22#ifndef EXT4_IOC_MOVE_EXT
23#define EXT4_IOC_MOVE_EXT _IOWR('f', 15, struct move_extent)
24struct move_extent {
25 __u32 reserved; /* should be zero */
26 __u32 donor_fd; /* donor file descriptor */
27 __u64 orig_start; /* logical start offset in block for orig */
28 __u64 donor_start; /* logical start offset in block for donor */
29 __u64 len; /* block length to be moved */
30 __u64 moved_len; /* moved block length */
31};
32#endif
33
34struct e4defrag_data {
35 int donor_fd;
36 int bsz;
37};
38
39struct e4defrag_options {
a1f871c7 40 void *pad;
9c25d2e3
DM
41 unsigned int inplace;
42 char * donor_name;
43};
44
45static struct fio_option options[] = {
46 {
47 .name = "donorname",
48 .type = FIO_OPT_STR_STORE,
49 .off1 = offsetof(struct e4defrag_options, donor_name),
50 .help = "File used as a block donor",
e90a0adf
JA
51 .category = FIO_OPT_C_ENGINE,
52 .group = FIO_OPT_G_E4DEFRAG,
9c25d2e3
DM
53 },
54 {
55 .name = "inplace",
56 .type = FIO_OPT_INT,
57 .off1 = offsetof(struct e4defrag_options, inplace),
58 .minval = 0,
59 .maxval = 1,
60 .help = "Alloc and free space inside defrag event",
e90a0adf
JA
61 .category = FIO_OPT_C_ENGINE,
62 .group = FIO_OPT_G_E4DEFRAG,
9c25d2e3
DM
63 },
64 {
65 .name = NULL,
66 },
67};
68
69static int fio_e4defrag_init(struct thread_data *td)
70{
71 int r, len = 0;
72 struct e4defrag_options *o = td->eo;
73 struct e4defrag_data *ed;
74 struct stat stub;
75 char donor_name[PATH_MAX];
76
77 if (!strlen(o->donor_name)) {
78 log_err("'donorname' options required\n");
79 return 1;
80 }
81
82 ed = malloc(sizeof(*ed));
83 if (!ed) {
43e0d132 84 td_verror(td, ENOMEM, "io_queue_init");
9c25d2e3
DM
85 return 1;
86 }
87 memset(ed, 0 ,sizeof(*ed));
88
89 if (td->o.directory)
90 len = sprintf(donor_name, "%s/", td->o.directory);
91 sprintf(donor_name + len, "%s", o->donor_name);
92
93 ed->donor_fd = open(donor_name, O_CREAT|O_WRONLY, 0644);
94 if (ed->donor_fd < 0) {
43e0d132 95 td_verror(td, errno, "io_queue_init");
4e0a8fa2 96 log_err("Can't open donor file %s err:%d", donor_name, ed->donor_fd);
9c25d2e3
DM
97 free(ed);
98 return 1;
99 }
100
101 if (!o->inplace) {
8a1db9a1
JA
102 long long __len = td->o.file_size_high - td->o.start_offset;
103 r = fallocate(ed->donor_fd, 0, td->o.start_offset, __len);
9c25d2e3
DM
104 if (r)
105 goto err;
106 }
107 r = fstat(ed->donor_fd, &stub);
108 if (r)
109 goto err;
110
111 ed->bsz = stub.st_blksize;
112 td->io_ops->data = ed;
113 return 0;
114err:
115 td_verror(td, errno, "io_queue_init");
116 close(ed->donor_fd);
117 free(ed);
118 return 1;
119}
120
121static void fio_e4defrag_cleanup(struct thread_data *td)
122{
123 struct e4defrag_data *ed = td->io_ops->data;
124 if (ed) {
125 if (ed->donor_fd >= 0)
126 close(ed->donor_fd);
127 free(ed);
128 }
129}
130
131
132static int fio_e4defrag_queue(struct thread_data *td, struct io_u *io_u)
133{
134
135 int ret;
136 unsigned long long len;
137 struct move_extent me;
138 struct fio_file *f = io_u->file;
139 struct e4defrag_data *ed = td->io_ops->data;
140 struct e4defrag_options *o = td->eo;
141
142 fio_ro_check(td, io_u);
143
144 /* Theoretically defragmentation should not change data, but it
145 * changes data layout. So this function handle only DDIR_WRITE
146 * in order to satisfy strict read only access pattern
147 */
148 if (io_u->ddir != DDIR_WRITE) {
e12d2800 149 io_u->error = EINVAL;
9c25d2e3
DM
150 return FIO_Q_COMPLETED;
151 }
152
153 if (o->inplace) {
154 ret = fallocate(ed->donor_fd, 0, io_u->offset, io_u->xfer_buflen);
e12d2800 155 if (ret)
9c25d2e3 156 goto out;
9c25d2e3
DM
157 }
158
159 memset(&me, 0, sizeof(me));
160 me.donor_fd = ed->donor_fd;
161 me.orig_start = io_u->offset / ed->bsz;
162 me.donor_start = me.orig_start;
163 len = (io_u->offset + io_u->xfer_buflen + ed->bsz -1);
164 me.len = len / ed->bsz - me.orig_start;
165
166 ret = ioctl(f->fd, EXT4_IOC_MOVE_EXT, &me);
167 len = me.moved_len * ed->bsz;
168
9c25d2e3
DM
169 if (len > io_u->xfer_buflen)
170 len = io_u->xfer_buflen;
171
172 if (len != io_u->xfer_buflen) {
173 io_u->resid = io_u->xfer_buflen - len;
174 io_u->error = 0;
175 }
176 if (ret)
177 io_u->error = errno;
e12d2800
DM
178
179 if (o->inplace)
9c25d2e3 180 ret = ftruncate(ed->donor_fd, 0);
9c25d2e3 181out:
e12d2800
DM
182 if (ret && !io_u->error)
183 io_u->error = errno;
9c25d2e3
DM
184
185 return FIO_Q_COMPLETED;
186}
187
188static struct ioengine_ops ioengine = {
189 .name = "e4defrag",
190 .version = FIO_IOOPS_VERSION,
191 .init = fio_e4defrag_init,
192 .queue = fio_e4defrag_queue,
193 .open_file = generic_open_file,
194 .close_file = generic_close_file,
195 .get_file_size = generic_get_file_size,
196 .flags = FIO_SYNCIO,
197 .cleanup = fio_e4defrag_cleanup,
198 .options = options,
199 .option_struct_size = sizeof(struct e4defrag_options),
200
201};
202
203static void fio_init fio_syncio_register(void)
204{
205 register_ioengine(&ioengine);
206}
207
208static void fio_exit fio_syncio_unregister(void)
209{
210 unregister_ioengine(&ioengine);
211}