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.
21 struct flist_head list;
22 unsigned int references;
25 #define MAX_FILELOCKS 128
27 static struct filelock_data {
28 struct flist_head list;
31 struct flist_head free_list;
32 struct fio_filelock ffs[MAX_FILELOCKS];
35 static void put_filelock(struct fio_filelock *ff)
37 flist_add(&ff->list, &fld->free_list);
40 static struct fio_filelock *__get_filelock(void)
42 struct fio_filelock *ff;
44 if (flist_empty(&fld->free_list))
47 ff = flist_first_entry(&fld->free_list, struct fio_filelock, list);
48 flist_del_init(&ff->list);
52 static struct fio_filelock *get_filelock(int trylock, int *retry)
54 struct fio_filelock *ff;
57 ff = __get_filelock();
61 fio_sem_up(&fld->lock);
63 fio_sem_down(&fld->lock);
70 int fio_filelock_init(void)
74 fld = smalloc(sizeof(*fld));
78 INIT_FLIST_HEAD(&fld->list);
79 INIT_FLIST_HEAD(&fld->free_list);
81 if (__fio_sem_init(&fld->lock, FIO_SEM_UNLOCKED))
84 for (i = 0; i < MAX_FILELOCKS; i++) {
85 struct fio_filelock *ff = &fld->ffs[i];
87 if (__fio_sem_init(&ff->lock, FIO_SEM_UNLOCKED))
89 flist_add_tail(&ff->list, &fld->free_list);
98 void fio_filelock_exit(void)
103 assert(flist_empty(&fld->list));
104 __fio_sem_remove(&fld->lock);
106 while (!flist_empty(&fld->free_list)) {
107 struct fio_filelock *ff;
109 ff = flist_first_entry(&fld->free_list, struct fio_filelock, list);
111 flist_del_init(&ff->list);
112 __fio_sem_remove(&ff->lock);
119 static struct fio_filelock *fio_hash_find(uint32_t hash)
121 struct flist_head *entry;
122 struct fio_filelock *ff;
124 flist_for_each(entry, &fld->list) {
125 ff = flist_entry(entry, struct fio_filelock, list);
126 if (ff->hash == hash)
133 static struct fio_filelock *fio_hash_get(uint32_t hash, int trylock)
135 struct fio_filelock *ff;
137 ff = fio_hash_find(hash);
141 ff = get_filelock(trylock, &retry);
146 * If we dropped the main lock, re-lookup the hash in case
147 * someone else added it meanwhile. If it's now there,
151 struct fio_filelock *__ff;
153 __ff = fio_hash_find(hash);
162 flist_add(&ff->list, &fld->list);
168 static bool __fio_lock_file(const char *fname, int trylock)
170 struct fio_filelock *ff;
173 hash = jhash(fname, strlen(fname), 0);
175 fio_sem_down(&fld->lock);
176 ff = fio_hash_get(hash, trylock);
179 fio_sem_up(&fld->lock);
187 fio_sem_down(&ff->lock);
191 if (!fio_sem_down_trylock(&ff->lock))
194 fio_sem_down(&fld->lock);
197 * If we raced and the only reference to the lock is us, we can
200 if (ff->references != 1) {
205 fio_sem_up(&fld->lock);
208 fio_sem_down(&ff->lock);
215 bool fio_trylock_file(const char *fname)
217 return __fio_lock_file(fname, 1);
220 void fio_lock_file(const char *fname)
222 __fio_lock_file(fname, 0);
225 void fio_unlock_file(const char *fname)
227 struct fio_filelock *ff;
230 hash = jhash(fname, strlen(fname), 0);
232 fio_sem_down(&fld->lock);
234 ff = fio_hash_find(hash);
236 int refs = --ff->references;
237 fio_sem_up(&ff->lock);
239 flist_del_init(&ff->list);
243 log_err("fio: file not found for unlocking\n");
245 fio_sem_up(&fld->lock);