[PATCH] SG IO engine: reduce allocations and memory leaks
[fio.git] / filesetup.c
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
11 /*
12  * Check if the file exists and it's large enough.
13  */
14 static int file_ok(struct thread_data *td, struct fio_file *f)
15 {
16         struct stat st;
17
18         if (td->filetype != FIO_TYPE_FILE || (td->io_ops->flags & FIO_NULLIO))
19                 return 0;
20
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
29 static 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;
35
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
47         if (posix_fallocate(f->fd, 0, f->file_size) < 0) {
48                 td_verror(td, errno);
49                 goto err;
50         }
51
52         b = malloc(td->max_bs[DDIR_WRITE]);
53         memset(b, 0, td->max_bs[DDIR_WRITE]);
54
55         left = f->file_size;
56         while (left && !td->terminate) {
57                 bs = td->max_bs[DDIR_WRITE];
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;
85 err:
86         close(f->fd);
87         f->fd = -1;
88         return 1;
89 }
90
91 static int create_files(struct thread_data *td)
92 {
93         struct fio_file *f;
94         int i, err, need_create;
95
96         for_each_file(td, f, i)
97                 f->file_size = td->total_file_size / td->nr_files;
98
99         /*
100          * unless specifically asked for overwrite, let normal io extend it
101          */
102         if (!td->overwrite)
103                 return 0;
104
105         need_create = 0;
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 == DDIR_WRITE &&
111                             !td->overwrite) {
112                                 unlink(f->file_name);
113                                 file_there = 0;
114                         }
115
116                         need_create += !file_there;
117                 }
118         }
119
120         if (!need_create)
121                 return 0;
122
123         if (!td->total_file_size) {
124                 log_err("Need size for create\n");
125                 td_verror(td, EINVAL);
126                 return 1;
127         }
128
129         temp_stall_ts = 1;
130         fprintf(f_out, "%s: Laying out IO file(s) (%u x %LuMiB == %LuMiB)\n",
131                                 td->name, td->nr_uniq_files,
132                                 (td->total_file_size >> 20) / td->nr_uniq_files,
133                                 td->total_file_size >> 20);
134
135         err = 0;
136         for_each_file(td, f, i) {
137                 /*
138                  * Only unlink files that we created.
139                  */
140                 f->unlink = 0;
141                 if (file_ok(td, f)) {
142                         f->unlink = td->unlink;
143                         err = create_file(td, f);
144                         if (err)
145                                 break;
146                 }
147         }
148
149         temp_stall_ts = 0;
150         return err;
151 }
152
153 static int file_size(struct thread_data *td, struct fio_file *f)
154 {
155         struct stat st;
156
157         if (td->overwrite) {
158                 if (fstat(f->fd, &st) == -1) {
159                         td_verror(td, errno);
160                         return 1;
161                 }
162
163                 f->real_file_size = st.st_size;
164
165                 if (!f->file_size || f->file_size > f->real_file_size)
166                         f->file_size = f->real_file_size;
167         } else
168                 f->real_file_size = f->file_size;
169
170         return 0;
171 }
172
173 static int bdev_size(struct thread_data *td, struct fio_file *f)
174 {
175         unsigned long long bytes;
176         int r;
177
178         r = blockdev_size(f->fd, &bytes);
179         if (r) {
180                 td_verror(td, r);
181                 return 1;
182         }
183
184         f->real_file_size = bytes;
185
186         /*
187          * no extend possibilities, so limit size to device size if too large
188          */
189         if (!f->file_size || f->file_size > f->real_file_size)
190                 f->file_size = f->real_file_size;
191
192         f->file_size -= f->file_offset;
193         return 0;
194 }
195
196 static int get_file_size(struct thread_data *td, struct fio_file *f)
197 {
198         int ret = 0;
199
200         if (td->filetype == FIO_TYPE_FILE)
201                 ret = file_size(td, f);
202         else if (td->filetype == FIO_TYPE_BD)
203                 ret = bdev_size(td, f);
204         else
205                 f->real_file_size = -1;
206
207         if (ret)
208                 return ret;
209
210         if (f->file_offset > f->real_file_size) {
211                 log_err("%s: offset extends end (%Lu > %Lu)\n", td->name, f->file_offset, f->real_file_size);
212                 return 1;
213         }
214
215         return 0;
216 }
217
218 int file_invalidate_cache(struct thread_data *td, struct fio_file *f)
219 {
220         int ret = 0;
221
222         /*
223          * FIXME: add blockdev flushing too
224          */
225         if (td->io_ops->flags & FIO_MMAPIO)
226                 ret = madvise(f->mmap, f->file_size, MADV_DONTNEED);
227         else if (td->filetype == FIO_TYPE_FILE)
228                 ret = fadvise(f->fd, f->file_offset, f->file_size, POSIX_FADV_DONTNEED);
229         else if (td->filetype == FIO_TYPE_BD)
230                 ret = blockdev_invalidate_cache(f->fd);
231         else if (td->filetype == FIO_TYPE_CHAR)
232                 ret = 0;
233
234         if (ret < 0) {
235                 td_verror(td, errno);
236                 return 1;
237         }
238
239         return 0;
240 }
241
242 static int __setup_file_mmap(struct thread_data *td, struct fio_file *f)
243 {
244         int flags;
245
246         if (td_rw(td))
247                 flags = PROT_READ | PROT_WRITE;
248         else if (td_write(td)) {
249                 flags = PROT_WRITE;
250
251                 if (td->verify != VERIFY_NONE)
252                         flags |= PROT_READ;
253         } else
254                 flags = PROT_READ;
255
256         f->mmap = mmap(NULL, f->file_size, flags, MAP_SHARED, f->fd, f->file_offset);
257         if (f->mmap == MAP_FAILED) {
258                 f->mmap = NULL;
259                 td_verror(td, errno);
260                 return 1;
261         }
262
263         if (td->invalidate_cache && file_invalidate_cache(td, f))
264                 return 1;
265
266         if (td->sequential) {
267                 if (madvise(f->mmap, f->file_size, MADV_SEQUENTIAL) < 0) {
268                         td_verror(td, errno);
269                         return 1;
270                 }
271         } else {
272                 if (madvise(f->mmap, f->file_size, MADV_RANDOM) < 0) {
273                         td_verror(td, errno);
274                         return 1;
275                 }
276         }
277
278         return 0;
279 }
280
281 static int setup_files_mmap(struct thread_data *td)
282 {
283         struct fio_file *f;
284         int i, err = 0;
285
286         for_each_file(td, f, i) {
287                 err = __setup_file_mmap(td, f);
288                 if (err)
289                         break;
290         }
291
292         return err;
293 }
294
295 static int __setup_file_plain(struct thread_data *td, struct fio_file *f)
296 {
297         if (td->invalidate_cache && file_invalidate_cache(td, f))
298                 return 1;
299
300         if (td->sequential) {
301                 if (fadvise(f->fd, f->file_offset, f->file_size, POSIX_FADV_SEQUENTIAL) < 0) {
302                         td_verror(td, errno);
303                         return 1;
304                 }
305         } else {
306                 if (fadvise(f->fd, f->file_offset, f->file_size, POSIX_FADV_RANDOM) < 0) {
307                         td_verror(td, errno);
308                         return 1;
309                 }
310         }
311
312         return 0;
313 }
314
315 static int setup_files_plain(struct thread_data *td)
316 {
317         struct fio_file *f;
318         int i, err = 0;
319
320         for_each_file(td, f, i) {
321                 err = __setup_file_plain(td, f);
322                 if (err)
323                         break;
324         }
325
326         return err;
327 }
328
329 static int setup_file(struct thread_data *td, struct fio_file *f)
330 {
331         int flags = 0;
332
333         if (td->io_ops->flags & FIO_NETIO)
334                 return 0;
335
336         /*
337          * we need a valid file descriptor, but don't create a real file.
338          * lets just dup stdout, seems like a sensible approach.
339          */
340         if (td->io_ops->flags & FIO_NULLIO)
341                 f->fd = dup(STDOUT_FILENO);
342         else {
343                 if (td->odirect)
344                         flags |= OS_O_DIRECT;
345                 if (td->sync_io)
346                         flags |= O_SYNC;
347
348                 if (td_write(td) || td_rw(td)) {
349                         flags |= O_RDWR;
350
351                         if (td->filetype == FIO_TYPE_FILE) {
352                                 if (!td->overwrite)
353                                         flags |= O_TRUNC;
354
355                                 flags |= O_CREAT;
356                         }
357
358                         f->fd = open(f->file_name, flags, 0600);
359                 } else {
360                         if (td->filetype == FIO_TYPE_CHAR)
361                                 flags |= O_RDWR;
362                         else
363                                 flags |= O_RDONLY;
364
365                         f->fd = open(f->file_name, flags);
366                 }
367         }
368
369         if (f->fd == -1) {
370                 td_verror(td, errno);
371                 return 1;
372         }
373
374         if (get_file_size(td, f))
375                 return 1;
376
377         return 0;
378 }
379
380 int open_files(struct thread_data *td)
381 {
382         struct fio_file *f;
383         int i, err = 0;
384
385         for_each_file(td, f, i) {
386                 err = setup_file(td, f);
387                 if (err)
388                         break;
389         }
390
391         if (!err)
392                 return 0;
393
394         for_each_file(td, f, i) {
395                 if (f->fd != -1) {
396                         close(f->fd);
397                         f->fd = -1;
398                 }
399         }
400
401         return err;
402 }
403
404 int setup_files(struct thread_data *td)
405 {
406         struct fio_file *f;
407         int err, i;
408
409         /*
410          * if ioengine defines a setup() method, it's responsible for
411          * setting up everything in the td->files[] area.
412          */
413         if (td->io_ops->setup)
414                 return td->io_ops->setup(td);
415
416         if (create_files(td))
417                 return 1;
418
419         err = open_files(td);
420         if (err)
421                 return err;
422
423         /*
424          * Recalculate the total file size now that files are set up.
425          */
426         td->total_file_size = 0;
427         for_each_file(td, f, i)
428                 td->total_file_size += f->file_size;
429
430         td->io_size = td->total_file_size;
431         if (td->io_size == 0) {
432                 log_err("%s: no io blocks\n", td->name);
433                 td_verror(td, EINVAL);
434                 return 1;
435         }
436
437         if (!td->zone_size)
438                 td->zone_size = td->io_size;
439
440         td->total_io_size = td->io_size * td->loops;
441
442         if (td->io_ops->flags & FIO_MMAPIO)
443                 err = setup_files_mmap(td);
444         else
445                 err = setup_files_plain(td);
446
447         for_each_file(td, f, i) {
448                 if (f->fd != -1) {
449                         close(f->fd);
450                         f->fd = -1;
451                 }
452         }
453
454         return err;
455 }
456
457 void close_files(struct thread_data *td)
458 {
459         struct fio_file *f;
460         int i;
461
462         for_each_file(td, f, i) {
463                 if (!td->filename && f->unlink &&
464                     td->filetype == FIO_TYPE_FILE) {
465                         unlink(f->file_name);
466                         free(f->file_name);
467                         f->file_name = NULL;
468                 }
469                 if (f->fd != -1) {
470                         close(f->fd);
471                         f->fd = -1;
472                 }
473                 if (f->mmap) {
474                         munmap(f->mmap, f->file_size);
475                         f->mmap = NULL;
476                 }
477         }
478
479         td->filename = NULL;
480         free(td->files);
481         td->files = NULL;
482         td->nr_files = 0;
483 }