- /* Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+ /* Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include "ovs-thread.h"
#include "timeval.h"
#include "util.h"
-#include "vlog.h"
+#include "openvswitch/vlog.h"
VLOG_DEFINE_THIS_MODULE(lockfile);
dev_t device;
ino_t inode;
int fd;
+ HANDLE lock_handle;
};
/* Lock table.
static void lockfile_unhash(struct lockfile *);
static int lockfile_try_lock(const char *name, pid_t *pidp,
- struct lockfile **lockfilep);
+ struct lockfile **lockfilep)
+ OVS_REQUIRES(&lock_table_mutex);
+static void lockfile_do_unlock(struct lockfile * lockfile)
+ OVS_REQUIRES(&lock_table_mutex);
/* Returns the name of the lockfile that would be created for locking a file
* named 'filename_'. The caller is responsible for freeing the returned name,
* symlink, not one for each. */
filename = follow_symlinks(filename_);
slash = strrchr(filename, '/');
+
+#ifdef _WIN32
+ char *backslash = strrchr(filename, '\\');
+ if (backslash && (!slash || backslash > slash)) {
+ slash = backslash;
+ }
+#endif
+
lockname = (slash
? xasprintf("%.*s/.%s.~lock~",
(int) (slash - filename), filename, slash + 1)
if (error == EACCES) {
error = EAGAIN;
}
- if (pid) {
+ if (pid == getpid()) {
+ VLOG_WARN("%s: cannot lock file because this process has already "
+ "locked it", lock_name);
+ } else if (pid) {
VLOG_WARN("%s: cannot lock file because it is already locked by "
"pid %ld", lock_name, (long int) pid);
} else {
{
if (lockfile) {
ovs_mutex_lock(&lock_table_mutex);
- lockfile_unhash(lockfile);
+ lockfile_do_unlock(lockfile);
ovs_mutex_unlock(&lock_table_mutex);
COVERAGE_INC(lockfile_unlock);
return lockfile;
}
+#ifdef _WIN32
+static void
+lockfile_do_unlock(struct lockfile *lockfile)
+ OVS_REQUIRES(&lock_table_mutex)
+{
+ if (lockfile->fd >= 0) {
+ OVERLAPPED overl;
+ overl.hEvent = 0;
+ overl.Offset = 0;
+ overl.OffsetHigh = 0;
+ UnlockFileEx(lockfile->lock_handle, 0, 1, 0, &overl);
+
+ close(lockfile->fd);
+ lockfile->fd = -1;
+ }
+}
+
+static int
+lockfile_try_lock(const char *name, pid_t *pidp, struct lockfile **lockfilep)
+ OVS_REQUIRES(&lock_table_mutex)
+{
+ HANDLE lock_handle;
+ BOOL retval;
+ OVERLAPPED overl;
+ struct lockfile *lockfile;
+ int fd;
+
+ *pidp = 0;
+
+ fd = open(name, O_RDWR | O_CREAT, 0600);
+ if (fd < 0) {
+ VLOG_WARN("%s: failed to open lock file: %s",
+ name, ovs_strerror(errno));
+ return errno;
+ }
+
+ lock_handle = (HANDLE)_get_osfhandle(fd);
+ if (lock_handle < 0) {
+ VLOG_WARN("%s: failed to get the file handle: %s",
+ name, ovs_strerror(errno));
+ return errno;
+ }
+
+ /* Lock the file 'name' for the region that includes just the first
+ * byte. */
+ overl.hEvent = 0;
+ overl.Offset = 0;
+ overl.OffsetHigh = 0;
+ retval = LockFileEx(lock_handle, LOCKFILE_EXCLUSIVE_LOCK
+ | LOCKFILE_FAIL_IMMEDIATELY, 0, 1, 0, &overl);
+ if (!retval) {
+ VLOG_DBG("Failed to lock file : %s", ovs_lasterror_to_string());
+ *pidp = getpid();
+ return EDEADLK;
+ }
+
+ lockfile = xmalloc(sizeof *lockfile);
+ lockfile->name = xstrdup(name);
+ lockfile->fd = fd;
+ lockfile->lock_handle = lock_handle;
+
+ *lockfilep = lockfile;
+ return 0;
+}
+#else /* !_WIN32 */
+static void
+lockfile_do_unlock(struct lockfile *lockfile)
+{
+ lockfile_unhash(lockfile);
+}
+
static int
lockfile_try_lock(const char *name, pid_t *pidp, struct lockfile **lockfilep)
OVS_REQUIRES(&lock_table_mutex)
/* Check whether we've already got a lock on that file. */
if (!stat(name, &s)) {
if (lockfile_find(s.st_dev, s.st_ino)) {
+ *pidp = getpid();
return EDEADLK;
}
} else if (errno != ENOENT) {
}
return error;
}
-
+#endif