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