dovecot: fsck won't fail anymore with "corrupted index", all pro...
dovecot at dovecot.org
dovecot at dovecot.org
Sat Sep 15 10:06:00 EEST 2007
details: http://hg.dovecot.org/dovecot/rev/29f427039e00
changeset: 6377:29f427039e00
user: Timo Sirainen <tss at iki.fi>
date: Sat Sep 15 10:05:56 2007 +0300
description:
fsck won't fail anymore with "corrupted index", all problems are fixed.
Added mail_index_fsck_locked().
diffstat:
8 files changed, 85 insertions(+), 45 deletions(-)
src/lib-index/mail-index-fsck.c | 69 +++++++++++++++++++++----------
src/lib-index/mail-index-map.c | 6 +-
src/lib-index/mail-index-private.h | 7 ++-
src/lib-index/mail-index-sync.c | 13 +----
src/lib-index/mail-index-view-private.h | 4 +
src/lib-index/mail-index-view-sync.c | 6 ++
src/lib-index/mail-index-view.c | 20 ++++++--
src/lib-index/mail-index.h | 5 --
diffs (truncated from 322 to 300 lines):
diff -r 9b9436231ce0 -r 29f427039e00 src/lib-index/mail-index-fsck.c
--- a/src/lib-index/mail-index-fsck.c Sat Sep 15 09:56:29 2007 +0300
+++ b/src/lib-index/mail-index-fsck.c Sat Sep 15 10:05:56 2007 +0300
@@ -24,17 +24,16 @@ static void mail_index_fsck_error(struct
map->hdr.field, hdr.field); \
}
-static int
-mail_index_fsck_map(struct mail_index *index, struct mail_index_map *map,
- bool *lock, const char **error_r)
+static int mail_index_fsck_map(struct mail_index *index,
+ struct mail_index_map *map, bool *lock)
{
struct mail_index_header hdr;
- const struct mail_index_record *rec;
+ struct mail_index_record *rec, *next_rec;
uint32_t file_seq;
uoff_t file_offset;
uint32_t i, last_uid;
-
- *error_r = NULL;
+ bool logged_unordered_uids = FALSE, logged_zero_uids = FALSE;
+ bool records_dropped = FALSE;
if (*lock) {
if (mail_transaction_log_sync_lock(index->log, &file_seq,
@@ -79,10 +78,31 @@ mail_index_fsck_map(struct mail_index *i
hdr.first_deleted_uid_lowwater = 0;
rec = map->rec_map->records; last_uid = 0;
- for (i = 0; i < map->rec_map->records_count; i++) {
+ for (i = 0; i < map->rec_map->records_count; ) {
+ next_rec = PTR_OFFSET(rec, hdr.record_size);
if (rec->uid <= last_uid) {
- *error_r = "Record UIDs are not ordered";
- return 0;
+ /* log an error once, and skip this record */
+ if (rec->uid == 0) {
+ if (!logged_zero_uids) {
+ mail_index_fsck_error(index,
+ "Record UIDs have zeroes");
+ logged_zero_uids = TRUE;
+ }
+ } else {
+ if (!logged_unordered_uids) {
+ mail_index_fsck_error(index,
+ "Record UIDs unordered");
+ logged_unordered_uids = TRUE;
+ }
+ }
+ /* not the fastest way when we're skipping lots of
+ records, but this should happen rarely so don't
+ bother optimizing. */
+ memmove(rec, next_rec, hdr.record_size *
+ (map->rec_map->records_count - i - 1));
+ map->rec_map->records_count--;
+ records_dropped = TRUE;
+ continue;
}
hdr.messages_count++;
@@ -99,7 +119,13 @@ mail_index_fsck_map(struct mail_index *i
hdr.first_deleted_uid_lowwater = rec->uid;
last_uid = rec->uid;
- rec = CONST_PTR_OFFSET(rec, hdr.record_size);
+ rec = next_rec;
+ i++;
+ }
+
+ if (records_dropped) {
+ /* all existing views are broken now */
+ index->inconsistency_id++;
}
if (hdr.next_uid <= last_uid) {
@@ -134,12 +160,11 @@ mail_index_fsck_map(struct mail_index *i
CHECK(first_recent_uid, !=);
map->hdr = hdr;
- return 1;
+ return 0;
}
int mail_index_fsck(struct mail_index *index)
{
- const char *error = NULL;
struct mail_index_map *map;
bool lock = !index->log_locked;
int ret;
@@ -150,22 +175,24 @@ int mail_index_fsck(struct mail_index *i
mail_index_unmap(&index->map);
index->map = map;
- ret = mail_index_fsck_map(index, map, &lock, &error);
- if (ret > 0) {
+ ret = mail_index_fsck_map(index, map, &lock);
+ if (ret == 0) {
map->write_base_header = TRUE;
map->write_atomic = TRUE;
mail_index_write(index, FALSE);
}
- if (error != NULL) {
- mail_index_set_error(index, "Corrupted index file %s: %s",
- index->filepath, error);
- }
- if (ret == 0)
- mail_index_mark_corrupted(index);
-
if (lock)
mail_transaction_log_sync_unlock(index->log);
return ret;
}
+
+void mail_index_fsck_locked(struct mail_index *index)
+{
+ int ret;
+
+ i_assert(index->log_locked);
+ ret = mail_index_fsck(index);
+ i_assert(ret == 0);
+}
diff -r 9b9436231ce0 -r 29f427039e00 src/lib-index/mail-index-map.c
--- a/src/lib-index/mail-index-map.c Sat Sep 15 09:56:29 2007 +0300
+++ b/src/lib-index/mail-index-map.c Sat Sep 15 10:05:56 2007 +0300
@@ -685,7 +685,7 @@ static int mail_index_map_latest_file(st
mail_index_unlock(index, &lock_id);
}
- for (try = 0; ret > 0 && try < 2; try++) {
+ for (try = 0; ret > 0; try++) {
/* make sure the header is ok before using this mapping */
ret = mail_index_map_check_header(new_map);
if (ret > 0) {
@@ -694,13 +694,13 @@ static int mail_index_map_latest_file(st
else if (mail_index_map_parse_keywords(new_map) < 0)
ret = 0;
}
- if (ret != 0)
+ if (ret != 0 || try == 2)
break;
/* fsck and try again */
old_map = index->map;
index->map = new_map;
- ret = mail_index_fsck(index);
+ ret = mail_index_fsck(index) < 0 ? -1 : 1;
/* fsck cloned the map, so we'll have to update it */
mail_index_unmap(&new_map);
diff -r 9b9436231ce0 -r 29f427039e00 src/lib-index/mail-index-private.h
--- a/src/lib-index/mail-index-private.h Sat Sep 15 09:56:29 2007 +0300
+++ b/src/lib-index/mail-index-private.h Sat Sep 15 10:05:56 2007 +0300
@@ -169,6 +169,8 @@ struct mail_index {
struct mail_index_map *map;
uint32_t indexid;
+ unsigned int inconsistency_id;
+
/* last_read_log_file_* contains the seq/offsets we last read from
the main index file's headers. these are used to figure out when
the main index file should be updated, and if we can update it
@@ -260,8 +262,7 @@ struct mail_index_map *mail_index_map_al
If we mmap()ed the index file, the map is returned locked.
- Returns 1 = ok, 0 = corrupted, -1 = error. If non-fatal problems were found,
- 1 is returned but index->fsck=TRUE is set. */
+ Returns 1 = ok, 0 = corrupted, -1 = error. */
int mail_index_map(struct mail_index *index,
enum mail_index_sync_handler_type type);
/* Unreference given mapping and unmap it if it's dropped to zero. */
@@ -291,6 +292,8 @@ void mail_index_view_transaction_ref(str
void mail_index_view_transaction_ref(struct mail_index_view *view);
void mail_index_view_transaction_unref(struct mail_index_view *view);
+void mail_index_fsck_locked(struct mail_index *index);
+
int mail_index_set_error(struct mail_index *index, const char *fmt, ...)
__attr_format__(2, 3);
/* "%s failed with index file %s: %m" */
diff -r 9b9436231ce0 -r 29f427039e00 src/lib-index/mail-index-sync.c
--- a/src/lib-index/mail-index-sync.c Sat Sep 15 09:56:29 2007 +0300
+++ b/src/lib-index/mail-index-sync.c Sat Sep 15 10:05:56 2007 +0300
@@ -335,10 +335,11 @@ int mail_index_sync_begin_to(struct mail
transaction log except for expunges. They're synced in
mail_index_sync_commit(). */
if ((ret = mail_index_map(index, MAIL_INDEX_SYNC_HANDLER_HEAD)) <= 0) {
- if (ret == 0 || mail_index_fsck(index) <= 0) {
+ if (ret == 0) {
mail_transaction_log_sync_unlock(index->log);
return -1;
}
+
/* let's try again */
if (mail_index_map(index, MAIL_INDEX_SYNC_HANDLER_HEAD) <= 0) {
mail_transaction_log_sync_unlock(index->log);
@@ -360,10 +361,7 @@ int mail_index_sync_begin_to(struct mail
mail_index_set_error(index,
"broken sync positions in index file %s",
index->filepath);
- if (mail_index_fsck(index) <= 0) {
- mail_transaction_log_sync_unlock(index->log);
- return -1;
- }
+ mail_index_fsck_locked(index);
}
ctx = i_new(struct mail_index_sync_ctx, 1);
@@ -385,11 +383,8 @@ int mail_index_sync_begin_to(struct mail
hdr->log_file_tail_offset) < 0) {
/* if a log file is missing, there's nothing we can do except
to skip over it. fix the problem with fsck and try again. */
+ mail_index_fsck_locked(index);
mail_index_sync_rollback(&ctx);
- if (mail_index_fsck(index) <= 0) {
- mail_transaction_log_sync_unlock(index->log);
- return -1;
- }
return mail_index_sync_begin_to(index, ctx_r, view_r, trans_r,
log_file_seq, log_file_offset,
flags);
diff -r 9b9436231ce0 -r 29f427039e00 src/lib-index/mail-index-view-private.h
--- a/src/lib-index/mail-index-view-private.h Sat Sep 15 09:56:29 2007 +0300
+++ b/src/lib-index/mail-index-view-private.h Sat Sep 15 10:05:56 2007 +0300
@@ -48,7 +48,9 @@ struct mail_index_view {
struct mail_index *index;
struct mail_transaction_log_view *log_view;
- unsigned int indexid;
+ uint32_t indexid;
+ unsigned int inconsistency_id;
+
struct mail_index_map *map;
/* After syncing view, map is replaced with sync_new_map. */
struct mail_index_map *sync_new_map;
diff -r 9b9436231ce0 -r 29f427039e00 src/lib-index/mail-index-view-sync.c
--- a/src/lib-index/mail-index-view-sync.c Sat Sep 15 09:56:29 2007 +0300
+++ b/src/lib-index/mail-index-view-sync.c Sat Sep 15 10:05:56 2007 +0300
@@ -266,6 +266,12 @@ int mail_index_view_sync_begin(struct ma
i_assert(!view->syncing);
i_assert(view->transactions == 0);
+
+ if (mail_index_view_is_inconsistent(view)) {
+ mail_index_set_error(view->index, "%s view is inconsistent",
+ view->index->filepath);
+ return -1;
+ }
sync_expunges = (flags & MAIL_INDEX_VIEW_SYNC_FLAG_NOEXPUNGES) == 0;
if (sync_expunges) {
diff -r 9b9436231ce0 -r 29f427039e00 src/lib-index/mail-index-view.c
--- a/src/lib-index/mail-index-view.c Sat Sep 15 09:56:29 2007 +0300
+++ b/src/lib-index/mail-index-view.c Sat Sep 15 10:05:56 2007 +0300
@@ -56,7 +56,8 @@ static void _view_close(struct mail_inde
bool mail_index_view_is_inconsistent(struct mail_index_view *view)
{
- if (view->index->indexid != view->indexid)
+ if (view->index->indexid != view->indexid ||
+ view->index->inconsistency_id != view->inconsistency_id)
view->inconsistent = TRUE;
return view->inconsistent;
}
@@ -132,6 +133,7 @@ _view_lookup_full(struct mail_index_view
_view_lookup_full(struct mail_index_view *view, uint32_t seq,
struct mail_index_map **map_r, bool *expunged_r)
{
+ static struct mail_index_record broken_rec;
struct mail_index_map *map;
const struct mail_index_record *rec, *head_rec;
@@ -140,13 +142,18 @@ _view_lookup_full(struct mail_index_view
/* look up the record */
rec = MAIL_INDEX_MAP_IDX(view->map, seq-1);
if (rec->uid == 0) {
- mail_index_set_error(view->index, "Corrupted Index file %s: "
- "Record [%u].uid=0", view->index->filepath, seq);
- mail_index_mark_corrupted(view->index);
-
+ if (!view->inconsistent) {
+ mail_index_set_error(view->index,
+ "Corrupted Index file %s: Record [%u].uid=0",
+ view->index->filepath, seq);
+ (void)mail_index_fsck(view->index);
+ view->inconsistent = TRUE;
+ }
+
+ /* we'll need to return something so the caller doesn't crash */
*map_r = view->map;
*expunged_r = TRUE;
- return rec;
+ return &broken_rec;
}
if (view->map == view->index->map) {
/* view's mapping is latest. we can use it directly. */
@@ -610,6 +617,7 @@ mail_index_view_open_with_map(struct mai
More information about the dovecot-cvs
mailing list