2 * ioe_e4defrag: ioengine for git://git.kernel.dk/fio.git
4 * IO engine that does regular EXT4_IOC_MOVE_EXT ioctls to simulate
16 #include "../optgroup.h"
18 #ifndef EXT4_IOC_MOVE_EXT
19 #define EXT4_IOC_MOVE_EXT _IOWR('f', 15, struct 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 */
30 struct e4defrag_data {
35 struct e4defrag_options {
41 static struct fio_option options[] = {
44 .lname = "Donor Name",
45 .type = FIO_OPT_STR_STORE,
46 .off1 = offsetof(struct e4defrag_options, donor_name),
47 .help = "File used as a block donor",
48 .category = FIO_OPT_C_ENGINE,
49 .group = FIO_OPT_G_E4DEFRAG,
55 .off1 = offsetof(struct e4defrag_options, inplace),
58 .help = "Alloc and free space inside defrag event",
59 .category = FIO_OPT_C_ENGINE,
60 .group = FIO_OPT_G_E4DEFRAG,
67 static int fio_e4defrag_init(struct thread_data *td)
70 struct e4defrag_options *o = td->eo;
71 struct e4defrag_data *ed;
73 char donor_name[PATH_MAX];
75 if (!strlen(o->donor_name)) {
76 log_err("'donorname' options required\n");
80 ed = malloc(sizeof(*ed));
82 td_verror(td, ENOMEM, "io_queue_init");
85 memset(ed, 0 ,sizeof(*ed));
88 len = sprintf(donor_name, "%s/", td->o.directory);
89 sprintf(donor_name + len, "%s", o->donor_name);
91 ed->donor_fd = open(donor_name, O_CREAT|O_WRONLY, 0644);
92 if (ed->donor_fd < 0) {
93 td_verror(td, errno, "io_queue_init");
94 log_err("Can't open donor file %s err:%d\n", donor_name, ed->donor_fd);
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);
105 r = fstat(ed->donor_fd, &stub);
109 ed->bsz = stub.st_blksize;
110 td->io_ops_data = ed;
113 td_verror(td, errno, "io_queue_init");
119 static void fio_e4defrag_cleanup(struct thread_data *td)
121 struct e4defrag_data *ed = td->io_ops_data;
123 if (ed->donor_fd >= 0)
130 static enum fio_q_status fio_e4defrag_queue(struct thread_data *td,
135 unsigned long long len;
136 struct move_extent me;
137 struct fio_file *f = io_u->file;
138 struct e4defrag_data *ed = td->io_ops_data;
139 struct e4defrag_options *o = td->eo;
141 fio_ro_check(td, io_u);
143 /* Theoretically defragmentation should not change data, but it
144 * changes data layout. So this function handle only DDIR_WRITE
145 * in order to satisfy strict read only access pattern
147 if (io_u->ddir != DDIR_WRITE) {
148 io_u->error = EINVAL;
149 return FIO_Q_COMPLETED;
153 ret = fallocate(ed->donor_fd, 0, io_u->offset, io_u->xfer_buflen);
158 memset(&me, 0, sizeof(me));
159 me.donor_fd = ed->donor_fd;
160 me.orig_start = io_u->offset / ed->bsz;
161 me.donor_start = me.orig_start;
162 len = (io_u->offset + io_u->xfer_buflen + ed->bsz -1);
163 me.len = len / ed->bsz - me.orig_start;
165 ret = ioctl(f->fd, EXT4_IOC_MOVE_EXT, &me);
166 len = me.moved_len * ed->bsz;
168 if (len > io_u->xfer_buflen)
169 len = io_u->xfer_buflen;
171 if (len != io_u->xfer_buflen) {
173 io_u->resid = io_u->xfer_buflen - len;
176 /* access beyond i_size */
177 io_u->error = EINVAL;
184 ret = ftruncate(ed->donor_fd, 0);
186 if (ret && !io_u->error)
189 return FIO_Q_COMPLETED;
192 static struct ioengine_ops ioengine = {
194 .version = FIO_IOOPS_VERSION,
195 .init = fio_e4defrag_init,
196 .queue = fio_e4defrag_queue,
197 .open_file = generic_open_file,
198 .close_file = generic_close_file,
199 .get_file_size = generic_get_file_size,
201 .cleanup = fio_e4defrag_cleanup,
203 .option_struct_size = sizeof(struct e4defrag_options),
207 static void fio_init fio_syncio_register(void)
209 register_ioengine(&ioengine);
212 static void fio_exit fio_syncio_unregister(void)
214 unregister_ioengine(&ioengine);