flist: add flist_first_entry()
[fio.git] / filelock.c
CommitLineData
243bfe19
JA
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
17struct fio_filelock {
18 uint32_t hash;
19 struct fio_mutex lock;
20 struct flist_head list;
21 unsigned int references;
22};
23
24static struct flist_head *filelock_list;
25static struct fio_mutex *filelock_lock;
26
27int 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
43void 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
55static 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
69static 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
85int 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
121void 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
136void 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}