Branch data Line data Source code
1 : : /* Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
2 : : *
3 : : * Licensed under the Apache License, Version 2.0 (the "License");
4 : : * you may not use this file except in compliance with the License.
5 : : * You may obtain a copy of the License at:
6 : : *
7 : : * http://www.apache.org/licenses/LICENSE-2.0
8 : : *
9 : : * Unless required by applicable law or agreed to in writing, software
10 : : * distributed under the License is distributed on an "AS IS" BASIS,
11 : : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : : * See the License for the specific language governing permissions and
13 : : * limitations under the License.
14 : : */
15 : :
16 : : #include <config.h>
17 : :
18 : : #include "lockfile.h"
19 : :
20 : : #include <errno.h>
21 : : #include <fcntl.h>
22 : : #include <stdlib.h>
23 : : #include <string.h>
24 : : #include <sys/stat.h>
25 : : #include <unistd.h>
26 : :
27 : : #include "coverage.h"
28 : : #include "hash.h"
29 : : #include "openvswitch/hmap.h"
30 : : #include "ovs-thread.h"
31 : : #include "timeval.h"
32 : : #include "util.h"
33 : : #include "openvswitch/vlog.h"
34 : :
35 : 50338 : VLOG_DEFINE_THIS_MODULE(lockfile);
36 : :
37 : 155368 : COVERAGE_DEFINE(lockfile_lock);
38 : 138484 : COVERAGE_DEFINE(lockfile_error);
39 : 155260 : COVERAGE_DEFINE(lockfile_unlock);
40 : :
41 : : struct lockfile {
42 : : struct hmap_node hmap_node;
43 : : char *name;
44 : : dev_t device;
45 : : ino_t inode;
46 : : int fd;
47 : : HANDLE lock_handle;
48 : : };
49 : :
50 : : /* Lock table.
51 : : *
52 : : * We have to do this stupid dance because POSIX says that closing *any* file
53 : : * descriptor for a file on which a process holds a lock drops *all* locks on
54 : : * that file. That means that we can't afford to open a lockfile more than
55 : : * once. */
56 : : static struct ovs_mutex lock_table_mutex = OVS_MUTEX_INITIALIZER;
57 : : static struct hmap lock_table__ = HMAP_INITIALIZER(&lock_table__);
58 : : static struct hmap *const lock_table OVS_GUARDED_BY(lock_table_mutex)
59 : : = &lock_table__;
60 : :
61 : : static void lockfile_unhash(struct lockfile *);
62 : : static int lockfile_try_lock(const char *name, pid_t *pidp,
63 : : struct lockfile **lockfilep)
64 : : OVS_REQUIRES(&lock_table_mutex);
65 : : static void lockfile_do_unlock(struct lockfile * lockfile)
66 : : OVS_REQUIRES(&lock_table_mutex);
67 : :
68 : : /* Returns the name of the lockfile that would be created for locking a file
69 : : * named 'filename_'. The caller is responsible for freeing the returned name,
70 : : * with free(), when it is no longer needed. */
71 : : char *
72 : 2826 : lockfile_name(const char *filename_)
73 : : {
74 : : char *filename;
75 : : const char *slash;
76 : : char *lockname;
77 : :
78 : : /* If 'filename_' is a symlink, base the name of the lockfile on the
79 : : * symlink's target rather than the name of the symlink. That way, if a
80 : : * file is symlinked, but there is no symlink for its lockfile, then there
81 : : * is only a single lockfile for both the source and the target of the
82 : : * symlink, not one for each. */
83 : 2826 : filename = follow_symlinks(filename_);
84 : 2826 : slash = strrchr(filename, '/');
85 : :
86 : : #ifdef _WIN32
87 : : char *backslash = strrchr(filename, '\\');
88 : : if (backslash && (!slash || backslash > slash)) {
89 : : slash = backslash;
90 : : }
91 : : #endif
92 : :
93 : 2826 : lockname = (slash
94 : 1720 : ? xasprintf("%.*s/.%s.~lock~",
95 : 860 : (int) (slash - filename), filename, slash + 1)
96 [ + + ]: 2826 : : xasprintf(".%s.~lock~", filename));
97 : 2826 : free(filename);
98 : :
99 : 2826 : return lockname;
100 : : }
101 : :
102 : : /* Locks the configuration file against modification by other processes and
103 : : * re-reads it from disk.
104 : : *
105 : : * Returns 0 on success, otherwise a positive errno value. On success,
106 : : * '*lockfilep' is set to point to a new "struct lockfile *" that may be
107 : : * unlocked with lockfile_unlock(). On failure, '*lockfilep' is set to
108 : : * NULL. Will not block if the lock cannot be immediately acquired. */
109 : : int
110 : 2826 : lockfile_lock(const char *file, struct lockfile **lockfilep)
111 : : {
112 : : /* Only exclusive ("write") locks are supported. This is not a problem
113 : : * because the Open vSwitch code that currently uses lock files does so in
114 : : * stylized ways such that any number of readers may access a file while it
115 : : * is being written. */
116 : : char *lock_name;
117 : : pid_t pid;
118 : : int error;
119 : :
120 : 2826 : COVERAGE_INC(lockfile_lock);
121 : :
122 : 2826 : lock_name = lockfile_name(file);
123 : :
124 : 2826 : ovs_mutex_lock(&lock_table_mutex);
125 : 2826 : error = lockfile_try_lock(lock_name, &pid, lockfilep);
126 : 2826 : ovs_mutex_unlock(&lock_table_mutex);
127 : :
128 [ + + ]: 2826 : if (error) {
129 : 12 : COVERAGE_INC(lockfile_error);
130 [ - + ]: 12 : if (error == EACCES) {
131 : 0 : error = EAGAIN;
132 : : }
133 [ + + ]: 12 : if (pid == getpid()) {
134 [ + - ]: 10 : VLOG_WARN("%s: cannot lock file because this process has already "
135 : : "locked it", lock_name);
136 [ + - ]: 2 : } else if (pid) {
137 [ + - ]: 2 : VLOG_WARN("%s: cannot lock file because it is already locked by "
138 : : "pid %ld", lock_name, (long int) pid);
139 : : } else {
140 [ # # ]: 0 : VLOG_WARN("%s: failed to lock file: %s",
141 : : lock_name, ovs_strerror(error));
142 : : }
143 : : }
144 : :
145 : 2826 : free(lock_name);
146 : 2826 : return error;
147 : : }
148 : :
149 : : /* Unlocks 'lockfile', which must have been created by a call to
150 : : * lockfile_lock(), and frees 'lockfile'. */
151 : : void
152 : 2832 : lockfile_unlock(struct lockfile *lockfile)
153 : : {
154 [ + + ]: 2832 : if (lockfile) {
155 : 2808 : ovs_mutex_lock(&lock_table_mutex);
156 : 2808 : lockfile_do_unlock(lockfile);
157 : 2808 : ovs_mutex_unlock(&lock_table_mutex);
158 : :
159 : 2808 : COVERAGE_INC(lockfile_unlock);
160 : 2808 : free(lockfile->name);
161 : 2808 : free(lockfile);
162 : : }
163 : 2832 : }
164 : :
165 : : /* Marks all the currently locked lockfiles as no longer locked. It makes
166 : : * sense to call this function after fork(), because a child created by fork()
167 : : * does not hold its parents' locks. */
168 : : void
169 : 2077 : lockfile_postfork(void)
170 : : {
171 : : struct lockfile *lockfile;
172 : :
173 : 2077 : ovs_mutex_lock(&lock_table_mutex);
174 [ + + ][ - + ]: 2079 : HMAP_FOR_EACH (lockfile, hmap_node, lock_table) {
175 [ + - ]: 2 : if (lockfile->fd >= 0) {
176 [ + - ]: 2 : VLOG_WARN("%s: child does not inherit lock", lockfile->name);
177 : 2 : lockfile_unhash(lockfile);
178 : : }
179 : : }
180 : 2077 : ovs_mutex_unlock(&lock_table_mutex);
181 : 2077 : }
182 : :
183 : : static uint32_t
184 : 7903 : lockfile_hash(dev_t device, ino_t inode)
185 : : {
186 : 7903 : return hash_bytes(&device, sizeof device,
187 : : hash_bytes(&inode, sizeof inode, 0));
188 : : }
189 : :
190 : : static struct lockfile *
191 : 5089 : lockfile_find(dev_t device, ino_t inode) OVS_REQUIRES(&lock_table_mutex)
192 : : {
193 : : struct lockfile *lockfile;
194 : :
195 [ + + ][ - + ]: 5089 : HMAP_FOR_EACH_WITH_HASH (lockfile, hmap_node,
196 : : lockfile_hash(device, inode), lock_table) {
197 [ + - ][ + - ]: 10 : if (lockfile->device == device && lockfile->inode == inode) {
198 : 10 : return lockfile;
199 : : }
200 : : }
201 : 5079 : return NULL;
202 : : }
203 : :
204 : : static void
205 : 2810 : lockfile_unhash(struct lockfile *lockfile) OVS_REQUIRES(&lock_table_mutex)
206 : : {
207 [ + + ]: 2810 : if (lockfile->fd >= 0) {
208 : 2809 : close(lockfile->fd);
209 : 2809 : lockfile->fd = -1;
210 : 2809 : hmap_remove(lock_table, &lockfile->hmap_node);
211 : : }
212 : 2810 : }
213 : :
214 : : static struct lockfile *
215 : 2814 : lockfile_register(const char *name, dev_t device, ino_t inode, int fd)
216 : : OVS_REQUIRES(&lock_table_mutex)
217 : : {
218 : : struct lockfile *lockfile;
219 : :
220 : 2814 : lockfile = lockfile_find(device, inode);
221 [ - + ]: 2814 : if (lockfile) {
222 [ # # ]: 0 : VLOG_ERR("%s: lock file disappeared and reappeared!", name);
223 : 0 : lockfile_unhash(lockfile);
224 : : }
225 : :
226 : 2814 : lockfile = xmalloc(sizeof *lockfile);
227 : 2814 : lockfile->name = xstrdup(name);
228 : 2814 : lockfile->device = device;
229 : 2814 : lockfile->inode = inode;
230 : 2814 : lockfile->fd = fd;
231 : 2814 : hmap_insert(lock_table, &lockfile->hmap_node,
232 : : lockfile_hash(device, inode));
233 : 2814 : return lockfile;
234 : : }
235 : :
236 : : #ifdef _WIN32
237 : : static void
238 : : lockfile_do_unlock(struct lockfile *lockfile)
239 : : OVS_REQUIRES(&lock_table_mutex)
240 : : {
241 : : if (lockfile->fd >= 0) {
242 : : OVERLAPPED overl;
243 : : overl.hEvent = 0;
244 : : overl.Offset = 0;
245 : : overl.OffsetHigh = 0;
246 : : UnlockFileEx(lockfile->lock_handle, 0, 1, 0, &overl);
247 : :
248 : : close(lockfile->fd);
249 : : lockfile->fd = -1;
250 : : }
251 : : }
252 : :
253 : : static int
254 : : lockfile_try_lock(const char *name, pid_t *pidp, struct lockfile **lockfilep)
255 : : OVS_REQUIRES(&lock_table_mutex)
256 : : {
257 : : HANDLE lock_handle;
258 : : BOOL retval;
259 : : OVERLAPPED overl;
260 : : struct lockfile *lockfile;
261 : : int fd;
262 : :
263 : : *pidp = 0;
264 : :
265 : : fd = open(name, O_RDWR | O_CREAT, 0600);
266 : : if (fd < 0) {
267 : : VLOG_WARN("%s: failed to open lock file: %s",
268 : : name, ovs_strerror(errno));
269 : : return errno;
270 : : }
271 : :
272 : : lock_handle = (HANDLE)_get_osfhandle(fd);
273 : : if (lock_handle < 0) {
274 : : VLOG_WARN("%s: failed to get the file handle: %s",
275 : : name, ovs_strerror(errno));
276 : : return errno;
277 : : }
278 : :
279 : : /* Lock the file 'name' for the region that includes just the first
280 : : * byte. */
281 : : overl.hEvent = 0;
282 : : overl.Offset = 0;
283 : : overl.OffsetHigh = 0;
284 : : retval = LockFileEx(lock_handle, LOCKFILE_EXCLUSIVE_LOCK
285 : : | LOCKFILE_FAIL_IMMEDIATELY, 0, 1, 0, &overl);
286 : : if (!retval) {
287 : : VLOG_DBG("Failed to lock file : %s", ovs_lasterror_to_string());
288 : : *pidp = getpid();
289 : : return EDEADLK;
290 : : }
291 : :
292 : : lockfile = xmalloc(sizeof *lockfile);
293 : : lockfile->name = xstrdup(name);
294 : : lockfile->fd = fd;
295 : : lockfile->lock_handle = lock_handle;
296 : :
297 : : *lockfilep = lockfile;
298 : : return 0;
299 : : }
300 : : #else /* !_WIN32 */
301 : : static void
302 : 2808 : lockfile_do_unlock(struct lockfile *lockfile)
303 : : {
304 : 2808 : lockfile_unhash(lockfile);
305 : 2808 : }
306 : :
307 : : static int
308 : 2826 : lockfile_try_lock(const char *name, pid_t *pidp, struct lockfile **lockfilep)
309 : : OVS_REQUIRES(&lock_table_mutex)
310 : : {
311 : : struct flock l;
312 : : struct stat s;
313 : : int error;
314 : : int fd;
315 : :
316 : 2826 : *lockfilep = NULL;
317 : 2826 : *pidp = 0;
318 : :
319 : : /* Check whether we've already got a lock on that file. */
320 [ + + ]: 2826 : if (!stat(name, &s)) {
321 [ + + ]: 2275 : if (lockfile_find(s.st_dev, s.st_ino)) {
322 : 10 : *pidp = getpid();
323 : 10 : return EDEADLK;
324 : : }
325 [ - + ]: 551 : } else if (errno != ENOENT) {
326 [ # # ]: 0 : VLOG_WARN("%s: failed to stat lock file: %s",
327 : : name, ovs_strerror(errno));
328 : 0 : return errno;
329 : : }
330 : :
331 : : /* Open the lock file. */
332 : 2816 : fd = open(name, O_RDWR | O_CREAT, 0600);
333 [ - + ]: 2816 : if (fd < 0) {
334 [ # # ]: 0 : VLOG_WARN("%s: failed to open lock file: %s",
335 : : name, ovs_strerror(errno));
336 : 0 : return errno;
337 : : }
338 : :
339 : : /* Get the inode and device number for the lock table. */
340 [ - + ]: 2816 : if (fstat(fd, &s)) {
341 [ # # ]: 0 : VLOG_ERR("%s: failed to fstat lock file: %s",
342 : : name, ovs_strerror(errno));
343 : 0 : close(fd);
344 : 0 : return errno;
345 : : }
346 : :
347 : : /* Try to lock the file. */
348 : 2816 : memset(&l, 0, sizeof l);
349 : 2816 : l.l_type = F_WRLCK;
350 : 2816 : l.l_whence = SEEK_SET;
351 : 2816 : l.l_start = 0;
352 : 2816 : l.l_len = 0;
353 : :
354 [ + + ]: 2816 : error = fcntl(fd, F_SETLK, &l) == -1 ? errno : 0;
355 : :
356 [ + + ]: 2816 : if (!error) {
357 : 2814 : *lockfilep = lockfile_register(name, s.st_dev, s.st_ino, fd);
358 : : } else {
359 [ + - ][ + - ]: 2 : if (!fcntl(fd, F_GETLK, &l) && l.l_type != F_UNLCK) {
360 : 2 : *pidp = l.l_pid;
361 : : }
362 : 2 : close(fd);
363 : : }
364 : 2826 : return error;
365 : : }
366 : : #endif
|