mbox-lock.c revision b3febb0933fdce10394d25093e23ce0a5aadddd3
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen/* Copyright (C) 2002 Timo Sirainen */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "lib.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "mbox-storage.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "mbox-file.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "mbox-lock.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include <time.h>
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include <stdlib.h>
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include <unistd.h>
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include <fcntl.h>
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include <sys/stat.h>
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#ifdef HAVE_FLOCK
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen# include <sys/file.h>
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#endif
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen/* 0.1 .. 0.2msec */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#define LOCK_RANDOM_USLEEP_TIME (100000 + (unsigned int)rand() % 100000)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen/* lock methods to use in wanted order */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#define DEFAULT_READ_LOCK_METHODS "fcntl"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#define DEFAULT_WRITE_LOCK_METHODS "dotlock fcntl"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen/* lock timeout */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#define DEFAULT_LOCK_TIMEOUT 300
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen/* assume stale dotlock if mbox file hasn't changed for n seconds */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#define DEFAULT_DOTLOCK_CHANGE_TIMEOUT 30
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstruct dotlock_context {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct index_mailbox *ibox;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen int lock_type;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen int last_stale;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen};
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenenum mbox_lock_type {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen MBOX_LOCK_DOTLOCK,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen MBOX_LOCK_FCNTL,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen MBOX_LOCK_FLOCK,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen MBOX_LOCK_LOCKF,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen MBOX_LOCK_COUNT
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen};
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstruct mbox_lock_data {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen enum mbox_lock_type type;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const char *name;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen int (*func)(struct index_mailbox *ibox, int lock_type,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen time_t max_wait_time);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen};
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic int mbox_lock_fcntl(struct index_mailbox *ibox, int lock_type,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen time_t max_wait_time);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#ifdef HAVE_FLOCK
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic int mbox_lock_flock(struct index_mailbox *ibox, int lock_type,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen time_t max_wait_time);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#else
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen# define mbox_lock_flock NULL
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#endif
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#ifdef HAVE_LOCKF
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic int mbox_lock_lockf(struct index_mailbox *ibox, int lock_type,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen time_t max_wait_time);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#else
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen# define mbox_lock_lockf NULL
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#endif
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstruct mbox_lock_data lock_data[] = {
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen { MBOX_LOCK_DOTLOCK, "dotlock", NULL },
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen { MBOX_LOCK_FCNTL, "fcntl", mbox_lock_fcntl },
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen { MBOX_LOCK_FLOCK, "flock", mbox_lock_flock },
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen { MBOX_LOCK_LOCKF, "lockf", mbox_lock_lockf },
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen { 0, NULL, NULL }
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen};
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainenstatic int lock_settings_initialized = FALSE;
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainenstatic enum mbox_lock_type read_locks[MBOX_LOCK_COUNT+1];
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainenstatic enum mbox_lock_type write_locks[MBOX_LOCK_COUNT+1];
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainenstatic int lock_timeout, dotlock_change_timeout;
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainenstatic int mbox_unlock_files(struct index_mailbox *ibox);
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic void mbox_read_lock_methods(const char *str, const char *env,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen enum mbox_lock_type *locks)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen enum mbox_lock_type type;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const char *const *lock;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen int i, dest;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen for (lock = t_strsplit(str, " "), dest = 0; *lock != NULL; lock++) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen for (type = 0; lock_data[type].name != NULL; type++) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (strcasecmp(*lock, lock_data[type].name) == 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen type = lock_data[type].type;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen break;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (lock_data[type].name == NULL)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_fatal("%s: Invalid value %s", env, *lock);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (lock_data[type].func == NULL && type != MBOX_LOCK_DOTLOCK) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_fatal("%s: Support for lock type %s "
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "not compiled into binary", env, *lock);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen for (i = 0; i < dest; i++) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (locks[i] == type)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_fatal("%s: Duplicated value %s", env, *lock);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (type == MBOX_LOCK_DOTLOCK && dest != 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_fatal("%s: dotlock must be first in the list", *lock);
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen /* @UNSAFE */
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen locks[dest++] = type;
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen }
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen locks[dest] = (enum mbox_lock_type)-1;
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic void mbox_init_lock_settings(void)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const char *str;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen str = getenv("MBOX_READ_LOCKS");
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (str == NULL) str = DEFAULT_READ_LOCK_METHODS;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mbox_read_lock_methods(str, "MBOX_READ_LOCKS", read_locks);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen str = getenv("MBOX_WRITE_LOCKS");
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (str == NULL) str = DEFAULT_WRITE_LOCK_METHODS;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mbox_read_lock_methods(str, "MBOX_WRITE_LOCKS", write_locks);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen str = getenv("MBOX_LOCK_TIMEOUT");
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen lock_timeout = str == NULL ? DEFAULT_LOCK_TIMEOUT : atoi(str);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen str = getenv("MBOX_DOTLOCK_CHANGE_TIMEOUT");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen dotlock_change_timeout = str == NULL ?
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen DEFAULT_DOTLOCK_CHANGE_TIMEOUT : atoi(str);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen lock_settings_initialized = TRUE;
6d2b3ce2c6ef62334985ece4f0ab8b154e0e9560Timo Sirainen}
6d2b3ce2c6ef62334985ece4f0ab8b154e0e9560Timo Sirainen
6d2b3ce2c6ef62334985ece4f0ab8b154e0e9560Timo Sirainen#ifdef HAVE_FLOCK
6d2b3ce2c6ef62334985ece4f0ab8b154e0e9560Timo Sirainenstatic int mbox_lock_flock(struct index_mailbox *ibox, int lock_type,
6d2b3ce2c6ef62334985ece4f0ab8b154e0e9560Timo Sirainen time_t max_wait_time)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen time_t now, last_notify;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (lock_type == F_WRLCK)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen lock_type = LOCK_EX;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen else if (lock_type == F_RDLCK)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen lock_type = LOCK_SH;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen else
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen lock_type = LOCK_UN;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen last_notify = 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen while (flock(ibox->mbox_fd, lock_type | LOCK_NB) < 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (errno != EWOULDBLOCK) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mbox_set_syscall_error(ibox, "flock()");
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return -1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (max_wait_time == 0)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return 0;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen now = time(NULL);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (now >= max_wait_time)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return 0;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (now != last_notify) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen index_storage_lock_notify(ibox,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen MAILBOX_LOCK_NOTIFY_MAILBOX_ABORT,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen max_wait_time - now);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen usleep(LOCK_RANDOM_USLEEP_TIME);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return 1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#endif
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#ifdef HAVE_LOCKF
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic int mbox_lock_lockf(struct index_mailbox *ibox, int lock_type,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen time_t max_wait_time)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen time_t now, last_notify;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (lock_type != F_UNLCK)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen lock_type = F_TLOCK;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen else
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen lock_type = F_ULOCK;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen last_notify = 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen while (lockf(ibox->mbox_fd, lock_type, 0) < 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (errno != EAGAIN) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mbox_set_syscall_error(ibox, "lockf()");
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return -1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (max_wait_time == 0)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return 0;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen now = time(NULL);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (now >= max_wait_time)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (now != last_notify) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen index_storage_lock_notify(ibox,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen MAILBOX_LOCK_NOTIFY_MAILBOX_ABORT,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen max_wait_time - now);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen usleep(LOCK_RANDOM_USLEEP_TIME);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return 1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#endif
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic int mbox_lock_fcntl(struct index_mailbox *ibox, int lock_type,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen time_t max_wait_time)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct flock fl;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen time_t now;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen int wait_type;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen memset(&fl, 0, sizeof(fl));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen fl.l_type = lock_type;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen fl.l_whence = SEEK_SET;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen fl.l_start = 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen fl.l_len = 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen wait_type = max_wait_time == 0 ? F_SETLK : F_SETLKW;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen while (fcntl(ibox->mbox_fd, wait_type, &fl) < 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (errno != EINTR) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (errno != EAGAIN && errno != EACCES)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mbox_set_syscall_error(ibox, "fcntl()");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen now = time(NULL);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (max_wait_time != 0 && now >= max_wait_time)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen index_storage_lock_notify(ibox,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen MAILBOX_LOCK_NOTIFY_MAILBOX_ABORT,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen max_wait_time - now);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return 1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic int mbox_file_locks(struct index_mailbox *ibox, int lock_type,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen time_t max_wait_time)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen enum mbox_lock_type *lock_types;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct stat st;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen int i, ret;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* now we need to have the file itself locked. open it if needed. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (stat(ibox->path, &st) < 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mbox_set_syscall_error(ibox, "stat()");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (st.st_ino != ibox->mbox_ino ||
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen !CMP_DEV_T(st.st_dev, ibox->mbox_dev))
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mbox_file_close(ibox);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (ibox->mbox_fd == -1) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (mbox_file_open(ibox) < 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen (void)mbox_unlock_files(ibox);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen lock_types = lock_type == F_WRLCK ? write_locks : read_locks;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen for (i = 0; lock_types[i] != (enum mbox_lock_type)-1; i++) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (lock_data[lock_types[i]].type != MBOX_LOCK_DOTLOCK) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ret = lock_data[lock_types[i]].func(ibox, lock_type,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen max_wait_time);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (ret <= 0)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return ret;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return 1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic int mbox_file_unlock(struct index_mailbox *ibox)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen enum mbox_lock_type *lock_types;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen int i, ret = 0;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen lock_types = ibox->mbox_lock_type == F_WRLCK ? write_locks : read_locks;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen for (i = 0; lock_types[i] != (enum mbox_lock_type)-1; i++) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (lock_data[lock_types[i]].type != MBOX_LOCK_DOTLOCK) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (lock_data[lock_types[i]].func(ibox, F_UNLCK, 0) < 0)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ret = -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return ret;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic int dotlock_callback(unsigned int secs_left, int stale, void *context)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct dotlock_context *ctx = context;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (stale && !ctx->last_stale) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (mbox_file_locks(ctx->ibox, ctx->lock_type, 0) <= 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* we couldn't get fcntl/flock - it's really locked */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ctx->last_stale = TRUE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return FALSE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen (void)mbox_file_unlock(ctx->ibox);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ctx->last_stale = stale;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen index_storage_lock_notify(ctx->ibox, stale ?
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen MAILBOX_LOCK_NOTIFY_MAILBOX_OVERRIDE :
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen MAILBOX_LOCK_NOTIFY_MAILBOX_ABORT,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen secs_left);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return TRUE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenint mbox_lock(struct index_mailbox *ibox, int lock_type,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen unsigned int *lock_id_r)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen time_t max_wait_time;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen int ret;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* allow only unlock -> shared/exclusive or exclusive -> shared */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(lock_type == F_RDLCK || lock_type == F_WRLCK);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(lock_type == F_RDLCK || ibox->mbox_lock_type != F_RDLCK);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (ibox->mbox_lock_type == lock_type) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ibox->mbox_locks++;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return 1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen index_storage_lock_notify_reset(ibox);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (!lock_settings_initialized)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mbox_init_lock_settings();
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen max_wait_time = time(NULL) + lock_timeout;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* make .lock file first to protect overwriting the file */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (((lock_type == F_RDLCK && read_locks[0] == MBOX_LOCK_DOTLOCK) ||
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen (lock_type == F_WRLCK && write_locks[0] == MBOX_LOCK_DOTLOCK)) &&
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ibox->mbox_dotlock.ino == 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct dotlock_context ctx;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ctx.ibox = ibox;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ctx.lock_type = lock_type;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ctx.last_stale = -1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ret = file_lock_dotlock(ibox->path, NULL, FALSE, lock_timeout,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen dotlock_change_timeout, 0,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen dotlock_callback, &ctx,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen &ibox->mbox_dotlock);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen if (ret < 0) {
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen mbox_set_syscall_error(ibox, "file_lock_dotlock()");
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen return -1;
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen }
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen if (ret == 0) {
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen mail_storage_set_error(ibox->box.storage,
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen "Timeout while waiting for lock");
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen return 0;
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen }
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen }
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen ibox->mbox_lock_type = lock_type;
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen ret = mbox_file_locks(ibox, ibox->mbox_lock_type, max_wait_time);
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen if (ret <= 0) {
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen (void)mbox_unlock_files(ibox);
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen if (ret == 0) {
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen mail_storage_set_error(ibox->box.storage,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "Timeout while waiting for lock");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return ret;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen *lock_id_r = ++ibox->mbox_lock_id;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ibox->mbox_locks++;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return 1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic int mbox_unlock_files(struct index_mailbox *ibox)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen int ret = 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (ibox->mbox_fd != -1) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (mbox_file_unlock(ibox) < 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ret = -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (ibox->mbox_dotlock.ino != 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (file_unlock_dotlock(ibox->path, &ibox->mbox_dotlock) <= 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mbox_set_syscall_error(ibox, "file_unlock_dotlock()");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ret = -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ibox->mbox_dotlock.ino = 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* make sure we don't keep mmap() between locks */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mbox_file_close_stream(ibox);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ibox->mbox_lock_id++;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ibox->mbox_lock_type = F_UNLCK;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return ret;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenint mbox_unlock(struct index_mailbox *ibox, unsigned int lock_id)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_assert(ibox->mbox_locks > 0);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_assert(ibox->mbox_lock_id == lock_id);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (--ibox->mbox_locks > 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return mbox_unlock_files(ibox);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen