engines: rename option specific pad from 'td' to 'pad'
[fio.git] / engines / e4defrag.c
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)
23 struct 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
33 struct e4defrag_data {
34         int donor_fd;
35         int bsz;
36 };
37
38 struct e4defrag_options {
39         void *pad;
40         unsigned int inplace;
41         char * donor_name;
42 };
43
44 static 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                 .category = FIO_OPT_C_ENGINE,
51                 .group  = FIO_OPT_G_E4DEFRAG,
52         },
53         {
54                 .name   = "inplace",
55                 .type   = FIO_OPT_INT,
56                 .off1   = offsetof(struct e4defrag_options, inplace),
57                 .minval = 0,
58                 .maxval = 1,
59                 .help   = "Alloc and free space inside defrag event",
60                 .category = FIO_OPT_C_ENGINE,
61                 .group  = FIO_OPT_G_E4DEFRAG,
62         },
63         {
64                 .name   = NULL,
65         },
66 };
67
68 static int fio_e4defrag_init(struct thread_data *td)
69 {
70         int r, len = 0;
71         struct e4defrag_options *o = td->eo;
72         struct e4defrag_data *ed;
73         struct stat stub;
74         char donor_name[PATH_MAX];
75
76         if (!strlen(o->donor_name)) {
77                 log_err("'donorname' options required\n");
78                 return 1;
79         }
80
81         ed = malloc(sizeof(*ed));
82         if (!ed) {
83                 td_verror(td, ENOMEM, "io_queue_init");
84                 return 1;
85         }
86         memset(ed, 0 ,sizeof(*ed));
87
88         if (td->o.directory)
89                 len = sprintf(donor_name, "%s/", td->o.directory);
90         sprintf(donor_name + len, "%s", o->donor_name);
91
92         ed->donor_fd = open(donor_name, O_CREAT|O_WRONLY, 0644);
93         if (ed->donor_fd < 0) {
94                 td_verror(td, errno, "io_queue_init");
95                 log_err("Can't open donor file %s err:%d", donor_name, ed->donor_fd);
96                 free(ed);
97                 return 1;
98         }
99
100         if (!o->inplace) {
101                 long long len = td->o.file_size_high - td->o.start_offset;
102                 r = fallocate(ed->donor_fd, 0, td->o.start_offset, len);
103                 if (r)
104                         goto err;
105         }
106         r = fstat(ed->donor_fd, &stub);
107         if (r)
108                 goto err;
109
110         ed->bsz = stub.st_blksize;
111         td->io_ops->data = ed;
112         return 0;
113 err:
114         td_verror(td, errno, "io_queue_init");
115         close(ed->donor_fd);
116         free(ed);
117         return 1;
118 }
119
120 static void fio_e4defrag_cleanup(struct thread_data *td)
121 {
122         struct e4defrag_data *ed = td->io_ops->data;
123         if (ed) {
124                 if (ed->donor_fd >= 0)
125                         close(ed->donor_fd);
126                 free(ed);
127         }
128 }
129
130
131 static int fio_e4defrag_queue(struct thread_data *td, struct io_u *io_u)
132 {
133
134         int ret;
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;
140
141         fio_ro_check(td, io_u);
142
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
146          */
147         if (io_u->ddir != DDIR_WRITE) {
148                 io_u->error = EINVAL;
149                 return FIO_Q_COMPLETED;
150         }
151
152         if (o->inplace) {
153                 ret = fallocate(ed->donor_fd, 0, io_u->offset, io_u->xfer_buflen);
154                 if (ret)
155                         goto out;
156         }
157
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;
164
165         ret = ioctl(f->fd, EXT4_IOC_MOVE_EXT, &me);
166         len = me.moved_len * ed->bsz;
167
168         if (len > io_u->xfer_buflen)
169                 len = io_u->xfer_buflen;
170
171         if (len != io_u->xfer_buflen) {
172                 io_u->resid = io_u->xfer_buflen - len;
173                 io_u->error = 0;
174         }
175         if (ret)
176                 io_u->error = errno;
177
178         if (o->inplace)
179                 ret = ftruncate(ed->donor_fd, 0);
180 out:
181         if (ret && !io_u->error)
182                 io_u->error = errno;
183
184         return FIO_Q_COMPLETED;
185 }
186
187 static struct ioengine_ops ioengine = {
188         .name                   = "e4defrag",
189         .version                = FIO_IOOPS_VERSION,
190         .init                   = fio_e4defrag_init,
191         .queue                  = fio_e4defrag_queue,
192         .open_file              = generic_open_file,
193         .close_file             = generic_close_file,
194         .get_file_size          = generic_get_file_size,
195         .flags                  = FIO_SYNCIO,
196         .cleanup                = fio_e4defrag_cleanup,
197         .options                = options,
198         .option_struct_size     = sizeof(struct e4defrag_options),
199
200 };
201
202 static void fio_init fio_syncio_register(void)
203 {
204         register_ioengine(&ioengine);
205 }
206
207 static void fio_exit fio_syncio_unregister(void)
208 {
209         unregister_ioengine(&ioengine);
210 }