changeset 15629:ce0bd8ab1459

dsync: Added support back for dsync locking. Only the source directory is now locked to avoid deadlocks when both source and destination are locked. This of course now means that both source and destination is allowed to run dsync at the same time, which isn't ideal either..
author Timo Sirainen <tss@iki.fi>
date Thu, 10 Jan 2013 10:21:27 +0200
parents f6d69bc1beed
children 7035da8cfaf4
files src/doveadm/dsync/doveadm-dsync.c
diffstat 1 files changed, 66 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/src/doveadm/dsync/doveadm-dsync.c	Thu Jan 10 10:02:47 2013 +0200
+++ b/src/doveadm/dsync/doveadm-dsync.c	Thu Jan 10 10:21:27 2013 +0200
@@ -28,7 +28,8 @@
 #include <unistd.h>
 #include <ctype.h>
 
-#define DSYNC_COMMON_GETOPT_ARGS "+adEfm:n:r:Rs:"
+#define DSYNC_LOCK_FILENAME ".dovecot-sync.lock"
+#define DSYNC_COMMON_GETOPT_ARGS "+adEfl:m:n:r:Rs:"
 
 struct dsync_cmd_context {
 	struct doveadm_mail_cmd_context ctx;
@@ -348,9 +349,8 @@
 }
 
 static int
-cmd_dsync_run(struct doveadm_mail_cmd_context *_ctx, struct mail_user *user)
+cmd_dsync_run_real(struct dsync_cmd_context *ctx, struct mail_user *user)
 {
-	struct dsync_cmd_context *ctx = (struct dsync_cmd_context *)_ctx;
 	struct dsync_ibc *ibc, *ibc2 = NULL;
 	struct dsync_brain *brain;
 	struct mail_namespace *sync_ns = NULL;
@@ -407,7 +407,7 @@
 	}
 
 	if (dsync_brain_deinit(&brain) < 0)
-		_ctx->exit_code = EX_TEMPFAIL;
+		ctx->ctx.exit_code = EX_TEMPFAIL;
 	dsync_ibc_deinit(&ibc);
 	if (ibc2 != NULL)
 		dsync_ibc_deinit(&ibc2);
@@ -427,6 +427,62 @@
 	return ret;
 }
 
+static int dsync_lock(struct mail_user *user, unsigned int lock_timeout,
+		      const char **path_r, struct file_lock **lock_r)
+{
+	const char *home, *path;
+	int ret, fd;
+
+	if ((ret = mail_user_get_home(user, &home)) < 0) {
+		i_error("Couldn't look up user's home dir");
+		return -1;
+	}
+	if (ret == 0) {
+		i_error("User has no home directory");
+		return -1;
+	}
+
+	path = t_strconcat(home, "/"DSYNC_LOCK_FILENAME, NULL);
+	fd = creat(path, 0600);
+	if (fd == -1) {
+		i_error("Couldn't create lock %s: %m", path);
+		return -1;
+	}
+
+	if (file_wait_lock(fd, path, F_WRLCK, FILE_LOCK_METHOD_FCNTL,
+			   lock_timeout, lock_r) <= 0) {
+		i_error("Couldn't lock %s: %m", path);
+		(void)close(fd);
+		return -1;
+	}
+	*path_r = path;
+	return fd;
+}
+
+static int
+cmd_dsync_run(struct doveadm_mail_cmd_context *_ctx, struct mail_user *user)
+{
+	struct dsync_cmd_context *ctx = (struct dsync_cmd_context *)_ctx;
+	const char *lock_path;
+	struct file_lock *lock;
+	int lock_fd, ret;
+
+	if (!ctx->lock)
+		return cmd_dsync_run_real(ctx, user);
+
+	lock_fd = dsync_lock(user, ctx->lock_timeout, &lock_path, &lock);
+	if (lock_fd == -1) {
+		_ctx->exit_code = EX_TEMPFAIL;
+		return -1;
+	} else {
+		ret = cmd_dsync_run_real(ctx, user);
+		file_lock_free(&lock);
+		if (close(lock_fd) < 0)
+			i_error("close(%s) failed: %m", lock_path);
+		return ret;
+	}
+}
+
 static int cmd_dsync_prerun(struct doveadm_mail_cmd_context *_ctx,
 			    struct mail_storage_service_user *service_user,
 			    const char **error_r)
@@ -527,6 +583,11 @@
 	case 'f':
 		ctx->sync_type = DSYNC_BRAIN_SYNC_TYPE_FULL;
 		break;
+	case 'l':
+		ctx->lock = TRUE;
+		if (str_to_uint(optarg, &ctx->lock_timeout) < 0)
+			i_error("Invalid -l parameter: %s", optarg);
+		break;
 	case 'm':
 		ctx->mailbox = optarg;
 		break;
@@ -623,11 +684,6 @@
 		/* dsync wrapper detection flag */
 		legacy_dsync = TRUE;
 		break;
-	case 'l':
-		ctx->lock = TRUE;
-		if (str_to_uint(optarg, &ctx->lock_timeout) < 0)
-			i_error("Invalid -l parameter: %s", optarg);
-		break;
 	case 'r':
 		ctx->rawlog_path = optarg;
 		break;
@@ -642,7 +698,7 @@
 	struct dsync_cmd_context *ctx;
 
 	ctx = doveadm_mail_cmd_alloc(struct dsync_cmd_context);
-	ctx->ctx.getopt_args = "El:r:";
+	ctx->ctx.getopt_args = "Er:";
 	ctx->ctx.v.parse_arg = cmd_mailbox_dsync_server_parse_arg;
 	ctx->ctx.v.run = cmd_dsync_server_run;
 	ctx->sync_type = DSYNC_BRAIN_SYNC_TYPE_CHANGED;