mbox-lock.c revision ff7056842f14fd3b30a2d327dfab165b9d15dd30
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen/* Copyright (C) 2002 Timo Sirainen */
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "lib.h"
6dc4af35c045e10609b13fe80f9cf33f3a06c3ceTimo Sirainen#include "mail-index-private.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "mbox-storage.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "mbox-file.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "mbox-lock.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include <time.h>
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include <stdlib.h>
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include <unistd.h>
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include <fcntl.h>
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include <sys/stat.h>
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#ifdef HAVE_FLOCK
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen# include <sys/file.h>
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#endif
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen/* 0.1 .. 0.2msec */
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#define LOCK_RANDOM_USLEEP_TIME (100000 + (unsigned int)rand() % 100000)
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen/* lock methods to use in wanted order */
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen#define DEFAULT_READ_LOCK_METHODS "fcntl"
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen#define DEFAULT_WRITE_LOCK_METHODS "dotlock fcntl"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen/* lock timeout */
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen#define MBOX_DEFAULT_LOCK_TIMEOUT (5*60)
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen/* assume stale dotlock if mbox file hasn't changed for n seconds */
cfddb734b85ceaf49451d2f68aaad64a860ca6f6Timo Sirainen#define DEFAULT_DOTLOCK_CHANGE_TIMEOUT (120)
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainenenum mbox_lock_type {
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen MBOX_LOCK_DOTLOCK,
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen MBOX_LOCK_FCNTL,
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen MBOX_LOCK_FLOCK,
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen MBOX_LOCK_LOCKF,
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen MBOX_LOCK_COUNT
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen};
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainenstruct mbox_lock_context {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen struct mbox_mailbox *mbox;
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen int lock_status[MBOX_LOCK_COUNT];
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen bool checked_file;
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen int lock_type;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen bool dotlock_last_stale;
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen};
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainenstruct mbox_lock_data {
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen enum mbox_lock_type type;
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen const char *name;
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen int (*func)(struct mbox_lock_context *ctx, int lock_type,
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen time_t max_wait_time);
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen};
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainenstatic int mbox_lock_dotlock(struct mbox_lock_context *ctx, int lock_type,
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen time_t max_wait_time);
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainenstatic int mbox_lock_fcntl(struct mbox_lock_context *ctx, int lock_type,
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen time_t max_wait_time);
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen#ifdef HAVE_FLOCK
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainenstatic int mbox_lock_flock(struct mbox_lock_context *ctx, int lock_type,
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen time_t max_wait_time);
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen#else
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen# define mbox_lock_flock NULL
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen#endif
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen#ifdef HAVE_LOCKF
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainenstatic int mbox_lock_lockf(struct mbox_lock_context *ctx, int lock_type,
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen time_t max_wait_time);
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen#else
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen# define mbox_lock_lockf NULL
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen#endif
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainenstruct mbox_lock_data lock_data[] = {
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen { MBOX_LOCK_DOTLOCK, "dotlock", mbox_lock_dotlock },
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen { MBOX_LOCK_FCNTL, "fcntl", mbox_lock_fcntl },
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen { MBOX_LOCK_FLOCK, "flock", mbox_lock_flock },
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen { MBOX_LOCK_LOCKF, "lockf", mbox_lock_lockf },
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen { 0, NULL, NULL }
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen};
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainenstatic bool lock_settings_initialized = FALSE;
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainenstatic enum mbox_lock_type read_locks[MBOX_LOCK_COUNT+1];
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainenstatic enum mbox_lock_type write_locks[MBOX_LOCK_COUNT+1];
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainenstatic int lock_timeout, dotlock_change_timeout;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainenstatic int mbox_lock_list(struct mbox_lock_context *ctx, int lock_type,
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen time_t max_wait_time, int idx);
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainenstatic int mbox_unlock_files(struct mbox_lock_context *ctx);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainenstatic void mbox_read_lock_methods(const char *str, const char *env,
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen enum mbox_lock_type *locks)
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen{
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen enum mbox_lock_type type;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen const char *const *lock;
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen int i, dest;
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen for (lock = t_strsplit(str, " "), dest = 0; *lock != NULL; lock++) {
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen for (type = 0; lock_data[type].name != NULL; type++) {
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen if (strcasecmp(*lock, lock_data[type].name) == 0) {
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen type = lock_data[type].type;
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen break;
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen }
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen }
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen if (lock_data[type].name == NULL)
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen i_fatal("%s: Invalid value %s", env, *lock);
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen if (lock_data[type].func == NULL) {
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen i_fatal("%s: Support for lock type %s "
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen "not compiled into binary", env, *lock);
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen }
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen for (i = 0; i < dest; i++) {
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen if (locks[i] == type)
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen i_fatal("%s: Duplicated value %s", env, *lock);
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen }
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen /* @UNSAFE */
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen locks[dest++] = type;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen }
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen locks[dest] = (enum mbox_lock_type)-1;
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen}
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainenstatic void mbox_init_lock_settings(void)
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen{
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen const char *str;
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen int r, w;
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen str = getenv("MBOX_READ_LOCKS");
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen if (str == NULL) str = DEFAULT_READ_LOCK_METHODS;
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen mbox_read_lock_methods(str, "MBOX_READ_LOCKS", read_locks);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen str = getenv("MBOX_WRITE_LOCKS");
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen if (str == NULL) str = DEFAULT_WRITE_LOCK_METHODS;
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen mbox_read_lock_methods(str, "MBOX_WRITE_LOCKS", write_locks);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen /* check that read/write list orders match. write_locks must contain
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen at least read_locks and possibly more. */
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen for (r = w = 0; write_locks[w] != (enum mbox_lock_type)-1; w++) {
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen if (read_locks[r] == (enum mbox_lock_type)-1)
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen break;
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen if (read_locks[r] == write_locks[w])
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen r++;
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen }
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen if (read_locks[r] != (enum mbox_lock_type)-1) {
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen i_fatal("mbox read/write lock list settings are invalid. "
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen "Lock ordering must be the same with both, "
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen "and write locks must contain all read locks "
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen "(and possibly more)");
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen }
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen str = getenv("MBOX_LOCK_TIMEOUT");
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen lock_timeout = str == NULL ? MBOX_DEFAULT_LOCK_TIMEOUT : atoi(str);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen str = getenv("MBOX_DOTLOCK_CHANGE_TIMEOUT");
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen dotlock_change_timeout = str == NULL ?
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen DEFAULT_DOTLOCK_CHANGE_TIMEOUT : atoi(str);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen lock_settings_initialized = TRUE;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen}
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainenstatic int mbox_file_open_latest(struct mbox_lock_context *ctx, int lock_type)
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen{
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen struct mbox_mailbox *mbox = ctx->mbox;
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen struct stat st;
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen if (ctx->checked_file || lock_type == F_UNLCK)
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen return 0;
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (mbox->mbox_fd != -1) {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (stat(mbox->path, &st) < 0) {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen mbox_set_syscall_error(mbox, "stat()");
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen return -1;
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen }
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (st.st_ino != mbox->mbox_ino ||
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen !CMP_DEV_T(st.st_dev, mbox->mbox_dev))
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen mbox_file_close(mbox);
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen }
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (mbox->mbox_fd == -1) {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (mbox_file_open(mbox) < 0)
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen return -1;
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen }
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen ctx->checked_file = TRUE;
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen return 0;
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen}
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainenstatic bool dotlock_callback(unsigned int secs_left, bool stale, void *context)
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen{
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen struct mbox_lock_context *ctx = context;
a505d1beb29cbffab724b92ad16d0c44ebbaffb9Timo Sirainen enum mbox_lock_type *lock_types;
a505d1beb29cbffab724b92ad16d0c44ebbaffb9Timo Sirainen int i;
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen if (stale && !ctx->dotlock_last_stale) {
a505d1beb29cbffab724b92ad16d0c44ebbaffb9Timo Sirainen /* get next index we wish to try locking. it's the one after
a505d1beb29cbffab724b92ad16d0c44ebbaffb9Timo Sirainen dotlocking. */
a505d1beb29cbffab724b92ad16d0c44ebbaffb9Timo Sirainen lock_types = ctx->lock_type == F_WRLCK ||
a505d1beb29cbffab724b92ad16d0c44ebbaffb9Timo Sirainen (ctx->lock_type == F_UNLCK &&
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen ctx->mbox->mbox_lock_type == F_WRLCK) ?
a505d1beb29cbffab724b92ad16d0c44ebbaffb9Timo Sirainen write_locks : read_locks;
a505d1beb29cbffab724b92ad16d0c44ebbaffb9Timo Sirainen
a505d1beb29cbffab724b92ad16d0c44ebbaffb9Timo Sirainen for (i = 0; lock_types[i] != (enum mbox_lock_type)-1; i++) {
a505d1beb29cbffab724b92ad16d0c44ebbaffb9Timo Sirainen if (lock_types[i] == MBOX_LOCK_DOTLOCK)
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen break;
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen }
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen
a505d1beb29cbffab724b92ad16d0c44ebbaffb9Timo Sirainen if (lock_types[i] != (enum mbox_lock_type)-1 &&
a505d1beb29cbffab724b92ad16d0c44ebbaffb9Timo Sirainen lock_types[i+1] != (enum mbox_lock_type)-1) {
a505d1beb29cbffab724b92ad16d0c44ebbaffb9Timo Sirainen i++;
a505d1beb29cbffab724b92ad16d0c44ebbaffb9Timo Sirainen if (mbox_lock_list(ctx, ctx->lock_type, 0, i) <= 0) {
a505d1beb29cbffab724b92ad16d0c44ebbaffb9Timo Sirainen /* we couldn't get fd lock -
a505d1beb29cbffab724b92ad16d0c44ebbaffb9Timo Sirainen it's really locked */
a505d1beb29cbffab724b92ad16d0c44ebbaffb9Timo Sirainen ctx->dotlock_last_stale = TRUE;
a505d1beb29cbffab724b92ad16d0c44ebbaffb9Timo Sirainen return FALSE;
a505d1beb29cbffab724b92ad16d0c44ebbaffb9Timo Sirainen }
a505d1beb29cbffab724b92ad16d0c44ebbaffb9Timo Sirainen (void)mbox_lock_list(ctx, F_UNLCK, 0, i);
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen }
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen }
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen ctx->dotlock_last_stale = stale;
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen index_storage_lock_notify(&ctx->mbox->ibox, stale ?
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen MAILBOX_LOCK_NOTIFY_MAILBOX_OVERRIDE :
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen MAILBOX_LOCK_NOTIFY_MAILBOX_ABORT,
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen secs_left);
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen return TRUE;
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen}
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainenstatic int mbox_lock_dotlock(struct mbox_lock_context *ctx, int lock_type,
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen time_t max_wait_time __attr_unused__)
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen{
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen struct mbox_mailbox *mbox = ctx->mbox;
13c6532dc104d23061e6901783ceb1ff8872c206Timo Sirainen struct dotlock_settings set;
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen int ret;
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen if (lock_type == F_UNLCK) {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (!mbox->mbox_dotlocked)
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen return 1;
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (file_dotlock_delete(&mbox->mbox_dotlock) <= 0) {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen mbox_set_syscall_error(mbox, "file_dotlock_delete()");
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen ret = -1;
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen }
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen mbox->mbox_dotlocked = FALSE;
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen return 1;
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen }
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (mbox->mbox_dotlocked)
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen return 1;
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen ctx->dotlock_last_stale = -1;
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen
13c6532dc104d23061e6901783ceb1ff8872c206Timo Sirainen memset(&set, 0, sizeof(set));
ccc895c0358108d2304239063e940b7d75f364abTimo Sirainen set.use_excl_lock = (mbox->storage->storage.flags &
6e1e9e341ffe21a69a23229c2b896d03066a071eTimo Sirainen MAIL_STORAGE_FLAG_DOTLOCK_USE_EXCL) != 0;
13c6532dc104d23061e6901783ceb1ff8872c206Timo Sirainen set.timeout = lock_timeout;
13c6532dc104d23061e6901783ceb1ff8872c206Timo Sirainen set.stale_timeout = dotlock_change_timeout;
13c6532dc104d23061e6901783ceb1ff8872c206Timo Sirainen set.callback = dotlock_callback;
13c6532dc104d23061e6901783ceb1ff8872c206Timo Sirainen set.context = ctx;
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen ret = file_dotlock_create(&set, mbox->path, 0, &mbox->mbox_dotlock);
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen if (ret < 0) {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen mbox_set_syscall_error(mbox, "file_lock_dotlock()");
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen return -1;
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen }
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen if (ret == 0) {
ccc895c0358108d2304239063e940b7d75f364abTimo Sirainen mail_storage_set_error(&mbox->storage->storage,
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen MAIL_ERROR_TEMP, MAIL_ERRSTR_LOCK_TIMEOUT);
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen return 0;
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen }
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen mbox->mbox_dotlocked = TRUE;
13c6532dc104d23061e6901783ceb1ff8872c206Timo Sirainen
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen if (mbox_file_open_latest(ctx, lock_type) < 0)
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen return -1;
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen return 1;
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen}
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#ifdef HAVE_FLOCK
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainenstatic int mbox_lock_flock(struct mbox_lock_context *ctx, int lock_type,
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen time_t max_wait_time)
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen{
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen time_t now, last_notify;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen if (mbox_file_open_latest(ctx, lock_type) < 0)
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen return -1;
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (lock_type == F_UNLCK && ctx->mbox->mbox_fd == -1)
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen return 1;
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen if (lock_type == F_WRLCK)
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen lock_type = LOCK_EX;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen else if (lock_type == F_RDLCK)
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen lock_type = LOCK_SH;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen else
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen lock_type = LOCK_UN;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen last_notify = 0;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen while (flock(ctx->mbox->mbox_fd, lock_type | LOCK_NB) < 0) {
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen if (errno != EWOULDBLOCK) {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen mbox_set_syscall_error(ctx->mbox, "flock()");
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen return -1;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen }
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen now = time(NULL);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen if (now >= max_wait_time)
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen return 0;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen if (now != last_notify) {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen index_storage_lock_notify(&ctx->mbox->ibox,
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen MAILBOX_LOCK_NOTIFY_MAILBOX_ABORT,
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen max_wait_time - now);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen }
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen usleep(LOCK_RANDOM_USLEEP_TIME);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen }
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen return 1;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen}
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#endif
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen#ifdef HAVE_LOCKF
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainenstatic int mbox_lock_lockf(struct mbox_lock_context *ctx, int lock_type,
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen time_t max_wait_time)
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen{
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen time_t now, last_notify;
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen if (mbox_file_open_latest(ctx, lock_type) < 0)
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen return -1;
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (lock_type == F_UNLCK && ctx->mbox->mbox_fd == -1)
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen return 1;
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen if (lock_type != F_UNLCK)
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen lock_type = F_TLOCK;
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen else
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen lock_type = F_ULOCK;
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen last_notify = 0;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen while (lockf(ctx->mbox->mbox_fd, lock_type, 0) < 0) {
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen if (errno != EAGAIN) {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen mbox_set_syscall_error(ctx->mbox, "lockf()");
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen return -1;
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen }
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen now = time(NULL);
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen if (now >= max_wait_time)
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen return 0;
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen if (now != last_notify) {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen index_storage_lock_notify(&ctx->mbox->ibox,
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen MAILBOX_LOCK_NOTIFY_MAILBOX_ABORT,
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen max_wait_time - now);
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen }
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen usleep(LOCK_RANDOM_USLEEP_TIME);
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen }
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen return 1;
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen}
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen#endif
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainenstatic int mbox_lock_fcntl(struct mbox_lock_context *ctx, int lock_type,
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen time_t max_wait_time)
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen{
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen struct flock fl;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen time_t now;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen unsigned int next_alarm;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen int wait_type;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen if (mbox_file_open_latest(ctx, lock_type) < 0)
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen return -1;
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (lock_type == F_UNLCK && ctx->mbox->mbox_fd == -1)
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen return 1;
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen
b3febb0933fdce10394d25093e23ce0a5aadddd3Timo Sirainen memset(&fl, 0, sizeof(fl));
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen fl.l_type = lock_type;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen fl.l_whence = SEEK_SET;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen fl.l_start = 0;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen fl.l_len = 0;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
822b71c04ddd61cb08a0104f9e58f55334725e2aTimo Sirainen if (max_wait_time == 0) {
7c27b0ab7213121ea43994499c04059413f6d0f2Timo Sirainen /* usually we're waiting here, but if we came from
7c27b0ab7213121ea43994499c04059413f6d0f2Timo Sirainen mbox_lock_dotlock(), we just want to try locking */
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen wait_type = F_SETLK;
822b71c04ddd61cb08a0104f9e58f55334725e2aTimo Sirainen } else {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen wait_type = F_SETLKW;
822b71c04ddd61cb08a0104f9e58f55334725e2aTimo Sirainen now = time(NULL);
822b71c04ddd61cb08a0104f9e58f55334725e2aTimo Sirainen if (now >= max_wait_time)
822b71c04ddd61cb08a0104f9e58f55334725e2aTimo Sirainen alarm(1);
822b71c04ddd61cb08a0104f9e58f55334725e2aTimo Sirainen else
822b71c04ddd61cb08a0104f9e58f55334725e2aTimo Sirainen alarm(I_MIN(max_wait_time - now, 5));
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen while (fcntl(ctx->mbox->mbox_fd, wait_type, &fl) < 0) {
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen if (errno != EINTR) {
88de8e8fb4ad86f59ac0c4d85f5a9103dfd3fcc0Timo Sirainen if ((errno == EACCES || errno == EAGAIN) &&
88de8e8fb4ad86f59ac0c4d85f5a9103dfd3fcc0Timo Sirainen wait_type == F_SETLK) {
88de8e8fb4ad86f59ac0c4d85f5a9103dfd3fcc0Timo Sirainen /* non-blocking lock trying failed */
88de8e8fb4ad86f59ac0c4d85f5a9103dfd3fcc0Timo Sirainen return 0;
88de8e8fb4ad86f59ac0c4d85f5a9103dfd3fcc0Timo Sirainen }
c817e46049c4dc07f7bbc16f43f903ab7ea9ae7dTimo Sirainen mbox_set_syscall_error(ctx->mbox, "fcntl()");
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen alarm(0);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen return -1;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen }
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen now = time(NULL);
822b71c04ddd61cb08a0104f9e58f55334725e2aTimo Sirainen if (now >= max_wait_time) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen alarm(0);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen return 0;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen /* notify locks once every 5 seconds.
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen try to use rounded values. */
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen next_alarm = (max_wait_time - now) % 5;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (next_alarm == 0)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen next_alarm = 5;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen alarm(next_alarm);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen index_storage_lock_notify(&ctx->mbox->ibox,
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen MAILBOX_LOCK_NOTIFY_MAILBOX_ABORT,
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen max_wait_time - now);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen }
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen alarm(0);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen return 1;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen}
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainenstatic int mbox_lock_list(struct mbox_lock_context *ctx, int lock_type,
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen time_t max_wait_time, int idx)
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen{
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen enum mbox_lock_type *lock_types;
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen enum mbox_lock_type type;
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen int i, ret = 0, lock_status;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen ctx->lock_type = lock_type;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen lock_types = lock_type == F_WRLCK ||
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen (lock_type == F_UNLCK && ctx->mbox->mbox_lock_type == F_WRLCK) ?
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen write_locks : read_locks;
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen for (i = idx; lock_types[i] != (enum mbox_lock_type)-1; i++) {
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen type = lock_types[i];
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen lock_status = lock_type != F_UNLCK;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen if (ctx->lock_status[type] == lock_status)
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen continue;
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen ctx->lock_status[type] = lock_status;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen ret = lock_data[type].func(ctx, lock_type, max_wait_time);
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen if (ret <= 0)
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen break;
fc1696e32dd732a5bbabc3c8f64810448e327043Timo Sirainen }
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen return ret;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen}
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainenstatic int mbox_update_locking(struct mbox_mailbox *mbox, int lock_type)
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen{
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen struct mbox_lock_context ctx;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen time_t max_wait_time;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen int ret, i;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen bool drop_locks;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen index_storage_lock_notify_reset(&mbox->ibox);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen if (!lock_settings_initialized)
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen mbox_init_lock_settings();
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (mbox->mbox_fd == -1 && mbox->mbox_file_stream != NULL) {
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen /* read-only mbox stream. no need to lock. */
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen i_assert(mbox->mbox_readonly);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen mbox->mbox_lock_type = lock_type;
c817e46049c4dc07f7bbc16f43f903ab7ea9ae7dTimo Sirainen return 1;
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen }
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen max_wait_time = time(NULL) + lock_timeout;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen memset(&ctx, 0, sizeof(ctx));
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen ctx.mbox = mbox;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (mbox->mbox_lock_type == F_WRLCK) {
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen /* dropping to shared lock. first drop those that we
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen don't remove completely. */
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen for (i = 0; i < MBOX_LOCK_COUNT; i++)
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen ctx.lock_status[i] = 1;
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen for (i = 0; read_locks[i] != (enum mbox_lock_type)-1; i++)
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen ctx.lock_status[read_locks[i]] = 0;
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen drop_locks = TRUE;
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen } else {
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen drop_locks = FALSE;
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen }
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen mbox->mbox_lock_type = lock_type;
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen ret = mbox_lock_list(&ctx, lock_type, max_wait_time, 0);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen if (ret <= 0) {
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen if (!drop_locks)
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen (void)mbox_unlock_files(&ctx);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen if (ret == 0) {
ccc895c0358108d2304239063e940b7d75f364abTimo Sirainen mail_storage_set_error(&mbox->storage->storage,
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen MAIL_ERROR_TEMP, MAIL_ERRSTR_LOCK_TIMEOUT);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen }
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen return ret;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen }
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen if (drop_locks) {
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen /* dropping to shared lock: drop the locks that are only
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen in write list */
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen memset(ctx.lock_status, 0, sizeof(ctx.lock_status));
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen for (i = 0; write_locks[i] != (enum mbox_lock_type)-1; i++)
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen ctx.lock_status[write_locks[i]] = 1;
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen for (i = 0; read_locks[i] != (enum mbox_lock_type)-1; i++)
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen ctx.lock_status[read_locks[i]] = 0;
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen mbox->mbox_lock_type = F_WRLCK;
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen (void)mbox_lock_list(&ctx, F_UNLCK, 0, 0);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen mbox->mbox_lock_type = F_RDLCK;
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen }
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen return 1;
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen}
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainenint mbox_lock(struct mbox_mailbox *mbox, int lock_type,
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen unsigned int *lock_id_r)
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen{
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen int ret;
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen /* allow only unlock -> shared/exclusive or exclusive -> shared */
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen i_assert(lock_type == F_RDLCK || lock_type == F_WRLCK);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen i_assert(lock_type == F_RDLCK || mbox->mbox_lock_type != F_RDLCK);
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen
6dc4af35c045e10609b13fe80f9cf33f3a06c3ceTimo Sirainen /* mbox must be locked before index */
6dc4af35c045e10609b13fe80f9cf33f3a06c3ceTimo Sirainen i_assert(mbox->ibox.index->lock_type != F_WRLCK);
6dc4af35c045e10609b13fe80f9cf33f3a06c3ceTimo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (mbox->mbox_lock_type == F_UNLCK) {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen ret = mbox_update_locking(mbox, lock_type);
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen if (ret <= 0)
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen return ret;
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen mbox->mbox_lock_id += 2;
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen }
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen if (lock_type == F_RDLCK) {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen mbox->mbox_shared_locks++;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen *lock_id_r = mbox->mbox_lock_id;
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen } else {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen mbox->mbox_excl_locks++;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen *lock_id_r = mbox->mbox_lock_id + 1;
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen }
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen return 1;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen}
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainenstatic int mbox_unlock_files(struct mbox_lock_context *ctx)
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen{
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen int ret = 0;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen if (mbox_lock_list(ctx, F_UNLCK, 0, 0) < 0)
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen ret = -1;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen ctx->mbox->mbox_lock_id += 2;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen ctx->mbox->mbox_lock_type = F_UNLCK;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen return ret;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen}
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainenint mbox_unlock(struct mbox_mailbox *mbox, unsigned int lock_id)
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen{
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen struct mbox_lock_context ctx;
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen int i;
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen i_assert(mbox->mbox_lock_id == (lock_id & ~1));
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen if (lock_id & 1) {
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen /* dropping exclusive lock */
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen i_assert(mbox->mbox_excl_locks > 0);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (--mbox->mbox_excl_locks > 0)
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen return 0;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (mbox->mbox_shared_locks > 0) {
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen /* drop to shared lock */
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (mbox_update_locking(mbox, F_RDLCK) < 0)
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen return -1;
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen return 0;
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen }
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen } else {
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen /* dropping shared lock */
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen i_assert(mbox->mbox_shared_locks > 0);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (--mbox->mbox_shared_locks > 0)
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen return 0;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (mbox->mbox_excl_locks > 0)
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen return 0;
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen }
2c7ab05ef98c46eb70c8ba6ea85e49749aafb2a3Timo Sirainen /* all locks gone */
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen memset(&ctx, 0, sizeof(ctx));
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen ctx.mbox = mbox;
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen for (i = 0; i < MBOX_LOCK_COUNT; i++)
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen ctx.lock_status[i] = 1;
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen
704efd0b34e3611e3decf1d559fe6a93214b0bd0Timo Sirainen return mbox_unlock_files(&ctx);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen}