2 * file/directory operations engine
4 * IO engine that doesn't do any IO, just operates files/directories
5 * and tracks the latency of the operation.
11 #include <sys/types.h>
15 #include "../optgroup.h"
16 #include "../oslib/statx.h"
19 UNKNOWN_OP_ENGINE = 0,
25 enum fio_ddir stat_ddir;
26 enum fio_engine op_engine;
29 struct filestat_options {
31 unsigned int stat_type;
35 FIO_FILESTAT_STAT = 1,
36 FIO_FILESTAT_LSTAT = 2,
37 FIO_FILESTAT_STATX = 3,
40 static struct fio_option options[] = {
45 .off1 = offsetof(struct filestat_options, stat_type),
46 .help = "Specify stat system call type to measure lookup/getattr performance",
50 .oval = FIO_FILESTAT_STAT,
51 .help = "Use stat(2)",
54 .oval = FIO_FILESTAT_LSTAT,
55 .help = "Use lstat(2)",
58 .oval = FIO_FILESTAT_STATX,
59 .help = "Use statx(2) if exists",
62 .category = FIO_OPT_C_ENGINE,
63 .group = FIO_OPT_G_FILESTAT,
70 static int setup_dirs(struct thread_data *td)
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",
89 static int open_file(struct thread_data *td, struct fio_file *f)
91 struct timespec start;
92 int do_lat = !td->o.disable_lat;
93 struct fc_data *fcd = td->io_ops_data;
95 dprint(FD_FILE, "fd open %s\n", f->file_name);
97 if (f->filetype != FIO_TYPE_FILE) {
98 log_err("fio: only files are supported\n");
101 if (!strcmp(f->file_name, "-")) {
102 log_err("fio: can't read/write to stdin/out\n");
107 fio_gettime(&start, NULL);
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);
114 log_err("fio: unknown file/directory operation engine\n");
119 char buf[FIO_VERROR_SIZE];
122 snprintf(buf, sizeof(buf), "open(%s)", f->file_name);
123 td_verror(td, e, buf);
128 struct fc_data *data = td->io_ops_data;
131 nsec = ntime_since_now(&start);
132 add_clat_sample(td, data->stat_ddir, nsec, 0, 0, 0, 0);
138 static int stat_file(struct thread_data *td, struct fio_file *f)
140 struct filestat_options *o = td->eo;
141 struct timespec start;
142 int do_lat = !td->o.disable_lat;
145 struct statx statxbuf;
150 dprint(FD_FILE, "fd stat %s\n", f->file_name);
152 if (f->filetype != FIO_TYPE_FILE) {
153 log_err("fio: only files are supported\n");
156 if (!strcmp(f->file_name, "-")) {
157 log_err("fio: can't read/write to stdin/out\n");
162 fio_gettime(&start, NULL);
164 switch (o->stat_type) {
165 case FIO_FILESTAT_STAT:
166 ret = stat(f->file_name, &statbuf);
168 case FIO_FILESTAT_LSTAT:
169 ret = lstat(f->file_name, &statbuf);
171 case FIO_FILESTAT_STATX:
173 abspath = realpath(f->file_name, NULL);
175 ret = statx(-1, abspath, 0, STATX_ALL, &statxbuf);
189 char buf[FIO_VERROR_SIZE];
192 snprintf(buf, sizeof(buf), "stat(%s) type=%u", f->file_name,
194 td_verror(td, e, buf);
199 struct fc_data *data = td->io_ops_data;
202 nsec = ntime_since_now(&start);
203 add_clat_sample(td, data->stat_ddir, nsec, 0, 0, 0, 0);
209 static int delete_file(struct thread_data *td, struct fio_file *f)
211 struct timespec start;
212 int do_lat = !td->o.disable_lat;
213 struct fc_data *fcd = td->io_ops_data;
216 dprint(FD_FILE, "fd delete %s\n", f->file_name);
218 if (f->filetype != FIO_TYPE_FILE) {
219 log_err("fio: only files are supported\n");
222 if (!strcmp(f->file_name, "-")) {
223 log_err("fio: can't read/write to stdin/out\n");
228 fio_gettime(&start, NULL);
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);
235 log_err("fio: unknown file/directory operation engine\n");
240 char buf[FIO_VERROR_SIZE];
243 snprintf(buf, sizeof(buf), "delete(%s)", f->file_name);
244 td_verror(td, e, buf);
249 struct fc_data *data = td->io_ops_data;
252 nsec = ntime_since_now(&start);
253 add_clat_sample(td, data->stat_ddir, nsec, 0, 0, 0, 0);
259 static int invalidate_do_nothing(struct thread_data *td, struct fio_file *f)
261 /* do nothing because file not opened */
265 static enum fio_q_status queue_io(struct thread_data *td, struct io_u *io_u)
267 return FIO_Q_COMPLETED;
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.
275 static int get_file_size(struct thread_data *td, struct fio_file *f)
277 f->real_file_size = td_min_bs(td);
281 static int init(struct thread_data *td)
283 struct fc_data *data;
285 data = calloc(1, sizeof(*data));
288 data->stat_ddir = DDIR_READ;
289 else if (td_write(td))
290 data->stat_ddir = DDIR_WRITE;
292 data->op_engine = UNKNOWN_OP_ENGINE;
294 if (!strncmp(td->o.ioengine, "file", 4)) {
295 data->op_engine = FILE_OP_ENGINE;
296 dprint(FD_FILE, "Operate engine type: file\n");
298 if (!strncmp(td->o.ioengine, "dir", 3)) {
299 data->op_engine = DIR_OP_ENGINE;
300 dprint(FD_FILE, "Operate engine type: directory\n");
303 td->io_ops_data = data;
307 static void cleanup(struct thread_data *td)
309 struct fc_data *data = td->io_ops_data;
314 static int remove_dir(struct thread_data *td, struct fio_file *f)
316 dprint(FD_FILE, "remove directory %s\n", f->file_name);
317 return rmdir(f->file_name);
320 static struct ioengine_ops ioengine_filecreate = {
321 .name = "filecreate",
322 .version = FIO_IOOPS_VERSION,
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,
333 static struct ioengine_ops ioengine_filestat = {
335 .version = FIO_IOOPS_VERSION,
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,
345 .option_struct_size = sizeof(struct filestat_options),
348 static struct ioengine_ops ioengine_filedelete = {
349 .name = "filedelete",
350 .version = FIO_IOOPS_VERSION,
352 .invalidate = invalidate_do_nothing,
355 .get_file_size = generic_get_file_size,
356 .open_file = delete_file,
357 .flags = FIO_SYNCIO | FIO_FAKEIO |
358 FIO_NOSTATS | FIO_NOFILEHASH,
361 static struct ioengine_ops ioengine_dircreate = {
363 .version = FIO_IOOPS_VERSION,
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,
375 static struct ioengine_ops ioengine_dirstat = {
377 .version = FIO_IOOPS_VERSION,
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,
389 .option_struct_size = sizeof(struct filestat_options),
392 static struct ioengine_ops ioengine_dirdelete = {
394 .version = FIO_IOOPS_VERSION,
397 .invalidate = invalidate_do_nothing,
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,
407 static void fio_init fio_fileoperations_register(void)
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);
417 static void fio_exit fio_fileoperations_unregister(void)
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);