From: Timo Sirainen Date: Sun, 7 Feb 2010 01:25:32 +0000 (+0200) Subject: Added support for marking mailbox index deleted. Don't allow any changes after that. X-Git-Tag: 2.0.beta3~143 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=651fc0f1e43fef3e02e0e7b5f498973b05f641d7;p=thirdparty%2Fdovecot%2Fcore.git Added support for marking mailbox index deleted. Don't allow any changes after that. This is going to help with race conditions when deleting mailboxes. --HG-- branch : HEAD --- diff --git a/src/doveadm/doveadm-dump-log.c b/src/doveadm/doveadm-dump-log.c index ff579fa660..1c483584dd 100644 --- a/src/doveadm/doveadm-dump-log.c +++ b/src/doveadm/doveadm-dump-log.c @@ -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; } diff --git a/src/lib-index/mail-index-private.h b/src/lib-index/mail-index-private.h index da66b58ba7..b659fa522d 100644 --- a/src/lib-index/mail-index-private.h +++ b/src/lib-index/mail-index-private.h @@ -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; diff --git a/src/lib-index/mail-index-sync-update.c b/src/lib-index/mail-index-sync-update.c index 4ae9a56bb1..ff81205bd1 100644 --- a/src/lib-index/mail-index-sync-update.c +++ b/src/lib-index/mail-index-sync-update.c @@ -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", diff --git a/src/lib-index/mail-index-transaction-export.c b/src/lib-index/mail-index-transaction-export.c index 8a2f6fa9b7..a125e2db79 100644 --- a/src/lib-index/mail-index-transaction-export.c +++ b/src/lib-index/mail-index-transaction-export.c @@ -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 diff --git a/src/lib-index/mail-index-transaction-private.h b/src/lib-index/mail-index-transaction-private.h index e39d5e3ca4..038627860f 100644 --- a/src/lib-index/mail-index-transaction-private.h +++ b/src/lib-index/mail-index-transaction-private.h @@ -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. */ diff --git a/src/lib-index/mail-index-transaction-update.c b/src/lib-index/mail-index-transaction-update.c index 29c6a85765..88e4f5f494 100644 --- a/src/lib-index/mail-index-transaction-update.c +++ b/src/lib-index/mail-index-transaction-update.c @@ -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) diff --git a/src/lib-index/mail-index-transaction.c b/src/lib-index/mail-index-transaction.c index 819a5f2482..64506359b5 100644 --- a/src/lib-index/mail-index-transaction.c +++ b/src/lib-index/mail-index-transaction.c @@ -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)); diff --git a/src/lib-index/mail-index.c b/src/lib-index/mail-index.c index b5cb9df57c..f57b65b9c3 100644 --- a/src/lib-index/mail-index.c +++ b/src/lib-index/mail-index.c @@ -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; diff --git a/src/lib-index/mail-index.h b/src/lib-index/mail-index.h index 1ef56606ee..4e8a912826 100644 --- a/src/lib-index/mail-index.h +++ b/src/lib-index/mail-index.h @@ -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, diff --git a/src/lib-index/mail-transaction-log-file.c b/src/lib-index/mail-transaction-log-file.c index e248445f33..bfabc64d95 100644 --- a/src/lib-index/mail-transaction-log-file.c +++ b/src/lib-index/mail-transaction-log-file.c @@ -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); diff --git a/src/lib-index/mail-transaction-log-private.h b/src/lib-index/mail-transaction-log-private.h index f5f6bf779b..96eac19a5a 100644 --- a/src/lib-index/mail-transaction-log-private.h +++ b/src/lib-index/mail-transaction-log-private.h @@ -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; diff --git a/src/lib-index/mail-transaction-log.h b/src/lib-index/mail-transaction-log.h index 330e5c49aa..2e4a315713 100644 --- a/src/lib-index/mail-transaction-log.h +++ b/src/lib-index/mail-transaction-log.h @@ -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, diff --git a/src/lib-storage/index/cydir/cydir-save.c b/src/lib-storage/index/cydir/cydir-save.c index 27e241eef8..e3967c61be 100644 --- a/src/lib-storage/index/cydir/cydir-save.c +++ b/src/lib-storage/index/cydir/cydir-save.c @@ -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; diff --git a/src/lib-storage/index/dbox-multi/mdbox-save.c b/src/lib-storage/index/dbox-multi/mdbox-save.c index 38ba3f808c..9a6ca98702 100644 --- a/src/lib-storage/index/dbox-multi/mdbox-save.c +++ b/src/lib-storage/index/dbox-multi/mdbox-save.c @@ -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; diff --git a/src/lib-storage/index/dbox-single/sdbox-save.c b/src/lib-storage/index/dbox-single/sdbox-save.c index b2ec4d7210..0ddfe64a31 100644 --- a/src/lib-storage/index/dbox-single/sdbox-save.c +++ b/src/lib-storage/index/dbox-single/sdbox-save.c @@ -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, diff --git a/src/lib-storage/index/index-storage.c b/src/lib-storage/index/index-storage.c index 8f30abe551..84eef027f9 100644 --- a/src/lib-storage/index/index-storage.c +++ b/src/lib-storage/index/index-storage.c @@ -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); } diff --git a/src/lib-storage/index/index-transaction.c b/src/lib-storage/index/index-transaction.c index c107a8a973..509ad35003 100644 --- a/src/lib-storage/index/index-transaction.c +++ b/src/lib-storage/index/index-transaction.c @@ -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; diff --git a/src/lib-storage/index/maildir/maildir-copy.c b/src/lib-storage/index/maildir/maildir-copy.c index 9ec7527bbe..caaabb8bc5 100644 --- a/src/lib-storage/index/maildir/maildir-copy.c +++ b/src/lib-storage/index/maildir/maildir-copy.c @@ -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); diff --git a/src/lib-storage/index/maildir/maildir-save.c b/src/lib-storage/index/maildir/maildir-save.c index ec307f7329..5b77d534fc 100644 --- a/src/lib-storage/index/maildir/maildir-save.c +++ b/src/lib-storage/index/maildir/maildir-save.c @@ -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, '/'); diff --git a/src/lib-storage/index/mbox/mbox-save.c b/src/lib-storage/index/mbox/mbox-save.c index 912492f633..43148513a6 100644 --- a/src/lib-storage/index/mbox/mbox-save.c +++ b/src/lib-storage/index/mbox/mbox-save.c @@ -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;