Mercurial > dovecot > core-2.2
changeset 12388:952dc335eb75
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.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Thu, 04 Nov 2010 17:50:42 +0000 |
parents | ed94f6d615ef |
children | 16abe905f897 |
files | src/lib-fs/fs-posix.c |
diffstat | 1 files changed, 20 insertions(+), 6 deletions(-) [+] |
line wrap: on
line diff
--- 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 0; + return 1; dir = t_strdup_until(path, fname); - if (mkdir_parents(dir, 0700) < 0 && errno != EEXIST) { + if (mkdir_parents(dir, 0700) == 0) + return 0; + 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);