[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