dovecot-2.2: lib: If file_wait_lock*() fails, try to include the...

dovecot at dovecot.org dovecot at dovecot.org
Thu Sep 25 12:50:29 UTC 2014


details:   http://hg.dovecot.org/dovecot-2.2/rev/6ed1eee94d31
changeset: 17842:6ed1eee94d31
user:      Timo Sirainen <tss at iki.fi>
date:      Thu Sep 25 15:50:03 2014 +0300
description:
lib: If file_wait_lock*() fails, try to include the current pid holding the lock in error message.
This is currently supported via fcntl(F_GETLK) and also via Linux
/proc/locks.

diffstat:

 src/lib/file-lock.c |  98 ++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 94 insertions(+), 4 deletions(-)

diffs (131 lines):

diff -r 576da94fd669 -r 6ed1eee94d31 src/lib/file-lock.c
--- a/src/lib/file-lock.c	Thu Sep 25 15:37:48 2014 +0300
+++ b/src/lib/file-lock.c	Thu Sep 25 15:50:03 2014 +0300
@@ -1,8 +1,10 @@
 /* Copyright (c) 2002-2014 Dovecot authors, see the included COPYING file */
 
 #include "lib.h"
+#include "istream.h"
 #include "file-lock.h"
 
+#include <sys/stat.h>
 #ifdef HAVE_FLOCK
 #  include <sys/file.h>
 #endif
@@ -56,6 +58,92 @@
 				    lock_r, error_r);
 }
 
+static const char *
+file_lock_find_fcntl(int lock_fd, int lock_type)
+{
+	struct flock fl;
+
+	memset(&fl, 0, sizeof(fl));
+	fl.l_type = lock_type;
+	fl.l_whence = SEEK_SET;
+	fl.l_start = 0;
+	fl.l_len = 0;
+
+	if (fcntl(lock_fd, F_GETLK, &fl) < 0 ||
+	    fl.l_type == F_UNLCK || fl.l_pid == -1 || fl.l_pid == 0)
+		return "";
+	return t_strdup_printf(" (%s lock held by pid %ld)",
+		fl.l_type == F_RDLCK ? "READ" : "WRITE", (long)fl.l_pid);
+}
+
+static const char *
+file_lock_find_proc_locks(int lock_fd ATTR_UNUSED)
+{
+	/* do anything except Linux support this? don't bother trying it for
+	   OSes we don't know about. */
+#ifdef __linux__
+	static bool have_proc_locks = TRUE;
+	struct stat st;
+	char node_buf[MAX_INT_STRLEN*3 + 2 + 1];
+	struct istream *input;
+	const char *line, *lock_type = "";
+	pid_t pid = 0;
+	int fd;
+
+	if (!have_proc_locks)
+		return FALSE;
+
+	if (fstat(lock_fd, &st) < 0)
+		return "";
+	i_snprintf(node_buf, sizeof(node_buf), "%02x:%02x:%llu",
+		   major(st.st_dev), minor(st.st_dev),
+		   (unsigned long long)st.st_ino);
+	fd = open("/proc/locks", O_RDONLY);
+	if (fd == -1) {
+		have_proc_locks = FALSE;
+		return "";
+	}
+	input = i_stream_create_fd_autoclose(&fd, 512);
+	while (pid == 0 && (line = i_stream_read_next_line(input)) != NULL) T_BEGIN {
+		const char *const *args = t_strsplit_spaces(line, " ");
+
+		/* number: FLOCK/POSIX ADVISORY READ/WRITE pid
+		   major:minor:inode region-start region-end */
+		if (str_array_length(args) < 8)
+			continue;
+		if (strcmp(args[5], node_buf) == 0) {
+			lock_type = strcmp(args[3], "READ") == 0 ?
+				"READ" : "WRITE";
+			if (str_to_pid(args[4], &pid) < 0)
+				pid = 0;
+		}
+	} T_END;
+	i_stream_destroy(&input);
+	if (pid == 0) {
+		/* not found */
+		return "";
+	}
+	if (pid == getpid())
+		return " (BUG: lock is held by our own process)";
+	return t_strdup_printf(" (%s lock held by pid %ld)", lock_type, (long)pid);
+#else
+	return "";
+#endif
+}
+
+static const char *
+file_lock_find(int lock_fd, enum file_lock_method lock_method, int lock_type)
+{
+	const char *ret;
+
+	if (lock_method == FILE_LOCK_METHOD_FCNTL) {
+		ret = file_lock_find_fcntl(lock_fd, lock_type);
+		if (ret[0] != '\0')
+			return ret;
+	}
+	return file_lock_find_proc_locks(lock_fd);
+}
+
 static int file_lock_do(int fd, const char *path, int lock_type,
 			enum file_lock_method lock_method,
 			unsigned int timeout_secs, const char **error_r)
@@ -107,8 +195,9 @@
 			errno = EAGAIN;
 			*error_r = t_strdup_printf(
 				"fcntl(%s, %s, F_SETLKW) locking failed: "
-				"Timed out after %u seconds",
-				path, lock_type_str, timeout_secs);
+				"Timed out after %u seconds%s",
+				path, lock_type_str, timeout_secs,
+				file_lock_find(fd, lock_method, lock_type));
 			return 0;
 		}
 		*error_r = t_strdup_printf("fcntl(%s, %s, %s) locking failed: %m",
@@ -152,8 +241,9 @@
 		if (errno == EINTR) {
 			errno = EAGAIN;
 			*error_r = t_strdup_printf("flock(%s, %s) failed: "
-				"Timed out after %u seconds",
-				path, lock_type_str, timeout_secs);
+				"Timed out after %u seconds%s",
+				path, lock_type_str, timeout_secs,
+				file_lock_find(fd, lock_method, lock_type));
 			return 0;
 		}
 		*error_r = t_strdup_printf("flock(%s, %s) failed: %m",


More information about the dovecot-cvs mailing list