mbox-lock.c revision 64a29ac489669aee924a9ada2c60260e30451a02
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw/* Copyright (c) 2002-2008 Dovecot authors, see the included COPYING file */
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw#include "lib.h"
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw#include "nfs-workarounds.h"
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw#include "mail-index-private.h"
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw#include "mbox-storage.h"
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw#include "mbox-file.h"
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw#include "mbox-lock.h"
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw#include <time.h>
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw#include <stdlib.h>
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw#include <unistd.h>
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw#include <fcntl.h>
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw#include <sys/stat.h>
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw#ifdef HAVE_FLOCK
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw# include <sys/file.h>
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw#endif
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw/* 0.1 .. 0.2msec */
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw#define LOCK_RANDOM_USLEEP_TIME (100000 + (unsigned int)rand() % 100000)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw/* lock methods to use in wanted order */
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw#define DEFAULT_READ_LOCK_METHODS "fcntl"
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw#define DEFAULT_WRITE_LOCK_METHODS "dotlock fcntl"
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw/* lock timeout */
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw#define MBOX_DEFAULT_LOCK_TIMEOUT (5*60)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw/* assume stale dotlock if mbox file hasn't changed for n seconds */
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw#define DEFAULT_DOTLOCK_CHANGE_TIMEOUT (120)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xwenum mbox_lock_type {
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw MBOX_LOCK_DOTLOCK,
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw MBOX_LOCK_DOTLOCK_TRY,
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw MBOX_LOCK_FCNTL,
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw MBOX_LOCK_FLOCK,
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw MBOX_LOCK_LOCKF,
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw MBOX_LOCK_COUNT
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw};
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xwstruct mbox_lock_context {
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw struct mbox_mailbox *mbox;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw int lock_status[MBOX_LOCK_COUNT];
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw bool checked_file;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw int lock_type;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw bool dotlock_last_stale;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw bool fcntl_locked;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw};
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xwstruct mbox_lock_data {
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw enum mbox_lock_type type;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw const char *name;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw int (*func)(struct mbox_lock_context *ctx, int lock_type,
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw time_t max_wait_time);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw};
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xwstatic int mbox_lock_dotlock(struct mbox_lock_context *ctx, int lock_type,
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw time_t max_wait_time);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xwstatic int mbox_lock_dotlock_try(struct mbox_lock_context *ctx, int lock_type,
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw time_t max_wait_time);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xwstatic int mbox_lock_fcntl(struct mbox_lock_context *ctx, int lock_type,
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw time_t max_wait_time);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw#ifdef HAVE_FLOCK
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xwstatic int mbox_lock_flock(struct mbox_lock_context *ctx, int lock_type,
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw time_t max_wait_time);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw#else
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw# define mbox_lock_flock NULL
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw#endif
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw#ifdef HAVE_LOCKF
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xwstatic int mbox_lock_lockf(struct mbox_lock_context *ctx, int lock_type,
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw time_t max_wait_time);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw#else
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw# define mbox_lock_lockf NULL
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw#endif
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xwstruct mbox_lock_data lock_data[] = {
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw { MBOX_LOCK_DOTLOCK, "dotlock", mbox_lock_dotlock },
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw { MBOX_LOCK_DOTLOCK_TRY, "dotlock_try", mbox_lock_dotlock_try },
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw { MBOX_LOCK_FCNTL, "fcntl", mbox_lock_fcntl },
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw { MBOX_LOCK_FLOCK, "flock", mbox_lock_flock },
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw { MBOX_LOCK_LOCKF, "lockf", mbox_lock_lockf },
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw { 0, NULL, NULL }
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw};
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xwstatic bool lock_settings_initialized = FALSE;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xwstatic enum mbox_lock_type read_locks[MBOX_LOCK_COUNT+1];
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xwstatic enum mbox_lock_type write_locks[MBOX_LOCK_COUNT+1];
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xwstatic int lock_timeout, dotlock_change_timeout;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xwstatic int mbox_lock_list(struct mbox_lock_context *ctx, int lock_type,
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw time_t max_wait_time, int idx);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xwstatic int mbox_unlock_files(struct mbox_lock_context *ctx);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xwstatic void mbox_read_lock_methods(const char *str, const char *env,
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw enum mbox_lock_type *locks)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw{
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw enum mbox_lock_type type;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw const char *const *lock;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw int i, dest;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw for (lock = t_strsplit(str, " "), dest = 0; *lock != NULL; lock++) {
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw for (type = 0; lock_data[type].name != NULL; type++) {
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (strcasecmp(*lock, lock_data[type].name) == 0) {
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw type = lock_data[type].type;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw break;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw }
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw }
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (lock_data[type].name == NULL)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw i_fatal("%s: Invalid value %s", env, *lock);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (lock_data[type].func == NULL) {
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw i_fatal("%s: Support for lock type %s "
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw "not compiled into binary", env, *lock);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw }
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw for (i = 0; i < dest; i++) {
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (locks[i] == type)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw i_fatal("%s: Duplicated value %s", env, *lock);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw }
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw /* @UNSAFE */
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw locks[dest++] = type;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw }
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw locks[dest] = (enum mbox_lock_type)-1;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw}
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xwstatic void mbox_init_lock_settings(void)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw{
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw const char *str;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw int r, w;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw str = getenv("MBOX_READ_LOCKS");
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (str == NULL) str = DEFAULT_READ_LOCK_METHODS;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw mbox_read_lock_methods(str, "MBOX_READ_LOCKS", read_locks);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw str = getenv("MBOX_WRITE_LOCKS");
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (str == NULL) str = DEFAULT_WRITE_LOCK_METHODS;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw mbox_read_lock_methods(str, "MBOX_WRITE_LOCKS", write_locks);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw /* check that read/write list orders match. write_locks must contain
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw at least read_locks and possibly more. */
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw for (r = w = 0; write_locks[w] != (enum mbox_lock_type)-1; w++) {
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (read_locks[r] == (enum mbox_lock_type)-1)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw break;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (read_locks[r] == write_locks[w])
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw r++;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw }
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (read_locks[r] != (enum mbox_lock_type)-1) {
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw i_fatal("mbox read/write lock list settings are invalid. "
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw "Lock ordering must be the same with both, "
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw "and write locks must contain all read locks "
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw "(and possibly more)");
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw }
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw str = getenv("MBOX_LOCK_TIMEOUT");
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw lock_timeout = str == NULL ? MBOX_DEFAULT_LOCK_TIMEOUT : atoi(str);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw str = getenv("MBOX_DOTLOCK_CHANGE_TIMEOUT");
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw dotlock_change_timeout = str == NULL ?
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw DEFAULT_DOTLOCK_CHANGE_TIMEOUT : atoi(str);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw lock_settings_initialized = TRUE;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw}
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xwstatic int mbox_file_open_latest(struct mbox_lock_context *ctx, int lock_type)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw{
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw struct mbox_mailbox *mbox = ctx->mbox;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw struct stat st;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (ctx->checked_file || lock_type == F_UNLCK)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw return 0;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (mbox->mbox_fd != -1) {
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw /* we could flush NFS file handle cache here if we wanted to
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw be sure that the file is latest, but mbox files get rarely
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw deleted and the flushing might cause errors (e.g. EBUSY for
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw trying to flush a /var/mail mountpoint) */
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (nfs_safe_stat(mbox->path, &st) < 0) {
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw mbox_set_syscall_error(mbox, "stat()");
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw return -1;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw }
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (st.st_ino != mbox->mbox_ino ||
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw !CMP_DEV_T(st.st_dev, mbox->mbox_dev))
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw mbox_file_close(mbox);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw }
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (mbox->mbox_fd == -1) {
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (mbox_file_open(mbox) < 0)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw return -1;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw }
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw ctx->checked_file = TRUE;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw return 0;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw}
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xwstatic bool dotlock_callback(unsigned int secs_left, bool stale, void *context)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw{
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw struct mbox_lock_context *ctx = context;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw enum mbox_lock_type *lock_types;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw int i;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (stale && !ctx->dotlock_last_stale) {
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw /* get next index we wish to try locking. it's the one after
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw dotlocking. */
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw lock_types = ctx->lock_type == F_WRLCK ||
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw (ctx->lock_type == F_UNLCK &&
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw ctx->mbox->mbox_lock_type == F_WRLCK) ?
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw write_locks : read_locks;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw for (i = 0; lock_types[i] != (enum mbox_lock_type)-1; i++) {
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (lock_types[i] == MBOX_LOCK_DOTLOCK)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw break;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw }
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (lock_types[i] != (enum mbox_lock_type)-1 &&
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw lock_types[i+1] != (enum mbox_lock_type)-1) {
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw i++;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (mbox_lock_list(ctx, ctx->lock_type, 0, i) <= 0) {
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw /* we couldn't get fd lock -
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw it's really locked */
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw ctx->dotlock_last_stale = TRUE;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw return FALSE;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw }
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw (void)mbox_lock_list(ctx, F_UNLCK, 0, i);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw }
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw }
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw ctx->dotlock_last_stale = stale;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw index_storage_lock_notify(&ctx->mbox->ibox, stale ?
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw MAILBOX_LOCK_NOTIFY_MAILBOX_OVERRIDE :
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw MAILBOX_LOCK_NOTIFY_MAILBOX_ABORT,
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw secs_left);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw return TRUE;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw}
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xwstatic int
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xwmbox_lock_dotlock_int(struct mbox_lock_context *ctx, int lock_type, bool try)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw{
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw struct mbox_mailbox *mbox = ctx->mbox;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw struct dotlock_settings set;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw int ret;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (lock_type == F_UNLCK) {
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (!mbox->mbox_dotlocked)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw return 1;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (file_dotlock_delete(&mbox->mbox_dotlock) <= 0) {
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw mbox_set_syscall_error(mbox, "file_dotlock_delete()");
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw ret = -1;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw }
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw mbox->mbox_dotlocked = FALSE;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw return 1;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw }
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (mbox->mbox_dotlocked)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw return 1;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw ctx->dotlock_last_stale = -1;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw memset(&set, 0, sizeof(set));
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw set.use_excl_lock = (mbox->storage->storage.flags &
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw MAIL_STORAGE_FLAG_DOTLOCK_USE_EXCL) != 0;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw set.nfs_flush = (mbox->storage->storage.flags &
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw MAIL_STORAGE_FLAG_NFS_FLUSH_STORAGE) != 0;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw set.timeout = lock_timeout;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw set.stale_timeout = dotlock_change_timeout;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw set.callback = dotlock_callback;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw set.context = ctx;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw ret = file_dotlock_create(&set, mbox->path, 0, &mbox->mbox_dotlock);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (ret < 0) {
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if ((ENOSPACE(errno) || errno == EACCES) && try)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw return 1;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw mbox_set_syscall_error(mbox, "file_lock_dotlock()");
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw return -1;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw }
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (ret == 0) {
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw mail_storage_set_error(&mbox->storage->storage,
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw MAIL_ERROR_TEMP, MAIL_ERRSTR_LOCK_TIMEOUT);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw return 0;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw }
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw mbox->mbox_dotlocked = TRUE;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (mbox_file_open_latest(ctx, lock_type) < 0)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw return -1;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw return 1;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw}
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xwstatic int mbox_lock_dotlock(struct mbox_lock_context *ctx, int lock_type,
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw time_t max_wait_time ATTR_UNUSED)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw{
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw return mbox_lock_dotlock_int(ctx, lock_type, FALSE);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw}
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xwstatic int mbox_lock_dotlock_try(struct mbox_lock_context *ctx, int lock_type,
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw time_t max_wait_time ATTR_UNUSED)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw{
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw return mbox_lock_dotlock_int(ctx, lock_type, TRUE);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw}
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw#ifdef HAVE_FLOCK
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xwstatic int mbox_lock_flock(struct mbox_lock_context *ctx, int lock_type,
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw time_t max_wait_time)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw{
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw time_t now, last_notify;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (mbox_file_open_latest(ctx, lock_type) < 0)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw return -1;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (lock_type == F_UNLCK && ctx->mbox->mbox_fd == -1)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw return 1;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (lock_type == F_WRLCK)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw lock_type = LOCK_EX;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw else if (lock_type == F_RDLCK)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw lock_type = LOCK_SH;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw else
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw lock_type = LOCK_UN;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw last_notify = 0;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw while (flock(ctx->mbox->mbox_fd, lock_type | LOCK_NB) < 0) {
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (errno != EWOULDBLOCK) {
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw mbox_set_syscall_error(ctx->mbox, "flock()");
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw return -1;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw }
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw now = time(NULL);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (now >= max_wait_time)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw return 0;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (now != last_notify) {
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw index_storage_lock_notify(&ctx->mbox->ibox,
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw MAILBOX_LOCK_NOTIFY_MAILBOX_ABORT,
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw max_wait_time - now);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw }
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw usleep(LOCK_RANDOM_USLEEP_TIME);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw }
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw return 1;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw}
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw#endif
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw#ifdef HAVE_LOCKF
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xwstatic int mbox_lock_lockf(struct mbox_lock_context *ctx, int lock_type,
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw time_t max_wait_time)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw{
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw time_t now, last_notify;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (mbox_file_open_latest(ctx, lock_type) < 0)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw return -1;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (lock_type == F_UNLCK && ctx->mbox->mbox_fd == -1)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw return 1;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (lock_type != F_UNLCK)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw lock_type = F_TLOCK;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw else
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw lock_type = F_ULOCK;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw last_notify = 0;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw while (lockf(ctx->mbox->mbox_fd, lock_type, 0) < 0) {
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (errno != EAGAIN) {
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw mbox_set_syscall_error(ctx->mbox, "lockf()");
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw return -1;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw }
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw now = time(NULL);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (now >= max_wait_time)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw return 0;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (now != last_notify) {
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw index_storage_lock_notify(&ctx->mbox->ibox,
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw MAILBOX_LOCK_NOTIFY_MAILBOX_ABORT,
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw max_wait_time - now);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw }
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw usleep(LOCK_RANDOM_USLEEP_TIME);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw }
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw return 1;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw}
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw#endif
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xwstatic int mbox_lock_fcntl(struct mbox_lock_context *ctx, int lock_type,
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw time_t max_wait_time)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw{
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw struct flock fl;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw time_t now;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw unsigned int next_alarm;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw int wait_type;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (mbox_file_open_latest(ctx, lock_type) < 0)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw return -1;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (lock_type == F_UNLCK && ctx->mbox->mbox_fd == -1)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw return 1;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw memset(&fl, 0, sizeof(fl));
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw fl.l_type = lock_type;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw fl.l_whence = SEEK_SET;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw fl.l_start = 0;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw fl.l_len = 0;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (max_wait_time == 0) {
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw /* usually we're waiting here, but if we came from
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw mbox_lock_dotlock(), we just want to try locking */
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw wait_type = F_SETLK;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw } else {
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw wait_type = F_SETLKW;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw now = time(NULL);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (now >= max_wait_time)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw alarm(1);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw else
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw alarm(I_MIN(max_wait_time - now, 5));
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw }
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw while (fcntl(ctx->mbox->mbox_fd, wait_type, &fl) < 0) {
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (errno != EINTR) {
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if ((errno == EACCES || errno == EAGAIN) &&
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw wait_type == F_SETLK) {
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw /* non-blocking lock trying failed */
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw return 0;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw }
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw mbox_set_syscall_error(ctx->mbox, "fcntl()");
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw alarm(0);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw return -1;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw }
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw now = time(NULL);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (now >= max_wait_time) {
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw alarm(0);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw return 0;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw }
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw /* notify locks once every 5 seconds.
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw try to use rounded values. */
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw next_alarm = (max_wait_time - now) % 5;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (next_alarm == 0)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw next_alarm = 5;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw alarm(next_alarm);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw index_storage_lock_notify(&ctx->mbox->ibox,
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw MAILBOX_LOCK_NOTIFY_MAILBOX_ABORT,
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw max_wait_time - now);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw }
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw alarm(0);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw ctx->fcntl_locked = TRUE;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw return 1;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw}
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xwstatic int mbox_lock_list(struct mbox_lock_context *ctx, int lock_type,
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw time_t max_wait_time, int idx)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw{
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw enum mbox_lock_type *lock_types;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw enum mbox_lock_type type;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw int i, ret = 0, lock_status;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw ctx->lock_type = lock_type;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw lock_types = lock_type == F_WRLCK ||
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw (lock_type == F_UNLCK && ctx->mbox->mbox_lock_type == F_WRLCK) ?
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw write_locks : read_locks;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw for (i = idx; lock_types[i] != (enum mbox_lock_type)-1; i++) {
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw type = lock_types[i];
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw lock_status = lock_type != F_UNLCK;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (ctx->lock_status[type] == lock_status)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw continue;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw ctx->lock_status[type] = lock_status;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw ret = lock_data[type].func(ctx, lock_type, max_wait_time);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (ret <= 0)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw break;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw }
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw return ret;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw}
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xwstatic int mbox_update_locking(struct mbox_mailbox *mbox, int lock_type,
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw bool *fcntl_locked_r)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw{
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw struct mbox_lock_context ctx;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw time_t max_wait_time;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw int ret, i;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw bool drop_locks;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw *fcntl_locked_r = FALSE;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw index_storage_lock_notify_reset(&mbox->ibox);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (!lock_settings_initialized)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw mbox_init_lock_settings();
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (mbox->mbox_fd == -1 && mbox->mbox_file_stream != NULL) {
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw /* read-only mbox stream. no need to lock. */
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw i_assert(mbox->mbox_readonly);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw mbox->mbox_lock_type = lock_type;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw return 1;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw }
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw max_wait_time = time(NULL) + lock_timeout;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw memset(&ctx, 0, sizeof(ctx));
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw ctx.mbox = mbox;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (mbox->mbox_lock_type == F_WRLCK) {
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw /* dropping to shared lock. first drop those that we
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw don't remove completely. */
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw for (i = 0; i < MBOX_LOCK_COUNT; i++)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw ctx.lock_status[i] = 1;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw for (i = 0; read_locks[i] != (enum mbox_lock_type)-1; i++)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw ctx.lock_status[read_locks[i]] = 0;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw drop_locks = TRUE;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw } else {
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw drop_locks = FALSE;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw }
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw mbox->mbox_lock_type = lock_type;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw ret = mbox_lock_list(&ctx, lock_type, max_wait_time, 0);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (ret <= 0) {
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (!drop_locks)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw (void)mbox_unlock_files(&ctx);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (ret == 0) {
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw mail_storage_set_error(&mbox->storage->storage,
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw MAIL_ERROR_TEMP, MAIL_ERRSTR_LOCK_TIMEOUT);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw }
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw return ret;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw }
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (drop_locks) {
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw /* dropping to shared lock: drop the locks that are only
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw in write list */
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw memset(ctx.lock_status, 0, sizeof(ctx.lock_status));
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw for (i = 0; write_locks[i] != (enum mbox_lock_type)-1; i++)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw ctx.lock_status[write_locks[i]] = 1;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw for (i = 0; read_locks[i] != (enum mbox_lock_type)-1; i++)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw ctx.lock_status[read_locks[i]] = 0;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw mbox->mbox_lock_type = F_WRLCK;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw (void)mbox_lock_list(&ctx, F_UNLCK, 0, 0);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw mbox->mbox_lock_type = F_RDLCK;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw }
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw *fcntl_locked_r = ctx.fcntl_locked;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw return 1;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw}
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xwint mbox_lock(struct mbox_mailbox *mbox, int lock_type,
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw unsigned int *lock_id_r)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw{
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw bool fcntl_locked;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw int ret;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw /* allow only unlock -> shared/exclusive or exclusive -> shared */
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw i_assert(lock_type == F_RDLCK || lock_type == F_WRLCK);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw i_assert(lock_type == F_RDLCK || mbox->mbox_lock_type != F_RDLCK);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw /* mbox must be locked before index */
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw i_assert(mbox->ibox.index->lock_type != F_WRLCK);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (mbox->mbox_lock_type == F_UNLCK) {
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw ret = mbox_update_locking(mbox, lock_type, &fcntl_locked);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (ret <= 0)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw return ret;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if ((mbox->storage->storage.flags &
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw MAIL_STORAGE_FLAG_NFS_FLUSH_STORAGE) != 0) {
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (fcntl_locked) {
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw nfs_flush_attr_cache_fd_locked(mbox->path,
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw mbox->mbox_fd);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw nfs_flush_read_cache_locked(mbox->path,
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw mbox->mbox_fd);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw } else {
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw nfs_flush_attr_cache_unlocked(mbox->path);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw nfs_flush_read_cache_unlocked(mbox->path,
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw mbox->mbox_fd);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw }
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw }
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw mbox->mbox_lock_id += 2;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw }
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (lock_type == F_RDLCK) {
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw mbox->mbox_shared_locks++;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw *lock_id_r = mbox->mbox_lock_id;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw } else {
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw mbox->mbox_excl_locks++;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw *lock_id_r = mbox->mbox_lock_id + 1;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw }
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw return 1;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw}
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xwstatic int mbox_unlock_files(struct mbox_lock_context *ctx)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw{
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw int ret = 0;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (mbox_lock_list(ctx, F_UNLCK, 0, 0) < 0)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw ret = -1;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw ctx->mbox->mbox_lock_id += 2;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw ctx->mbox->mbox_lock_type = F_UNLCK;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw return ret;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw}
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xwint mbox_unlock(struct mbox_mailbox *mbox, unsigned int lock_id)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw{
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw struct mbox_lock_context ctx;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw bool fcntl_locked;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw int i;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw i_assert(mbox->mbox_lock_id == (lock_id & ~1));
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (lock_id & 1) {
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw /* dropping exclusive lock */
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw i_assert(mbox->mbox_excl_locks > 0);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (--mbox->mbox_excl_locks > 0)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw return 0;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (mbox->mbox_shared_locks > 0) {
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw /* drop to shared lock */
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (mbox_update_locking(mbox, F_RDLCK,
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw &fcntl_locked) < 0)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw return -1;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw return 0;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw }
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw } else {
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw /* dropping shared lock */
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw i_assert(mbox->mbox_shared_locks > 0);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (--mbox->mbox_shared_locks > 0)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw return 0;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw if (mbox->mbox_excl_locks > 0)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw return 0;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw }
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw /* all locks gone */
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw memset(&ctx, 0, sizeof(ctx));
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw ctx.mbox = mbox;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw for (i = 0; i < MBOX_LOCK_COUNT; i++)
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw ctx.lock_status[i] = 1;
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw return mbox_unlock_files(&ctx);
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw}
d39a76e7b087a3d0927cbe6898dc0a6770fa6c68xw