]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
Added support for marking mailbox index deleted. Don't allow any changes after that.
authorTimo Sirainen <tss@iki.fi>
Sun, 7 Feb 2010 01:25:32 +0000 (03:25 +0200)
committerTimo Sirainen <tss@iki.fi>
Sun, 7 Feb 2010 01:25:32 +0000 (03:25 +0200)
This is going to help with race conditions when deleting mailboxes.

--HG--
branch : HEAD

20 files changed:
src/doveadm/doveadm-dump-log.c
src/lib-index/mail-index-private.h
src/lib-index/mail-index-sync-update.c
src/lib-index/mail-index-transaction-export.c
src/lib-index/mail-index-transaction-private.h
src/lib-index/mail-index-transaction-update.c
src/lib-index/mail-index-transaction.c
src/lib-index/mail-index.c
src/lib-index/mail-index.h
src/lib-index/mail-transaction-log-file.c
src/lib-index/mail-transaction-log-private.h
src/lib-index/mail-transaction-log.h
src/lib-storage/index/cydir/cydir-save.c
src/lib-storage/index/dbox-multi/mdbox-save.c
src/lib-storage/index/dbox-single/sdbox-save.c
src/lib-storage/index/index-storage.c
src/lib-storage/index/index-transaction.c
src/lib-storage/index/maildir/maildir-copy.c
src/lib-storage/index/maildir/maildir-save.c
src/lib-storage/index/mbox/mbox-save.c

index ff579fa660ccc0a1b396d92048948ebb95fb6e4a..1c483584ddd5dcdce16051b4bb01bfdf6a9fb72d 100644 (file)
@@ -109,6 +109,9 @@ static const char *log_record_type(unsigned int type)
        case MAIL_TRANSACTION_MODSEQ_UPDATE:
                name = "modseq-update";
                break;
+       case MAIL_TRANSACTION_INDEX_DELETED:
+               name = "index-deleted";
+               break;
        default:
                name = t_strdup_printf("unknown: %x", type);
                break;
@@ -411,6 +414,8 @@ static void log_record_print(const struct mail_transaction_header *hdr,
                }
                break;
        }
+       case MAIL_TRANSACTION_INDEX_DELETED:
+               break;
        default:
                break;
        }
index da66b58ba7177c6967d934b0250f0ba9b2511b47..b659fa522d48943842818f04de74d4f81d3bb0df 100644 (file)
@@ -226,6 +226,7 @@ struct mail_index {
        unsigned int index_lock_timeout:1;
 
        unsigned int opened:1;
+       unsigned int index_deleted:1; /* no changes allowed anymore */
        unsigned int log_locked:1;
        unsigned int readonly:1;
        unsigned int mapping:1;
index 4ae9a56bb180363990a2690f92398ac3b676afc7..ff81205bd198a06fe44517a7114ed063ecf46211 100644 (file)
@@ -814,6 +814,12 @@ int mail_index_sync_record(struct mail_index_sync_map_ctx *ctx,
                ret = sync_modseq_update(ctx, rec, hdr->size);
                break;
        }
+       case MAIL_TRANSACTION_INDEX_DELETED:
+               if ((hdr->type & MAIL_TRANSACTION_EXTERNAL) == 0)
+                       break;
+               /* transaction log syncing should have already set this */
+               i_assert(ctx->view->index->index_deleted);
+               break;
        default:
                mail_index_sync_set_corrupted(ctx,
                        "Unknown transaction record type 0x%x",
index 8a2f6fa9b73dd8e518d564628cefce16dfaceea1..a125e2db790a959180d0c788d007f68c235581ad 100644 (file)
@@ -455,6 +455,13 @@ void mail_index_transaction_export(struct mail_index_transaction *t,
                                  MAIL_TRANSACTION_HEADER_UPDATE);
        }
 
+       if (t->index_deleted) {
+               static uint8_t null4[4] = { 0, 0, 0, 0 };
+               mail_transaction_log_append_add(ctx.append_ctx,
+                                               MAIL_TRANSACTION_INDEX_DELETED,
+                                               &null4, 4);
+       }
+
        /* Update the tail offsets only when committing the sync transaction.
           Other transactions may not know the latest tail offset and might
           end up shrinking it. (Alternatively the shrinking tail offsets could
index e39d5e3ca42f5f634fc44d471abaf6b0f8a9949e..038627860f82ac857bae2638b21a5d3badccd6b6 100644 (file)
@@ -85,6 +85,7 @@ struct mail_index_transaction {
        unsigned int pre_hdr_changed:1;
        unsigned int post_hdr_changed:1;
        unsigned int reset:1;
+       unsigned int index_deleted:1;
        /* non-extension updates. flag updates don't change this because
           they may be added and removed, so be sure to check that the updates
           array is non-empty also. */
index 29c6a8576596ea086aea98e35671cadaceaa1678..88e4f5f4946f20a0965de3437aeac6f2498424d6 100644 (file)
@@ -97,6 +97,7 @@ void mail_index_transaction_reset_v(struct mail_index_transaction *t)
        t->pre_hdr_changed = FALSE;
        t->post_hdr_changed = FALSE;
        t->reset = FALSE;
+       t->index_deleted = FALSE;
        t->log_updates = FALSE;
        t->log_ext_updates = FALSE;
 }
