Merge commit '10a89ef04df5669c5cdd02f786150a7ab8454e01'
[sliver-openvswitch.git] / lib / lockfile.c
index db84aeb..14e553d 100644 (file)
@@ -1,4 +1,4 @@
- /* Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
+ /* Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -55,7 +55,8 @@ struct lockfile {
 static struct hmap lock_table = HMAP_INITIALIZER(&lock_table);
 
 static void lockfile_unhash(struct lockfile *);
-static int lockfile_try_lock(const char *name, struct lockfile **lockfilep);
+static int lockfile_try_lock(const char *name, pid_t *pidp,
+                             struct lockfile **lockfilep);
 
 /* 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,
@@ -98,21 +99,27 @@ lockfile_lock(const char *file, struct lockfile **lockfilep)
      * stylized ways such that any number of readers may access a file while it
      * is being written. */
     char *lock_name;
+    pid_t pid;
     int error;
 
     COVERAGE_INC(lockfile_lock);
 
     lock_name = lockfile_name(file);
 
-    error = lockfile_try_lock(lock_name, lockfilep);
+    error = lockfile_try_lock(lock_name, &pid, lockfilep);
 
     if (error) {
         COVERAGE_INC(lockfile_error);
         if (error == EACCES) {
             error = EAGAIN;
         }
-        VLOG_WARN("%s: failed to lock file: %s",
-                  lock_name, strerror(error));
+        if (pid) {
+            VLOG_WARN("%s: cannot lock file because it is already locked by "
+                      "pid %ld", lock_name, (long int) pid);
+        } else {
+            VLOG_WARN("%s: failed to lock file: %s",
+                      lock_name, ovs_strerror(error));
+        }
     }
 
     free(lock_name);
@@ -201,7 +208,7 @@ lockfile_register(const char *name, dev_t device, ino_t inode, int fd)
 }
 
 static int
-lockfile_try_lock(const char *name, struct lockfile **lockfilep)
+lockfile_try_lock(const char *name, pid_t *pidp, struct lockfile **lockfilep)
 {
     struct flock l;
     struct stat s;
@@ -209,6 +216,7 @@ lockfile_try_lock(const char *name, struct lockfile **lockfilep)
     int fd;
 
     *lockfilep = NULL;
+    *pidp = 0;
 
     /* Check whether we've already got a lock on that file. */
     if (!stat(name, &s)) {
@@ -217,7 +225,7 @@ lockfile_try_lock(const char *name, struct lockfile **lockfilep)
         }
     } else if (errno != ENOENT) {
         VLOG_WARN("%s: failed to stat lock file: %s",
-                  name, strerror(errno));
+                  name, ovs_strerror(errno));
         return errno;
     }
 
@@ -225,13 +233,14 @@ lockfile_try_lock(const char *name, struct lockfile **lockfilep)
     fd = open(name, O_RDWR | O_CREAT, 0600);
     if (fd < 0) {
         VLOG_WARN("%s: failed to open lock file: %s",
-                  name, strerror(errno));
+                  name, ovs_strerror(errno));
         return errno;
     }
 
     /* Get the inode and device number for the lock table. */
     if (fstat(fd, &s)) {
-        VLOG_ERR("%s: failed to fstat lock file: %s", name, strerror(errno));
+        VLOG_ERR("%s: failed to fstat lock file: %s",
+                 name, ovs_strerror(errno));
         close(fd);
         return errno;
     }
@@ -243,13 +252,14 @@ lockfile_try_lock(const char *name, struct lockfile **lockfilep)
     l.l_start = 0;
     l.l_len = 0;
 
-    time_disable_restart();
     error = fcntl(fd, F_SETLK, &l) == -1 ? errno : 0;
-    time_enable_restart();
 
     if (!error) {
         *lockfilep = lockfile_register(name, s.st_dev, s.st_ino, fd);
     } else {
+        if (!fcntl(fd, F_GETLK, &l) && l.l_type != F_UNLCK) {
+            *pidp = l.l_pid;
+        }
         close(fd);
     }
     return error;