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