1 /* 2 * Really simple exclusive file locking based on filename. 3 * No hash indexing, just a list, so only works well for < 100 files or 4 * so. But that's more than what fio needs, so should be fine. 5 */ 6 #include <inttypes.h> 7 #include <string.h> 8 #include <assert.h> 9 10 #include "flist.h" 11 #include "filelock.h" 12 #include "smalloc.h" 13 #include "mutex.h" 14 #include "hash.h" 15 #include "log.h" 16 17 struct fio_filelock { 18 uint32_t hash; 19 struct fio_mutex lock; 20 struct flist_head list; 21 unsigned int references; 22 }; 23 24 static struct flist_head *filelock_list; 25 static struct fio_mutex *filelock_lock; 26 27 int fio_filelock_init(void) 28 { 29 filelock_list = smalloc(sizeof(*filelock_list)); 30 if (!filelock_list) 31 return 1; 32 33 INIT_FLIST_HEAD(filelock_list); 34 filelock_lock = fio_mutex_init(FIO_MUTEX_UNLOCKED); 35 if (!filelock_lock) { 36 sfree(filelock_list); 37 return 1; 38 } 39 40 return 0; 41 } 42 43 void fio_filelock_exit(void) 44 { 45 if (!filelock_list) 46 return; 47 48 assert(flist_empty(filelock_list)); 49 sfree(filelock_list); 50 filelock_list = NULL; 51 fio_mutex_remove(filelock_lock); 52 filelock_lock = NULL; 53 } 54 55 static struct fio_filelock *fio_hash_find(uint32_t hash) 56 { 57 struct flist_head *entry; 58 struct fio_filelock *ff; 59 60 flist_for_each(entry, filelock_list) { 61 ff = flist_entry(entry, struct fio_filelock, list); 62 if (ff->hash == hash) 63 return ff; 64 } 65 66 return NULL; 67 } 68 69 static struct fio_filelock *fio_hash_get(uint32_t hash) 70 { 71 struct fio_filelock *ff; 72 73 ff = fio_hash_find(hash); 74 if (!ff) { 75 ff = smalloc(sizeof(*ff)); 76 ff->hash = hash; 77 __fio_mutex_init(&ff->lock, FIO_MUTEX_UNLOCKED); 78 ff->references = 0; 79 flist_add(&ff->list, filelock_list); 80 } 81 82 return ff; 83 } 84 85 int fio_trylock_file(const char *fname) 86 { 87 struct fio_filelock *ff; 88 uint32_t hash; 89 90 hash = jhash(fname, strlen(fname), 0); 91 92 fio_mutex_down(filelock_lock); 93 ff = fio_hash_get(hash); 94 ff->references++; 95 fio_mutex_up(filelock_lock); 96 97 if (!fio_mutex_down_trylock(&ff->lock)) 98 return 0; 99 100 fio_mutex_down(filelock_lock); 101 102 /* 103 * If we raced and the only reference to the lock is us, we can 104 * grab it 105 */ 106 if (ff->references != 1) { 107 ff->references--; 108 ff = NULL; 109 } 110 111 fio_mutex_up(filelock_lock); 112 113 if (ff) { 114 fio_mutex_down(&ff->lock); 115 return 0; 116 } 117 118 return 1; 119 } 120 121 void fio_lock_file(const char *fname) 122 { 123 struct fio_filelock *ff; 124 uint32_t hash; 125 126 hash = jhash(fname, strlen(fname), 0); 127 128 fio_mutex_down(filelock_lock); 129 ff = fio_hash_get(hash); 130 ff->references++; 131 fio_mutex_up(filelock_lock); 132 133 fio_mutex_down(&ff->lock); 134 } 135 136 void fio_unlock_file(const char *fname) 137 { 138 struct fio_filelock *ff; 139 uint32_t hash; 140 141 hash = jhash(fname, strlen(fname), 0); 142 143 fio_mutex_down(filelock_lock); 144 145 ff = fio_hash_find(hash); 146 if (ff) { 147 ff->references--; 148 fio_mutex_up(&ff->lock); 149 if (!ff->references) { 150 flist_del(&ff->list); 151 sfree(ff); 152 } 153 } else 154 log_err("fio: file not found for unlocking\n"); 155 156 fio_mutex_up(filelock_lock); 157 } 158