engines/fileoperations: use local var for ioengine data
[fio.git] / engines / fileoperations.c
CommitLineData
910c72df 1/*
a7a817a2 2 * file/directory operations engine
910c72df 3 *
a7a817a2 4 * IO engine that doesn't do any IO, just operates files/directories
5 * and tracks the latency of the operation.
910c72df
FS
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
a7a817a2 18enum fio_engine {
19 UNKNOWN_OP_ENGINE = 0,
20 FILE_OP_ENGINE = 1,
21 DIR_OP_ENGINE = 2,
22};
910c72df
FS
23
24struct fc_data {
25 enum fio_ddir stat_ddir;
a7a817a2 26 enum fio_engine op_engine;
910c72df
FS
27};
28
29struct filestat_options {
30 void *pad;
31 unsigned int stat_type;
32};
33
34enum {
35 FIO_FILESTAT_STAT = 1,
36 FIO_FILESTAT_LSTAT = 2,
37 FIO_FILESTAT_STATX = 3,
38};
39
40static 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
a7a817a2 70static 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
910c72df
FS
89static int open_file(struct thread_data *td, struct fio_file *f)
90{
91 struct timespec start;
92 int do_lat = !td->o.disable_lat;
caa20ee5 93 struct fc_data *fcd = td->io_ops_data;
910c72df
FS
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
caa20ee5 109 if (fcd->op_engine == FILE_OP_ENGINE)
a7a817a2 110 f->fd = open(f->file_name, O_CREAT|O_RDWR, 0600);
caa20ee5 111 else if (fcd->op_engine == DIR_OP_ENGINE)
a7a817a2 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 }
910c72df
FS
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
138static 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
910c72df
FS
209static int delete_file(struct thread_data *td, struct fio_file *f)
210{
211 struct timespec start;
212 int do_lat = !td->o.disable_lat;
caa20ee5 213 struct fc_data *fcd = td->io_ops_data;
910c72df
FS
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
caa20ee5 230 if (fcd->op_engine == FILE_OP_ENGINE)
a7a817a2 231 ret = unlink(f->file_name);
caa20ee5 232 else if (fcd->op_engine == DIR_OP_ENGINE)
a7a817a2 233 ret = rmdir(f->file_name);
234 else {
235 log_err("fio: unknown file/directory operation engine\n");
236 return 1;
237 }
238
910c72df
FS
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
259static 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
265static 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 */
275static 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
281static 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
a7a817a2 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
910c72df
FS
303 td->io_ops_data = data;
304 return 0;
305}
306
307static void cleanup(struct thread_data *td)
308{
309 struct fc_data *data = td->io_ops_data;
310
311 free(data);
312}
313
a7a817a2 314static 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
910c72df
FS
320static 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
333static 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
348static 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
a7a817a2 361static 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
375static 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
392static 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
910c72df
FS
407static void fio_init fio_fileoperations_register(void)
408{
409 register_ioengine(&ioengine_filecreate);
410 register_ioengine(&ioengine_filestat);
411 register_ioengine(&ioengine_filedelete);
a7a817a2 412 register_ioengine(&ioengine_dircreate);
413 register_ioengine(&ioengine_dirstat);
414 register_ioengine(&ioengine_dirdelete);
910c72df
FS
415}
416
417static void fio_exit fio_fileoperations_unregister(void)
418{
419 unregister_ioengine(&ioengine_filecreate);
420 unregister_ioengine(&ioengine_filestat);
421 unregister_ioengine(&ioengine_filedelete);
a7a817a2 422 unregister_ioengine(&ioengine_dircreate);
423 unregister_ioengine(&ioengine_dirstat);
424 unregister_ioengine(&ioengine_dirdelete);
910c72df 425}