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;
                }


Reply via email to