+static bool __is_already_allocated(const char *fname, bool set)
+{
+ struct flist_head *entry;
+ bool ret;
+
+ ret = file_bloom_exists(fname, set);
+ if (!ret)
+ return ret;
+
+ flist_for_each(entry, &filename_list) {
+ struct file_name *fn;
+
+ fn = flist_entry(entry, struct file_name, list);
+
+ if (!strcmp(fn->filename, fname))
+ return true;
+ }
+
+ return false;
+}
+
+static bool is_already_allocated(const char *fname)
+{
+ bool ret;
+
+ fio_file_hash_lock();
+ ret = __is_already_allocated(fname, false);
+ fio_file_hash_unlock();
+
+ return ret;
+}
+
+static void set_already_allocated(const char *fname)
+{
+ struct file_name *fn;
+
+ fn = malloc(sizeof(struct file_name));
+ fn->filename = strdup(fname);
+
+ fio_file_hash_lock();
+ if (!__is_already_allocated(fname, true)) {
+ flist_add_tail(&fn->list, &filename_list);
+ fn = NULL;
+ }
+ fio_file_hash_unlock();
+
+ if (fn) {
+ free(fn->filename);
+ free(fn);
+ }
+}
+
+static void free_already_allocated(void)
+{
+ struct flist_head *entry, *tmp;
+ struct file_name *fn;
+
+ if (flist_empty(&filename_list))
+ return;
+
+ fio_file_hash_lock();
+ flist_for_each_safe(entry, tmp, &filename_list) {
+ fn = flist_entry(entry, struct file_name, list);
+ free(fn->filename);
+ flist_del(&fn->list);
+ free(fn);
+ }
+
+ fio_file_hash_unlock();
+}
+
+static struct fio_file *alloc_new_file(struct thread_data *td)
+{
+ struct fio_file *f;
+
+ if (td_ioengine_flagged(td, FIO_NOFILEHASH))
+ f = calloc(1, sizeof(*f));
+ else
+ f = scalloc(1, sizeof(*f));
+ if (!f) {
+ assert(0);
+ return NULL;
+ }
+
+ f->fd = -1;
+ f->shadow_fd = -1;
+ fio_file_reset(td, f);
+ return f;
+}
+
+bool exists_and_not_regfile(const char *filename)
+{
+ struct stat sb;
+
+ if (lstat(filename, &sb) == -1)
+ return false;
+
+#ifndef WIN32 /* NOT Windows */
+ if (S_ISREG(sb.st_mode))
+ return false;
+#else
+ /* \\.\ is the device namespace in Windows, where every file
+ * is a device node */
+ if (S_ISREG(sb.st_mode) && strncmp(filename, "\\\\.\\", 4) != 0)
+ return false;
+#endif
+
+ return true;
+}
+
+static bool create_work_dirs(struct thread_data *td, const char *fname)
+{
+ char path[PATH_MAX];
+ char *start, *end;
+
+ if (td->o.directory) {
+ snprintf(path, PATH_MAX, "%s%c%s", td->o.directory,
+ FIO_OS_PATH_SEPARATOR, fname);
+ start = strstr(path, fname);
+ } else {
+ snprintf(path, PATH_MAX, "%s", fname);
+ start = path;
+ }
+
+ end = start;
+ while ((end = strchr(end, FIO_OS_PATH_SEPARATOR)) != NULL) {
+ if (end == start)
+ break;
+ *end = '\0';
+ errno = 0;
+#ifdef CONFIG_HAVE_MKDIR_TWO
+ if (mkdir(path, 0600) && errno != EEXIST) {
+#else
+ if (mkdir(path) && errno != EEXIST) {
+#endif
+ log_err("fio: failed to create dir (%s): %d\n",
+ start, errno);
+ return false;
+ }
+ *end = FIO_OS_PATH_SEPARATOR;
+ end++;
+ }
+ td->flags |= TD_F_DIRS_CREATED;
+ return true;
+}
+
+int add_file(struct thread_data *td, const char *fname, int numjob, int inc)