Commit | Line | Data |
---|---|---|
73ccd14e SF |
1 | /* |
2 | * filestat engine | |
3 | * | |
4 | * IO engine that doesn't do any IO, just stat files and tracks the latency | |
5 | * of the file stat. | |
6 | */ | |
7 | #include <stdio.h> | |
95f31f7d | 8 | #include <stdlib.h> |
73ccd14e SF |
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" | |
c446eff0 | 15 | #include "../optgroup.h" |
95f31f7d | 16 | #include "../oslib/statx.h" |
73ccd14e SF |
17 | |
18 | struct fc_data { | |
19 | enum fio_ddir stat_ddir; | |
20 | }; | |
21 | ||
c446eff0 TK |
22 | struct filestat_options { |
23 | void *pad; | |
93a13ba5 TK |
24 | unsigned int stat_type; |
25 | }; | |
26 | ||
27 | enum { | |
28 | FIO_FILESTAT_STAT = 1, | |
29 | FIO_FILESTAT_LSTAT = 2, | |
95f31f7d | 30 | FIO_FILESTAT_STATX = 3, |
c446eff0 TK |
31 | }; |
32 | ||
33 | static struct fio_option options[] = { | |
34 | { | |
93a13ba5 TK |
35 | .name = "stat_type", |
36 | .lname = "stat_type", | |
37 | .type = FIO_OPT_STR, | |
38 | .off1 = offsetof(struct filestat_options, stat_type), | |
39 | .help = "Specify stat system call type to measure lookup/getattr performance", | |
40 | .def = "stat", | |
41 | .posval = { | |
42 | { .ival = "stat", | |
43 | .oval = FIO_FILESTAT_STAT, | |
44 | .help = "Use stat(2)", | |
45 | }, | |
46 | { .ival = "lstat", | |
47 | .oval = FIO_FILESTAT_LSTAT, | |
48 | .help = "Use lstat(2)", | |
49 | }, | |
93a13ba5 TK |
50 | { .ival = "statx", |
51 | .oval = FIO_FILESTAT_STATX, | |
95f31f7d | 52 | .help = "Use statx(2) if exists", |
93a13ba5 | 53 | }, |
93a13ba5 | 54 | }, |
c446eff0 TK |
55 | .category = FIO_OPT_C_ENGINE, |
56 | .group = FIO_OPT_G_FILESTAT, | |
57 | }, | |
58 | { | |
59 | .name = NULL, | |
60 | }, | |
61 | }; | |
62 | ||
73ccd14e SF |
63 | static int stat_file(struct thread_data *td, struct fio_file *f) |
64 | { | |
c446eff0 | 65 | struct filestat_options *o = td->eo; |
73ccd14e SF |
66 | struct timespec start; |
67 | int do_lat = !td->o.disable_lat; | |
68 | struct stat statbuf; | |
95f31f7d TK |
69 | #ifndef WIN32 |
70 | struct statx statxbuf; | |
71 | char *abspath; | |
72 | #endif | |
73ccd14e SF |
73 | int ret; |
74 | ||
75 | dprint(FD_FILE, "fd stat %s\n", f->file_name); | |
76 | ||
77 | if (f->filetype != FIO_TYPE_FILE) { | |
78 | log_err("fio: only files are supported\n"); | |
79 | return 1; | |
80 | } | |
81 | if (!strcmp(f->file_name, "-")) { | |
82 | log_err("fio: can't read/write to stdin/out\n"); | |
83 | return 1; | |
84 | } | |
85 | ||
86 | if (do_lat) | |
87 | fio_gettime(&start, NULL); | |
88 | ||
93a13ba5 TK |
89 | switch (o->stat_type){ |
90 | case FIO_FILESTAT_STAT: | |
c446eff0 | 91 | ret = stat(f->file_name, &statbuf); |
93a13ba5 TK |
92 | break; |
93 | case FIO_FILESTAT_LSTAT: | |
94 | ret = lstat(f->file_name, &statbuf); | |
95 | break; | |
95f31f7d TK |
96 | case FIO_FILESTAT_STATX: |
97 | #ifndef WIN32 | |
98 | abspath = realpath(f->file_name, NULL); | |
99 | if (abspath) { | |
100 | ret = statx(-1, abspath, 0, STATX_ALL, &statxbuf); | |
101 | free(abspath); | |
102 | } else | |
103 | ret = -1; | |
104 | #else | |
105 | ret = -1; | |
106 | #endif | |
107 | break; | |
93a13ba5 TK |
108 | default: |
109 | ret = -1; | |
110 | break; | |
111 | } | |
73ccd14e SF |
112 | |
113 | if (ret == -1) { | |
114 | char buf[FIO_VERROR_SIZE]; | |
115 | int e = errno; | |
116 | ||
93a13ba5 TK |
117 | snprintf(buf, sizeof(buf), "stat(%s) type=%u", f->file_name, |
118 | o->stat_type); | |
73ccd14e SF |
119 | td_verror(td, e, buf); |
120 | return 1; | |
121 | } | |
122 | ||
123 | if (do_lat) { | |
124 | struct fc_data *data = td->io_ops_data; | |
125 | uint64_t nsec; | |
126 | ||
127 | nsec = ntime_since_now(&start); | |
b2a432bf | 128 | add_clat_sample(td, data->stat_ddir, nsec, 0, 0, 0); |
73ccd14e SF |
129 | } |
130 | ||
131 | return 0; | |
132 | } | |
133 | ||
134 | static enum fio_q_status queue_io(struct thread_data *td, struct io_u fio_unused *io_u) | |
135 | { | |
136 | return FIO_Q_COMPLETED; | |
137 | } | |
138 | ||
139 | static int init(struct thread_data *td) | |
140 | { | |
141 | struct fc_data *data; | |
142 | ||
143 | data = calloc(1, sizeof(*data)); | |
144 | ||
145 | if (td_read(td)) | |
146 | data->stat_ddir = DDIR_READ; | |
147 | else if (td_write(td)) | |
148 | data->stat_ddir = DDIR_WRITE; | |
149 | ||
150 | td->io_ops_data = data; | |
151 | return 0; | |
152 | } | |
153 | ||
154 | static void cleanup(struct thread_data *td) | |
155 | { | |
156 | struct fc_data *data = td->io_ops_data; | |
157 | ||
158 | free(data); | |
159 | } | |
160 | ||
161 | static int stat_invalidate(struct thread_data *td, struct fio_file *f) | |
162 | { | |
163 | /* do nothing because file not opened */ | |
164 | return 0; | |
165 | } | |
166 | ||
167 | static struct ioengine_ops ioengine = { | |
168 | .name = "filestat", | |
169 | .version = FIO_IOOPS_VERSION, | |
170 | .init = init, | |
171 | .cleanup = cleanup, | |
172 | .queue = queue_io, | |
173 | .invalidate = stat_invalidate, | |
174 | .get_file_size = generic_get_file_size, | |
175 | .open_file = stat_file, | |
176 | .flags = FIO_SYNCIO | FIO_FAKEIO | | |
177 | FIO_NOSTATS | FIO_NOFILEHASH, | |
c446eff0 TK |
178 | .options = options, |
179 | .option_struct_size = sizeof(struct filestat_options), | |
73ccd14e SF |
180 | }; |
181 | ||
182 | static void fio_init fio_filestat_register(void) | |
183 | { | |
184 | register_ioengine(&ioengine); | |
185 | } | |
186 | ||
187 | static void fio_exit fio_filestat_unregister(void) | |
188 | { | |
189 | unregister_ioengine(&ioengine); | |
190 | } |