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