@@ -1169,6 +1170,13 @@ void mail_index_reset(struct mail_index_transaction *t)
        t->reset = TRUE;
 }
 
+void mail_index_set_deleted(struct mail_index_transaction *t)
+{
+       i_assert((t->flags & MAIL_INDEX_TRANSACTION_FLAG_EXTERNAL) != 0);
+
+       t->index_deleted = TRUE;
+}
+
 void mail_index_transaction_set_max_modseq(struct mail_index_transaction *t,
                                           uint64_t max_modseq,
                                           ARRAY_TYPE(seq_range) *seqs)
index 819a5f24824be433fd291b83332ff333c6e81335..64506359b55592c608e5b8bb271b71df891aa490 100644 (file)
@@ -213,6 +213,11 @@ int mail_index_transaction_commit_full(struct mail_index_transaction **_t,
                mail_index_transaction_rollback(_t);
                return -1;
        }
+       if (t->view->index->index_deleted) {
+               /* no further changes allowed */
+               mail_index_transaction_rollback(_t);
+               return -1;
+       }
 
        *_t = NULL;
        memset(result_r, 0, sizeof(*result_r));
index b5cb9df57cecc9ac82692293e747396faaf6d146..f57b65b9c3b7751aee17cbe3fd828ece7216a429 100644 (file)
@@ -744,6 +744,11 @@ void mail_index_mark_corrupted(struct mail_index *index)
        }
 }
 
