Commit | Line | Data |
---|---|---|
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 | ||
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 | } |