X-Git-Url: https://git.kernel.dk/?p=fio.git;a=blobdiff_plain;f=filesetup.c;h=3e2ccf9b9b4061b0e943c4487f8e6a93ddd625ff;hp=76b3f9359bad79b44b21d17a8edb74f869b15b7a;hb=d33c7846cc5f175177e194a5489282780e2a04c4;hpb=6cc78de0059146ed2344438b16ffff28fed42915 diff --git a/filesetup.c b/filesetup.c index 76b3f935..3e2ccf9b 100644 --- a/filesetup.c +++ b/filesetup.c @@ -143,7 +143,7 @@ static int extend_file(struct thread_data *td, struct fio_file *f) if (unlink_file || new_layout) { int ret; - dprint(FD_FILE, "layout unlink %s\n", f->file_name); + dprint(FD_FILE, "layout %d unlink %d %s\n", new_layout, unlink_file, f->file_name); ret = td_io_unlink_file(td, f); if (ret != 0 && ret != ENOENT) { @@ -198,6 +198,9 @@ static int extend_file(struct thread_data *td, struct fio_file *f) } } + + dprint(FD_FILE, "fill file %s, size %llu\n", f->file_name, (unsigned long long) f->real_file_size); + left = f->real_file_size; bs = td->o.max_bs[DDIR_WRITE]; if (bs > left) @@ -226,11 +229,16 @@ static int extend_file(struct thread_data *td, struct fio_file *f) if (r < 0) { int __e = errno; - if (__e == ENOSPC) { + if (__e == ENOSPC || __e == EDQUOT) { + const char *__e_name; if (td->o.fill_device) break; - log_info("fio: ENOSPC on laying out " - "file, stopping\n"); + if (__e == ENOSPC) + __e_name = "ENOSPC"; + else + __e_name = "EDQUOT"; + log_info("fio: %s on laying out " + "file, stopping\n", __e_name); } td_verror(td, errno, "write"); } else @@ -338,6 +346,95 @@ error: return ret; } +/* + * Generic function to prepopulate regular file with data. + * Useful if you want to make sure I/O engine has data to read. + * Leaves f->fd open on success, caller must close. + */ +int generic_prepopulate_file(struct thread_data *td, struct fio_file *f) +{ + int flags; + unsigned long long left, bs; + char *b = NULL; + + /* generic function for regular files only */ + assert(f->filetype == FIO_TYPE_FILE); + + if (read_only) { + log_err("fio: refusing to write a file due to read-only\n"); + return 0; + } + + flags = O_WRONLY; + if (td->o.allow_create) + flags |= O_CREAT; + +#ifdef WIN32 + flags |= _O_BINARY; +#endif + + dprint(FD_FILE, "open file %s, flags %x\n", f->file_name, flags); + f->fd = open(f->file_name, flags, 0644); + if (f->fd < 0) { + int err = errno; + + if (err == ENOENT && !td->o.allow_create) + log_err("fio: file creation disallowed by " + "allow_file_create=0\n"); + else + td_verror(td, err, "open"); + return 1; + } + + 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) { + ssize_t r; + + if (bs > left) + bs = left; + + fill_io_buffer(td, b, bs, bs); + + r = write(f->fd, b, bs); + + if (r > 0) { + left -= r; + } else { + td_verror(td, errno, "write"); + goto err; + } + } + + if (td->terminate) { + dprint(FD_FILE, "terminate unlink %s\n", f->file_name); + td_io_unlink_file(td, f); + } else if (td->o.create_fsync) { + if (fsync(f->fd) < 0) { + td_verror(td, errno, "fsync"); + goto err; + } + } + + free(b); + return 0; +err: + close(f->fd); + f->fd = -1; + if (b) + free(b); + return 1; +} + unsigned long long get_rand_file_size(struct thread_data *td) { unsigned long long ret, sized; @@ -930,7 +1027,6 @@ int longest_existing_path(char *path) { while (!done) { buf_pos = strrchr(buf, FIO_OS_PATH_SEPARATOR); if (!buf_pos) { - done = true; offset = 0; break; } @@ -985,6 +1081,44 @@ static bool create_work_dirs(struct thread_data *td, const char *fname) return true; } +int setup_shared_file(struct thread_data *td) +{ + struct fio_file *f; + uint64_t file_size; + int err = 0; + + if (td->o.nr_files > 1) { + log_err("fio: shared file setup called for multiple files\n"); + return -1; + } + + get_file_sizes(td); + + f = td->files[0]; + + if (f == NULL) { + log_err("fio: NULL shared file\n"); + return -1; + } + + file_size = thread_number * td->o.size; + dprint(FD_FILE, "shared setup %s real_file_size=%llu, desired=%llu\n", + f->file_name, (unsigned long long)f->real_file_size, (unsigned long long)file_size); + + if (f->real_file_size < file_size) { + dprint(FD_FILE, "fio: extending shared file\n"); + f->real_file_size = file_size; + err = extend_file(td, f); + if (!err) + err = __file_invalidate_cache(td, f, 0, f->real_file_size); + get_file_sizes(td); + dprint(FD_FILE, "shared setup new real_file_size=%llu\n", + (unsigned long long)f->real_file_size); + } + + return err; +} + /* * Open the files and setup files sizes, creating files if necessary. */ @@ -999,7 +1133,7 @@ int setup_files(struct thread_data *td) const unsigned long long bs = td_min_bs(td); uint64_t fs = 0; - dprint(FD_FILE, "setup files\n"); + dprint(FD_FILE, "setup files (thread_number=%d, subjob_number=%d)\n", td->thread_number, td->subjob_number); old_state = td_bump_runstate(td, TD_SETTING_UP); @@ -1026,6 +1160,13 @@ int setup_files(struct thread_data *td) if (err) goto err_out; + if (td->o.zone_mode == ZONE_MODE_ZBD) { + err = zbd_init_files(td); + if (err) + goto err_out; + } + zbd_recalc_options_with_zone_granularity(td); + if (o->read_iolog_file) goto done; @@ -1254,6 +1395,43 @@ int setup_files(struct thread_data *td) temp_stall_ts = 0; } + if (err) + goto err_out; + + /* + * Prepopulate files with data. It might be expected to read some + * "real" data instead of zero'ed files (if no writes to file occurred + * prior to a read job). Engine has to provide a way to do that. + */ + if (td->io_ops->prepopulate_file) { + temp_stall_ts = 1; + + for_each_file(td, f, i) { + if (output_format & FIO_OUTPUT_NORMAL) { + log_info("%s: Prepopulating IO file (%s)\n", + o->name, f->file_name); + } + + err = td->io_ops->prepopulate_file(td, f); + if (err) + break; + + err = __file_invalidate_cache(td, f, f->file_offset, + f->io_size); + + /* + * Shut up static checker + */ + if (f->fd != -1) + close(f->fd); + + f->fd = -1; + if (err) + break; + } + temp_stall_ts = 0; + } + if (err) goto err_out; @@ -1269,16 +1447,17 @@ int setup_files(struct thread_data *td) } done: - if (o->create_only) - td->done = 1; - - td_restore_runstate(td, old_state); - if (td->o.zone_mode == ZONE_MODE_ZBD) { err = zbd_setup_files(td); if (err) goto err_out; } + + if (o->create_only) + td->done = 1; + + td_restore_runstate(td, old_state); + return 0; err_offset: @@ -1316,14 +1495,14 @@ static void __init_rand_distribution(struct thread_data *td, struct fio_file *f) seed = jhash(f->file_name, strlen(f->file_name), 0) * td->thread_number; if (!td->o.rand_repeatable) - seed = td->rand_seeds[4]; + seed = td->rand_seeds[FIO_RAND_BLOCK_OFF]; if (td->o.random_distribution == FIO_RAND_DIST_ZIPF) - zipf_init(&f->zipf, nranges, td->o.zipf_theta.u.f, seed); + zipf_init(&f->zipf, nranges, td->o.zipf_theta.u.f, td->o.random_center.u.f, seed); else if (td->o.random_distribution == FIO_RAND_DIST_PARETO) - pareto_init(&f->zipf, nranges, td->o.pareto_h.u.f, seed); + pareto_init(&f->zipf, nranges, td->o.pareto_h.u.f, td->o.random_center.u.f, seed); else if (td->o.random_distribution == FIO_RAND_DIST_GAUSS) - gauss_init(&f->gauss, nranges, td->o.gauss_dev.u.f, seed); + gauss_init(&f->gauss, nranges, td->o.gauss_dev.u.f, td->o.random_center.u.f, seed); } static bool init_rand_distribution(struct thread_data *td) @@ -1348,7 +1527,7 @@ static bool init_rand_distribution(struct thread_data *td) /* * Check if the number of blocks exceeds the randomness capability of - * the selected generator. Tausworthe is 32-bit, the others are fullly + * the selected generator. Tausworthe is 32-bit, the others are fully * 64-bit capable. */ static int check_rand_gen_limits(struct thread_data *td, struct fio_file *f, @@ -1893,11 +2072,12 @@ void dup_files(struct thread_data *td, struct thread_data *org) if (!org->files) return; - td->files = malloc(org->files_index * sizeof(f)); + td->files = calloc(org->files_index, sizeof(f)); if (td->o.file_lock_mode != FILE_LOCK_NONE) td->file_locks = malloc(org->files_index); + assert(org->files_index >= org->o.nr_files); for_each_file(org, f, i) { struct fio_file *__f;