X-Git-Url: https://git.kernel.dk/?p=fio.git;a=blobdiff_plain;f=filesetup.c;h=b240891d1daf86b89bc734b1a71968fe8d25caa8;hp=969e7cc0a70e4a06ce6c287f6f88dcc8d0c87b68;hb=7c5f4cdbd54d6447104e1311ab3021b87dacebb0;hpb=4e795a3e0940509bd991682ec029000b6aa8881b diff --git a/filesetup.c b/filesetup.c index 969e7cc0..b240891d 100644 --- a/filesetup.c +++ b/filesetup.c @@ -130,6 +130,9 @@ static int extend_file(struct thread_data *td, struct fio_file *f) } #endif /* CONFIG_POSIX_FALLOCATE */ + /* + * If our jobs don't require regular files initially, we're done. + */ if (!new_layout) goto done; @@ -370,16 +373,38 @@ static int get_file_size(struct thread_data *td, struct fio_file *f) if (f->filetype == FIO_TYPE_FILE) ret = file_size(td, f); - else if (f->filetype == FIO_TYPE_BD) + else if (f->filetype == FIO_TYPE_BLOCK) ret = bdev_size(td, f); else if (f->filetype == FIO_TYPE_CHAR) ret = char_size(td, f); else - f->real_file_size = -1; + f->real_file_size = -1ULL; + /* + * Leave ->real_file_size with 0 since it could be expectation + * of initial setup for regular files. + */ if (ret) return ret; + /* + * If ->real_file_size is -1, a conditional for the message + * "offset extends end" is always true, but it makes no sense, + * so just return the same value here. + */ + if (f->real_file_size == -1ULL) { + log_info("%s: failed to get file size of %s\n", td->o.name, + f->file_name); + return 1; + } + + if (td->o.start_offset && f->file_offset == 0) + dprint(FD_FILE, "offset of file %s not initialized yet\n", + f->file_name); + /* + * ->file_offset normally hasn't been initialized yet, so this + * is basically always false. + */ if (f->file_offset > f->real_file_size) { log_err("%s: offset extends end (%llu > %llu)\n", td->o.name, (unsigned long long) f->file_offset, @@ -420,7 +445,7 @@ static int __file_invalidate_cache(struct thread_data *td, struct fio_file *f, ret = posix_fadvise(f->fd, off, len, POSIX_FADV_DONTNEED); if (ret) errval = ret; - } else if (f->filetype == FIO_TYPE_BD) { + } else if (f->filetype == FIO_TYPE_BLOCK) { int retry_count = 0; ret = blockdev_invalidate_cache(f); @@ -498,9 +523,6 @@ int file_lookup_open(struct fio_file *f, int flags) __f = lookup_file_hash(f->file_name); if (__f) { dprint(FD_FILE, "found file in hash %s\n", f->file_name); - /* - * racy, need the __f->lock locked - */ f->lock = __f->lock; from_hash = 1; } else { @@ -597,7 +619,8 @@ open_again: f->fd = dup(STDIN_FILENO); else from_hash = file_lookup_open(f, flags); - } else { //td trim + } else if (td_trim(td)) { + assert(!td_rw(td)); /* should have matched above */ flags |= O_RDWR; from_hash = file_lookup_open(f, flags); } @@ -652,6 +675,10 @@ open_again: return 0; } +/* + * This function i.e. get_file_size() is the default .get_file_size + * implementation of majority of I/O engines. + */ int generic_get_file_size(struct thread_data *td, struct fio_file *f) { return get_file_size(td, f); @@ -667,7 +694,7 @@ static int get_file_sizes(struct thread_data *td) int err = 0; for_each_file(td, f, i) { - dprint(FD_FILE, "get file size for %p/%d/%p\n", f, i, + dprint(FD_FILE, "get file size for %p/%d/%s\n", f, i, f->file_name); if (td_io_get_file_size(td, f)) { @@ -679,6 +706,13 @@ static int get_file_sizes(struct thread_data *td) clear_error(td); } + /* + * There are corner cases where we end up with -1 for + * ->real_file_size due to unsupported file type, etc. + * We then just set to size option value divided by number + * of files, similar to the way file ->io_size is set. + * stat(2) failure doesn't set ->real_file_size to -1. + */ if (f->real_file_size == -1ULL && td->o.size) f->real_file_size = td->o.size / td->o.nr_files; } @@ -709,7 +743,7 @@ static unsigned long long get_fs_free_counts(struct thread_data *td) struct stat sb; char buf[256]; - if (f->filetype == FIO_TYPE_BD || f->filetype == FIO_TYPE_CHAR) { + if (f->filetype == FIO_TYPE_BLOCK || f->filetype == FIO_TYPE_CHAR) { if (f->real_file_size != -1ULL) ret += f->real_file_size; continue; @@ -795,7 +829,9 @@ int setup_files(struct thread_data *td) goto done; /* - * if ioengine defines a setup() method, it's responsible for + * Find out physical size of files or devices for this thread, + * before we determine I/O size and range of our targets. + * If ioengine defines a setup() method, it's responsible for * opening the files and setting f->real_file_size to indicate * the valid range for that file. */ @@ -836,7 +872,7 @@ int setup_files(struct thread_data *td) /* * Calculate per-file size and potential extra size for the - * first files, if needed. + * first files, if needed (i.e. if we don't have a fixed size). */ if (!o->file_size_low && o->nr_files) { uint64_t all_fs; @@ -858,11 +894,18 @@ int setup_files(struct thread_data *td) for_each_file(td, f, i) { f->file_offset = get_start_offset(td, f); + /* + * Update ->io_size depending on options specified. + * ->file_size_low being 0 means filesize option isn't set. + * Non zero ->file_size_low equals ->file_size_high means + * filesize option is set in a fixed size format. + * Non zero ->file_size_low not equals ->file_size_high means + * filesize option is set in a range format. + */ if (!o->file_size_low) { /* - * no file size range given, file size is equal to - * total size divided by number of files. If that is - * zero, set it to the real file size. If the size + * no file size or range given, file size is equal to + * total size divided by number of files. If the size * doesn't divide nicely with the min blocksize, * make the first files bigger. */ @@ -872,8 +915,24 @@ int setup_files(struct thread_data *td) f->io_size += bs; } - if (!f->io_size) + /* + * We normally don't come here, but if the result is 0, + * set it to the real file size. This could be size of + * the existing one if it already exists, but otherwise + * will be set to 0. A new file won't be created because + * ->io_size + ->file_offset equals ->real_file_size. + */ + if (!f->io_size) { + if (f->file_offset > f->real_file_size) + goto err_offset; f->io_size = f->real_file_size - f->file_offset; + log_info("fio: forcing file %s size to %llu\n", + f->file_name, + (unsigned long long)f->io_size); + if (!f->io_size) + log_info("fio: file %s may be ignored\n", + f->file_name); + } } else if (f->real_file_size < o->file_size_low || f->real_file_size > o->file_size_high) { if (f->file_offset > o->file_size_low) @@ -907,9 +966,9 @@ int setup_files(struct thread_data *td) if (!o->create_on_open) { need_extend++; extend_size += (f->io_size + f->file_offset); + fio_file_set_extend(f); } else f->real_file_size = f->io_size + f->file_offset; - fio_file_set_extend(f); } } @@ -943,14 +1002,21 @@ int setup_files(struct thread_data *td) } /* - * See if we need to extend some files + * See if we need to extend some files, typically needed when our + * target regular files don't exist yet, but our jobs require them + * initially due to read I/Os. */ if (need_extend) { temp_stall_ts = 1; - if (output_format & FIO_OUTPUT_NORMAL) - log_info("%s: Laying out IO file(s) (%u file(s) /" - " %lluMB)\n", o->name, need_extend, - extend_size >> 20); + if (output_format & FIO_OUTPUT_NORMAL) { + log_info("%s: Laying out IO file%s (%u file%s / %s%lluMiB)\n", + o->name, + need_extend > 1 ? "s" : "", + need_extend, + need_extend > 1 ? "s" : "", + need_extend > 1 ? "total " : "", + extend_size >> 20); + } for_each_file(td, f, i) { unsigned long long old_len = -1ULL, extend_len = -1ULL; @@ -997,8 +1063,8 @@ int setup_files(struct thread_data *td) * stored entries. */ if (!o->read_iolog_file) { - if (o->io_limit) - td->total_io_size = o->io_limit * o->loops; + if (o->io_size) + td->total_io_size = o->io_size * o->loops; else td->total_io_size = o->size * o->loops; } @@ -1229,12 +1295,12 @@ static void get_file_type(struct fio_file *f) /* \\.\ is the device namespace in Windows, where every file is * a block device */ if (strncmp(f->file_name, "\\\\.\\", 4) == 0) - f->filetype = FIO_TYPE_BD; + f->filetype = FIO_TYPE_BLOCK; #endif if (!stat(f->file_name, &sb)) { if (S_ISBLK(sb.st_mode)) - f->filetype = FIO_TYPE_BD; + f->filetype = FIO_TYPE_BLOCK; else if (S_ISCHR(sb.st_mode)) f->filetype = FIO_TYPE_CHAR; else if (S_ISFIFO(sb.st_mode))