[PATCH] Add support for writing aggregate bandwidth log
[fio.git] / filesetup.c
CommitLineData
53cdc686
JA
1#include <unistd.h>
2#include <fcntl.h>
3#include <string.h>
4#include <assert.h>
5#include <sys/stat.h>
6#include <sys/mman.h>
7
8#include "fio.h"
9#include "os.h"
10
25205e97
JA
11/*
12 * Check if the file exists and it's large enough.
13 */
14static int file_ok(struct thread_data *td, struct fio_file *f)
53cdc686 15{
b2a15192 16 struct stat st;
53cdc686 17
b2a15192
JA
18 if (td->filetype != FIO_TYPE_FILE)
19 return 0;
20
25205e97
JA
21 if (stat(f->file_name, &st) == -1)
22 return 1;
23 else if (st.st_size < (off_t) f->file_size)
24 return 1;
25
26 return 0;
27}
28
29static int create_file(struct thread_data *td, struct fio_file *f)
30{
31 unsigned long long left;
32 unsigned int bs;
33 char *b;
34 int r;
b2a15192 35
53cdc686
JA
36 f->fd = open(f->file_name, O_WRONLY | O_CREAT | O_TRUNC, 0644);
37 if (f->fd < 0) {
38 td_verror(td, errno);
39 return 1;
40 }
41
42 if (ftruncate(f->fd, f->file_size) == -1) {
43 td_verror(td, errno);
44 goto err;
45 }
46
40f8298c
JA
47 if (posix_fallocate(f->fd, 0, f->file_size) < 0) {
48 td_verror(td, errno);
49 goto err;
50 }
51
a00735e6
JA
52 b = malloc(td->max_bs[DDIR_WRITE]);
53 memset(b, 0, td->max_bs[DDIR_WRITE]);
53cdc686
JA
54
55 left = f->file_size;
56 while (left && !td->terminate) {
a00735e6 57 bs = td->max_bs[DDIR_WRITE];
53cdc686
JA
58 if (bs > left)
59 bs = left;
60
61 r = write(f->fd, b, bs);
62
63 if (r == (int) bs) {
64 left -= bs;
65 continue;
66 } else {
67 if (r < 0)
68 td_verror(td, errno);
69 else
70 td_verror(td, EIO);
71
72 break;
73 }
74 }
75
76 if (td->terminate)
77 unlink(f->file_name);
78 else if (td->create_fsync)
79 fsync(f->fd);
80
81 free(b);
82 close(f->fd);
83 f->fd = -1;
84 return 0;
85err:
86 close(f->fd);
87 f->fd = -1;
88 return 1;
89}
90
91static int create_files(struct thread_data *td)
92{
93 struct fio_file *f;
25205e97 94 int i, err, need_create;
53cdc686 95
f697125a
JA
96 for_each_file(td, f, i)
97 f->file_size = td->total_file_size / td->nr_files;
98
53cdc686
JA
99 /*
100 * unless specifically asked for overwrite, let normal io extend it
101 */
f697125a 102 if (!td->overwrite)
53cdc686 103 return 0;
53cdc686 104
25205e97 105 need_create = 0;
eff6861d
JA
106 if (td->filetype == FIO_TYPE_FILE) {
107 for_each_file(td, f, i) {
108 int file_there = !file_ok(td, f);
109
110 if (file_there && td->ddir == WRITE && !td->overwrite) {
111 unlink(f->file_name);
112 file_there = 0;
113 }
114
115 need_create += !file_there;
116 }
117 }
25205e97 118
25205e97
JA
119 if (!need_create)
120 return 0;
121
f1027063
JA
122 if (!td->total_file_size) {
123 log_err("Need size for create\n");
124 td_verror(td, EINVAL);
125 return 1;
126 }
127
53cdc686 128 temp_stall_ts = 1;
1e97cce9 129 fprintf(f_out, "%s: Laying out IO file(s) (%u x %LuMiB == %LuMiB)\n",
13f8e2d2
JA
130 td->name, td->nr_uniq_files,
131 (td->total_file_size >> 20) / td->nr_uniq_files,
25205e97 132 td->total_file_size >> 20);
53cdc686
JA
133
134 err = 0;
135 for_each_file(td, f, i) {
9b031dc8
JA
136 /*
137 * Only unlink files that we created.
138 */
139 f->unlink = 0;
25205e97 140 if (file_ok(td, f)) {
9b031dc8 141 f->unlink = td->unlink;
25205e97
JA
142 err = create_file(td, f);
143 if (err)
144 break;
145 }
53cdc686
JA
146 }
147
148 temp_stall_ts = 0;
149 return err;
150}
151
152static int file_size(struct thread_data *td, struct fio_file *f)
153{
154 struct stat st;
155
156 if (td->overwrite) {
157 if (fstat(f->fd, &st) == -1) {
158 td_verror(td, errno);
159 return 1;
160 }
161
162 f->real_file_size = st.st_size;
163
164 if (!f->file_size || f->file_size > f->real_file_size)
165 f->file_size = f->real_file_size;
745508dd
JA
166 } else
167 f->real_file_size = f->file_size;
53cdc686 168
53cdc686
JA
169 return 0;
170}
171
172static int bdev_size(struct thread_data *td, struct fio_file *f)
173{
174 unsigned long long bytes;
175 int r;
176
177 r = blockdev_size(f->fd, &bytes);
178 if (r) {
179 td_verror(td, r);
180 return 1;
181 }
182
183 f->real_file_size = bytes;
184
185 /*
186 * no extend possibilities, so limit size to device size if too large
187 */
188 if (!f->file_size || f->file_size > f->real_file_size)
189 f->file_size = f->real_file_size;
190
191 f->file_size -= f->file_offset;
192 return 0;
193}
194
195static int get_file_size(struct thread_data *td, struct fio_file *f)
196{
197 int ret = 0;
198
199 if (td->filetype == FIO_TYPE_FILE)
200 ret = file_size(td, f);
201 else if (td->filetype == FIO_TYPE_BD)
202 ret = bdev_size(td, f);
203 else
204 f->real_file_size = -1;
205
206 if (ret)
207 return ret;
208
209 if (f->file_offset > f->real_file_size) {
210 log_err("%s: offset extends end (%Lu > %Lu)\n", td->name, f->file_offset, f->real_file_size);
211 return 1;
212 }
213
53cdc686
JA
214 return 0;
215}
216
e5b401d4
JA
217int file_invalidate_cache(struct thread_data *td, struct fio_file *f)
218{
219 int ret = 0;
220
221 /*
222 * FIXME: add blockdev flushing too
223 */
224 if (td->io_ops->flags & FIO_MMAPIO)
225 ret = madvise(f->mmap, f->file_size, MADV_DONTNEED);
226 else if (td->filetype == FIO_TYPE_FILE)
227 ret = fadvise(f->fd, f->file_offset, f->file_size, POSIX_FADV_DONTNEED);
228 else if (td->filetype == FIO_TYPE_BD)
229 ret = blockdev_invalidate_cache(f->fd);
230 else if (td->filetype == FIO_TYPE_CHAR)
231 ret = 0;
232
233 if (ret < 0) {
234 td_verror(td, errno);
235 return 1;
236 }
237
238 return 0;
239}
240
53cdc686
JA
241static int __setup_file_mmap(struct thread_data *td, struct fio_file *f)
242{
243 int flags;
244
245 if (td_rw(td))
246 flags = PROT_READ | PROT_WRITE;
247 else if (td_write(td)) {
248 flags = PROT_WRITE;
249
250 if (td->verify != VERIFY_NONE)
251 flags |= PROT_READ;
252 } else
253 flags = PROT_READ;
254
255 f->mmap = mmap(NULL, f->file_size, flags, MAP_SHARED, f->fd, f->file_offset);
256 if (f->mmap == MAP_FAILED) {
257 f->mmap = NULL;
258 td_verror(td, errno);
259 return 1;
260 }
261
e5b401d4
JA
262 if (td->invalidate_cache && file_invalidate_cache(td, f))
263 return 1;
53cdc686
JA
264
265 if (td->sequential) {
266 if (madvise(f->mmap, f->file_size, MADV_SEQUENTIAL) < 0) {
267 td_verror(td, errno);
268 return 1;
269 }
270 } else {
271 if (madvise(f->mmap, f->file_size, MADV_RANDOM) < 0) {
272 td_verror(td, errno);
273 return 1;
274 }
275 }
276
277 return 0;
278}
279
280static int setup_files_mmap(struct thread_data *td)
281{
282 struct fio_file *f;
283 int i, err = 0;
284
285 for_each_file(td, f, i) {
286 err = __setup_file_mmap(td, f);
287 if (err)
288 break;
289 }
290
291 return err;
292}
293
294static int __setup_file_plain(struct thread_data *td, struct fio_file *f)
295{
e5b401d4
JA
296 if (td->invalidate_cache && file_invalidate_cache(td, f))
297 return 1;
53cdc686
JA
298
299 if (td->sequential) {
300 if (fadvise(f->fd, f->file_offset, f->file_size, POSIX_FADV_SEQUENTIAL) < 0) {
301 td_verror(td, errno);
302 return 1;
303 }
304 } else {
305 if (fadvise(f->fd, f->file_offset, f->file_size, POSIX_FADV_RANDOM) < 0) {
306 td_verror(td, errno);
307 return 1;
308 }
309 }
310
311 return 0;
312}
313
314static int setup_files_plain(struct thread_data *td)
315{
316 struct fio_file *f;
317 int i, err = 0;
318
319 for_each_file(td, f, i) {
320 err = __setup_file_plain(td, f);
321 if (err)
322 break;
323 }
324
325 return err;
326}
327
328static int setup_file(struct thread_data *td, struct fio_file *f)
329{
53cdc686
JA
330 int flags = 0;
331
53cdc686
JA
332 if (td->odirect)
333 flags |= OS_O_DIRECT;
7abf833d
JA
334 if (td->sync_io)
335 flags |= O_SYNC;
53cdc686
JA
336
337 if (td_write(td) || td_rw(td)) {
7abf833d
JA
338 flags |= O_RDWR;
339
53cdc686
JA
340 if (td->filetype == FIO_TYPE_FILE) {
341 if (!td->overwrite)
342 flags |= O_TRUNC;
343
344 flags |= O_CREAT;
345 }
53cdc686
JA
346
347 f->fd = open(f->file_name, flags, 0600);
348 } else {
349 if (td->filetype == FIO_TYPE_CHAR)
350 flags |= O_RDWR;
351 else
352 flags |= O_RDONLY;
353
354 f->fd = open(f->file_name, flags);
355 }
356
357 if (f->fd == -1) {
358 td_verror(td, errno);
359 return 1;
360 }
361
362 if (get_file_size(td, f))
363 return 1;
364
365 return 0;
366}
367
21972cde
JA
368int open_files(struct thread_data *td)
369{
370 struct fio_file *f;
371 int i, err = 0;
372
373 for_each_file(td, f, i) {
374 err = setup_file(td, f);
375 if (err)
376 break;
377 }
378
7abf833d
JA
379 if (!err)
380 return 0;
381
382 for_each_file(td, f, i) {
383 if (f->fd != -1) {
384 close(f->fd);
385 f->fd = -1;
386 }
387 }
388
21972cde
JA
389 return err;
390}
391
53cdc686
JA
392int setup_files(struct thread_data *td)
393{
394 struct fio_file *f;
21972cde 395 int err, i;
53cdc686
JA
396
397 /*
398 * if ioengine defines a setup() method, it's responsible for
399 * setting up everything in the td->files[] area.
400 */
401 if (td->io_ops->setup)
402 return td->io_ops->setup(td);
403
404 if (create_files(td))
405 return 1;
406
21972cde 407 err = open_files(td);
f1027063
JA
408 if (err)
409 return err;
410
0a7eb121
JA
411 /*
412 * Recalculate the total file size now that files are set up.
413 */
414 td->total_file_size = 0;
415 for_each_file(td, f, i)
416 td->total_file_size += f->file_size;
417
f1027063 418 td->io_size = td->total_file_size;
53cdc686
JA
419 if (td->io_size == 0) {
420 log_err("%s: no io blocks\n", td->name);
421 td_verror(td, EINVAL);
422 return 1;
423 }
424
425 if (!td->zone_size)
426 td->zone_size = td->io_size;
427
428 td->total_io_size = td->io_size * td->loops;
429
430 if (td->io_ops->flags & FIO_MMAPIO)
21972cde 431 err = setup_files_mmap(td);
53cdc686 432 else
21972cde
JA
433 err = setup_files_plain(td);
434
435 for_each_file(td, f, i) {
436 if (f->fd != -1) {
437 close(f->fd);
438 f->fd = -1;
439 }
440 }
441
442 return err;
53cdc686
JA
443}
444
445void close_files(struct thread_data *td)
446{
0ab8db89 447 struct fio_file *f;
53cdc686
JA
448 int i;
449
0ab8db89 450 for_each_file(td, f, i) {
9b031dc8 451 if (!td->filename && f->unlink &&
02bcaa8c 452 td->filetype == FIO_TYPE_FILE) {
132ad46d
JA
453 unlink(f->file_name);
454 free(f->file_name);
455 f->file_name = NULL;
456 }
21972cde
JA
457 if (f->fd != -1) {
458 close(f->fd);
459 f->fd = -1;
460 }
53cdc686
JA
461 if (f->mmap) {
462 munmap(f->mmap, f->file_size);
463 f->mmap = NULL;
464 }
465 }
b4a6a59a 466
132ad46d 467 td->filename = NULL;
b4a6a59a
JA
468 free(td->files);
469 td->files = NULL;
470 td->nr_files = 0;
53cdc686 471}