]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-storage: Fixed some race condition crashes with LAYOUT=index
authorTimo Sirainen <tss@iki.fi>
Tue, 7 Oct 2014 18:35:44 +0000 (21:35 +0300)
committerTimo Sirainen <tss@iki.fi>
Tue, 7 Oct 2014 18:35:44 +0000 (21:35 +0300)
src/lib-storage/list/mailbox-list-index-backend.c
src/lib-storage/list/mailbox-list-index.c
src/lib-storage/list/mailbox-list-index.h

index 5b39f242f961095481ab72e696ea0282f3010912..293d5fb43b4c1326cbb7abfc35bf9074a45f7333 100644 (file)
@@ -66,8 +66,8 @@ static char index_list_get_hierarchy_sep(struct mailbox_list *list ATTR_UNUSED)
 }
 
 static int
-index_list_get_node(struct index_mailbox_list *list, const char *name,
-                   struct mailbox_list_index_node **node_r)
+index_list_get_refreshed_node(struct index_mailbox_list *list, const char *name,
+                             struct mailbox_list_index_node **node_r)
 {
        struct mailbox_list_index_node *node;
 
@@ -81,6 +81,33 @@ index_list_get_node(struct index_mailbox_list *list, const char *name,
        return 1;
 }
 
+static int
+index_list_get_refreshed_node_seq(struct index_mailbox_list *list,
+                                 struct mail_index_view *view,
+                                 const char *name,
+                                 struct mailbox_list_index_node **node_r,
+                                 uint32_t *seq_r)
+{
+       unsigned int i;
+       int ret;
+
+       *node_r = NULL;
+       *seq_r = 0;
+
+       for (i = 0; i < 2; i++) {
+               if ((ret = index_list_get_refreshed_node(list, name, node_r)) <= 0)
+                       return ret;
+               if (mail_index_lookup_seq(view, (*node_r)->uid, seq_r))
+                       return 1;
+               /* mailbox was just expunged. refreshing should notice it. */
+               if (mailbox_list_index_refresh_force(&list->list) < 0)
+                       return -1;
+       }
+       i_panic("mailbox list index: refreshing doesn't lose expunged uid=%u",
+               (*node_r)->uid);
+       return -1;
+}
+
 static const char *
 index_get_guid_path(struct mailbox_list *_list, const char *root_dir,
                    const guid_128_t mailbox_guid)
@@ -124,22 +151,35 @@ index_list_get_path(struct mailbox_list *_list, const char *name,
        if (!mailbox_list_set_get_root_path(&_list->set, type, &root_dir))
                return 0;
 
-       if ((ret = index_list_get_node(list, name, &node)) <= 0) {
-               if (ret == 0) {
-                       mailbox_list_set_error(_list, MAIL_ERROR_NOTFOUND,
-                               T_MAIL_ERR_MAILBOX_NOT_FOUND(name));
+       if (ilist->sync_ctx != NULL) {
+               /* we could get here during sync from
+                  index_list_mailbox_create_selectable() */
+               view = ilist->sync_ctx->view;
+               node = mailbox_list_index_lookup(&list->list, name);
+               if (node == NULL) {
+                       seq = 0;
+                       ret = 0;
+               } else if (mail_index_lookup_seq(view, node->uid, &seq)) {
+                       ret = 1;
+               } else {
+                       i_panic("mailbox list index: lost uid=%u", node->uid);
+               }
+       } else {
+               view = mail_index_view_open(ilist->index);
+               ret = index_list_get_refreshed_node_seq(list, view, name, &node, &seq);
+               if (ret < 0) {
+                       mail_index_view_close(&view);
+                       return -1;
                }
-               return -1;
        }
-       /* we could get here during sync from
-          index_list_mailbox_create_selectable() */
-       view = ilist->sync_ctx == NULL ? mail_index_view_open(ilist->index) :
-               ilist->sync_ctx->view;
-       if (!mail_index_lookup_seq(view, node->uid, &seq))
-               i_panic("mailbox list index: lost uid=%u", node->uid);
-       if (!mailbox_list_index_status(_list, view, seq, 0,
-                                      &status, mailbox_guid) ||
-           guid_128_is_empty(mailbox_guid)) {
+       i_assert(ret == 0 || seq != 0);
+       if (ret == 0) {
+               mailbox_list_set_error(_list, MAIL_ERROR_NOTFOUND,
+                                      T_MAIL_ERR_MAILBOX_NOT_FOUND(name));
+               ret = -1;
+       } else if (!mailbox_list_index_status(_list, view, seq, 0,
+                                             &status, mailbox_guid) ||
+                  guid_128_is_empty(mailbox_guid)) {
                mailbox_list_set_error(_list, MAIL_ERROR_NOTFOUND,
                                       T_MAIL_ERR_MAILBOX_NOT_FOUND(name));
                ret = -1;
@@ -188,7 +228,7 @@ index_list_node_exists(struct index_mailbox_list *list, const char *name,
 
        *existence_r = MAILBOX_EXISTENCE_NONE;
 
-       if ((ret = index_list_get_node(list, name, &node)) < 0)
+       if ((ret = index_list_get_refreshed_node(list, name, &node)) < 0)
                return -1;
        if (ret == 0)
                return 0;
@@ -435,16 +475,12 @@ index_list_delete_entry(struct index_mailbox_list *list, const char *name,
        const void *data;
        bool expunged;
        uint32_t seq;
-       int ret;
 
        if (mailbox_list_index_sync_begin(&list->list, &sync_ctx) < 0)
                return -1;
 
-       if ((ret = index_list_get_node(list, name, &node)) < 0) {
-               (void)mailbox_list_index_sync_end(&sync_ctx, FALSE);
-               return -1;
-       }
-       if (ret == 0) {
+       node = mailbox_list_index_lookup(&list->list, name);
+       if (node == NULL) {
                (void)mailbox_list_index_sync_end(&sync_ctx, FALSE);
                mailbox_list_set_error(&list->list, MAIL_ERROR_NOTFOUND,
                                       T_MAIL_ERR_MAILBOX_NOT_FOUND(name));
@@ -552,7 +588,6 @@ index_list_rename_mailbox(struct mailbox_list *_oldlist, const char *oldname,
        const void *data;
        bool created, expunged;
        uint32_t oldseq, newseq;
-       int ret;
 
        if (_oldlist != _newlist) {
                mailbox_list_set_error(_oldlist, MAIL_ERROR_NOTPOSSIBLE,
@@ -563,11 +598,8 @@ index_list_rename_mailbox(struct mailbox_list *_oldlist, const char *oldname,
        if (mailbox_list_index_sync_begin(&list->list, &sync_ctx) < 0)
                return -1;
 
-       if ((ret = index_list_get_node(list, oldname, &oldnode)) < 0) {
-               (void)mailbox_list_index_sync_end(&sync_ctx, FALSE);
-               return -1;
-       }
-       if (ret == 0) {
+       oldnode = mailbox_list_index_lookup(&list->list, oldname);
+       if (oldnode == NULL) {
                (void)mailbox_list_index_sync_end(&sync_ctx, FALSE);
                mailbox_list_set_error(&list->list, MAIL_ERROR_NOTFOUND,
                        T_MAIL_ERR_MAILBOX_NOT_FOUND(oldname));
index efd08e17d500d0588b6396bb1dc163ce6692cb02..4c243ee2b72ffbf984ae0fbdee32d7afeebffe80 100644 (file)
@@ -362,8 +362,6 @@ bool mailbox_list_index_need_refresh(struct mailbox_list_index *ilist,
 int mailbox_list_index_refresh(struct mailbox_list *list)
 {
        struct mailbox_list_index *ilist = INDEX_LIST_CONTEXT(list);
-       struct mail_index_view *view;
-       int ret;
 
        if (ilist->syncing)
                return 0;
@@ -376,6 +374,17 @@ int mailbox_list_index_refresh(struct mailbox_list *list)
                return 0;
        }
 
+       return mailbox_list_index_refresh_force(list);
+}
+
+int mailbox_list_index_refresh_force(struct mailbox_list *list)
+{
+       struct mailbox_list_index *ilist = INDEX_LIST_CONTEXT(list);
+       struct mail_index_view *view;
+       int ret;
+
+       i_assert(!ilist->syncing);
+
        ilist->last_refresh_timeval = ioloop_timeval;
        if (mailbox_list_index_index_open(list) < 0)
                return -1;
index 8b0b3cc1b5e052784346d66506a872eb490b2645..85aefbe40d6d9af9035ae1d923481f96066e7d8a 100644 (file)
@@ -142,7 +142,11 @@ void mailbox_list_index_node_unlink(struct mailbox_list_index *ilist,
 int mailbox_list_index_index_open(struct mailbox_list *list);
 bool mailbox_list_index_need_refresh(struct mailbox_list_index *ilist,
                                     struct mail_index_view *view);
+/* Refresh the index, but only if it hasn't been refreshed "recently"
+   (= within this same ioloop run) */
 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);
 
 struct mailbox_list_index_node *