dovecot-2.2: lib-index: If header is corrupted after syncing, lo...

dovecot at dovecot.org dovecot at dovecot.org
Sun May 10 09:31:47 UTC 2015


details:   http://hg.dovecot.org/dovecot-2.2/rev/69630e6048fd
changeset: 18627:69630e6048fd
user:      Timo Sirainen <tss at iki.fi>
date:      Sun May 10 12:28:09 2015 +0300
description:
lib-index: If header is corrupted after syncing, log the reason why.

diffstat:

 src/lib-index/mail-index-map-hdr.c     |  102 ++++++++++++++++++++++----------
 src/lib-index/mail-index-map-read.c    |   22 +++++-
 src/lib-index/mail-index-private.h     |   10 ++-
 src/lib-index/mail-index-sync-update.c |    8 +-
 4 files changed, 100 insertions(+), 42 deletions(-)

diffs (299 lines):

diff -r fddd3dbdf987 -r 69630e6048fd src/lib-index/mail-index-map-hdr.c
--- a/src/lib-index/mail-index-map-hdr.c	Sun May 10 12:05:06 2015 +0300
+++ b/src/lib-index/mail-index-map-hdr.c	Sun May 10 12:28:09 2015 +0300
@@ -167,7 +167,7 @@
 
 bool mail_index_check_header_compat(struct mail_index *index,
 				    const struct mail_index_header *hdr,
-				    uoff_t file_size)
+				    uoff_t file_size, const char **error_r)
 {
         enum mail_index_header_compat_flags compat_flags = 0;
 
@@ -176,35 +176,34 @@
 #endif
 
 	if (hdr->major_version != MAIL_INDEX_MAJOR_VERSION) {
-		/* major version change - handle silently(?) */
+		/* major version change */
+		*error_r = t_strdup_printf("Major version changed (%u != %u)",
+			hdr->major_version, MAIL_INDEX_MAJOR_VERSION);
 		return FALSE;
 	}
 	if ((hdr->flags & MAIL_INDEX_HDR_FLAG_CORRUPTED) != 0) {
 		/* we've already complained about it */
+		*error_r = "Header's corrupted flag is set";
 		return FALSE;
 	}
 
 	if (hdr->compat_flags != compat_flags) {
 		/* architecture change */
-		mail_index_set_error(index, "Rebuilding index file %s: "
-				     "CPU architecture changed",
-				     index->filepath);
+		*error_r = "CPU architecture changed";
 		return FALSE;
 	}
 
 	if (hdr->base_header_size < MAIL_INDEX_HEADER_MIN_SIZE ||
 	    hdr->header_size < hdr->base_header_size) {
-		mail_index_set_error(index, "Corrupted index file %s: "
-				     "Corrupted header sizes (base %u, full %u)",
-				     index->filepath, hdr->base_header_size,
-				     hdr->header_size);
+		*error_r = t_strdup_printf(
+			"Corrupted header sizes (base %u, full %u)",
+			hdr->base_header_size, hdr->header_size);
 		return FALSE;
 	}
 	if (hdr->header_size > file_size) {
-		mail_index_set_error(index, "Corrupted index file %s: "
-				     "Corrupted header size (%u > %"PRIuUOFF_T")",
-				     index->filepath, hdr->header_size,
-				     file_size);
+		*error_r = t_strdup_printf(
+			"Header size is larger than file (%u > %"PRIuUOFF_T")",
+			hdr->header_size, file_size);
 		return FALSE;
 	}
 
@@ -218,7 +217,6 @@
 		index->indexid = hdr->indexid;
 		mail_transaction_log_indexid_changed(index->log);
 	}
-
 	return TRUE;
 }
 
@@ -233,33 +231,51 @@
 	}
 }
 
