[Dovecot] readdir and rename don't mix; patch included
Mike Abbott
michael.abbott at apple.com
Wed Jul 8 04:20:37 EEST 2009
Enclosed please find a patch to dovecot-1.1.16 that fixes a common
problem we see under load on Mac OS X and HFS+.
The symptom is that sometimes readdir() returns EINVAL. The problem
is that readdir() and rename() don't mix well, and maildir_scan_dir()
renames messages from new/ to cur/. The solution I chose is just to
retry scanning the directory, since code to rescan is already
present. An alternative solution would be to read the entire
directory first, then process the contents; that is, to do all the
readdirs before any renames.
The patch is like Apple's previous ones, all tagged with /*APPLE*/ and
formatted to simplify our merges. Please reformat it as you desire.
It should also apply easily to 1.2.0.
--- dovecot-1.1.16/src/lib-storage/index/maildir/maildir-sync.c
2009-05-20 16:42:49.000000000 -0500
+++ dovecot/src/lib-storage/index/maildir/maildir-sync.c 2009-07-07
19:50:37.000000000 -0500
@@ -354,7 +354,8 @@
return -1;
}
-static int maildir_scan_dir(struct maildir_sync_context *ctx, bool
new_dir)
+static int maildir_scan_dir(struct maildir_sync_context *ctx, bool
new_dir,
+ bool final) /* APPLE */
{
struct mail_storage *storage = &ctx->mbox->storage->storage;
const char *path;
@@ -486,6 +487,11 @@
}
}
+ /* APPLE - rename can cause readdir to fail with EINVAL; force
+ quiet rescan unless this is the final such rescan already */
+ if (errno == EINVAL && move_count && !final)
+ move_count = MAILDIR_RENAME_RESCAN_COUNT + 1;
+ else /* APPLE reduce code deltas */
if (errno != 0) {
mail_storage_set_critical(storage,
"readdir(%s) failed: %m", path);
@@ -772,7 +778,8 @@
that new/ dir is checked as well. it's a good idea anyway. */
unsigned int count = 0;
- while ((ret = maildir_scan_dir(ctx, TRUE)) > 0) {
+ while ((ret = maildir_scan_dir(ctx, TRUE,
+ count == MAILDIR_SCAN_DIR_MAX_COUNT)) > 0) { /* APPLE */
/* rename()d at least some files, which might have
caused some other files to be missed. check again
(see MAILDIR_RENAME_RESCAN_COUNT). */
@@ -783,7 +790,8 @@
return -1;
if (cur_changed) {
- if (maildir_scan_dir(ctx, FALSE) < 0)
+ if (maildir_scan_dir(ctx, FALSE,
+ FALSE) < 0) /* APPLE */
return -1;
}
More information about the dovecot
mailing list