mail-index-lock.c revision 5c1a8aee989af87bddefd71e2aa83aa2bd695155
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen/* Copyright (C) 2003-2004 Timo Sirainen */
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen/*
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen Locking is meant to be as transparent as possible. Anything that locks
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen the index must either keep it only a short time, or be prepared that the
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen lock is lost.
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen Lock is lost in only one situation: when we try to get an exclusive lock
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen but we already have a shared lock. Then we'll drop all shared locks and
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen get the exclusive lock.
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen Locking should never fail or timeout. Exclusive locks must be kept as short
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen time as possible. Shared locks can be long living, so if can't get exclusive
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen lock directly within 2 seconds, we'll replace the index file with a copy of
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen it. That means the shared lock holders can keep using the old file while
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen we're modifying the new file.
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen lock_id is used to figure out if acquired lock is still valid. Shared
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen locks have even numbers, exclusive locks have odd numbers. The number is
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen increased by two every time the lock is dropped.
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen mail_index_lock_shared() -> lock_id=2
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen mail_index_lock_shared() -> lock_id=2
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen mail_index_lock_exclusive() -> lock_id=5 (had to drop shared locks)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen mail_index_lock_shared() -> lock_id=4
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen Only 4 and 5 locks are valid at this time.
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen*/
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen#include "lib.h"
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen#include "mmap-util.h"
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen#include "file-lock.h"
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen#include "write-full.h"
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen#include "mail-index-private.h"
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen#include <stdio.h>
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen#include <sys/stat.h>
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainenstatic int mail_index_reopen(struct mail_index *index, int fd)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen{
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen int ret;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen mail_index_unmap(index, index->map);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen index->map = NULL;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (close(index->fd) < 0)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen mail_index_set_syscall_error(index, "close()");
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen index->fd = fd;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen ret = fd < 0 ? mail_index_try_open(index, NULL) :
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen mail_index_map(index, FALSE);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (ret <= 0) {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen // FIXME: serious problem, we'll just crash later..
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen return -1;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen }
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen return 0;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen}
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainenstatic int mail_index_has_changed(struct mail_index *index)
cfa9359fbd6a967ccdcd553c5e483a093885ab6fTimo Sirainen{
cfa9359fbd6a967ccdcd553c5e483a093885ab6fTimo Sirainen struct stat st1, st2;
cfa9359fbd6a967ccdcd553c5e483a093885ab6fTimo Sirainen
cfa9359fbd6a967ccdcd553c5e483a093885ab6fTimo Sirainen if (fstat(index->fd, &st1) < 0)
cfa9359fbd6a967ccdcd553c5e483a093885ab6fTimo Sirainen return mail_index_set_syscall_error(index, "fstat()");
cfa9359fbd6a967ccdcd553c5e483a093885ab6fTimo Sirainen if (stat(index->filepath, &st2) < 0)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen return mail_index_set_syscall_error(index, "stat()");
b0be0bead3d6963149f7f2a9504b8ab5aced9af5Timo Sirainen
cfa9359fbd6a967ccdcd553c5e483a093885ab6fTimo Sirainen if (st1.st_ino != st2.st_ino ||
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen !CMP_DEV_T(st1.st_dev, st2.st_dev)) {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (mail_index_reopen(index, -1) < 0)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen return -1;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen return 1;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen } else {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen return 0;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen }
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen}
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainenstatic int mail_index_lock_mprotect(struct mail_index *index, int lock_type)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen{
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen int prot;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (index->map != NULL &&
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen !MAIL_INDEX_MAP_IS_IN_MEMORY(index->map)) {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen prot = lock_type == F_UNLCK ? PROT_NONE :
cfa9359fbd6a967ccdcd553c5e483a093885ab6fTimo Sirainen lock_type == F_WRLCK ? (PROT_READ|PROT_WRITE) :
cfa9359fbd6a967ccdcd553c5e483a093885ab6fTimo Sirainen PROT_READ;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (mprotect(index->map->mmap_base,
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen index->map->file_size, prot) < 0) {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen mail_index_set_syscall_error(index, "mprotect()");
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen return -1;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen }
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen }
b0be0bead3d6963149f7f2a9504b8ab5aced9af5Timo Sirainen return 0;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen}
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainenstatic int mail_index_lock(struct mail_index *index, int lock_type,
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen unsigned int timeout_secs, int update_index,
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen unsigned int *lock_id_r)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen{
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen int ret;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen i_assert(lock_type == F_RDLCK || lock_type == F_WRLCK);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
b0be0bead3d6963149f7f2a9504b8ab5aced9af5Timo Sirainen if (index->fcntl_locks_disable) {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen /* FIXME: exclusive locking will rewrite the index file every
b0be0bead3d6963149f7f2a9504b8ab5aced9af5Timo Sirainen time. shouldn't really be needed.. reading doesn't require
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen locks then, though */
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (lock_type == F_WRLCK)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen return 0;
cfa9359fbd6a967ccdcd553c5e483a093885ab6fTimo Sirainen if (update_index && index->lock_type == F_UNLCK) {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (mail_index_has_changed(index) < 0)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen return -1;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen }
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (mail_index_lock_mprotect(index, lock_type) < 0)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen return -1;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen index->lock_type = lock_type;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen return 1;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen }
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (lock_type == F_WRLCK && index->lock_type == F_RDLCK) {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen /* drop shared locks */
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen i_assert(index->excl_lock_count == 0);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (file_wait_lock(index->fd, F_UNLCK) < 0)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen mail_index_set_syscall_error(index, "file_wait_lock()");
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen index->shared_lock_count = 0;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen index->lock_type = F_UNLCK;
cfa9359fbd6a967ccdcd553c5e483a093885ab6fTimo Sirainen index->lock_id += 2; /* make sure failures below work right */
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen }
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (index->excl_lock_count > 0 || index->shared_lock_count > 0) {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen i_assert(lock_type == F_RDLCK || index->excl_lock_count > 0);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (lock_type == F_RDLCK) {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen index->shared_lock_count++;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen *lock_id_r = index->lock_id;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen } else {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen index->excl_lock_count++;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen *lock_id_r = index->lock_id + 1;
cfa9359fbd6a967ccdcd553c5e483a093885ab6fTimo Sirainen }
cfa9359fbd6a967ccdcd553c5e483a093885ab6fTimo Sirainen return 1;
cfa9359fbd6a967ccdcd553c5e483a093885ab6fTimo Sirainen }
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen i_assert(index->lock_type == F_UNLCK);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (update_index && lock_type != F_WRLCK) {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (mail_index_has_changed(index) < 0)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen return -1;
cfa9359fbd6a967ccdcd553c5e483a093885ab6fTimo Sirainen }
cfa9359fbd6a967ccdcd553c5e483a093885ab6fTimo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen do {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen ret = file_wait_lock_full(index->fd, lock_type, timeout_secs,
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen NULL, NULL);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (ret <= 0) {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (ret == 0)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen return 0;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen mail_index_set_syscall_error(index, "file_wait_lock()");
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen return -1;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen }
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (lock_type == F_WRLCK) {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen /* we need to have the latest index file locked -
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen check if it's been updated. */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if ((ret = mail_index_has_changed(index)) < 0) {
2498b8003eb181001b0c4fd45763c462b45493d1Timo Sirainen (void)file_wait_lock(index->fd, F_UNLCK);
2498b8003eb181001b0c4fd45763c462b45493d1Timo Sirainen return -1;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (ret > 0)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen continue;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen } while (0);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen index->lock_type = lock_type;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen index->lock_id += 2;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (lock_type == F_RDLCK) {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen index->shared_lock_count++;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen *lock_id_r = index->lock_id;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen } else {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen index->excl_lock_count++;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen *lock_id_r = index->lock_id + 1;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen }
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (mail_index_lock_mprotect(index, lock_type) < 0)
2498b8003eb181001b0c4fd45763c462b45493d1Timo Sirainen return -1;
2498b8003eb181001b0c4fd45763c462b45493d1Timo Sirainen return 1;
2498b8003eb181001b0c4fd45763c462b45493d1Timo Sirainen}
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainenint mail_index_lock_shared(struct mail_index *index, int update_index,
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen unsigned int *lock_id_r)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen{
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen int ret;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen ret = mail_index_lock(index, F_RDLCK, DEFAULT_LOCK_TIMEOUT,
cfa9359fbd6a967ccdcd553c5e483a093885ab6fTimo Sirainen update_index, lock_id_r);
cfa9359fbd6a967ccdcd553c5e483a093885ab6fTimo Sirainen if (ret > 0)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen return 0;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (ret < 0)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen return -1;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen mail_index_set_error(index, "Timeout while waiting for release of "
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen "shared fcntl() lock for index file %s",
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen index->filepath);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen index->index_lock_timeout = TRUE;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen return -1;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen}
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenstatic int mail_index_copy(struct mail_index *index)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen{
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen const char *path;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen int ret, fd;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen fd = mail_index_create_tmp_file(index, &path);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (fd == -1)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen return -1;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen (void)mail_index_lock_mprotect(index, F_RDLCK);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen ret = write_full(fd, index->map->hdr, sizeof(*index->map->hdr));
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (ret < 0 || write_full(fd, index->map->records,
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen index->map->records_count *
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen sizeof(struct mail_index_record)) < 0) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen mail_index_file_set_syscall_error(index, path, "write_full()");
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen (void)close(fd);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen (void)unlink(path);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return -1;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen i_assert(index->copy_lock_path == NULL);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen index->copy_lock_path = i_strdup(path);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return fd;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen}
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainenstatic int mail_index_lock_exclusive_copy(struct mail_index *index)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen{
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen int fd;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen i_assert(index->log_locked);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (index->copy_lock_path != NULL) {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen index->excl_lock_count++;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen return 0;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* copy the index to index.tmp and use it. when */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen fd = mail_index_copy(index);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (fd == -1)
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen return -1;
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen index->lock_type = F_WRLCK;
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen index->excl_lock_count++;
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen if (mail_index_reopen(index, fd) < 0) {
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen /* FIXME: do this without another reopen which drops locks
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen and causes potential crashes */
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen i_assert(index->excl_lock_count == 1);
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen i_free(index->copy_lock_path);
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen index->copy_lock_path = NULL;
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* go back to old index */
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen (void)mail_index_reopen(index, -1);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen index->lock_type = F_UNLCK;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen index->excl_lock_count = 0;
b0be0bead3d6963149f7f2a9504b8ab5aced9af5Timo Sirainen index->shared_lock_count = 0;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen return -1;
b0be0bead3d6963149f7f2a9504b8ab5aced9af5Timo Sirainen }
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen i_assert(index->excl_lock_count == 1);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return 0;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen}
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainenint mail_index_lock_exclusive(struct mail_index *index,
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen unsigned int *lock_id_r)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen{
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen int ret;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen /* exclusive transaction log lock protects exclusive locking
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen for the main index file */
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen i_assert(index->log_locked);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen /* wait two seconds for exclusive lock */
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen ret = mail_index_lock(index, F_WRLCK, 2, TRUE, lock_id_r);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (ret > 0)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen return 0;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (ret < 0)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen return -1;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen *lock_id_r = index->lock_id + 1;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen return mail_index_lock_exclusive_copy(index);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen}
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainenstatic int mail_index_copy_lock_finish(struct mail_index *index)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen{
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen if (index->shared_lock_count > 0) {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen /* leave ourself shared locked. */
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (file_try_lock(index->fd, F_RDLCK) <= 0) {
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen mail_index_file_set_syscall_error(index,
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen index->copy_lock_path,
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen "file_try_lock()");
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen return -1;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen }
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen }
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (fsync(index->fd) < 0) {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen mail_index_file_set_syscall_error(index, index->copy_lock_path,
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen "fsync()");
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen return -1;
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen }
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (rename(index->copy_lock_path, index->filepath) < 0) {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen mail_index_set_error(index, "rename(%s, %s) failed: %m",
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen index->copy_lock_path, index->filepath);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return -1;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen }
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen i_free(index->copy_lock_path);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen index->copy_lock_path = NULL;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen return 0;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen}
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainenstatic void mail_index_excl_unlock_finish(struct mail_index *index)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen{
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (index->map != NULL && index->map->write_to_disk) {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen i_assert(index->log_locked);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (index->copy_lock_path != NULL) {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen /* new mapping replaces the old */
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen (void)unlink(index->copy_lock_path);
b0be0bead3d6963149f7f2a9504b8ab5aced9af5Timo Sirainen i_free(index->copy_lock_path);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen index->copy_lock_path = NULL;
b0be0bead3d6963149f7f2a9504b8ab5aced9af5Timo Sirainen }
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen if (mail_index_copy(index) < 0)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen mail_index_set_inconsistent(index);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen }
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen if (index->copy_lock_path != NULL) {
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen i_assert(index->log_locked);
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen if (mail_index_copy_lock_finish(index) < 0)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen mail_index_set_inconsistent(index);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen}
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenvoid mail_index_unlock(struct mail_index *index, unsigned int lock_id)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen{
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if ((lock_id & 1) == 0) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* shared lock */
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen if (mail_index_is_locked(index, lock_id)) {
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen i_assert(index->shared_lock_count > 0);
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen index->shared_lock_count--;
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen }
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen } else {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen /* exclusive lock */
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen i_assert(lock_id == index->lock_id + 1);
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen i_assert(index->excl_lock_count > 0);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (--index->excl_lock_count == 0)
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen mail_index_excl_unlock_finish(index);
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen }
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (index->shared_lock_count == 0 && index->excl_lock_count == 0) {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen index->lock_id += 2;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen index->lock_type = F_UNLCK;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen (void)mail_index_lock_mprotect(index, F_UNLCK);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (!index->fcntl_locks_disable) {
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen if (file_wait_lock(index->fd, F_UNLCK) < 0) {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen mail_index_set_syscall_error(index,
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen "file_wait_lock()");
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen }
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen }
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen }
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen}
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainenint mail_index_is_locked(struct mail_index *index, unsigned int lock_id)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen{
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen return (index->lock_id ^ lock_id) <= 1;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen}
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen