engines/fileoperations: use local var for ioengine data
[fio.git] / engines / fileoperations.c
1 /*
2  * file/directory operations engine
3  *
4  * IO engine that doesn't do any IO, just operates files/directories
5  * and tracks the latency of the operation.
6  */
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <fcntl.h>
10 #include <errno.h>
11 #include <sys/types.h>
12 #include <sys/stat.h>
13 #include <unistd.h>
14 #include "../fio.h"
15 #include "../optgroup.h"
16 #include "../oslib/statx.h"
17
18 enum fio_engine {
19         UNKNOWN_OP_ENGINE = 0,
20         FILE_OP_ENGINE = 1,
21         DIR_OP_ENGINE = 2,
22 };
23
24 struct fc_data {
25         enum fio_ddir stat_ddir;
26         enum fio_engine op_engine;
27 };
28
29 struct filestat_options {
30         void *pad;
31         unsigned int stat_type;
32 };
33
34 enum {
35         FIO_FILESTAT_STAT       = 1,
36         FIO_FILESTAT_LSTAT      = 2,
37         FIO_FILESTAT_STATX      = 3,
38 };
39
40 static struct fio_option options[] = {
41         {
42                 .name   = "stat_type",
43                 .lname  = "stat_type",
44                 .type   = FIO_OPT_STR,
45                 .off1   = offsetof(struct filestat_options, stat_type),
46                 .help   = "Specify stat system call type to measure lookup/getattr performance",
47                 .def    = "stat",
48                 .posval = {
49                           { .ival = "stat",
50                             .oval = FIO_FILESTAT_STAT,
51                             .help = "Use stat(2)",
52                           },
53                           { .ival = "lstat",
54                             .oval = FIO_FILESTAT_LSTAT,
55                             .help = "Use lstat(2)",
56                           },
57                           { .ival = "statx",
58                             .oval = FIO_FILESTAT_STATX,
59                             .help = "Use statx(2) if exists",
60                           },
61                 },
62                 .category = FIO_OPT_C_ENGINE,
63                 .group  = FIO_OPT_G_FILESTAT,
64         },
65         {
66                 .name   = NULL,
67         },
68 };
69
70 static int setup_dirs(struct thread_data *td)
71 {
72         int ret = 0;
73         int i;
74         struct fio_file *f;
75
76         for_each_file(td, f, i) {
77                 dprint(FD_FILE, "setup directory %s\n", f->file_name);
78                 ret = fio_mkdir(f->file_name, 0700);
79                 if ((ret && errno != EEXIST)) {
80                         log_err("create directory %s failed with %d\n",
81                                 f->file_name, errno);
82                         break;
83                 }
84                 ret = 0;
85         }
86         return ret;
87 }
88
89 static int open_file(struct thread_data *td, struct fio_file *f)
90 {
91         struct timespec start;
92         int do_lat = !td->o.disable_lat;
93         struct fc_data *fcd = td->io_ops_data;
94
95         dprint(FD_FILE, "fd open %s\n", f->file_name);
96
97         if (f->filetype != FIO_TYPE_FILE) {
98                 log_err("fio: only files are supported\n");
99                 return 1;
100         }
101         if (!strcmp(f->file_name, "-")) {
102                 log_err("fio: can't read/write to stdin/out\n");
103                 return 1;
104         }
105
106         if (do_lat)
107                 fio_gettime(&start, NULL);
108
109         if (fcd->op_engine == FILE_OP_ENGINE)
110                 f->fd = open(f->file_name, O_CREAT|O_RDWR, 0600);
111         else if (fcd->op_engine == DIR_OP_ENGINE)
112                 f->fd = fio_mkdir(f->file_name, S_IFDIR);
113         else {
114                 log_err("fio: unknown file/directory operation engine\n");
115                 return 1;
116         }
117
118         if (f->fd == -1) {
119                 char buf[FIO_VERROR_SIZE];
120                 int e = errno;
121
122                 snprintf(buf, sizeof(buf), "open(%s)", f->file_name);
123                 td_verror(td, e, buf);
124                 return 1;
125         }
126
127         if (do_lat) {
128                 struct fc_data *data = td->io_ops_data;
129                 uint64_t nsec;
130
131                 nsec = ntime_since_now(&start);
132                 add_clat_sample(td, data->stat_ddir, nsec, 0, 0, 0, 0);
133         }
134
135         return 0;
136 }
137
138 static int stat_file(struct thread_data *td, struct fio_file *f)
139 {
140         struct filestat_options *o = td->eo;
141         struct timespec start;
142         int do_lat = !td->o.disable_lat;
143         struct stat statbuf;
144 #ifndef WIN32
145         struct statx statxbuf;
146         char *abspath;
147 #endif
148         int ret;
149
150         dprint(FD_FILE, "fd stat %s\n", f->file_name);
151
152         if (f->filetype != FIO_TYPE_FILE) {
153                 log_err("fio: only files are supported\n");
154                 return 1;
155         }
156         if (!strcmp(f->file_name, "-")) {
157                 log_err("fio: can't read/write to stdin/out\n");
158                 return 1;
159         }
160
161         if (do_lat)
162                 fio_gettime(&start, NULL);
163
164         switch (o->stat_type) {
165         case FIO_FILESTAT_STAT:
166                 ret = stat(f->file_name, &statbuf);
167                 break;
168         case FIO_FILESTAT_LSTAT:
169                 ret = lstat(f->file_name, &statbuf);
170                 break;
171         case FIO_FILESTAT_STATX:
172 #ifndef WIN32
173                 abspath = realpath(f->file_name, NULL);
174                 if (abspath) {
175                         ret = statx(-1, abspath, 0, STATX_ALL, &statxbuf);
176                         free(abspath);
177                 } else
178                         ret = -1;
179 #else
180                 ret = -1;
181 #endif
182                 break;
183         default:
184                 ret = -1;
185                 break;
186         }
187
188         if (ret == -1) {
189                 char buf[FIO_VERROR_SIZE];
190                 int e = errno;
191
192                 snprintf(buf, sizeof(buf), "stat(%s) type=%u", f->file_name,
193                         o->stat_type);
194                 td_verror(td, e, buf);
195                 return 1;
196         }
197
198         if (do_lat) {
199                 struct fc_data *data = td->io_ops_data;
200                 uint64_t nsec;
201
202                 nsec = ntime_since_now(&start);
203                 add_clat_sample(td, data->stat_ddir, nsec, 0, 0, 0, 0);
204         }
205
206         return 0;
207 }
208
209 static int delete_file(struct thread_data *td, struct fio_file *f)
210 {
211         struct timespec start;
212         int do_lat = !td->o.disable_lat;
213         struct fc_data *fcd = td->io_ops_data;
214         int ret;
215
216         dprint(FD_FILE, "fd delete %s\n", f->file_name);
217
218         if (f->filetype != FIO_TYPE_FILE) {
219                 log_err("fio: only files are supported\n");
220                 return 1;
221         }
222         if (!strcmp(f->file_name, "-")) {
223                 log_err("fio: can't read/write to stdin/out\n");
224                 return 1;
225         }
226
227         if (do_lat)
228                 fio_gettime(&start, NULL);
229
230         if (fcd->op_engine == FILE_OP_ENGINE)
231                 ret = unlink(f->file_name);
232         else if (fcd->op_engine == DIR_OP_ENGINE)
233                 ret = rmdir(f->file_name);
234         else {
235                 log_err("fio: unknown file/directory operation engine\n");
236                 return 1;
237         }
238
239         if (ret == -1) {
240                 char buf[FIO_VERROR_SIZE];
241                 int e = errno;
242
243                 snprintf(buf, sizeof(buf), "delete(%s)", f->file_name);
244                 td_verror(td, e, buf);
245                 return 1;
246         }
247
248         if (do_lat) {
249                 struct fc_data *data = td->io_ops_data;
250                 uint64_t nsec;
251
252                 nsec = ntime_since_now(&start);
253                 add_clat_sample(td, data->stat_ddir, nsec, 0, 0, 0, 0);
254         }
255
256         return 0;
257 }
258
259 static int invalidate_do_nothing(struct thread_data *td, struct fio_file *f)
260 {
261         /* do nothing because file not opened */
262         return 0;
263 }
264
265 static enum fio_q_status queue_io(struct thread_data *td, struct io_u *io_u)
266 {
267         return FIO_Q_COMPLETED;
268 }
269
270 /*
271  * Ensure that we at least have a block size worth of IO to do for each
272  * file. If the job file has td->o.size < nr_files * block_size, then
273  * fio won't do anything.
274  */
275 static int get_file_size(struct thread_data *td, struct fio_file *f)
276 {
277         f->real_file_size = td_min_bs(td);
278         return 0;
279 }
280
281 static int init(struct thread_data *td)
282 {
283         struct fc_data *data;
284
285         data = calloc(1, sizeof(*data));
286
287         if (td_read(td))
288                 data->stat_ddir = DDIR_READ;
289         else if (td_write(td))
290                 data->stat_ddir = DDIR_WRITE;
291
292         data->op_engine = UNKNOWN_OP_ENGINE;
293
294         if (!strncmp(td->o.ioengine, "file", 4)) {
295                 data->op_engine = FILE_OP_ENGINE;
296                 dprint(FD_FILE, "Operate engine type: file\n");
297         }
298         if (!strncmp(td->o.ioengine, "dir", 3)) {
299                 data->op_engine = DIR_OP_ENGINE;
300                 dprint(FD_FILE, "Operate engine type: directory\n");
301         }
302
303         td->io_ops_data = data;
304         return 0;
305 }
306
307 static void cleanup(struct thread_data *td)
308 {
309         struct fc_data *data = td->io_ops_data;
310
311         free(data);
312 }
313
314 static int remove_dir(struct thread_data *td, struct fio_file *f)
315 {
316         dprint(FD_FILE, "remove directory %s\n", f->file_name);
317         return rmdir(f->file_name);
318 }
319
320 static struct ioengine_ops ioengine_filecreate = {
321         .name           = "filecreate",
322         .version        = FIO_IOOPS_VERSION,
323         .init           = init,
324         .cleanup        = cleanup,
325         .queue          = queue_io,
326         .get_file_size  = get_file_size,
327         .open_file      = open_file,
328         .close_file     = generic_close_file,
329         .flags          = FIO_DISKLESSIO | FIO_SYNCIO | FIO_FAKEIO |
330                                 FIO_NOSTATS | FIO_NOFILEHASH,
331 };
332
333 static struct ioengine_ops ioengine_filestat = {
334         .name           = "filestat",
335         .version        = FIO_IOOPS_VERSION,
336         .init           = init,
337         .cleanup        = cleanup,
338         .queue          = queue_io,
339         .invalidate     = invalidate_do_nothing,
340         .get_file_size  = generic_get_file_size,
341         .open_file      = stat_file,
342         .flags          =  FIO_SYNCIO | FIO_FAKEIO |
343                                 FIO_NOSTATS | FIO_NOFILEHASH,
344         .options        = options,
345         .option_struct_size = sizeof(struct filestat_options),
346 };
347
348 static struct ioengine_ops ioengine_filedelete = {
349         .name           = "filedelete",
350         .version        = FIO_IOOPS_VERSION,
351         .init           = init,
352         .invalidate     = invalidate_do_nothing,
353         .cleanup        = cleanup,
354         .queue          = queue_io,
355         .get_file_size  = generic_get_file_size,
356         .open_file      = delete_file,
357         .flags          =  FIO_SYNCIO | FIO_FAKEIO |
358                                 FIO_NOSTATS | FIO_NOFILEHASH,
359 };
360
361 static struct ioengine_ops ioengine_dircreate = {
362         .name           = "dircreate",
363         .version        = FIO_IOOPS_VERSION,
364         .init           = init,
365         .cleanup        = cleanup,
366         .queue          = queue_io,
367         .get_file_size  = get_file_size,
368         .open_file      = open_file,
369         .close_file     = generic_close_file,
370         .unlink_file    = remove_dir,
371         .flags          = FIO_DISKLESSIO | FIO_SYNCIO | FIO_FAKEIO |
372                                 FIO_NOSTATS | FIO_NOFILEHASH,
373 };
374
375 static struct ioengine_ops ioengine_dirstat = {
376         .name           = "dirstat",
377         .version        = FIO_IOOPS_VERSION,
378         .setup          = setup_dirs,
379         .init           = init,
380         .cleanup        = cleanup,
381         .queue          = queue_io,
382         .invalidate     = invalidate_do_nothing,
383         .get_file_size  = generic_get_file_size,
384         .open_file      = stat_file,
385         .unlink_file    = remove_dir,
386         .flags          =  FIO_DISKLESSIO | FIO_SYNCIO | FIO_FAKEIO |
387                                 FIO_NOSTATS | FIO_NOFILEHASH,
388         .options        = options,
389         .option_struct_size = sizeof(struct filestat_options),
390 };
391
392 static struct ioengine_ops ioengine_dirdelete = {
393         .name           = "dirdelete",
394         .version        = FIO_IOOPS_VERSION,
395         .setup          = setup_dirs,
396         .init           = init,
397         .invalidate     = invalidate_do_nothing,
398         .cleanup        = cleanup,
399         .queue          = queue_io,
400         .get_file_size  = get_file_size,
401         .open_file      = delete_file,
402         .unlink_file    = remove_dir,
403         .flags          = FIO_DISKLESSIO | FIO_SYNCIO | FIO_FAKEIO |
404                                 FIO_NOSTATS | FIO_NOFILEHASH,
405 };
406
407 static void fio_init fio_fileoperations_register(void)
408 {
409         register_ioengine(&ioengine_filecreate);
410         register_ioengine(&ioengine_filestat);
411         register_ioengine(&ioengine_filedelete);
412         register_ioengine(&ioengine_dircreate);
413         register_ioengine(&ioengine_dirstat);
414         register_ioengine(&ioengine_dirdelete);
415 }
416
417 static void fio_exit fio_fileoperations_unregister(void)
418 {
419         unregister_ioengine(&ioengine_filecreate);
420         unregister_ioengine(&ioengine_filestat);
421         unregister_ioengine(&ioengine_filedelete);
422         unregister_ioengine(&ioengine_dircreate);
423         unregister_ioengine(&ioengine_dirstat);
424         unregister_ioengine(&ioengine_dirdelete);
425 }