From: Timo Sirainen Date: Mon, 15 Dec 2008 08:58:02 +0000 (+0200) Subject: maildir: Allow opening mailbox and expunging messages when uidlist couldn't be locked... X-Git-Tag: 1.2.alpha5~2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=ba3d9eeb0bec6ed8465d68fa2480ad085559b580;p=thirdparty%2Fdovecot%2Fcore.git maildir: Allow opening mailbox and expunging messages when uidlist couldn't be locked (e.g. out of quota). --HG-- branch : HEAD --- diff --git a/src/lib-storage/index/maildir/maildir-keywords.c b/src/lib-storage/index/maildir/maildir-keywords.c index 8ff8dbd2a3..cdfce78541 100644 --- a/src/lib-storage/index/maildir/maildir-keywords.c +++ b/src/lib-storage/index/maildir/maildir-keywords.c @@ -194,9 +194,6 @@ maildir_keywords_lookup(struct maildir_keywords *mk, const char *name) { void *p; - i_assert(mk->mbox == NULL || - maildir_uidlist_is_locked(mk->mbox->uidlist)); - p = hash_lookup(mk->hash, name); if (p == NULL) { if (mk->synced) @@ -256,6 +253,9 @@ maildir_keywords_lookup_or_create(struct maildir_keywords *mk, const char *name) if (i == count && count >= MAILDIR_MAX_KEYWORDS) return -1; + if (!maildir_uidlist_is_locked(mk->mbox->uidlist)) + return -1; + maildir_keywords_create(mk, name, i); return i; } @@ -266,9 +266,6 @@ maildir_keywords_idx(struct maildir_keywords *mk, unsigned int idx) const char *const *keywords; unsigned int count; - i_assert(mk->mbox == NULL || - maildir_uidlist_is_locked(mk->mbox->uidlist)); - keywords = array_get(&mk->list, &count); if (idx >= count) { if (mk->synced) diff --git a/src/lib-storage/index/maildir/maildir-sync-index.c b/src/lib-storage/index/maildir/maildir-sync-index.c index 79b8762568..1a502f74b7 100644 --- a/src/lib-storage/index/maildir/maildir-sync-index.c +++ b/src/lib-storage/index/maildir/maildir-sync-index.c @@ -105,15 +105,15 @@ static int maildir_sync_flags(struct maildir_mailbox *mbox, const char *path, return -1; } -static void maildir_handle_uid_insertion(struct maildir_index_sync_context *ctx, - enum maildir_uidlist_rec_flag uflags, - const char *filename, uint32_t uid) +static int maildir_handle_uid_insertion(struct maildir_index_sync_context *ctx, + enum maildir_uidlist_rec_flag uflags, + const char *filename, uint32_t uid) { int ret; if ((uflags & MAILDIR_UIDLIST_REC_FLAG_NONSYNCED) != 0) { /* partial syncing */ - return; + return 0; } /* most likely a race condition: we read the maildir, then someone else @@ -124,7 +124,7 @@ static void maildir_handle_uid_insertion(struct maildir_index_sync_context *ctx, ctx->mbox->maildir_hdr.cur_check_time = 0; maildir_uidlist_add_flags(ctx->mbox->uidlist, filename, MAILDIR_UIDLIST_REC_FLAG_RACING); - return; + return 0; } if (ctx->uidlist_sync_ctx == NULL) { @@ -132,7 +132,8 @@ static void maildir_handle_uid_insertion(struct maildir_index_sync_context *ctx, MAILDIR_UIDLIST_SYNC_PARTIAL | MAILDIR_UIDLIST_SYNC_KEEP_STATE, &ctx->uidlist_sync_ctx); - i_assert(ret > 0); + if (ret <= 0) + return -1; } uflags &= MAILDIR_UIDLIST_REC_FLAG_NEW_DIR; @@ -146,6 +147,7 @@ static void maildir_handle_uid_insertion(struct maildir_index_sync_context *ctx, i_warning("Maildir %s: Expunged message reappeared, giving a new UID " "(old uid=%u, file=%s)", ctx->mbox->path, uid, filename); + return 0; } int maildir_sync_index_begin(struct maildir_mailbox *mbox, @@ -283,7 +285,6 @@ int maildir_sync_index(struct maildir_index_sync_context *ctx, bool expunged, full_rescan = FALSE; i_assert(!mbox->syncing_commit); - i_assert(maildir_uidlist_is_locked(mbox->uidlist)); first_uid = 1; hdr = mail_index_get_header(view); @@ -328,8 +329,10 @@ int maildir_sync_index(struct maildir_index_sync_context *ctx, if (seq > hdr->messages_count) { if (uid < hdr_next_uid) { - maildir_handle_uid_insertion(ctx, uflags, - filename, uid); + if (maildir_handle_uid_insertion(ctx, uflags, + filename, + uid) < 0) + ret = -1; seq--; continue; } @@ -367,8 +370,9 @@ int maildir_sync_index(struct maildir_index_sync_context *ctx, } if (uid < rec->uid) { - maildir_handle_uid_insertion(ctx, uflags, - filename, uid); + if (maildir_handle_uid_insertion(ctx, uflags, + filename, uid) < 0) + ret = -1; seq--; continue; } diff --git a/src/lib-storage/index/maildir/maildir-sync.c b/src/lib-storage/index/maildir/maildir-sync.c index f454e46c8e..d2868223a7 100644 --- a/src/lib-storage/index/maildir/maildir-sync.c +++ b/src/lib-storage/index/maildir/maildir-sync.c @@ -670,7 +670,7 @@ static int maildir_sync_context(struct maildir_sync_context *ctx, bool forced, { enum maildir_uidlist_sync_flags sync_flags; enum maildir_uidlist_rec_flag flags; - bool new_changed, cur_changed; + bool new_changed, cur_changed, lock_failure; int ret; *lost_files_r = FALSE; @@ -741,15 +741,39 @@ static int maildir_sync_context(struct maildir_sync_context *ctx, bool forced, } ret = maildir_uidlist_sync_init(ctx->mbox->uidlist, sync_flags, &ctx->uidlist_sync_ctx); + lock_failure = ret <= 0; if (ret <= 0) { - /* failure / timeout */ - return ret; + struct mail_storage *storage = ctx->mbox->ibox.box.storage; + + if (ret == 0) { + /* timeout */ + return 0; + } + /* locking failed. sync anyway without locking so that it's + possible to expunge messages when out of quota. */ + if (forced) { + /* we're already forcing a sync, we're trying to find + a message that was probably already expunged, don't + loop for a long time trying to find it. */ + return -1; + } + ret = maildir_uidlist_sync_init(ctx->mbox->uidlist, sync_flags | + MAILDIR_UIDLIST_SYNC_NOLOCK, + &ctx->uidlist_sync_ctx); + i_assert(ret > 0); + + if (storage->callbacks->notify_no != NULL) { + storage->callbacks->notify_no(&ctx->mbox->ibox.box, + "Internal mailbox synchronization failure, " + "showing only old mails.", + storage->callback_context); + } } ctx->locked = maildir_uidlist_is_locked(ctx->mbox->uidlist); if (!ctx->locked) ctx->partial = TRUE; - if (!ctx->mbox->syncing_commit && ctx->locked) { + if (!ctx->mbox->syncing_commit && (ctx->locked || lock_failure)) { if (maildir_sync_index_begin(ctx->mbox, ctx, &ctx->index_sync_ctx) < 0) return -1; @@ -787,7 +811,7 @@ static int maildir_sync_context(struct maildir_sync_context *ctx, bool forced, ctx->mbox->maildir_hdr.cur_mtime = 0; } - if (!ctx->mbox->syncing_commit && ctx->locked) { + if (ctx->index_sync_ctx != NULL) { /* NOTE: index syncing here might cause a re-sync due to files getting lost, so this function might be called re-entrantly. */ @@ -801,7 +825,8 @@ static int maildir_sync_context(struct maildir_sync_context *ctx, bool forced, if (ret == 0) *lost_files_r = TRUE; - i_assert(maildir_uidlist_is_locked(ctx->mbox->uidlist)); + i_assert(maildir_uidlist_is_locked(ctx->mbox->uidlist) || + lock_failure); } if (find_uid != NULL && *find_uid != 0) { diff --git a/src/lib-storage/index/maildir/maildir-uidlist.c b/src/lib-storage/index/maildir/maildir-uidlist.c index b2b1033d1f..d59072a795 100644 --- a/src/lib-storage/index/maildir/maildir-uidlist.c +++ b/src/lib-storage/index/maildir/maildir-uidlist.c @@ -1287,14 +1287,21 @@ static void maildir_uidlist_mark_all(struct maildir_uidlist *uidlist, } } -int maildir_uidlist_sync_init(struct maildir_uidlist *uidlist, - enum maildir_uidlist_sync_flags sync_flags, - struct maildir_uidlist_sync_ctx **sync_ctx_r) +static int maildir_uidlist_sync_lock(struct maildir_uidlist *uidlist, + enum maildir_uidlist_sync_flags sync_flags, + bool *locked_r) { - struct maildir_uidlist_sync_ctx *ctx; - bool nonblock, refresh, locked; + bool nonblock, refresh; int ret; + *locked_r = FALSE; + + if ((sync_flags & MAILDIR_UIDLIST_SYNC_NOLOCK) != 0) { + if (maildir_uidlist_refresh(uidlist) < 0) + return -1; + return 1; + } + nonblock = (sync_flags & MAILDIR_UIDLIST_SYNC_TRYLOCK) != 0; refresh = (sync_flags & MAILDIR_UIDLIST_SYNC_NOREFRESH) == 0; @@ -1309,10 +1316,23 @@ int maildir_uidlist_sync_init(struct maildir_uidlist *uidlist, /* forcing the sync anyway */ if (maildir_uidlist_refresh(uidlist) < 0) return -1; - locked = FALSE; } else { - locked = TRUE; + *locked_r = TRUE; } + return 1; +} + +int maildir_uidlist_sync_init(struct maildir_uidlist *uidlist, + enum maildir_uidlist_sync_flags sync_flags, + struct maildir_uidlist_sync_ctx **sync_ctx_r) +{ + struct maildir_uidlist_sync_ctx *ctx; + bool locked; + int ret; + + ret = maildir_uidlist_sync_lock(uidlist, sync_flags, &locked); + if (ret <= 0) + return ret; *sync_ctx_r = ctx = i_new(struct maildir_uidlist_sync_ctx, 1); ctx->uidlist = uidlist; diff --git a/src/lib-storage/index/maildir/maildir-uidlist.h b/src/lib-storage/index/maildir/maildir-uidlist.h index d78e833b2b..9485c3ed9a 100644 --- a/src/lib-storage/index/maildir/maildir-uidlist.h +++ b/src/lib-storage/index/maildir/maildir-uidlist.h @@ -15,7 +15,8 @@ enum maildir_uidlist_sync_flags { MAILDIR_UIDLIST_SYNC_KEEP_STATE = 0x02, MAILDIR_UIDLIST_SYNC_FORCE = 0x04, MAILDIR_UIDLIST_SYNC_TRYLOCK = 0x08, - MAILDIR_UIDLIST_SYNC_NOREFRESH = 0x10 + MAILDIR_UIDLIST_SYNC_NOREFRESH = 0x10, + MAILDIR_UIDLIST_SYNC_NOLOCK = 0x20 }; enum maildir_uidlist_rec_flag {