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