dovecot-2.0: lib-fs / posix: If create/link/rename fails with EN...

dovecot at dovecot.org dovecot at dovecot.org
Thu Nov 4 19:50:46 EET 2010


details:   http://hg.dovecot.org/dovecot-2.0/rev/952dc335eb75
changeset: 12388:952dc335eb75
user:      Timo Sirainen <tss at iki.fi>
date:      Thu Nov 04 17:50:42 2010 +0000
description:
lib-fs / posix: If create/link/rename fails with ENOENT, try creating parent dir multiple times.
This avoids random failures when the parent dir happens to be removed at
just the right time.

diffstat:

 src/lib-fs/fs-posix.c |  26 ++++++++++++++++++++------
 1 files changed, 20 insertions(+), 6 deletions(-)

diffs (90 lines):

diff -r ed94f6d615ef -r 952dc335eb75 src/lib-fs/fs-posix.c
--- a/src/lib-fs/fs-posix.c	Thu Nov 04 17:00:42 2010 +0000
+++ b/src/lib-fs/fs-posix.c	Thu Nov 04 17:50:42 2010 +0000
@@ -18,6 +18,7 @@
 #include <sys/stat.h>
 
 #define FS_POSIX_DOTLOCK_STALE_TIMEOUT_SECS (60*10)
+#define MAX_MKDIR_RETRY_COUNT 5
 
 enum fs_posix_lock_method {
 	FS_POSIX_LOCK_METHOD_FLOCK,
@@ -85,13 +86,16 @@
 
 	fname = strrchr(path, '/');
 	if (fname == NULL)
+		return 1;
+	dir = t_strdup_until(path, fname);
+	if (mkdir_parents(dir, 0700) == 0)
 		return 0;
-	dir = t_strdup_until(path, fname);
-	if (mkdir_parents(dir, 0700) < 0 && errno != EEXIST) {
+	else if (errno == EEXIST)
+		return 1;
+	else {
 		fs_set_error(fs, "mkdir_parents(%s) failed: %m", dir);
 		return -1;
 	}
-	return 0;
 }
 
 static int
@@ -101,6 +105,7 @@
 	struct fs *_fs = &fs->fs;
 	string_t *str = t_str_new(256);
 	const char *slash = strrchr(path, '/');
+	unsigned int try_count = 0;
 	int fd;
 
 	if (slash != NULL)
@@ -108,10 +113,13 @@
 	str_append(str, fs->temp_file_prefix);
 
 	fd = safe_mkstemp_hostpid(str, 0600, (uid_t)-1, (gid_t)-1);
-	if (fd == -1 && errno == ENOENT && (flags & FS_OPEN_FLAG_MKDIR) != 0) {
+	while (fd == -1 && errno == ENOENT &&
+	       try_count <= MAX_MKDIR_RETRY_COUNT &&
+	       (flags & FS_OPEN_FLAG_MKDIR) != 0) {
 		if (fs_posix_create_parent_dir(_fs, path) < 0)
 			return -1;
 		fd = safe_mkstemp_hostpid(str, 0600, (uid_t)-1, (gid_t)-1);
+		try_count++;
 	}
 	if (fd == -1) {
 		fs_set_error(_fs, "safe_mkstemp(%s) failed: %m", str_c(str));
@@ -454,13 +462,16 @@
 
 static int fs_posix_link(struct fs *fs, const char *src, const char *dest)
 {
+	unsigned int try_count = 0;
 	int ret;
 
 	ret = link(src, dest);
-	if (ret < 0 && errno == ENOENT) {
+	while (ret < 0 && errno == ENOENT &&
+	       try_count <= MAX_MKDIR_RETRY_COUNT) {
 		if (fs_posix_create_parent_dir(fs, dest) < 0)
 			return -1;
 		ret = link(src, dest);
+		try_count++;
 	}
 	if (ret < 0) {
 		fs_set_error(fs, "link(%s, %s) failed: %m", src, dest);
@@ -471,13 +482,16 @@
 
 static int fs_posix_rename(struct fs *fs, const char *src, const char *dest)
 {
+	unsigned int try_count = 0;
 	int ret;
 
 	ret = rename(src, dest);
-	if (ret < 0 && errno == ENOENT) {
+	while (ret < 0 && errno == ENOENT &&
+	       try_count <= MAX_MKDIR_RETRY_COUNT) {
 		if (fs_posix_create_parent_dir(fs, dest) < 0)
 			return -1;
 		ret = rename(src, dest);
+		try_count++;
 	}
 	if (ret < 0) {
 		fs_set_error(fs, "link(%s, %s) failed: %m", src, dest);


More information about the dovecot-cvs mailing list