-int mail_index_map_check_header(struct mail_index_map *map)
+int mail_index_map_check_header(struct mail_index_map *map,
+				const char **error_r)
 {
 	struct mail_index *index = map->index;
 	const struct mail_index_header *hdr = &map->hdr;
 
-	if (!mail_index_check_header_compat(index, hdr, (uoff_t)-1))
+	if (!mail_index_check_header_compat(index, hdr, (uoff_t)-1, error_r))
 		return -1;
 
 	/* following some extra checks that only take a bit of CPU */
 	if (hdr->record_size < sizeof(struct mail_index_record)) {
-		mail_index_set_error(index, "Corrupted index file %s: "
-				     "record_size too small: %u < %"PRIuSIZE_T,
-				     index->filepath, hdr->record_size,
-				     sizeof(struct mail_index_record));
+		*error_r = t_strdup_printf(
+			"record_size too small (%u < %"PRIuSIZE_T")",
+			hdr->record_size, sizeof(struct mail_index_record));
 		return -1;
 	}
 
-	if (hdr->uid_validity == 0 && hdr->next_uid != 1)
+	if (hdr->uid_validity == 0 && hdr->next_uid != 1) {
+		*error_r = t_strdup_printf(
+			"uidvalidity=0, but next_uid=%u", hdr->next_uid);
 		return 0;
-	if (hdr->next_uid == 0)
+	}
+	if (hdr->next_uid == 0) {
+		*error_r = "next_uid=0";
 		return 0;
-	if (hdr->messages_count > map->rec_map->records_count)
+	}
+	if (hdr->messages_count > map->rec_map->records_count) {
+		*error_r = t_strdup_printf(
+			"messages_count is higher in header than record map (%u > %u)",
+			hdr->messages_count, map->rec_map->records_count);
 		return 0;
+	}
 
-	if (hdr->seen_messages_count > hdr->messages_count ||
-	    hdr->deleted_messages_count > hdr->messages_count)
+	if (hdr->seen_messages_count > hdr->messages_count) {
+		*error_r = t_strdup_printf(
+			"seen_messages_count %u > messages_count %u",
+			hdr->seen_messages_count, hdr->messages_count);
 		return 0;
+	}
+	if (hdr->deleted_messages_count > hdr->messages_count) {
+		*error_r = t_strdup_printf(
+			"deleted_messages_count %u > messages_count %u",
+			hdr->deleted_messages_count, hdr->messages_count);
+		return 0;
+	}
 	switch (hdr->minor_version) {
 	case 0:
 		/* upgrade silently from v1.0 */
@@ -279,11 +295,28 @@
 		map->hdr.unused_old_sync_size = 0;
 		map->hdr.unused_old_sync_stamp = 0;
 	}
-	if (hdr->first_recent_uid == 0 ||
-	    hdr->first_recent_uid > hdr->next_uid ||
-	    hdr->first_unseen_uid_lowwater > hdr->next_uid ||
-	    hdr->first_deleted_uid_lowwater > hdr->next_uid)
+	if (hdr->first_recent_uid == 0) {
+		*error_r = "first_recent_uid=0";
 		return 0;
+	}
+	if (hdr->first_recent_uid > hdr->next_uid) {
+		*error_r = t_strdup_printf(
+			"first_recent_uid %u > next_uid %u",
+			hdr->first_recent_uid, hdr->next_uid);
+		return 0;
+	}
+	if (hdr->first_unseen_uid_lowwater > hdr->next_uid) {
+		*error_r = t_strdup_printf(
+			"first_unseen_uid_lowwater %u > next_uid %u",
+			hdr->first_unseen_uid_lowwater, hdr->next_uid);
+		return 0;
+	}
+	if (hdr->first_deleted_uid_lowwater > hdr->next_uid) {
+		*error_r = t_strdup_printf(
+			"first_deleted_uid_lowwater %u > next_uid %u",
+			hdr->first_deleted_uid_lowwater, hdr->next_uid);
+		return 0;
+	}
 
 	if (hdr->messages_count > 0) {
 		/* last message's UID must be smaller than next_uid.
@@ -291,9 +324,16 @@
 		const struct mail_index_record *rec;
 
 		rec = MAIL_INDEX_REC_AT_SEQ(map, hdr->messages_count);
-		if (rec->uid == 0 || rec->uid >= hdr->next_uid)
+		if (rec->uid == 0) {
+			*error_r = "last message has uid=0";
+			return -1;
+		}
+		if (rec->uid >= hdr->next_uid) {
+			*error_r = t_strdup_printf(
+				"last message uid %u >= next_uid %u",
+				rec->uid, hdr->next_uid);
 			return 0;
+		}
 	}
-
 	return 1;
 }
diff -r fddd3dbdf987 -r 69630e6048fd src/lib-index/mail-index-map-read.c
--- a/src/lib-index/mail-index-map-read.c	Sun May 10 12:05:06 2015 +0300
+++ b/src/lib-index/mail-index-map-read.c	Sun May 10 12:28:09 2015 +0300
@@ -31,6 +31,7 @@
 	struct mail_index *index = map->index;
 	struct mail_index_record_map *rec_map = map->rec_map;
 	const struct mail_index_header *hdr;
+	const char *error;
 
 	i_assert(rec_map->mmap_base == NULL);
 
@@ -66,9 +67,11 @@
 		return 0;
 	}
 
-	if (!mail_index_check_header_compat(index, hdr, rec_map->mmap_size)) {
+	if (!mail_index_check_header_compat(index, hdr, rec_map->mmap_size, &error)) {
 		/* Can't use this file */
-		return 0;
+		mail_index_set_error(index, "Corrupted index file %s: %s",
+				     index->filepath, error);
+		return -1;
 	}
 
 	rec_map->mmap_used_size = hdr->header_size +
@@ -126,6 +129,7 @@
 	struct mail_index *index = map->index;
 	const struct mail_index_header *hdr;
 	unsigned char read_buf[IO_BLOCK_SIZE];
+	const char *error;
 	const void *buf;
 	void *data = NULL;
 	ssize_t ret;
@@ -146,9 +150,11 @@
 
 	if (ret >= 0 && pos >= MAIL_INDEX_HEADER_MIN_SIZE &&
 	    (ret > 0 || pos >= hdr->base_header_size)) {
-		if (!mail_index_check_header_compat(index, hdr, file_size)) {
+		if (!mail_index_check_header_compat(index, hdr, file_size, &error)) {
 			/* Can't use this file */
-			return 0;
+			mail_index_set_error(index, "Corrupted index file %s: %s",
+					     index->filepath, error);
+			return -1;
 		}
 
 		initial_buf_pos = pos;
@@ -295,6 +301,7 @@
 	struct stat st;
 	uoff_t file_size;
 	bool use_mmap, unusable = FALSE;
+	const char *error;
 	int ret, try;
 
 	ret = mail_index_reopen_if_changed(index);
@@ -339,7 +346,12 @@
 
 	for (try = 0; ret > 0; try++) {
 		/* make sure the header is ok before using this mapping */
-		ret = mail_index_map_check_header(new_map);
+		ret = mail_index_map_check_header(new_map, &error);
+		if (ret < 0) {
+			mail_index_set_error(index,
+				"Corrupted index file %s: %s",
+				index->filepath, error);
+		}
 		if (ret > 0) T_BEGIN {
 			if (mail_index_map_parse_extensions(new_map) < 0)
 				ret = 0;
diff -r fddd3dbdf987 -r 69630e6048fd src/lib-index/mail-index-private.h
--- a/src/lib-index/mail-index-private.h	Sun May 10 12:05:06 2015 +0300
+++ b/src/lib-index/mail-index-private.h	Sun May 10 12:28:09 2015 +0300
@@ -307,10 +307,16 @@
 				     uint32_t *first_seq_r,
 				     uint32_t *last_seq_r);
 
-int mail_index_map_check_header(struct mail_index_map *map);
+/* Returns 1 on success, 0 on non-critical errors we want to silently fix,
+   -1 if map isn't usable. The caller is responsible for logging the errors
+   if -1 is returned. */
+int mail_index_map_check_header(struct mail_index_map *map,
+				const char **error_r);
+/* Returns 1 if header is usable, 0 or -1 if not. The caller should log an
+   error if -1 is returned, but not if 0 is returned. */
 bool mail_index_check_header_compat(struct mail_index *index,
 				    const struct mail_index_header *hdr,
-				    uoff_t file_size);
+				    uoff_t file_size, const char **error_r);
 int mail_index_map_parse_extensions(struct mail_index_map *map);
 int mail_index_map_parse_keywords(struct mail_index_map *map);
 
diff -r fddd3dbdf987 -r 69630e6048fd src/lib-index/mail-index-sync-update.c
--- a/src/lib-index/mail-index-sync-update.c	Sun May 10 12:05:06 2015 +0300
+++ b/src/lib-index/mail-index-sync-update.c	Sun May 10 12:28:09 2015 +0300
@@ -911,7 +911,7 @@
 	const void *tdata;
 	uint32_t prev_seq;
 	uoff_t start_offset, prev_offset;
-	const char *reason;
+	const char *reason, *error;
 	int ret;
 	bool had_dirty, reset;
 
@@ -1075,10 +1075,10 @@
 
 	i_assert(index->map == map || type == MAIL_INDEX_SYNC_HANDLER_VIEW);
 
-	if (mail_index_map_check_header(map) <= 0) {
+	if (mail_index_map_check_header(map, &error) <= 0) {
 		mail_index_set_error(index,
-			"Synchronization corrupted index header: %s",
-			index->filepath);
+			"Synchronization corrupted index header %s: %s",
+			index->filepath, error);
 		(void)mail_index_fsck(index);
 		map = index->map;
 	} else if (sync_map_ctx.errors) {


More information about the dovecot-cvs mailing list