From a81c40fb46f6d447c1edc858be905e6626dae97a Mon Sep 17 00:00:00 2001 From: Timo Sirainen Date: Thu, 24 Nov 2016 17:52:01 +0200 Subject: [PATCH] lib-storge: Call mail_storage.list_index_corrupted() when needed The callback is called whenever mailbox list index appears to be corrupted with LAYOUT=index. The storage is responsible for adding to the index any mailboxes that are missing. --- .../list/mailbox-list-index-notify.c | 3 ++ .../list/mailbox-list-index-sync.c | 10 ++++ src/lib-storage/list/mailbox-list-index.c | 52 ++++++++++++++++++- src/lib-storage/list/mailbox-list-index.h | 4 ++ 4 files changed, 68 insertions(+), 1 deletion(-) diff --git a/src/lib-storage/list/mailbox-list-index-notify.c b/src/lib-storage/list/mailbox-list-index-notify.c index d19982142e..952d8f433f 100644 --- a/src/lib-storage/list/mailbox-list-index-notify.c +++ b/src/lib-storage/list/mailbox-list-index-notify.c @@ -778,6 +778,9 @@ int mailbox_list_index_notify_next(struct mailbox_list_notify *notify, if (!inotify->initialized) mailbox_list_index_notify_read_init(inotify); + if (mailbox_list_index_handle_corruption(notify->list) < 0) + return -1; + while (mailbox_list_index_notify_try_next(inotify)) { if ((inotify->notify_rec.events & inotify->notify.mask) != 0) { *rec_r = &inotify->notify_rec; diff --git a/src/lib-storage/list/mailbox-list-index-sync.c b/src/lib-storage/list/mailbox-list-index-sync.c index 411bdf9415..5eedd4f2d7 100644 --- a/src/lib-storage/list/mailbox-list-index-sync.c +++ b/src/lib-storage/list/mailbox-list-index-sync.c @@ -230,9 +230,11 @@ int mailbox_list_index_sync_begin(struct mailbox_list *list, struct mail_index_view *view; struct mail_index_transaction *trans; const struct mail_index_header *hdr; + bool fix_attempted = FALSE; i_assert(!ilist->syncing); +retry: if (mailbox_list_index_index_open(list) < 0) return -1; @@ -248,6 +250,14 @@ int mailbox_list_index_sync_begin(struct mailbox_list *list, mail_index_sync_rollback(&index_sync_ctx); return -1; } + if (ilist->call_corruption_callback && !fix_attempted) { + /* unlock and resync the index */ + mail_index_sync_rollback(&index_sync_ctx); + if (mailbox_list_index_handle_corruption(list) < 0) + return -1; + fix_attempted = TRUE; + goto retry; + } sync_ctx = i_new(struct mailbox_list_index_sync_context, 1); sync_ctx->list = list; diff --git a/src/lib-storage/list/mailbox-list-index.c b/src/lib-storage/list/mailbox-list-index.c index a56603c058..f27972e32c 100644 --- a/src/lib-storage/list/mailbox-list-index.c +++ b/src/lib-storage/list/mailbox-list-index.c @@ -413,6 +413,8 @@ int mailbox_list_index_parse(struct mailbox_list *list, /* nothing changed */ return 0; } + if ((hdr->flags & MAIL_INDEX_HDR_FLAG_FSCKD) != 0) + ilist->call_corruption_callback = TRUE; mailbox_list_index_reset(ilist); ilist->sync_log_file_seq = hdr->log_file_seq; @@ -425,6 +427,7 @@ int mailbox_list_index_parse(struct mailbox_list *list, mail_index_mark_corrupted(ilist->index); return -1; } + ilist->call_corruption_callback = TRUE; ilist->corrupted_names_or_parents = TRUE; } if (mailbox_list_index_parse_records(ilist, view, &error) < 0) { @@ -437,6 +440,7 @@ int mailbox_list_index_parse(struct mailbox_list *list, } /* FIXME: find any missing mailboxes, add them and write the index back. */ + ilist->call_corruption_callback = TRUE; ilist->corrupted_names_or_parents = TRUE; } return 0; @@ -500,7 +504,8 @@ int mailbox_list_index_refresh_force(struct mailbox_list *list) ret = mailbox_list_index_parse(list, view, FALSE); } mail_index_view_close(&view); - return ret; + + return mailbox_list_index_handle_corruption(list); } static void mailbox_list_index_refresh_timeout(struct mailbox_list *list) @@ -548,6 +553,51 @@ void mailbox_list_index_refresh_later(struct mailbox_list *list) } } +int mailbox_list_index_handle_corruption(struct mailbox_list *list) +{ + struct mailbox_list_index *ilist = INDEX_LIST_CONTEXT(list); + struct mail_storage *const *storagep; + int ret = 0; + + if (!ilist->call_corruption_callback) + return 0; + + /* make sure we don't recurse */ + if (ilist->handling_corruption) + return 0; + ilist->handling_corruption = TRUE; + + array_foreach(&list->ns->all_storages, storagep) { + if ((*storagep)->v.list_index_corrupted != NULL) { + if ((*storagep)->v.list_index_corrupted(*storagep) < 0) + ret = -1; + else { + /* FIXME: implement a generic handler that + just lists mailbox directories in filesystem + and adds the missing ones to the index. */ + } + } + } + if (ret == 0) + ret = mailbox_list_index_set_uncorrupted(list); + ilist->handling_corruption = FALSE; + return ret; +} + +int mailbox_list_index_set_uncorrupted(struct mailbox_list *list) +{ + struct mailbox_list_index *ilist = INDEX_LIST_CONTEXT(list); + struct mailbox_list_index_sync_context *sync_ctx; + + ilist->call_corruption_callback = FALSE; + + if (mailbox_list_index_sync_begin(list, &sync_ctx) < 0) + return -1; + + mail_index_unset_fscked(sync_ctx->trans); + return mailbox_list_index_sync_end(&sync_ctx, TRUE); +} + static void mailbox_list_index_deinit(struct mailbox_list *list) { struct mailbox_list_index *ilist = INDEX_LIST_CONTEXT(list); diff --git a/src/lib-storage/list/mailbox-list-index.h b/src/lib-storage/list/mailbox-list-index.h index 3697d67b83..e1dbdeb3a9 100644 --- a/src/lib-storage/list/mailbox-list-index.h +++ b/src/lib-storage/list/mailbox-list-index.h @@ -117,6 +117,8 @@ struct mailbox_list_index { unsigned int has_backing_store:1; unsigned int index_last_check_changed:1; unsigned int corrupted_names_or_parents:1; + unsigned int handling_corruption:1; + unsigned int call_corruption_callback:1; }; struct mailbox_list_index_iterate_context { @@ -156,6 +158,8 @@ int mailbox_list_index_refresh(struct mailbox_list *list); /* Refresh the index regardless of when the last refresh was done. */ int mailbox_list_index_refresh_force(struct mailbox_list *list); void mailbox_list_index_refresh_later(struct mailbox_list *list); +int mailbox_list_index_handle_corruption(struct mailbox_list *list); +int mailbox_list_index_set_uncorrupted(struct mailbox_list *list); struct mailbox_list_index_node * mailbox_list_index_node_find_sibling(struct mailbox_list_index_node *node,