diff --git a/filehash.c b/filehash.c index 71ec7b18c3..3e5250575d 100644 --- a/filehash.c +++ b/filehash.c @@ -14,9 +14,10 @@ #define BLOOM_SIZE 16*1024*1024 static unsigned int file_hash_size = HASH_BUCKETS * sizeof(struct flist_head); +static unsigned int sem_hash_size = HASH_BUCKETS * sizeof(struct fio_sem *); static struct flist_head *file_hash; -static struct fio_sem *hash_lock; +static struct fio_sem **hash_locks; static struct bloom *file_bloom; static unsigned short hash(const char *name) @@ -24,21 +25,38 @@ static unsigned short hash(const char *name) return jhash(name, strlen(name), 0) & HASH_MASK; } -void fio_file_hash_lock(void) +static unsigned int file_bucket(const char *file_name, struct flist_head *bucket) { - if (hash_lock) - fio_sem_down(hash_lock); + struct flist_head *head; + + head = &file_hash[hash(file_name)]; + if (bucket) + bucket = head; + + return head - file_hash; +} + +void fio_file_hash_lock(const char *file_name) +{ + unsigned int buckidx = file_bucket(file_name, NULL); + + if (hash_locks) + fio_sem_down(hash_locks[buckidx]); } -void fio_file_hash_unlock(void) +void fio_file_hash_unlock(const char *file_name) { - if (hash_lock) - fio_sem_up(hash_lock); + unsigned int buckidx = file_bucket(file_name, NULL); + + if (hash_locks) + fio_sem_up(hash_locks[buckidx]); } void remove_file_hash(struct fio_file *f) { - fio_sem_down(hash_lock); + unsigned long buckidx = file_bucket(f->file_name, NULL); + + fio_sem_down(hash_locks[buckidx]); if (fio_file_hashed(f)) { assert(!flist_empty(&f->hash_list)); @@ -46,7 +64,7 @@ void remove_file_hash(struct fio_file *f) fio_file_clear_hashed(f); } - fio_sem_up(hash_lock); + fio_sem_up(hash_locks[buckidx]); } static struct fio_file *__lookup_file_hash(const char *name) @@ -71,9 +89,9 @@ struct fio_file *lookup_file_hash(const char *name) { struct fio_file *f; - fio_sem_down(hash_lock); + fio_file_hash_lock(name); f = __lookup_file_hash(name); - fio_sem_up(hash_lock); + fio_file_hash_unlock(name); return f; } @@ -86,7 +104,7 @@ struct fio_file *add_file_hash(struct fio_file *f) INIT_FLIST_HEAD(&f->hash_list); - fio_sem_down(hash_lock); + fio_file_hash_lock(f->file_name); alias = __lookup_file_hash(f->file_name); if (!alias) { @@ -94,7 +112,7 @@ struct fio_file *add_file_hash(struct fio_file *f) flist_add_tail(&f->hash_list, &file_hash[hash(f->file_name)]); } - fio_sem_up(hash_lock); + fio_file_hash_unlock(f->file_name); return alias; } @@ -107,18 +125,19 @@ void file_hash_exit(void) { unsigned int i, has_entries = 0; - fio_sem_down(hash_lock); - for (i = 0; i < HASH_BUCKETS; i++) + for (i = 0; i < HASH_BUCKETS; i++) { + fio_sem_down(hash_locks[i]); has_entries += !flist_empty(&file_hash[i]); - fio_sem_up(hash_lock); + fio_sem_up(hash_locks[i]); + fio_sem_remove(hash_locks[i]); + } if (has_entries) log_err("fio: file hash not empty on exit\n"); sfree(file_hash); file_hash = NULL; - fio_sem_remove(hash_lock); - hash_lock = NULL; + hash_locks = NULL; bloom_free(file_bloom); file_bloom = NULL; } @@ -128,10 +147,12 @@ void file_hash_init(void) unsigned int i; file_hash = smalloc(file_hash_size); + hash_locks = smalloc(sem_hash_size); - for (i = 0; i < HASH_BUCKETS; i++) + for (i = 0; i < HASH_BUCKETS; i++) { INIT_FLIST_HEAD(&file_hash[i]); + hash_locks[i] = fio_sem_init(FIO_SEM_UNLOCKED); + } - hash_lock = fio_sem_init(FIO_SEM_UNLOCKED); file_bloom = bloom_new(BLOOM_SIZE); } diff --git a/filehash.h b/filehash.h index 5fecc3b100..81aefa63e5 100644 --- a/filehash.h +++ b/filehash.h @@ -8,8 +8,8 @@ extern void file_hash_exit(void); extern struct fio_file *lookup_file_hash(const char *); extern struct fio_file *add_file_hash(struct fio_file *); extern void remove_file_hash(struct fio_file *); -extern void fio_file_hash_lock(void); -extern void fio_file_hash_unlock(void); +extern void fio_file_hash_lock(const char *); +extern void fio_file_hash_unlock(const char *); extern bool file_bloom_exists(const char *, bool); #endif diff --git a/filesetup.c b/filesetup.c index 1e5f2fa7cb..a9307b6728 100644 --- a/filesetup.c +++ b/filesetup.c @@ -21,6 +21,8 @@ #include #endif +static const char *flist_bucket_name = "flist_bucket"; + static FLIST_HEAD(filename_list); /* @@ -1701,9 +1703,9 @@ static bool is_already_allocated(const char *fname) { bool ret; - fio_file_hash_lock(); + fio_file_hash_lock(fname); ret = __is_already_allocated(fname, false); - fio_file_hash_unlock(); + fio_file_hash_unlock(fname); return ret; } @@ -1715,12 +1717,12 @@ static void set_already_allocated(const char *fname) fn = malloc(sizeof(struct file_name)); fn->filename = strdup(fname); - fio_file_hash_lock(); + fio_file_hash_lock(flist_bucket_name); if (!__is_already_allocated(fname, true)) { flist_add_tail(&fn->list, &filename_list); fn = NULL; } - fio_file_hash_unlock(); + fio_file_hash_unlock(flist_bucket_name); if (fn) { free(fn->filename); @@ -1736,7 +1738,7 @@ static void free_already_allocated(void) if (flist_empty(&filename_list)) return; - fio_file_hash_lock(); + fio_file_hash_lock(flist_bucket_name); flist_for_each_safe(entry, tmp, &filename_list) { fn = flist_entry(entry, struct file_name, list); free(fn->filename); @@ -1744,7 +1746,7 @@ static void free_already_allocated(void) free(fn); } - fio_file_hash_unlock(); + fio_file_hash_unlock(flist_bucket_name); } static struct fio_file *alloc_new_file(struct thread_data *td)