+bool mail_index_is_deleted(struct mail_index *index)
+{
+       return index->index_deleted;
+}
+
 void mail_index_fchown(struct mail_index *index, int fd, const char *path)
 {
        mode_t mode;
index 1ef56606ee07904ae8f309cb3903b2f6d7a273f4..4e8a9128267cbbf5513fc0784809b36d37334526 100644 (file)
@@ -446,6 +446,12 @@ void mail_index_update_highest_modseq(struct mail_index_transaction *t,
 /* Reset the index before committing this transaction. This is usually done
    only when UIDVALIDITY changes. */
 void mail_index_reset(struct mail_index_transaction *t);
+/* Mark index deleted. No further changes will be possible after the
+   transaction has been committed. */
+void mail_index_set_deleted(struct mail_index_transaction *t);
+/* Returns TRUE if index has been set deleted. This gets set only after
+   index has been opened/refreshed and the transaction has been seen. */
+bool mail_index_is_deleted(struct mail_index *index);
 
 /* Lookup a keyword, returns TRUE if found, FALSE if not. */
 bool mail_index_keyword_lookup(struct mail_index *index,
index e248445f330f9322c84dde2b2e42b9892f58f5d4..bfabc64d9536bf7962d74f262aae1cab0e458420 100644 (file)
@@ -72,6 +72,7 @@ mail_transaction_log_file_alloc(struct mail_transaction_log *log,
        file->log = log;
        file->filepath = i_strdup(path);
        file->fd = -1;
+       file->index_deleted_offset = (uoff_t)-1;
        return file;
 }
 
@@ -1101,14 +1102,19 @@ log_file_track_sync(struct mail_transaction_log_file *file,
                return 0;
 
        /* external transactions: */
-       if ((hdr->type & MAIL_TRANSACTION_TYPE_MASK) ==
-           MAIL_TRANSACTION_HEADER_UPDATE) {
+       switch (hdr->type & MAIL_TRANSACTION_TYPE_MASK) {
+       case MAIL_TRANSACTION_HEADER_UPDATE:
                /* see if this updates mailbox_sync_offset */
                ret = log_file_track_mailbox_sync_offset_hdr(file, data,
                                                             trans_size -
                                                             sizeof(*hdr));
                if (ret != 0)
                        return ret < 0 ? -1 : 0;
+               break;
+       case MAIL_TRANSACTION_INDEX_DELETED:
+               file->log->index->index_deleted = TRUE;
+               file->index_deleted_offset = file->sync_offset + trans_size;
+               break;
        }
 
        if (file->max_tail_offset == file->sync_offset) {
@@ -1133,6 +1139,10 @@ mail_transaction_log_file_sync(struct mail_transaction_log_file *file)
 
        data = buffer_get_data(file->buffer, &size);
        while (file->sync_offset - file->buffer_offset + sizeof(*hdr) <= size) {
+               if (unlikely(file->index_deleted_offset == file->sync_offset)) {
+                       /* ignore everything that comes after _INDEX_DELETED */
+                       break;
+               }
                hdr = CONST_PTR_OFFSET(data, file->sync_offset -
                                       file->buffer_offset);
                trans_size = mail_index_offset_to_uint32(hdr->size);
index f5f6bf779be2aaa5cf6dfa96eec1918ed6d1c27e..96eac19a5a8d3c451fa86fe7104f46fcfd7733d8 100644 (file)
@@ -65,6 +65,10 @@ struct mail_transaction_log_file {
           sync_offset is less than this. */
        uoff_t saved_tail_sync_offset;
 
+       /* if we've seen _INDEX_DELETED transaction in this file, this is the
+          offset. otherwise (uoff_t)-1 */
+       uoff_t index_deleted_offset;
+
        struct modseq_cache modseq_cache[LOG_FILE_MODSEQ_CACHE_SIZE];
 
        struct file_lock *file_lock;
index 330e5c49aa044ba40af8f2c957035294908efd3b..2e4a3157139d9d01df880874cdba95beb67046a3 100644 (file)
@@ -42,6 +42,7 @@ enum mail_transaction_type {
        MAIL_TRANSACTION_UID_UPDATE             = 0x00004000,
        MAIL_TRANSACTION_MODSEQ_UPDATE          = 0x00008000,
        MAIL_TRANSACTION_EXT_HDR_UPDATE32       = 0x00010000,
+       MAIL_TRANSACTION_INDEX_DELETED          = 0x00020000,
 
        MAIL_TRANSACTION_TYPE_MASK              = 0x000fffff,
 
index 27e241eef83e132abbdd1b6da64d486d975a8055..e3967c61bea0be8889d62448e1c35b3a1790fe32 100644 (file)
@@ -85,6 +85,11 @@ int cydir_save_begin(struct mail_save_context *_ctx, struct istream *input)
        enum mail_flags save_flags;
        struct istream *crlf_input;
 
+       if (mail_index_is_deleted(ctx->mbox->ibox.index)) {
+               mailbox_set_deleted(trans->box);
+               return -1;
+       }
+
        T_BEGIN {
                const char *path;
 
index 38ba3f808cdd3b8a0c684e63ffc873fbb706410a..9a6ca987029c92d78691a42d6532eb4a73d4126f 100644 (file)
@@ -97,6 +97,11 @@ int mdbox_save_begin(struct mail_save_context *_ctx, struct istream *input)
        struct dbox_save_mail *save_mail;
        uoff_t mail_size, append_offset;
 
+       if (mail_index_is_deleted(ctx->mbox->ibox.index)) {
+               mailbox_set_deleted(_ctx->transaction->box);
+               return -1;
+       }
+
        /* get the size of the mail to be saved, if possible */
        if (i_stream_get_size(input, TRUE, &mail_size) <= 0) {
                const struct stat *st;
index b2ec4d72102878e1f44df656efb07fc6d9ce3c6e..0ddfe64a31821fbd13e55b5dfd23c490e24c6a7d 100644 (file)
@@ -78,6 +78,11 @@ int sdbox_save_begin(struct mail_save_context *_ctx, struct istream *input)
        struct dbox_file *file;
        int ret;
 
+       if (mail_index_is_deleted(ctx->mbox->ibox.index)) {
+               mailbox_set_deleted(_ctx->transaction->box);
+               return -1;
+       }
+
        file = sdbox_file_init(ctx->mbox, 0);
        ctx->append_ctx = dbox_file_append_init(file);
        ret = dbox_file_get_append_stream(ctx->append_ctx,
index 8f30abe5516cbc1d96ec314f08824b7814cdc05a..84eef027f93fdac52d42eccba1b627d0cc839310 100644 (file)
@@ -441,6 +441,11 @@ int index_storage_mailbox_open(struct mailbox *box)
        index_thread_mailbox_opened(ibox);
        if (hook_mailbox_opened != NULL)
                hook_mailbox_opened(box);
+
+       if (mail_index_is_deleted(ibox->index)) {
+               mailbox_set_deleted(box);
+               return -1;
+       }
        return 0;
 }
 
@@ -649,7 +654,10 @@ bool index_storage_is_inconsistent(struct mailbox *box)
 
 void mail_storage_set_index_error(struct index_mailbox *ibox)
 {
-       mail_storage_set_internal_error(ibox->box.storage);
+       if (mail_index_is_deleted(ibox->index))
+               mailbox_set_deleted(&ibox->box);
+       else
+               mail_storage_set_internal_error(ibox->box.storage);
        mail_index_reset_error(ibox->index);
 }
 
index c107a8a973ef0c31d8d8efb423b3b4b1283f1f0d..509ad3500357ae97ef0d2c3f449514a479e60da3 100644 (file)
@@ -122,6 +122,8 @@ int index_transaction_commit(struct mailbox_transaction_context *_t,
        _t->changes = changes_r;
 
        ret = mail_index_transaction_commit_full(&itrans, &result);
+       if (ret < 0 && mail_index_is_deleted(ibox->index))
+               mailbox_set_deleted(&ibox->box);
 
        changes_r->ignored_uid_changes = result.ignored_uid_changes;
        changes_r->ignored_modseq_changes = result.ignored_modseq_changes;
index 9ec7527bbef5f3d385be55c71bd2c50869f88aae..caaabb8bc5c90fce201e2551596421d3bd7f1294 100644 (file)
@@ -170,6 +170,11 @@ maildir_copy_hardlink(struct mail_save_context *ctx, struct mail *mail)
                return 0;
        }
 
+       if (mail_index_is_deleted(dest_mbox->ibox.index)) {
+               mailbox_set_deleted(&dest_mbox->ibox.box);
+               return -1;
+       }
+
        memset(&do_ctx, 0, sizeof(do_ctx));
        do_ctx.dest_path = str_new(default_pool, 512);
 
index ec307f73295bf77422dcd138a9c21b20c97d4105..5b77d534fc93052a89f8533c95a34edac1af0334 100644 (file)
@@ -305,6 +305,11 @@ static int maildir_create_tmp(struct maildir_mailbox *mbox, const char *dir,
        string_t *path;
        int fd;
 
+       if (mail_index_is_deleted(mbox->ibox.index)) {
+               mailbox_set_deleted(box);
+               return -1;
+       }
+
        path = t_str_new(256);
        str_append(path, dir);
        str_append_c(path, '/');
index 912492f633d7129cad13e2fe95e7b39126dafb89..43148513a683bdf8237a3b9fd8c08f3b462922b8 100644 (file)
@@ -261,6 +261,11 @@ mbox_save_init_file(struct mbox_save_context *ctx,
                return -1;
        }
 
+       if (mail_index_is_deleted(mbox->ibox.index)) {
+               mailbox_set_deleted(&mbox->ibox.box);
+               return -1;
+       }
+
        if ((_t->flags & MAILBOX_TRANSACTION_FLAG_ASSIGN_UIDS) != 0 ||
            ctx->ctx.uid != 0)
                want_mail = TRUE;