engines/fileoperations: remove extra blank lines
[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;
93
94 dprint(FD_FILE, "fd open %s\n", f->file_name);
95
96 if (f->filetype != FIO_TYPE_FILE) {
97 log_err("fio: only files are supported\n");
98 return 1;
99 }
100 if (!strcmp(f->file_name, "-")) {
101 log_err("fio: can't read/write to stdin/out\n");
102 return 1;
103 }
104
105 if (do_lat)
106 fio_gettime(&start, NULL);
107
a7a817a2 108 if (((struct fc_data *)td->io_ops_data)->op_engine == FILE_OP_ENGINE)
109 f->fd = open(f->file_name, O_CREAT|O_RDWR, 0600);
110 else if (((struct fc_data *)td->io_ops_data)->op_engine == DIR_OP_ENGINE)
111 f->fd = fio_mkdir(f->file_name, S_IFDIR);
112 else {
113 log_err("fio: unknown file/directory operation engine\n");
114 return 1;
115 }
910c72df
FS
116
117 if (f->fd == -1) {
118 char buf[FIO_VERROR_SIZE];
119 int e = errno;
120
121 snprintf(buf, sizeof(buf), "open(%s)", f->file_name);
122 td_verror(td, e, buf);
123 return 1;
124 }
125
126 if (do_lat) {
127 struct fc_data *data = td->io_ops_data;
128 uint64_t nsec;
129
130 nsec = ntime_since_now(&start);
131 add_clat_sample(td, data->stat_ddir, nsec, 0, 0, 0, 0);
132 }
133
134 return 0;
135}
136
137static int stat_file(struct thread_data *td, struct fio_file *f)
138{
139 struct filestat_options *o = td->eo;
140 struct timespec start;
141 int do_lat = !td->o.disable_lat;
142 struct stat statbuf;
143#ifndef WIN32
144 struct statx statxbuf;
145 char *abspath;
146#endif
147 int ret;
148
149 dprint(FD_FILE, "fd stat %s\n", f->file_name);
150
151 if (f->filetype != FIO_TYPE_FILE) {
152 log_err("fio: only files are supported\n");
153 return 1;
154 }
155 if (!strcmp(f->file_name, "-")) {
156 log_err("fio: can't read/write to stdin/out\n");
157 return 1;
158 }
159
160 if (do_lat)
161 fio_gettime(&start, NULL);
162
163 switch (o->stat_type) {
164 case FIO_FILESTAT_STAT:
165 ret = stat(f->file_name, &statbuf);
166 break;
167 case FIO_FILESTAT_LSTAT:
168 ret = lstat(f->file_name, &statbuf);
169 break;
170 case FIO_FILESTAT_STATX:
171#ifndef WIN32
172 abspath = realpath(f->file_name, NULL);
173 if (abspath) {
174 ret = statx(-1, abspath, 0, STATX_ALL, &statxbuf);
175 free(abspath);
176 } else
177 ret = -1;
178#else
179 ret = -1;
180#endif
181 break;
182 default:
183 ret = -1;
184 break;
185 }
186
187 if (ret == -1) {
188 char buf[FIO_VERROR_SIZE];
189 int e = errno;
190
191 snprintf(buf, sizeof(buf), "stat(%s) type=%u", f->file_name,
192 o->stat_type);
193 td_verror(td, e, buf);
194 return 1;
195 }
196
197 if (do_lat) {
198 struct fc_data *data = td->io_ops_data;
199 uint64_t nsec;
200
201 nsec = ntime_since_now(&start);
202 add_clat_sample(td, data->stat_ddir, nsec, 0, 0, 0, 0);
203 }
204
205 return 0;
206}
207
910c72df
FS
208static int delete_file(struct thread_data *td, struct fio_file *f)
209{
210 struct timespec start;
211 int do_lat = !td->o.disable_lat;
212 int ret;
213
214 dprint(FD_FILE, "fd delete %s\n", f->file_name);
215
216 if (f->filetype != FIO_TYPE_FILE) {
217 log_err("fio: only files are supported\n");
218 return 1;
219 }
220 if (!strcmp(f->file_name, "-")) {
221 log_err("fio: can't read/write to stdin/out\n");
222 return 1;
223 }
224
225 if (do_lat)
226 fio_gettime(&start, NULL);
227
a7a817a2 228 if (((struct fc_data *)td->io_ops_data)->op_engine == FILE_OP_ENGINE)
229 ret = unlink(f->file_name);
230 else if (((struct fc_data *)td->io_ops_data)->op_engine == DIR_OP_ENGINE)
231 ret = rmdir(f->file_name);
232 else {
233 log_err("fio: unknown file/directory operation engine\n");
234 return 1;
235 }
236
910c72df
FS
237 if (ret == -1) {
238 char buf[FIO_VERROR_SIZE];
239 int e = errno;
240
241 snprintf(buf, sizeof(buf), "delete(%s)", f->file_name);
242 td_verror(td, e, buf);
243 return 1;
244 }
245
246 if (do_lat) {
247 struct fc_data *data = td->io_ops_data;
248 uint64_t nsec;
249
250 nsec = ntime_since_now(&start);
251 add_clat_sample(td, data->stat_ddir, nsec, 0, 0, 0, 0);
252 }
253
254 return 0;
255}
256
257static int invalidate_do_nothing(struct thread_data *td, struct fio_file *f)
258{
259 /* do nothing because file not opened */
260 return 0;
261}
262
263static enum fio_q_status queue_io(struct thread_data *td, struct io_u *io_u)
264{
265 return FIO_Q_COMPLETED;
266}
267
268/*
269 * Ensure that we at least have a block size worth of IO to do for each
270 * file. If the job file has td->o.size < nr_files * block_size, then
271 * fio won't do anything.
272 */
273static int get_file_size(struct thread_data *td, struct fio_file *f)
274{
275 f->real_file_size = td_min_bs(td);
276 return 0;
277}
278
279static int init(struct thread_data *td)
280{
281 struct fc_data *data;
282
283 data = calloc(1, sizeof(*data));
284
285 if (td_read(td))
286 data->stat_ddir = DDIR_READ;
287 else if (td_write(td))
288 data->stat_ddir = DDIR_WRITE;
289
a7a817a2 290 data->op_engine = UNKNOWN_OP_ENGINE;
291
292 if (!strncmp(td->o.ioengine, "file", 4)) {
293 data->op_engine = FILE_OP_ENGINE;
294 dprint(FD_FILE, "Operate engine type: file\n");
295 }
296 if (!strncmp(td->o.ioengine, "dir", 3)) {
297 data->op_engine = DIR_OP_ENGINE;
298 dprint(FD_FILE, "Operate engine type: directory\n");
299 }
300
910c72df
FS
301 td->io_ops_data = data;
302 return 0;
303}
304
305static void cleanup(struct thread_data *td)
306{
307 struct fc_data *data = td->io_ops_data;
308
309 free(data);
310}
311
a7a817a2 312static int remove_dir(struct thread_data *td, struct fio_file *f)
313{
314 dprint(FD_FILE, "remove directory %s\n", f->file_name);
315 return rmdir(f->file_name);
316}
317
910c72df
FS
318static struct ioengine_ops ioengine_filecreate = {
319 .name = "filecreate",
320 .version = FIO_IOOPS_VERSION,
321 .init = init,
322 .cleanup = cleanup,
323 .queue = queue_io,
324 .get_file_size = get_file_size,
325 .open_file = open_file,
326 .close_file = generic_close_file,
327 .flags = FIO_DISKLESSIO | FIO_SYNCIO | FIO_FAKEIO |
328 FIO_NOSTATS | FIO_NOFILEHASH,
329};
330
331static struct ioengine_ops ioengine_filestat = {
332 .name = "filestat",
333 .version = FIO_IOOPS_VERSION,
334 .init = init,
335 .cleanup = cleanup,
336 .queue = queue_io,
337 .invalidate = invalidate_do_nothing,
338 .get_file_size = generic_get_file_size,
339 .open_file = stat_file,
340 .flags = FIO_SYNCIO | FIO_FAKEIO |
341 FIO_NOSTATS | FIO_NOFILEHASH,
342 .options = options,
343 .option_struct_size = sizeof(struct filestat_options),
344};
345
346static struct ioengine_ops ioengine_filedelete = {
347 .name = "filedelete",
348 .version = FIO_IOOPS_VERSION,
349 .init = init,
350 .invalidate = invalidate_do_nothing,
351 .cleanup = cleanup,
352 .queue = queue_io,
353 .get_file_size = generic_get_file_size,
354 .open_file = delete_file,
355 .flags = FIO_SYNCIO | FIO_FAKEIO |
356 FIO_NOSTATS | FIO_NOFILEHASH,
357};
358
a7a817a2 359static struct ioengine_ops ioengine_dircreate = {
360 .name = "dircreate",
361 .version = FIO_IOOPS_VERSION,
362 .init = init,
363 .cleanup = cleanup,
364 .queue = queue_io,
365 .get_file_size = get_file_size,
366 .open_file = open_file,
367 .close_file = generic_close_file,
368 .unlink_file = remove_dir,
369 .flags = FIO_DISKLESSIO | FIO_SYNCIO | FIO_FAKEIO |
370 FIO_NOSTATS | FIO_NOFILEHASH,
371};
372
373static struct ioengine_ops ioengine_dirstat = {
374 .name = "dirstat",
375 .version = FIO_IOOPS_VERSION,
376 .setup = setup_dirs,
377 .init = init,
378 .cleanup = cleanup,
379 .queue = queue_io,
380 .invalidate = invalidate_do_nothing,
381 .get_file_size = generic_get_file_size,
382 .open_file = stat_file,
383 .unlink_file = remove_dir,
384 .flags = FIO_DISKLESSIO | FIO_SYNCIO | FIO_FAKEIO |
385 FIO_NOSTATS | FIO_NOFILEHASH,
386 .options = options,
387 .option_struct_size = sizeof(struct filestat_options),
388};
389
390static struct ioengine_ops ioengine_dirdelete = {
391 .name = "dirdelete",
392 .version = FIO_IOOPS_VERSION,
393 .setup = setup_dirs,
394 .init = init,
395 .invalidate = invalidate_do_nothing,
396 .cleanup = cleanup,
397 .queue = queue_io,
398 .get_file_size = get_file_size,
399 .open_file = delete_file,
400 .unlink_file = remove_dir,
401 .flags = FIO_DISKLESSIO | FIO_SYNCIO | FIO_FAKEIO |
402 FIO_NOSTATS | FIO_NOFILEHASH,
403};
404
910c72df
FS
405static void fio_init fio_fileoperations_register(void)
406{
407 register_ioengine(&ioengine_filecreate);
408 register_ioengine(&ioengine_filestat);
409 register_ioengine(&ioengine_filedelete);
a7a817a2 410 register_ioengine(&ioengine_dircreate);
411 register_ioengine(&ioengine_dirstat);
412 register_ioengine(&ioengine_dirdelete);
910c72df
FS
413}
414
415static void fio_exit fio_fileoperations_unregister(void)
416{
417 unregister_ioengine(&ioengine_filecreate);
418 unregister_ioengine(&ioengine_filestat);
419 unregister_ioengine(&ioengine_filedelete);
a7a817a2 420 unregister_ioengine(&ioengine_dircreate);
421 unregister_ioengine(&ioengine_dirstat);
422 unregister_ioengine(&ioengine_dirdelete);
910c72df 423}