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