X-Git-Url: https://git.kernel.dk/?p=fio.git;a=blobdiff_plain;f=filesetup.c;h=362997c15856dbb83b2ab39a0a123e217dd65dd7;hp=c9f2b5ff9111f7afd1be58446d702bfc2e123d7a;hb=cbbdf1c8f1aa13c9030808720e04ea1081fd57eb;hpb=f227e2b61ffb099019e760b0c6bbacb17fa848c4 diff --git a/filesetup.c b/filesetup.c index c9f2b5ff..362997c1 100644 --- a/filesetup.c +++ b/filesetup.c @@ -38,12 +38,76 @@ static inline void clear_error(struct thread_data *td) td->verror[0] = '\0'; } +static inline int native_fallocate(struct thread_data *td, struct fio_file *f) +{ + bool success; + + success = fio_fallocate(f, 0, f->real_file_size); + dprint(FD_FILE, "native fallocate of file %s size %llu was " + "%ssuccessful\n", f->file_name, + (unsigned long long) f->real_file_size, + !success ? "un": ""); + + if (success) + return 0; + + if (errno == ENOSYS) + dprint(FD_FILE, "native fallocate is not implemented\n"); + + return -1; +} + +static void fallocate_file(struct thread_data *td, struct fio_file *f) +{ + int r; + + if (td->o.fill_device) + return; + + switch (td->o.fallocate_mode) { + case FIO_FALLOCATE_NATIVE: + r = native_fallocate(td, f); + if (r != 0) + log_err("fio: native_fallocate call failed: %s\n", + strerror(errno)); + break; + case FIO_FALLOCATE_NONE: + break; +#ifdef CONFIG_POSIX_FALLOCATE + case FIO_FALLOCATE_POSIX: + dprint(FD_FILE, "posix_fallocate file %s size %llu\n", + f->file_name, + (unsigned long long) f->real_file_size); + + r = posix_fallocate(f->fd, 0, f->real_file_size); + if (r > 0) + log_err("fio: posix_fallocate fails: %s\n", strerror(r)); + break; +#endif /* CONFIG_POSIX_FALLOCATE */ +#ifdef CONFIG_LINUX_FALLOCATE + case FIO_FALLOCATE_KEEP_SIZE: + dprint(FD_FILE, "fallocate(FALLOC_FL_KEEP_SIZE) " + "file %s size %llu\n", f->file_name, + (unsigned long long) f->real_file_size); + + r = fallocate(f->fd, FALLOC_FL_KEEP_SIZE, 0, f->real_file_size); + if (r != 0) + td_verror(td, errno, "fallocate"); + + break; +#endif /* CONFIG_LINUX_FALLOCATE */ + default: + log_err("fio: unknown fallocate mode: %d\n", td->o.fallocate_mode); + assert(0); + } +} + /* * Leaves f->fd open on success, caller must close */ static int extend_file(struct thread_data *td, struct fio_file *f) { - int r, new_layout = 0, unlink_file = 0, flags; + int new_layout = 0, unlink_file = 0, flags; unsigned long long left; unsigned int bs; char *b = NULL; @@ -100,43 +164,7 @@ static int extend_file(struct thread_data *td, struct fio_file *f) return 1; } -#ifdef CONFIG_POSIX_FALLOCATE - if (!td->o.fill_device) { - switch (td->o.fallocate_mode) { - case FIO_FALLOCATE_NONE: - break; - case FIO_FALLOCATE_POSIX: - dprint(FD_FILE, "posix_fallocate file %s size %llu\n", - f->file_name, - (unsigned long long) f->real_file_size); - - r = posix_fallocate(f->fd, 0, f->real_file_size); - if (r > 0) { - log_err("fio: posix_fallocate fails: %s\n", - strerror(r)); - } - break; -#ifdef CONFIG_LINUX_FALLOCATE - case FIO_FALLOCATE_KEEP_SIZE: - dprint(FD_FILE, - "fallocate(FALLOC_FL_KEEP_SIZE) " - "file %s size %llu\n", f->file_name, - (unsigned long long) f->real_file_size); - - r = fallocate(f->fd, FALLOC_FL_KEEP_SIZE, 0, - f->real_file_size); - if (r != 0) - td_verror(td, errno, "fallocate"); - - break; -#endif /* CONFIG_LINUX_FALLOCATE */ - default: - log_err("fio: unknown fallocate mode: %d\n", - td->o.fallocate_mode); - assert(0); - } - } -#endif /* CONFIG_POSIX_FALLOCATE */ + fallocate_file(td, f); /* * If our jobs don't require regular files initially, we're done. @@ -159,11 +187,20 @@ static int extend_file(struct thread_data *td, struct fio_file *f) } } - b = malloc(td->o.max_bs[DDIR_WRITE]); - left = f->real_file_size; + bs = td->o.max_bs[DDIR_WRITE]; + if (bs > left) + bs = left; + + b = malloc(bs); + if (!b) { + td_verror(td, errno, "malloc"); + goto err; + } + while (left && !td->terminate) { - bs = td->o.max_bs[DDIR_WRITE]; + ssize_t r; + if (bs > left) bs = left; @@ -228,7 +265,11 @@ static int pre_read_file(struct thread_data *td, struct fio_file *f) unsigned int bs; char *b; - if (td_ioengine_flagged(td, FIO_PIPEIO)) + if (td_ioengine_flagged(td, FIO_PIPEIO) || + td_ioengine_flagged(td, FIO_NOIO)) + return 0; + + if (f->filetype == FIO_TYPE_CHAR) return 0; if (!fio_file_open(f)) { @@ -241,8 +282,17 @@ static int pre_read_file(struct thread_data *td, struct fio_file *f) old_runstate = td_bump_runstate(td, TD_PRE_READING); + left = f->io_size; bs = td->o.max_bs[DDIR_READ]; + if (bs > left) + bs = left; + b = malloc(bs); + if (!b) { + td_verror(td, errno, "malloc"); + ret = 1; + goto error; + } memset(b, 0, bs); if (lseek(f->fd, f->file_offset, SEEK_SET) < 0) { @@ -252,8 +302,6 @@ static int pre_read_file(struct thread_data *td, struct fio_file *f) goto error; } - left = f->io_size; - while (left && !td->terminate) { if (bs > left) bs = left; @@ -479,8 +527,6 @@ static int __file_invalidate_cache(struct thread_data *td, struct fio_file *f, } if (ret < 0) errval = errno; - else if (ret) /* probably not supported */ - errval = ret; } else if (f->filetype == FIO_TYPE_CHAR || f->filetype == FIO_TYPE_PIPE) { dprint(FD_IO, "invalidate not supported %s\n", f->file_name); @@ -815,12 +861,42 @@ static unsigned long long get_fs_free_counts(struct thread_data *td) uint64_t get_start_offset(struct thread_data *td, struct fio_file *f) { struct thread_options *o = &td->o; + unsigned long long align_bs; + unsigned long long offset; if (o->file_append && f->filetype == FIO_TYPE_FILE) return f->real_file_size; - return td->o.start_offset + - td->subjob_number * td->o.offset_increment; + if (o->start_offset_percent > 0) { + /* + * if blockalign is provided, find the min across read, write, + * and trim + */ + if (fio_option_is_set(o, ba)) { + align_bs = (unsigned long long) min(o->ba[DDIR_READ], o->ba[DDIR_WRITE]); + align_bs = min((unsigned long long) o->ba[DDIR_TRIM], align_bs); + } else { + /* else take the minimum block size */ + align_bs = td_min_bs(td); + } + + /* calculate the raw offset */ + offset = (f->real_file_size * o->start_offset_percent / 100) + + (td->subjob_number * o->offset_increment); + + /* + * block align the offset at the next available boundary at + * ceiling(offset / align_bs) * align_bs + */ + offset = (offset / align_bs + (offset % align_bs != 0)) * align_bs; + + } else { + /* start_offset_percent not set */ + offset = o->start_offset + + td->subjob_number * o->offset_increment; + } + + return offset; } /* @@ -932,10 +1008,11 @@ int setup_files(struct thread_data *td) } /* - * 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 + * We normally don't come here for regular files, but + * if the result is 0 for a regular file, 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) { @@ -967,7 +1044,14 @@ int setup_files(struct thread_data *td) total_size = -1ULL; else { if (o->size_percent) { - f->io_size = (f->io_size * o->size_percent) / 100; + uint64_t file_size; + + file_size = f->io_size + f->file_offset; + f->io_size = (file_size * + o->size_percent) / 100; + if (f->io_size > (file_size - f->file_offset)) + f->io_size = file_size - f->file_offset; + f->io_size -= (f->io_size % td_min_bs(td)); } total_size += f->io_size; @@ -1103,10 +1187,11 @@ int pre_read_files(struct thread_data *td) dprint(FD_FILE, "pre_read files\n"); for_each_file(td, f, i) { - pre_read_file(td, f); + if (pre_read_file(td, f)) + return -1; } - return 1; + return 0; } static int __init_rand_distribution(struct thread_data *td, struct fio_file *f)