engines/xnvme: user space vfio based backend
[fio.git] / engines / fileoperations.c
1 /*
2  * fileoperations engine
3  *
4  * IO engine that doesn't do any IO, just operates files and tracks the latency
5  * of the file 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
19 struct fc_data {
20         enum fio_ddir stat_ddir;
21 };
22
23 struct filestat_options {
24         void *pad;
25         unsigned int stat_type;
26 };
27
28 enum {
29         FIO_FILESTAT_STAT       = 1,
30         FIO_FILESTAT_LSTAT      = 2,
31         FIO_FILESTAT_STATX      = 3,
32 };
33
34 static struct fio_option options[] = {
35         {
36                 .name   = "stat_type",
37                 .lname  = "stat_type",
38                 .type   = FIO_OPT_STR,
39                 .off1   = offsetof(struct filestat_options, stat_type),
40                 .help   = "Specify stat system call type to measure lookup/getattr performance",
41                 .def    = "stat",
42                 .posval = {
43                           { .ival = "stat",
44                             .oval = FIO_FILESTAT_STAT,
45                             .help = "Use stat(2)",
46                           },
47                           { .ival = "lstat",
48                             .oval = FIO_FILESTAT_LSTAT,
49                             .help = "Use lstat(2)",
50                           },
51                           { .ival = "statx",
52                             .oval = FIO_FILESTAT_STATX,
53                             .help = "Use statx(2) if exists",
54                           },
55                 },
56                 .category = FIO_OPT_C_ENGINE,
57                 .group  = FIO_OPT_G_FILESTAT,
58         },
59         {
60                 .name   = NULL,
61         },
62 };
63
64
65 static int open_file(struct thread_data *td, struct fio_file *f)
66 {
67         struct timespec start;
68         int do_lat = !td->o.disable_lat;
69
70         dprint(FD_FILE, "fd open %s\n", f->file_name);
71
72         if (f->filetype != FIO_TYPE_FILE) {
73                 log_err("fio: only files are supported\n");
74                 return 1;
75         }
76         if (!strcmp(f->file_name, "-")) {
77                 log_err("fio: can't read/write to stdin/out\n");
78                 return 1;
79         }
80
81         if (do_lat)
82                 fio_gettime(&start, NULL);
83
84         f->fd = open(f->file_name, O_CREAT|O_RDWR, 0600);
85
86         if (f->fd == -1) {
87                 char buf[FIO_VERROR_SIZE];
88                 int e = errno;
89
90                 snprintf(buf, sizeof(buf), "open(%s)", f->file_name);
91                 td_verror(td, e, buf);
92                 return 1;
93         }
94
95         if (do_lat) {
96                 struct fc_data *data = td->io_ops_data;
97                 uint64_t nsec;
98
99                 nsec = ntime_since_now(&start);
100                 add_clat_sample(td, data->stat_ddir, nsec, 0, 0, 0, 0);
101         }
102
103         return 0;
104 }
105
106 static int stat_file(struct thread_data *td, struct fio_file *f)
107 {
108         struct filestat_options *o = td->eo;
109         struct timespec start;
110         int do_lat = !td->o.disable_lat;
111         struct stat statbuf;
112 #ifndef WIN32
113         struct statx statxbuf;
114         char *abspath;
115 #endif
116         int ret;
117
118         dprint(FD_FILE, "fd stat %s\n", f->file_name);
119
120         if (f->filetype != FIO_TYPE_FILE) {
121                 log_err("fio: only files are supported\n");
122                 return 1;
123         }
124         if (!strcmp(f->file_name, "-")) {
125                 log_err("fio: can't read/write to stdin/out\n");
126                 return 1;
127         }
128
129         if (do_lat)
130                 fio_gettime(&start, NULL);
131
132         switch (o->stat_type) {
133         case FIO_FILESTAT_STAT:
134                 ret = stat(f->file_name, &statbuf);
135                 break;
136         case FIO_FILESTAT_LSTAT:
137                 ret = lstat(f->file_name, &statbuf);
138                 break;
139         case FIO_FILESTAT_STATX:
140 #ifndef WIN32
141                 abspath = realpath(f->file_name, NULL);
142                 if (abspath) {
143                         ret = statx(-1, abspath, 0, STATX_ALL, &statxbuf);
144                         free(abspath);
145                 } else
146                         ret = -1;
147 #else
148                 ret = -1;
149 #endif
150                 break;
151         default:
152                 ret = -1;
153                 break;
154         }
155
156         if (ret == -1) {
157                 char buf[FIO_VERROR_SIZE];
158                 int e = errno;
159
160                 snprintf(buf, sizeof(buf), "stat(%s) type=%u", f->file_name,
161                         o->stat_type);
162                 td_verror(td, e, buf);
163                 return 1;
164         }
165
166         if (do_lat) {
167                 struct fc_data *data = td->io_ops_data;
168                 uint64_t nsec;
169
170                 nsec = ntime_since_now(&start);
171                 add_clat_sample(td, data->stat_ddir, nsec, 0, 0, 0, 0);
172         }
173
174         return 0;
175 }
176
177
178 static int delete_file(struct thread_data *td, struct fio_file *f)
179 {
180         struct timespec start;
181         int do_lat = !td->o.disable_lat;
182         int ret;
183
184         dprint(FD_FILE, "fd delete %s\n", f->file_name);
185
186         if (f->filetype != FIO_TYPE_FILE) {
187                 log_err("fio: only files are supported\n");
188                 return 1;
189         }
190         if (!strcmp(f->file_name, "-")) {
191                 log_err("fio: can't read/write to stdin/out\n");
192                 return 1;
193         }
194
195         if (do_lat)
196                 fio_gettime(&start, NULL);
197
198         ret = unlink(f->file_name);
199
200         if (ret == -1) {
201                 char buf[FIO_VERROR_SIZE];
202                 int e = errno;
203
204                 snprintf(buf, sizeof(buf), "delete(%s)", f->file_name);
205                 td_verror(td, e, buf);
206                 return 1;
207         }
208
209         if (do_lat) {
210                 struct fc_data *data = td->io_ops_data;
211                 uint64_t nsec;
212
213                 nsec = ntime_since_now(&start);
214                 add_clat_sample(td, data->stat_ddir, nsec, 0, 0, 0, 0);
215         }
216
217         return 0;
218 }
219
220 static int invalidate_do_nothing(struct thread_data *td, struct fio_file *f)
221 {
222         /* do nothing because file not opened */
223         return 0;
224 }
225
226 static enum fio_q_status queue_io(struct thread_data *td, struct io_u *io_u)
227 {
228         return FIO_Q_COMPLETED;
229 }
230
231 /*
232  * Ensure that we at least have a block size worth of IO to do for each
233  * file. If the job file has td->o.size < nr_files * block_size, then
234  * fio won't do anything.
235  */
236 static int get_file_size(struct thread_data *td, struct fio_file *f)
237 {
238         f->real_file_size = td_min_bs(td);
239         return 0;
240 }
241
242 static int init(struct thread_data *td)
243 {
244         struct fc_data *data;
245
246         data = calloc(1, sizeof(*data));
247
248         if (td_read(td))
249                 data->stat_ddir = DDIR_READ;
250         else if (td_write(td))
251                 data->stat_ddir = DDIR_WRITE;
252
253         td->io_ops_data = data;
254         return 0;
255 }
256
257 static void cleanup(struct thread_data *td)
258 {
259         struct fc_data *data = td->io_ops_data;
260
261         free(data);
262 }
263
264 static struct ioengine_ops ioengine_filecreate = {
265         .name           = "filecreate",
266         .version        = FIO_IOOPS_VERSION,
267         .init           = init,
268         .cleanup        = cleanup,
269         .queue          = queue_io,
270         .get_file_size  = get_file_size,
271         .open_file      = open_file,
272         .close_file     = generic_close_file,
273         .flags          = FIO_DISKLESSIO | FIO_SYNCIO | FIO_FAKEIO |
274                                 FIO_NOSTATS | FIO_NOFILEHASH,
275 };
276
277 static struct ioengine_ops ioengine_filestat = {
278         .name           = "filestat",
279         .version        = FIO_IOOPS_VERSION,
280         .init           = init,
281         .cleanup        = cleanup,
282         .queue          = queue_io,
283         .invalidate     = invalidate_do_nothing,
284         .get_file_size  = generic_get_file_size,
285         .open_file      = stat_file,
286         .flags          =  FIO_SYNCIO | FIO_FAKEIO |
287                                 FIO_NOSTATS | FIO_NOFILEHASH,
288         .options        = options,
289         .option_struct_size = sizeof(struct filestat_options),
290 };
291
292 static struct ioengine_ops ioengine_filedelete = {
293         .name           = "filedelete",
294         .version        = FIO_IOOPS_VERSION,
295         .init           = init,
296         .invalidate     = invalidate_do_nothing,
297         .cleanup        = cleanup,
298         .queue          = queue_io,
299         .get_file_size  = generic_get_file_size,
300         .open_file      = delete_file,
301         .flags          =  FIO_SYNCIO | FIO_FAKEIO |
302                                 FIO_NOSTATS | FIO_NOFILEHASH,
303 };
304
305
306 static void fio_init fio_fileoperations_register(void)
307 {
308         register_ioengine(&ioengine_filecreate);
309         register_ioengine(&ioengine_filestat);
310         register_ioengine(&ioengine_filedelete);
311 }
312
313 static void fio_exit fio_fileoperations_unregister(void)
314 {
315         unregister_ioengine(&ioengine_filecreate);
316         unregister_ioengine(&ioengine_filestat);
317         unregister_ioengine(&ioengine_filedelete);
318 }