mail-index-lock.c revision 5ec0ca7ff13595daf0d096c17100afb352e6294a
7cb128dc4cae2a03a742f63ba7afee23c78e3af0Phil Carmody/* Copyright (C) 2003-2004 Timo Sirainen */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen/*
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen Locking should never fail or timeout. Exclusive locks must be kept as short
bdd36cfdba3ff66d25570a9ff568d69e1eb543cfTimo Sirainen time as possible. Shared locks can be long living, so if we can't get
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen exclusive lock directly within 2 seconds, we'll replace the index file with
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen a copy of it. That means the shared lock holders can keep using the old file
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen while we're modifying the new file.
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen lock_id is used to figure out if acquired lock is still valid. When index
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen file is reopened, the lock_id can become invalid. It doesn't matter however,
9522aa5f33cc37fe8ccd0d647cc51dd3ba6a9b55Timo Sirainen as no-one's going to modify the old file anymore.
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen lock_id also tells if we're referring to shared or exclusive lock. This
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen allows us to drop back to shared locking once all exclusive locks are
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen dropped. Shared locks have even numbers, exclusive locks have odd numbers.
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen The number is increased by two every time the lock is dropped or index file
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen is reopened.
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen*/
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "lib.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "mmap-util.h"
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen#include "file-lock.h"
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen#include "write-full.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "mail-index-private.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include <stdio.h>
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include <sys/stat.h>
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic int mail_index_reopen(struct mail_index *index, int fd)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct mail_index_map *old_map;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen unsigned int old_shared_locks, old_lock_id, lock_id = 0;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen int ret, old_fd, old_lock_type;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen old_map = index->map;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen old_fd = index->fd;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen index->map = NULL;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen index->hdr = NULL;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* new file, new locks. the old fd can keep it's locks, they don't
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen matter anymore as no-one's going to modify the file. */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen old_lock_type = index->lock_type;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen old_lock_id = index->lock_id;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen old_shared_locks = index->shared_lock_count;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (index->lock_type == F_RDLCK)
cf9d67e4a9bfee31cf3be05244555d51a3d1b9feTimo Sirainen index->lock_type = F_UNLCK;
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen index->lock_id += 2;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen index->shared_lock_count = 0;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
093b42b11c1236a687d3da564b26a324e2189ae6Timo Sirainen if (fd != -1) {
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen index->fd = fd;
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen ret = 0;
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen } else {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_assert(index->excl_lock_count == 0);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen ret = mail_index_try_open_only(index);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen if (ret > 0)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen ret = mail_index_lock_shared(index, FALSE, &lock_id);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen else if (ret == 0) {
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen /* index file is lost */
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen ret = -1;
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen }
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen }
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen if (ret == 0) {
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen if (mail_index_map(index, FALSE) <= 0)
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen ret = -1;
eb209d12e3b1cfed564c35cf19fdb1bf7fcc6811Timo Sirainen }
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen if (lock_id != 0)
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen mail_index_unlock(index, lock_id);
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen if (ret == 0) {
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen mail_index_unmap(index, old_map);
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen if (close(old_fd) < 0)
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen mail_index_set_syscall_error(index, "close()");
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen } else {
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen if (index->map != NULL)
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen mail_index_unmap(index, index->map);
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen if (index->fd != -1) {
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen if (close(index->fd) < 0)
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen mail_index_set_syscall_error(index, "close()");
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen }
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen index->map = old_map;
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen index->hdr = index->map->hdr;
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen index->fd = old_fd;
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen index->lock_type = old_lock_type;
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen index->lock_id = old_lock_id;
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen index->shared_lock_count = old_shared_locks;
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen }
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen return ret;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen}
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainenstatic int mail_index_has_changed(struct mail_index *index)
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen{
8b16d3b00f051401c97568697ccdbba48663759aTimo Sirainen struct stat st1, st2;
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen if (fstat(index->fd, &st1) < 0)
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen return mail_index_set_syscall_error(index, "fstat()");
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen if (stat(index->filepath, &st2) < 0) {
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen mail_index_set_syscall_error(index, "stat()");
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen if (errno != ENOENT)
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen return -1;
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen /* lost it? recreate */
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen (void)mail_index_mark_corrupted(index);
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen return -1;
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen }
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen if (st1.st_ino != st2.st_ino ||
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen !CMP_DEV_T(st1.st_dev, st2.st_dev)) {
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen if (mail_index_reopen(index, -1) < 0)
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen return -1;
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen return 1;
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen } else {
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen return 0;
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen }
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen}
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainenint mail_index_map_lock_mprotect(struct mail_index *index,
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen struct mail_index_map *map, int lock_type)
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen{
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen int prot;
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen if (!MAIL_INDEX_MAP_IS_IN_MEMORY(map)) {
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen prot = lock_type == F_UNLCK ? PROT_NONE :
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen lock_type == F_WRLCK ? (PROT_READ|PROT_WRITE) :
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen PROT_READ;
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen if (mprotect(map->mmap_base, map->mmap_size, prot) < 0) {
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen mail_index_set_syscall_error(index, "mprotect()");
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen return -1;
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen }
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen }
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen return 0;
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen}
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainenstatic int mail_index_lock_mprotect(struct mail_index *index, int lock_type)
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen{
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen if (index->map == NULL)
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen return 0;
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen return mail_index_map_lock_mprotect(index, index->map, lock_type);
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen}
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainenstatic int mail_index_lock(struct mail_index *index, int lock_type,
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen unsigned int timeout_secs, int update_index,
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen unsigned int *lock_id_r)
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen{
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen int ret;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_assert(lock_type == F_RDLCK || lock_type == F_WRLCK);
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (lock_type == F_RDLCK && index->lock_type != F_UNLCK) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen index->shared_lock_count++;
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen *lock_id_r = index->lock_id;
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen ret = 1;
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen } else if (lock_type == F_WRLCK && index->lock_type == F_WRLCK) {
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen index->excl_lock_count++;
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen *lock_id_r = index->lock_id + 1;
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen ret = 1;
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen } else {
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen ret = 0;
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen }
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen if (update_index && index->excl_lock_count == 0) {
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen if (mail_index_has_changed(index) < 0)
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen return -1;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen }
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen if (ret > 0)
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen return 1;
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen if (index->fcntl_locks_disable) {
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen /* FIXME: exclusive locking will rewrite the index file every
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen time. shouldn't really be needed.. reading doesn't require
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen locks then, though */
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen if (lock_type == F_WRLCK)
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen return 0;
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen if (update_index && index->lock_type == F_UNLCK) {
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen if (mail_index_has_changed(index) < 0)
4fda77c9e9fc68feb292c4dacae1fac49dd08165Timo Sirainen return -1;
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen }
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen if (mail_index_lock_mprotect(index, lock_type) < 0)
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen return -1;
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen index->shared_lock_count++;
ad404d294fedf792619aed432ed8de5174e9ce7cTimo Sirainen index->lock_type = F_RDLCK;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen *lock_id_r = index->lock_id;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return 1;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen ret = file_wait_lock_full(index->fd, lock_type, timeout_secs,
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen NULL, NULL);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen if (ret <= 0) {
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen if (ret == 0 || errno == EDEADLK) {
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen /* deadlock equals to timeout */
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen return 0;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen }
009217abb57a24a4076092e8e4e165545747839eStephan Bosch mail_index_set_syscall_error(index, "file_wait_lock()");
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen return -1;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen }
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen if (index->lock_type == F_UNLCK)
009217abb57a24a4076092e8e4e165545747839eStephan Bosch index->lock_id += 2;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen index->lock_type = lock_type;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen if (lock_type == F_RDLCK) {
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen index->shared_lock_count++;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen *lock_id_r = index->lock_id;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen } else {
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen index->excl_lock_count++;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen *lock_id_r = index->lock_id + 1;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen }
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen if (mail_index_lock_mprotect(index, lock_type) < 0)
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen return -1;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen return 1;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen}
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainenint mail_index_lock_shared(struct mail_index *index, int update_index,
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen unsigned int *lock_id_r)
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen{
009217abb57a24a4076092e8e4e165545747839eStephan Bosch int ret;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen ret = mail_index_lock(index, F_RDLCK, DEFAULT_LOCK_TIMEOUT,
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen update_index, lock_id_r);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen if (ret > 0)
009217abb57a24a4076092e8e4e165545747839eStephan Bosch return 0;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen if (ret < 0)
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen return -1;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen mail_index_set_error(index, "Timeout while waiting for release of "
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen "shared fcntl() lock for index file %s",
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen index->filepath);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen index->index_lock_timeout = TRUE;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen return -1;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen}
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainenstatic int mail_index_copy(struct mail_index *index)
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen{
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen const char *path;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen int ret, fd;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen fd = mail_index_create_tmp_file(index, &path);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (fd == -1)
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen return -1;
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (index->lock_type == F_UNLCK) {
cf9d67e4a9bfee31cf3be05244555d51a3d1b9feTimo Sirainen if (mail_index_lock_mprotect(index, F_RDLCK) < 0)
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen return -1;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen ret = write_full(fd, index->map->hdr, sizeof(*index->map->hdr));
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (ret < 0 || write_full(fd, index->map->records,
3c296d819c54e21ce05c3d2eeeedc79be42ac593Timo Sirainen index->map->records_count *
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen sizeof(struct mail_index_record)) < 0) {
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen mail_index_file_set_syscall_error(index, path, "write_full()");
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen (void)close(fd);
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen (void)unlink(path);
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen fd = -1;
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen } else {
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen i_assert(index->copy_lock_path == NULL);
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen index->copy_lock_path = i_strdup(path);
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen }
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen if (index->lock_type == F_UNLCK)
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen (void)mail_index_lock_mprotect(index, F_UNLCK);
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen return fd;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainenstatic int mail_index_lock_exclusive_copy(struct mail_index *index)
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen int fd, old_lock_type;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
cf9d67e4a9bfee31cf3be05244555d51a3d1b9feTimo Sirainen i_assert(index->log_locked);
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen if (index->copy_lock_path != NULL) {
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen index->excl_lock_count++;
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen return 0;
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen }
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen
9058f3006fffd25835ad701e1b2c3c8faafd3c80Timo Sirainen i_assert(index->excl_lock_count == 0);
9058f3006fffd25835ad701e1b2c3c8faafd3c80Timo Sirainen
9058f3006fffd25835ad701e1b2c3c8faafd3c80Timo Sirainen /* copy the index to index.tmp and use it */
28789c7ce1aa66ab21798bfb73ec64308b9a4de8Timo Sirainen fd = mail_index_copy(index);
28789c7ce1aa66ab21798bfb73ec64308b9a4de8Timo Sirainen if (fd == -1)
28789c7ce1aa66ab21798bfb73ec64308b9a4de8Timo Sirainen return -1;
28789c7ce1aa66ab21798bfb73ec64308b9a4de8Timo Sirainen
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen old_lock_type = index->lock_type;
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen index->lock_type = F_WRLCK;
87842f621233257b7a7945d994ba931508b34877Timo Sirainen index->excl_lock_count++;
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen if (mail_index_reopen(index, fd) < 0) {
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen i_assert(index->excl_lock_count == 1);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (unlink(index->copy_lock_path) < 0) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen mail_index_file_set_syscall_error(index,
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen index->copy_lock_path,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen "unlink()");
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_free(index->copy_lock_path);
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen index->copy_lock_path = NULL;
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen index->lock_type = old_lock_type;
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen index->excl_lock_count = 0;
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen return -1;
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen }
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen (void)mail_index_lock_mprotect(index, F_WRLCK);
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen return 0;
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen}
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainen
a4502a71879d6018bd2c64f13614bb619911dd9fTimo Sirainenint mail_index_lock_exclusive(struct mail_index *index,
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen unsigned int *lock_id_r)
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen{
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen int ret;
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen /* exclusive transaction log lock protects exclusive locking
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen for the main index file */
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen i_assert(index->log_locked);
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen /* wait two seconds for exclusive lock */
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen ret = mail_index_lock(index, F_WRLCK, 2, TRUE, lock_id_r);
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen if (ret > 0)
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen return 0;
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen if (ret < 0)
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen return -1;
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen if (mail_index_lock_exclusive_copy(index) < 0)
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen return -1;
28789c7ce1aa66ab21798bfb73ec64308b9a4de8Timo Sirainen *lock_id_r = index->lock_id + 1;
28789c7ce1aa66ab21798bfb73ec64308b9a4de8Timo Sirainen return 0;
28789c7ce1aa66ab21798bfb73ec64308b9a4de8Timo Sirainen}
28789c7ce1aa66ab21798bfb73ec64308b9a4de8Timo Sirainen
28789c7ce1aa66ab21798bfb73ec64308b9a4de8Timo Sirainenstatic int mail_index_copy_lock_finish(struct mail_index *index)
28789c7ce1aa66ab21798bfb73ec64308b9a4de8Timo Sirainen{
28789c7ce1aa66ab21798bfb73ec64308b9a4de8Timo Sirainen if (index->shared_lock_count > 0) {
87842f621233257b7a7945d994ba931508b34877Timo Sirainen /* leave ourself shared locked. */
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen if (file_try_lock(index->fd, F_RDLCK) <= 0) {
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen mail_index_file_set_syscall_error(index,
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen index->copy_lock_path,
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen "file_try_lock()");
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen return -1;
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen }
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (fsync(index->fd) < 0) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen mail_index_file_set_syscall_error(index, index->copy_lock_path,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen "fsync()");
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return -1;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen if (rename(index->copy_lock_path, index->filepath) < 0) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen mail_index_set_error(index, "rename(%s, %s) failed: %m",
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen index->copy_lock_path, index->filepath);
cf9d67e4a9bfee31cf3be05244555d51a3d1b9feTimo Sirainen return -1;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_free(index->copy_lock_path);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen index->copy_lock_path = NULL;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen return 0;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic void mail_index_excl_unlock_finish(struct mail_index *index)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (index->map != NULL && index->map->write_to_disk) {
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen i_assert(index->log_locked);
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen if (index->copy_lock_path != NULL) {
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen /* new mapping replaces the old */
9ffd3c8ca82bd2af8ca4f7e167339820ddcf1fe3Timo Sirainen (void)unlink(index->copy_lock_path);
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen i_free(index->copy_lock_path);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen index->copy_lock_path = NULL;
9ffd3c8ca82bd2af8ca4f7e167339820ddcf1fe3Timo Sirainen }
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (mail_index_copy(index) < 0)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen mail_index_set_inconsistent(index);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen }
9ffd3c8ca82bd2af8ca4f7e167339820ddcf1fe3Timo Sirainen
9ffd3c8ca82bd2af8ca4f7e167339820ddcf1fe3Timo Sirainen if (index->copy_lock_path != NULL) {
9ffd3c8ca82bd2af8ca4f7e167339820ddcf1fe3Timo Sirainen i_assert(index->log_locked);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen if (mail_index_copy_lock_finish(index) < 0)
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen mail_index_set_inconsistent(index);
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen }
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen}
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainenvoid mail_index_unlock(struct mail_index *index, unsigned int lock_id)
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen{
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen if ((lock_id & 1) == 0) {
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen /* shared lock */
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen if (!mail_index_is_locked(index, lock_id)) {
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen /* unlocking some older generation of the index file.
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen we've already closed the file so just ignore this. */
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen return;
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen }
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen i_assert(index->shared_lock_count > 0);
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen index->shared_lock_count--;
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen } else {
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen /* exclusive lock */
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen i_assert(lock_id == index->lock_id + 1);
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen i_assert(index->excl_lock_count > 0);
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (--index->excl_lock_count == 0)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen mail_index_excl_unlock_finish(index);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen }
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen if (index->shared_lock_count == 0 && index->excl_lock_count == 0) {
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen index->lock_id += 2;
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen index->lock_type = F_UNLCK;
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen (void)mail_index_lock_mprotect(index, F_UNLCK);
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen if (!index->fcntl_locks_disable) {
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen if (file_wait_lock(index->fd, F_UNLCK) < 0) {
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen mail_index_set_syscall_error(index,
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen "file_wait_lock()");
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen }
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen }
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen }
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen}
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainenint mail_index_is_locked(struct mail_index *index, unsigned int lock_id)
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen{
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen return (index->lock_id ^ lock_id) <= 1;
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen}
7bccaece91a0b1bc61111c30443d6bad6b22c6d0Timo Sirainen