mbox-lock.c revision 7c27b0ab7213121ea43994499c04059413f6d0f2
183bea41fa640dc8117f3eb45ff935cd81377a84Timo Sirainen/* Copyright (C) 2002 Timo Sirainen */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen#include "lib.h"
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen#include "mail-index-private.h"
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen#include "mbox-storage.h"
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen#include "mbox-file.h"
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen#include "mbox-lock.h"
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen#include <time.h>
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen#include <stdlib.h>
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen#include <unistd.h>
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen#include <fcntl.h>
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen#include <sys/stat.h>
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen#ifdef HAVE_FLOCK
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen# include <sys/file.h>
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen#endif
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen/* 0.1 .. 0.2msec */
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen#define LOCK_RANDOM_USLEEP_TIME (100000 + (unsigned int)rand() % 100000)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen/* lock methods to use in wanted order */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen#define DEFAULT_READ_LOCK_METHODS "fcntl"
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen#define DEFAULT_WRITE_LOCK_METHODS "dotlock fcntl"
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen/* lock timeout */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen#define DEFAULT_LOCK_TIMEOUT (10*60)
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen/* assume stale dotlock if mbox file hasn't changed for n seconds */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen#define DEFAULT_DOTLOCK_CHANGE_TIMEOUT (5*60)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainenenum mbox_lock_type {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen MBOX_LOCK_DOTLOCK,
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen MBOX_LOCK_FCNTL,
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen MBOX_LOCK_FLOCK,
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen MBOX_LOCK_LOCKF,
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen
1ff487015234b23c32cf8bb4c9f8c02922535b8eTimo Sirainen MBOX_LOCK_COUNT
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen};
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainenstruct mbox_lock_context {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen struct mbox_mailbox *mbox;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen int lock_status[MBOX_LOCK_COUNT];
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen int checked_file;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen int lock_type;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen int dotlock_last_stale;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen};
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
1ff487015234b23c32cf8bb4c9f8c02922535b8eTimo Sirainenstruct mbox_lock_data {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen enum mbox_lock_type type;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen const char *name;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen int (*func)(struct mbox_lock_context *ctx, int lock_type,
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen time_t max_wait_time);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen};
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainenstatic int mbox_lock_dotlock(struct mbox_lock_context *ctx, int lock_type,
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen time_t max_wait_time);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainenstatic int mbox_lock_fcntl(struct mbox_lock_context *ctx, int lock_type,
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen time_t max_wait_time);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen#ifdef HAVE_FLOCK
8bb360f9e5de1c25e4f875205bb06e8bf15dae14Timo Sirainenstatic int mbox_lock_flock(struct mbox_lock_context *ctx, int lock_type,
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen time_t max_wait_time);
c2f2a6cdf7dd55a4aabe72495cabb4deaa59cffcTimo Sirainen#else
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen# define mbox_lock_flock NULL
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen#endif
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen#ifdef HAVE_LOCKF
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainenstatic int mbox_lock_lockf(struct mbox_lock_context *ctx, int lock_type,
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen time_t max_wait_time);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen#else
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen# define mbox_lock_lockf NULL
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen#endif
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainenstruct mbox_lock_data lock_data[] = {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen { MBOX_LOCK_DOTLOCK, "dotlock", mbox_lock_dotlock },
1ff487015234b23c32cf8bb4c9f8c02922535b8eTimo Sirainen { MBOX_LOCK_FCNTL, "fcntl", mbox_lock_fcntl },
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen { MBOX_LOCK_FLOCK, "flock", mbox_lock_flock },
1ff487015234b23c32cf8bb4c9f8c02922535b8eTimo Sirainen { MBOX_LOCK_LOCKF, "lockf", mbox_lock_lockf },
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen { 0, NULL, NULL }
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen};
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen
1ff487015234b23c32cf8bb4c9f8c02922535b8eTimo Sirainenstatic int lock_settings_initialized = FALSE;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainenstatic enum mbox_lock_type read_locks[MBOX_LOCK_COUNT+1];
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainenstatic enum mbox_lock_type write_locks[MBOX_LOCK_COUNT+1];
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainenstatic int lock_timeout, dotlock_change_timeout;
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen
c2f2a6cdf7dd55a4aabe72495cabb4deaa59cffcTimo Sirainenstatic int mbox_lock_list(struct mbox_lock_context *ctx, int lock_type,
c2f2a6cdf7dd55a4aabe72495cabb4deaa59cffcTimo Sirainen time_t max_wait_time, int idx);
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainenstatic int mbox_unlock_files(struct mbox_lock_context *ctx);
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainenstatic void mbox_read_lock_methods(const char *str, const char *env,
c2f2a6cdf7dd55a4aabe72495cabb4deaa59cffcTimo Sirainen enum mbox_lock_type *locks)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen{
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen enum mbox_lock_type type;
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen const char *const *lock;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen int i, dest;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen for (lock = t_strsplit(str, " "), dest = 0; *lock != NULL; lock++) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen for (type = 0; lock_data[type].name != NULL; type++) {
c2f2a6cdf7dd55a4aabe72495cabb4deaa59cffcTimo Sirainen if (strcasecmp(*lock, lock_data[type].name) == 0) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen type = lock_data[type].type;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen break;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (lock_data[type].name == NULL)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen i_fatal("%s: Invalid value %s", env, *lock);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (lock_data[type].func == NULL) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen i_fatal("%s: Support for lock type %s "
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen "not compiled into binary", env, *lock);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
f16712057c1b82c6d2a3a4267c4521d357cd4b4cTimo Sirainen for (i = 0; i < dest; i++) {
cc3da53f3a49304a251bfae88f814505326ac210Timo Sirainen if (locks[i] == type)
cc3da53f3a49304a251bfae88f814505326ac210Timo Sirainen i_fatal("%s: Duplicated value %s", env, *lock);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* @UNSAFE */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen locks[dest++] = type;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen locks[dest] = (enum mbox_lock_type)-1;
51c331377beb4a2acb81aee4d12bc8ef6c496625Timo Sirainen}
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainenstatic void mbox_init_lock_settings(void)
51c331377beb4a2acb81aee4d12bc8ef6c496625Timo Sirainen{
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen const char *str;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen int r, w;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen str = getenv("MBOX_READ_LOCKS");
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (str == NULL) str = DEFAULT_READ_LOCK_METHODS;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen mbox_read_lock_methods(str, "MBOX_READ_LOCKS", read_locks);
cc3da53f3a49304a251bfae88f814505326ac210Timo Sirainen
cc3da53f3a49304a251bfae88f814505326ac210Timo Sirainen str = getenv("MBOX_WRITE_LOCKS");
cc3da53f3a49304a251bfae88f814505326ac210Timo Sirainen if (str == NULL) str = DEFAULT_WRITE_LOCK_METHODS;
cc3da53f3a49304a251bfae88f814505326ac210Timo Sirainen mbox_read_lock_methods(str, "MBOX_WRITE_LOCKS", write_locks);
cc3da53f3a49304a251bfae88f814505326ac210Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* check that read/write list orders match. write_locks must contain
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen at least read_locks and possibly more. */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen for (r = w = 0; write_locks[w] != (enum mbox_lock_type)-1; w++) {
c2f2a6cdf7dd55a4aabe72495cabb4deaa59cffcTimo Sirainen if (read_locks[r] == (enum mbox_lock_type)-1)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen break;
ad4cd18ba6c43fe94987408f81ed6547b29132d6Timo Sirainen if (read_locks[r] == write_locks[w])
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen r++;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (read_locks[r] != (enum mbox_lock_type)-1) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen i_fatal("mbox read/write lock list settings are invalid. "
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen "Lock ordering must be the same with both, "
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen "and write locks must contain all read locks "
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen "(and possibly more)");
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen str = getenv("MBOX_LOCK_TIMEOUT");
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen lock_timeout = str == NULL ? DEFAULT_LOCK_TIMEOUT : atoi(str);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen str = getenv("MBOX_DOTLOCK_CHANGE_TIMEOUT");
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen dotlock_change_timeout = str == NULL ?
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen DEFAULT_DOTLOCK_CHANGE_TIMEOUT : atoi(str);
c2f2a6cdf7dd55a4aabe72495cabb4deaa59cffcTimo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen lock_settings_initialized = TRUE;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen}
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainenstatic int mbox_file_open_latest(struct mbox_lock_context *ctx, int lock_type)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen{
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen struct mbox_mailbox *mbox = ctx->mbox;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen struct stat st;
c2f2a6cdf7dd55a4aabe72495cabb4deaa59cffcTimo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (ctx->checked_file || lock_type == F_UNLCK)
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen return 0;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (mbox->mbox_fd != -1) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (stat(mbox->path, &st) < 0) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen mbox_set_syscall_error(mbox, "stat()");
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen return -1;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
064ccad9cea2a75a0d6caa2c679b6cd22be58174Timo Sirainen if (st.st_ino != mbox->mbox_ino ||
064ccad9cea2a75a0d6caa2c679b6cd22be58174Timo Sirainen !CMP_DEV_T(st.st_dev, mbox->mbox_dev))
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen mbox_file_close(mbox);
f16712057c1b82c6d2a3a4267c4521d357cd4b4cTimo Sirainen }
064ccad9cea2a75a0d6caa2c679b6cd22be58174Timo Sirainen
064ccad9cea2a75a0d6caa2c679b6cd22be58174Timo Sirainen if (mbox->mbox_fd == -1) {
064ccad9cea2a75a0d6caa2c679b6cd22be58174Timo Sirainen if (mbox_file_open(mbox) < 0)
064ccad9cea2a75a0d6caa2c679b6cd22be58174Timo Sirainen return -1;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
064ccad9cea2a75a0d6caa2c679b6cd22be58174Timo Sirainen
064ccad9cea2a75a0d6caa2c679b6cd22be58174Timo Sirainen ctx->checked_file = TRUE;
064ccad9cea2a75a0d6caa2c679b6cd22be58174Timo Sirainen return 0;
064ccad9cea2a75a0d6caa2c679b6cd22be58174Timo Sirainen}
064ccad9cea2a75a0d6caa2c679b6cd22be58174Timo Sirainen
064ccad9cea2a75a0d6caa2c679b6cd22be58174Timo Sirainenstatic int dotlock_callback(unsigned int secs_left, int stale, void *context)
064ccad9cea2a75a0d6caa2c679b6cd22be58174Timo Sirainen{
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen struct mbox_lock_context *ctx = context;
064ccad9cea2a75a0d6caa2c679b6cd22be58174Timo Sirainen enum mbox_lock_type *lock_types;
064ccad9cea2a75a0d6caa2c679b6cd22be58174Timo Sirainen int i;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (stale && !ctx->dotlock_last_stale) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* get next index we wish to try locking. it's the one after
064ccad9cea2a75a0d6caa2c679b6cd22be58174Timo Sirainen dotlocking. */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen lock_types = ctx->lock_type == F_WRLCK ||
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen (ctx->lock_type == F_UNLCK &&
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen ctx->mbox->mbox_lock_type == F_WRLCK) ?
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen write_locks : read_locks;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen for (i = 0; lock_types[i] != (enum mbox_lock_type)-1; i++) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (lock_types[i] == MBOX_LOCK_DOTLOCK)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen break;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (lock_types[i] != (enum mbox_lock_type)-1 &&
f16712057c1b82c6d2a3a4267c4521d357cd4b4cTimo Sirainen lock_types[i+1] != (enum mbox_lock_type)-1) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen i++;
f16712057c1b82c6d2a3a4267c4521d357cd4b4cTimo Sirainen if (mbox_lock_list(ctx, ctx->lock_type, 0, i) <= 0) {
f16712057c1b82c6d2a3a4267c4521d357cd4b4cTimo Sirainen /* we couldn't get fd lock -
f16712057c1b82c6d2a3a4267c4521d357cd4b4cTimo Sirainen it's really locked */
51c331377beb4a2acb81aee4d12bc8ef6c496625Timo Sirainen ctx->dotlock_last_stale = TRUE;
51c331377beb4a2acb81aee4d12bc8ef6c496625Timo Sirainen return FALSE;
51c331377beb4a2acb81aee4d12bc8ef6c496625Timo Sirainen }
51c331377beb4a2acb81aee4d12bc8ef6c496625Timo Sirainen (void)mbox_lock_list(ctx, F_UNLCK, 0, i);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
f16712057c1b82c6d2a3a4267c4521d357cd4b4cTimo Sirainen ctx->dotlock_last_stale = stale;
f16712057c1b82c6d2a3a4267c4521d357cd4b4cTimo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen index_storage_lock_notify(&ctx->mbox->ibox, stale ?
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen MAILBOX_LOCK_NOTIFY_MAILBOX_OVERRIDE :
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen MAILBOX_LOCK_NOTIFY_MAILBOX_ABORT,
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen secs_left);
c2f2a6cdf7dd55a4aabe72495cabb4deaa59cffcTimo Sirainen return TRUE;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen}
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainenstatic int mbox_lock_dotlock(struct mbox_lock_context *ctx, int lock_type,
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen time_t max_wait_time __attr_unused__)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen{
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen struct mbox_mailbox *mbox = ctx->mbox;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen struct dotlock_settings set;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen int ret;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (lock_type == F_UNLCK) {
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen if (!mbox->mbox_dotlocked)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen return 1;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (file_dotlock_delete(&mbox->mbox_dotlock) <= 0) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen mbox_set_syscall_error(mbox, "file_dotlock_delete()");
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen ret = -1;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen mbox->mbox_dotlocked = FALSE;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen return 1;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen if (mbox->mbox_dotlocked)
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen return 1;
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen ctx->dotlock_last_stale = -1;
c2f2a6cdf7dd55a4aabe72495cabb4deaa59cffcTimo Sirainen
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen memset(&set, 0, sizeof(set));
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen set.timeout = lock_timeout;
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen set.stale_timeout = dotlock_change_timeout;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen set.callback = dotlock_callback;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen set.context = ctx;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen ret = file_dotlock_create(&set, mbox->path, 0, &mbox->mbox_dotlock);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (ret < 0) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen mbox_set_syscall_error(mbox, "file_lock_dotlock()");
cc3da53f3a49304a251bfae88f814505326ac210Timo Sirainen return -1;
cc3da53f3a49304a251bfae88f814505326ac210Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (ret == 0) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen mail_storage_set_error(STORAGE(mbox->storage),
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen "Timeout while waiting for lock");
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen return 0;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen mbox->mbox_dotlocked = TRUE;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (mbox_file_open_latest(ctx, lock_type) < 0)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen return -1;
4bd6702bfcb3568959acdb3cb68450aa76ed703bTimo Sirainen return 1;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen}
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen#ifdef HAVE_FLOCK
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainenstatic int mbox_lock_flock(struct mbox_lock_context *ctx, int lock_type,
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen time_t max_wait_time)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen{
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen time_t now, last_notify;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (mbox_file_open_latest(ctx, lock_type) < 0)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen return -1;
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (lock_type == F_UNLCK && ctx->mbox->mbox_fd == -1)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen return 1;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (lock_type == F_WRLCK)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen lock_type = LOCK_EX;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen else if (lock_type == F_RDLCK)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen lock_type = LOCK_SH;
c52eba0224a0ff239f4778a7f6ed5ce38d92a5ddTimo Sirainen else
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen lock_type = LOCK_UN;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen last_notify = 0;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen while (flock(ctx->mbox->mbox_fd, lock_type | LOCK_NB) < 0) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (errno != EWOULDBLOCK) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen mbox_set_syscall_error(ctx->mbox, "flock()");
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen return -1;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen now = time(NULL);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (now >= max_wait_time)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen return 0;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (now != last_notify) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen index_storage_lock_notify(&ctx->mbox->ibox,
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen MAILBOX_LOCK_NOTIFY_MAILBOX_ABORT,
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen max_wait_time - now);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen usleep(LOCK_RANDOM_USLEEP_TIME);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
f3aff3c6bf32d5bb0a61993b76a3fbe5ad798c09Timo Sirainen return 1;
200500ebd3c93a5771e7ae2f442659b9acb16eb6Timo Sirainen}
200500ebd3c93a5771e7ae2f442659b9acb16eb6Timo Sirainen#endif
200500ebd3c93a5771e7ae2f442659b9acb16eb6Timo Sirainen
f3aff3c6bf32d5bb0a61993b76a3fbe5ad798c09Timo Sirainen#ifdef HAVE_LOCKF
f3aff3c6bf32d5bb0a61993b76a3fbe5ad798c09Timo Sirainenstatic int mbox_lock_lockf(struct mbox_lock_context *ctx, int lock_type,
f3aff3c6bf32d5bb0a61993b76a3fbe5ad798c09Timo Sirainen time_t max_wait_time)
f3aff3c6bf32d5bb0a61993b76a3fbe5ad798c09Timo Sirainen{
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen time_t now, last_notify;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
f3aff3c6bf32d5bb0a61993b76a3fbe5ad798c09Timo Sirainen if (mbox_file_open_latest(ctx, lock_type) < 0)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen return -1;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
f3aff3c6bf32d5bb0a61993b76a3fbe5ad798c09Timo Sirainen if (lock_type == F_UNLCK && ctx->mbox->mbox_fd == -1)
f3aff3c6bf32d5bb0a61993b76a3fbe5ad798c09Timo Sirainen return 1;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (lock_type != F_UNLCK)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen lock_type = F_TLOCK;
1ff487015234b23c32cf8bb4c9f8c02922535b8eTimo Sirainen else
1ff487015234b23c32cf8bb4c9f8c02922535b8eTimo Sirainen lock_type = F_ULOCK;
1ff487015234b23c32cf8bb4c9f8c02922535b8eTimo Sirainen
1ff487015234b23c32cf8bb4c9f8c02922535b8eTimo Sirainen last_notify = 0;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen while (lockf(ctx->mbox->mbox_fd, lock_type, 0) < 0) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (errno != EAGAIN) {
15362cdf9df29fef8795e865957e17ec027a9ebfTimo Sirainen mbox_set_syscall_error(ctx->mbox, "lockf()");
15362cdf9df29fef8795e865957e17ec027a9ebfTimo Sirainen return -1;
15362cdf9df29fef8795e865957e17ec027a9ebfTimo Sirainen }
15362cdf9df29fef8795e865957e17ec027a9ebfTimo Sirainen
15362cdf9df29fef8795e865957e17ec027a9ebfTimo Sirainen now = time(NULL);
15362cdf9df29fef8795e865957e17ec027a9ebfTimo Sirainen if (now >= max_wait_time)
e161a5225abda0837b5deb8746ef808ba5e98d94Timo Sirainen return 0;
e161a5225abda0837b5deb8746ef808ba5e98d94Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (now != last_notify) {
e161a5225abda0837b5deb8746ef808ba5e98d94Timo Sirainen index_storage_lock_notify(&ctx->mbox->ibox,
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen MAILBOX_LOCK_NOTIFY_MAILBOX_ABORT,
15362cdf9df29fef8795e865957e17ec027a9ebfTimo Sirainen max_wait_time - now);
15362cdf9df29fef8795e865957e17ec027a9ebfTimo Sirainen }
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen usleep(LOCK_RANDOM_USLEEP_TIME);
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen }
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen return 1;
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen}
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen#endif
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainenstatic int mbox_lock_fcntl(struct mbox_lock_context *ctx, int lock_type,
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen time_t max_wait_time)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen{
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen struct flock fl;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen time_t now;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen unsigned int next_alarm;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen int wait_type;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (mbox_file_open_latest(ctx, lock_type) < 0)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen return -1;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (lock_type == F_UNLCK && ctx->mbox->mbox_fd == -1)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen return 1;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen memset(&fl, 0, sizeof(fl));
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen fl.l_type = lock_type;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen fl.l_whence = SEEK_SET;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen fl.l_start = 0;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen fl.l_len = 0;
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (max_wait_time == 0) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* usually we're waiting here, but if we came from
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen mbox_lock_dotlock(), we just want to try locking */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen wait_type = F_SETLK;
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen } else {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen wait_type = F_SETLKW;
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen now = time(NULL);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (now >= max_wait_time)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen alarm(1);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen else
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen alarm(I_MIN(max_wait_time - now, 5));
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen while (fcntl(ctx->mbox->mbox_fd, wait_type, &fl) < 0) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (errno != EINTR) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen mbox_set_syscall_error(ctx->mbox, "fcntl()");
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen alarm(0);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen return -1;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen now = time(NULL);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (now >= max_wait_time) {
alarm(0);
return 0;
}
/* notify locks once every 5 seconds.
try to use rounded values. */
next_alarm = (max_wait_time - now) % 5;
if (next_alarm == 0)
next_alarm = 5;
alarm(next_alarm);
index_storage_lock_notify(&ctx->mbox->ibox,
MAILBOX_LOCK_NOTIFY_MAILBOX_ABORT,
max_wait_time - now);
}
alarm(0);
return 1;
}
static int mbox_lock_list(struct mbox_lock_context *ctx, int lock_type,
time_t max_wait_time, int idx)
{
enum mbox_lock_type *lock_types;
enum mbox_lock_type type;
int i, ret = 0, lock_status;
ctx->lock_type = lock_type;
lock_types = lock_type == F_WRLCK ||
(lock_type == F_UNLCK && ctx->mbox->mbox_lock_type == F_WRLCK) ?
write_locks : read_locks;
for (i = idx; lock_types[i] != (enum mbox_lock_type)-1; i++) {
type = lock_types[i];
lock_status = lock_type != F_UNLCK;
if (ctx->lock_status[type] == lock_status)
continue;
ctx->lock_status[type] = lock_status;
ret = lock_data[type].func(ctx, lock_type, max_wait_time);
if (ret <= 0)
break;
}
return ret;
}
static int mbox_update_locking(struct mbox_mailbox *mbox, int lock_type)
{
struct mbox_lock_context ctx;
time_t max_wait_time;
int ret, i, drop_locks;
index_storage_lock_notify_reset(&mbox->ibox);
if (!lock_settings_initialized)
mbox_init_lock_settings();
if (mbox->mbox_fd == -1 && mbox->mbox_file_stream != NULL) {
/* read-only mbox stream. no need to lock. */
i_assert(mbox->mbox_readonly);
mbox->mbox_lock_type = lock_type;
return 1;
}
max_wait_time = time(NULL) + lock_timeout;
memset(&ctx, 0, sizeof(ctx));
ctx.mbox = mbox;
if (mbox->mbox_lock_type == F_WRLCK) {
/* dropping to shared lock. first drop those that we
don't remove completely. */
for (i = 0; i < MBOX_LOCK_COUNT; i++)
ctx.lock_status[i] = 1;
for (i = 0; read_locks[i] != (enum mbox_lock_type)-1; i++)
ctx.lock_status[read_locks[i]] = 0;
drop_locks = TRUE;
} else {
drop_locks = FALSE;
}
mbox->mbox_lock_type = lock_type;
ret = mbox_lock_list(&ctx, lock_type, max_wait_time, 0);
if (ret <= 0) {
if (!drop_locks)
(void)mbox_unlock_files(&ctx);
if (ret == 0) {
mail_storage_set_error(STORAGE(mbox->storage),
"Timeout while waiting for lock");
}
return ret;
}
if (drop_locks) {
/* dropping to shared lock: drop the locks that are only
in write list */
memset(ctx.lock_status, 0, sizeof(ctx.lock_status));
for (i = 0; write_locks[i] != (enum mbox_lock_type)-1; i++)
ctx.lock_status[write_locks[i]] = 1;
for (i = 0; read_locks[i] != (enum mbox_lock_type)-1; i++)
ctx.lock_status[read_locks[i]] = 0;
mbox->mbox_lock_type = F_WRLCK;
(void)mbox_lock_list(&ctx, F_UNLCK, 0, 0);
mbox->mbox_lock_type = F_RDLCK;
}
return 1;
}
int mbox_lock(struct mbox_mailbox *mbox, int lock_type,
unsigned int *lock_id_r)
{
int ret;
/* allow only unlock -> shared/exclusive or exclusive -> shared */
i_assert(lock_type == F_RDLCK || lock_type == F_WRLCK);
i_assert(lock_type == F_RDLCK || mbox->mbox_lock_type != F_RDLCK);
/* mbox must be locked before index */
i_assert(mbox->ibox.index->lock_type != F_WRLCK);
if (mbox->mbox_lock_type == F_UNLCK) {
ret = mbox_update_locking(mbox, lock_type);
if (ret <= 0)
return ret;
mbox->mbox_lock_id += 2;
}
if (lock_type == F_RDLCK) {
mbox->mbox_shared_locks++;
*lock_id_r = mbox->mbox_lock_id;
} else {
mbox->mbox_excl_locks++;
*lock_id_r = mbox->mbox_lock_id + 1;
}
return 1;
}
static int mbox_unlock_files(struct mbox_lock_context *ctx)
{
int ret = 0;
if (mbox_lock_list(ctx, F_UNLCK, 0, 0) < 0)
ret = -1;
if (ctx->mbox->ibox.mail_read_mmaped) {
/* make sure we don't keep mmap() between locks */
mbox_file_close_stream(ctx->mbox);
}
ctx->mbox->mbox_lock_id += 2;
ctx->mbox->mbox_lock_type = F_UNLCK;
return ret;
}
int mbox_unlock(struct mbox_mailbox *mbox, unsigned int lock_id)
{
struct mbox_lock_context ctx;
int i;
i_assert(mbox->mbox_lock_id == (lock_id & ~1));
if (lock_id & 1) {
/* dropping exclusive lock */
i_assert(mbox->mbox_excl_locks > 0);
if (--mbox->mbox_excl_locks > 0)
return 0;
if (mbox->mbox_shared_locks > 0) {
/* drop to shared lock */
if (mbox_update_locking(mbox, F_RDLCK) < 0)
return -1;
return 0;
}
} else {
/* dropping shared lock */
i_assert(mbox->mbox_shared_locks > 0);
if (--mbox->mbox_shared_locks > 0)
return 0;
if (mbox->mbox_excl_locks > 0)
return 0;
}
/* all locks gone */
memset(&ctx, 0, sizeof(ctx));
ctx.mbox = mbox;
for (i = 0; i < MBOX_LOCK_COUNT; i++)
ctx.lock_status[i] = 1;
return mbox_unlock_files(&ctx);
}