[PATCH] More size fixes
[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)
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         b = malloc(td->max_bs);
48         memset(b, 0, td->max_bs);
49
50         left = f->file_size;
51         while (left && !td->terminate) {
52                 bs = td->max_bs;
53                 if (bs > left)
54                         bs = left;
55
56                 r = write(f->fd, b, bs);
57
58                 if (r == (int) bs) {
59                         left -= bs;
60                         continue;
61                 } else {
62                         if (r < 0)
63                                 td_verror(td, errno);
64                         else
65                                 td_verror(td, EIO);
66
67                         break;
68                 }
69         }
70
71         if (td->terminate)
72                 unlink(f->file_name);
73         else if (td->create_fsync)
74                 fsync(f->fd);
75
76         free(b);
77         close(f->fd);
78         f->fd = -1;
79         return 0;
80 err:
81         close(f->fd);
82         f->fd = -1;
83         return 1;
84 }
85
86 static int create_files(struct thread_data *td)
87 {
88         struct fio_file *f;
89         int i, err, need_create;
90
91         /*
92          * unless specifically asked for overwrite, let normal io extend it
93          */
94         if (!td->overwrite) {
95                 for_each_file(td, f, i)
96                         f->file_size = td->total_file_size / td->nr_files;
97
98                 return 0;
99         }
100
101         need_create = 0;
102         if (td->filetype == FIO_TYPE_FILE)
103                 for_each_file(td, f, i)
104                         need_create += file_ok(td, f);
105
106         if (!need_create)
107                 return 0;
108
109         if (!td->total_file_size) {
110                 log_err("Need size for create\n");
111                 td_verror(td, EINVAL);
112                 return 1;
113         }
114
115         temp_stall_ts = 1;
116         fprintf(f_out, "%s: Laying out IO file(s) (%d x %LuMiB == %LuMiB)\n",
117                                 td->name, td->nr_files,
118                                 (td->total_file_size >> 20) / td->nr_files,
119                                 td->total_file_size >> 20);
120
121         err = 0;
122         for_each_file(td, f, i) {
123                 if (file_ok(td, f)) {
124                         err = create_file(td, f);
125                         if (err)
126                                 break;
127                 }
128         }
129
130         temp_stall_ts = 0;
131         return err;
132 }
133
134 static int file_size(struct thread_data *td, struct fio_file *f)
135 {
136         struct stat st;
137
138         if (td->overwrite) {
139                 if (fstat(f->fd, &st) == -1) {
140                         td_verror(td, errno);
141                         return 1;
142                 }
143
144                 f->real_file_size = st.st_size;
145
146                 if (!f->file_size || f->file_size > f->real_file_size)
147                         f->file_size = f->real_file_size;
148         }
149
150         f->file_size -= f->file_offset;
151         return 0;
152 }
153
154 static int bdev_size(struct thread_data *td, struct fio_file *f)
155 {
156         unsigned long long bytes;
157         int r;
158
159         r = blockdev_size(f->fd, &bytes);
160         if (r) {
161                 td_verror(td, r);
162                 return 1;
163         }
164
165         f->real_file_size = bytes;
166
167         /*
168          * no extend possibilities, so limit size to device size if too large
169          */
170         if (!f->file_size || f->file_size > f->real_file_size)
171                 f->file_size = f->real_file_size;
172
173         f->file_size -= f->file_offset;
174         return 0;
175 }
176
177 static int get_file_size(struct thread_data *td, struct fio_file *f)
178 {
179         int ret = 0;
180
181         if (td->filetype == FIO_TYPE_FILE)
182                 ret = file_size(td, f);
183         else if (td->filetype == FIO_TYPE_BD)
184                 ret = bdev_size(td, f);
185         else
186                 f->real_file_size = -1;
187
188         if (ret)
189                 return ret;
190
191         if (f->file_offset > f->real_file_size) {
192                 log_err("%s: offset extends end (%Lu > %Lu)\n", td->name, f->file_offset, f->real_file_size);
193                 return 1;
194         }
195
196         return 0;
197 }
198
199 int file_invalidate_cache(struct thread_data *td, struct fio_file *f)
200 {
201         int ret = 0;
202
203         /*
204          * FIXME: add blockdev flushing too
205          */
206         if (td->io_ops->flags & FIO_MMAPIO)
207                 ret = madvise(f->mmap, f->file_size, MADV_DONTNEED);
208         else if (td->filetype == FIO_TYPE_FILE)
209                 ret = fadvise(f->fd, f->file_offset, f->file_size, POSIX_FADV_DONTNEED);
210         else if (td->filetype == FIO_TYPE_BD)
211                 ret = blockdev_invalidate_cache(f->fd);
212         else if (td->filetype == FIO_TYPE_CHAR)
213                 ret = 0;
214
215         if (ret < 0) {
216                 td_verror(td, errno);
217                 return 1;
218         }
219
220         return 0;
221 }
222
223 static int __setup_file_mmap(struct thread_data *td, struct fio_file *f)
224 {
225         int flags;
226
227         if (td_rw(td))
228                 flags = PROT_READ | PROT_WRITE;
229         else if (td_write(td)) {
230                 flags = PROT_WRITE;
231
232                 if (td->verify != VERIFY_NONE)
233                         flags |= PROT_READ;
234         } else
235                 flags = PROT_READ;
236
237         f->mmap = mmap(NULL, f->file_size, flags, MAP_SHARED, f->fd, f->file_offset);
238         if (f->mmap == MAP_FAILED) {
239                 f->mmap = NULL;
240                 td_verror(td, errno);
241                 return 1;
242         }
243
244         if (td->invalidate_cache && file_invalidate_cache(td, f))
245                 return 1;
246
247         if (td->sequential) {
248                 if (madvise(f->mmap, f->file_size, MADV_SEQUENTIAL) < 0) {
249                         td_verror(td, errno);
250                         return 1;
251                 }
252         } else {
253                 if (madvise(f->mmap, f->file_size, MADV_RANDOM) < 0) {
254                         td_verror(td, errno);
255                         return 1;
256                 }
257         }
258
259         return 0;
260 }
261
262 static int setup_files_mmap(struct thread_data *td)
263 {
264         struct fio_file *f;
265         int i, err = 0;
266
267         for_each_file(td, f, i) {
268                 err = __setup_file_mmap(td, f);
269                 if (err)
270                         break;
271         }
272
273         return err;
274 }
275
276 static int __setup_file_plain(struct thread_data *td, struct fio_file *f)
277 {
278         if (td->invalidate_cache && file_invalidate_cache(td, f))
279                 return 1;
280
281         if (td->sequential) {
282                 if (fadvise(f->fd, f->file_offset, f->file_size, POSIX_FADV_SEQUENTIAL) < 0) {
283                         td_verror(td, errno);
284                         return 1;
285                 }
286         } else {
287                 if (fadvise(f->fd, f->file_offset, f->file_size, POSIX_FADV_RANDOM) < 0) {
288                         td_verror(td, errno);
289                         return 1;
290                 }
291         }
292
293         return 0;
294 }
295
296 static int setup_files_plain(struct thread_data *td)
297 {
298         struct fio_file *f;
299         int i, err = 0;
300
301         for_each_file(td, f, i) {
302                 err = __setup_file_plain(td, f);
303                 if (err)
304                         break;
305         }
306
307         return err;
308 }
309
310 static int setup_file(struct thread_data *td, struct fio_file *f)
311 {
312         int flags = 0;
313
314         if (td->odirect)
315                 flags |= OS_O_DIRECT;
316
317         if (td_write(td) || td_rw(td)) {
318                 if (td->filetype == FIO_TYPE_FILE) {
319                         if (!td->overwrite)
320                                 flags |= O_TRUNC;
321
322                         flags |= O_CREAT;
323                 }
324                 if (td->sync_io)
325                         flags |= O_SYNC;
326
327                 flags |= O_RDWR;
328
329                 f->fd = open(f->file_name, flags, 0600);
330         } else {
331                 if (td->filetype == FIO_TYPE_CHAR)
332                         flags |= O_RDWR;
333                 else
334                         flags |= O_RDONLY;
335
336                 f->fd = open(f->file_name, flags);
337         }
338
339         if (f->fd == -1) {
340                 td_verror(td, errno);
341                 return 1;
342         }
343
344         if (get_file_size(td, f))
345                 return 1;
346
347         return 0;
348 }
349
350 int setup_files(struct thread_data *td)
351 {
352         struct fio_file *f;
353         int i, err;
354
355         /*
356          * if ioengine defines a setup() method, it's responsible for
357          * setting up everything in the td->files[] area.
358          */
359         if (td->io_ops->setup)
360                 return td->io_ops->setup(td);
361
362         if (create_files(td))
363                 return 1;
364
365         err = 0;
366         for_each_file(td, f, i) {
367                 err = setup_file(td, f);
368                 if (err)
369                         break;
370         }
371
372         if (err)
373                 return err;
374
375         /*
376          * Recalculate the total file size now that files are set up.
377          */
378         td->total_file_size = 0;
379         for_each_file(td, f, i)
380                 td->total_file_size += f->file_size;
381
382         td->io_size = td->total_file_size;
383         if (td->io_size == 0) {
384                 log_err("%s: no io blocks\n", td->name);
385                 td_verror(td, EINVAL);
386                 return 1;
387         }
388
389         if (!td->zone_size)
390                 td->zone_size = td->io_size;
391
392         td->total_io_size = td->io_size * td->loops;
393
394         if (td->io_ops->flags & FIO_MMAPIO)
395                 return setup_files_mmap(td);
396         else
397                 return setup_files_plain(td);
398 }
399
400 void close_files(struct thread_data *td)
401 {
402         struct fio_file *f;
403         int i;
404
405         for_each_file(td, f, i) {
406                 if (f->fd != -1) {
407                         if (td->unlink && td->filetype == FIO_TYPE_FILE)
408                                 unlink(f->file_name);
409                         close(f->fd);
410                         f->fd = -1;
411                 }
412                 if (f->mmap) {
413                         munmap(f->mmap, f->file_size);
414                         f->mmap = NULL;
415                 }
416         }
417 }