[dovecot-cvs] dovecot/src/lib-storage/index/mbox mbox-lock.c, 1.7,
1.8
cras at procontrol.fi
cras at procontrol.fi
Sun Jun 20 13:37:47 EEST 2004
Update of /home/cvs/dovecot/src/lib-storage/index/mbox
In directory talvi:/tmp/cvs-serv9457/src/lib-storage/index/mbox
Modified Files:
mbox-lock.c
Log Message:
Don't require dotlocking to be first in locking list.
Index: mbox-lock.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib-storage/index/mbox/mbox-lock.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- mbox-lock.c 20 Jun 2004 03:25:34 -0000 1.7
+++ mbox-lock.c 20 Jun 2004 10:37:45 -0000 1.8
@@ -22,15 +22,9 @@
#define DEFAULT_READ_LOCK_METHODS "fcntl"
#define DEFAULT_WRITE_LOCK_METHODS "dotlock fcntl"
/* lock timeout */
-#define DEFAULT_LOCK_TIMEOUT 300
+#define DEFAULT_LOCK_TIMEOUT (10*60)
/* assume stale dotlock if mbox file hasn't changed for n seconds */
-#define DEFAULT_DOTLOCK_CHANGE_TIMEOUT 30
-
-struct dotlock_context {
- struct index_mailbox *ibox;
- int lock_type;
- int last_stale;
-};
+#define DEFAULT_DOTLOCK_CHANGE_TIMEOUT (5*60)
enum mbox_lock_type {
MBOX_LOCK_DOTLOCK,
@@ -41,30 +35,41 @@
MBOX_LOCK_COUNT
};
+struct mbox_lock_context {
+ struct index_mailbox *ibox;
+ int lock_status[MBOX_LOCK_COUNT];
+ int checked_file;
+
+ int lock_type;
+ int dotlock_last_stale;
+};
+
struct mbox_lock_data {
enum mbox_lock_type type;
const char *name;
- int (*func)(struct index_mailbox *ibox, int lock_type,
+ int (*func)(struct mbox_lock_context *ctx, int lock_type,
time_t max_wait_time);
};
-static int mbox_lock_fcntl(struct index_mailbox *ibox, int lock_type,
+static int mbox_lock_dotlock(struct mbox_lock_context *ctx, int lock_type,
+ time_t max_wait_time);
+static int mbox_lock_fcntl(struct mbox_lock_context *ctx, int lock_type,
time_t max_wait_time);
#ifdef HAVE_FLOCK
-static int mbox_lock_flock(struct index_mailbox *ibox, int lock_type,
+static int mbox_lock_flock(struct mbox_lock_context *ctx, int lock_type,
time_t max_wait_time);
#else
# define mbox_lock_flock NULL
#endif
#ifdef HAVE_LOCKF
-static int mbox_lock_lockf(struct index_mailbox *ibox, int lock_type,
+static int mbox_lock_lockf(struct mbox_lock_context *ctx, int lock_type,
time_t max_wait_time);
#else
# define mbox_lock_lockf NULL
#endif
struct mbox_lock_data lock_data[] = {
- { MBOX_LOCK_DOTLOCK, "dotlock", NULL },
+ { MBOX_LOCK_DOTLOCK, "dotlock", mbox_lock_dotlock },
{ MBOX_LOCK_FCNTL, "fcntl", mbox_lock_fcntl },
{ MBOX_LOCK_FLOCK, "flock", mbox_lock_flock },
{ MBOX_LOCK_LOCKF, "lockf", mbox_lock_lockf },
@@ -76,7 +81,9 @@
static enum mbox_lock_type write_locks[MBOX_LOCK_COUNT+1];
static int lock_timeout, dotlock_change_timeout;
-static int mbox_unlock_files(struct index_mailbox *ibox);
+static int mbox_lock_list(struct mbox_lock_context *ctx, int lock_type,
+ time_t max_wait_time, int idx);
+static int mbox_unlock_files(struct mbox_lock_context *ctx);
static void mbox_read_lock_methods(const char *str, const char *env,
enum mbox_lock_type *locks)
@@ -94,7 +101,7 @@
}
if (lock_data[type].name == NULL)
i_fatal("%s: Invalid value %s", env, *lock);
- if (lock_data[type].func == NULL && type != MBOX_LOCK_DOTLOCK) {
+ if (lock_data[type].func == NULL) {
i_fatal("%s: Support for lock type %s "
"not compiled into binary", env, *lock);
}
@@ -104,9 +111,6 @@
i_fatal("%s: Duplicated value %s", env, *lock);
}
- if (type == MBOX_LOCK_DOTLOCK && dest != 0)
- i_fatal("%s: dotlock must be first in the list", *lock);
-
/* @UNSAFE */
locks[dest++] = type;
}
@@ -135,12 +139,112 @@
lock_settings_initialized = TRUE;
}
+static int mbox_file_open_latest(struct mbox_lock_context *ctx, int lock_type)
+{
+ struct index_mailbox *ibox = ctx->ibox;
+ struct stat st;
+
+ if (ctx->checked_file || lock_type == F_UNLCK)
+ return 0;
+
+ if (ibox->mbox_fd != -1) {
+ if (stat(ibox->path, &st) < 0) {
+ mbox_set_syscall_error(ibox, "stat()");
+ return -1;
+ }
+
+ if (st.st_ino != ibox->mbox_ino ||
+ !CMP_DEV_T(st.st_dev, ibox->mbox_dev))
+ mbox_file_close(ibox);
+ }
+
+ if (ibox->mbox_fd == -1) {
+ if (mbox_file_open(ibox) < 0)
+ return -1;
+ }
+
+ ctx->checked_file = TRUE;
+ return 0;
+}
+
+static int dotlock_callback(unsigned int secs_left, int stale, void *context)
+{
+ struct mbox_lock_context *ctx = context;
+ int idx;
+
+ if (stale && !ctx->dotlock_last_stale) {
+ /* get next index we wish to try locking */
+ for (idx = MBOX_LOCK_COUNT; idx > 0; idx--) {
+ if (ctx->lock_status[idx-1])
+ break;
+ }
+
+ if (mbox_lock_list(ctx, ctx->lock_type, 0, idx) <= 0) {
+ /* we couldn't get fcntl/flock - it's really locked */
+ ctx->dotlock_last_stale = TRUE;
+ return FALSE;
+ }
+ (void)mbox_lock_list(ctx, F_UNLCK, 0, idx);
+ }
+ ctx->dotlock_last_stale = stale;
+
+ index_storage_lock_notify(ctx->ibox, stale ?
+ MAILBOX_LOCK_NOTIFY_MAILBOX_OVERRIDE :
+ MAILBOX_LOCK_NOTIFY_MAILBOX_ABORT,
+ secs_left);
+ return TRUE;
+}
+
+static int mbox_lock_dotlock(struct mbox_lock_context *ctx, int lock_type,
+ time_t max_wait_time __attr_unused__)
+{
+ struct index_mailbox *ibox = ctx->ibox;
+ int ret;
+
+ if (lock_type == F_UNLCK) {
+ if (ibox->mbox_dotlock.ino == 0)
+ return 1;
+
+ if (file_unlock_dotlock(ibox->path, &ibox->mbox_dotlock) <= 0) {
+ mbox_set_syscall_error(ibox, "file_unlock_dotlock()");
+ ret = -1;
+ }
+ ibox->mbox_dotlock.ino = 0;
+ return 1;
+ }
+
+ ctx->dotlock_last_stale = -1;
+
+ ret = file_lock_dotlock(ibox->path, NULL, FALSE, lock_timeout,
+ dotlock_change_timeout, 0,
+ dotlock_callback, ctx, &ibox->mbox_dotlock);
+
+ if (ret < 0) {
+ mbox_set_syscall_error(ibox, "file_lock_dotlock()");
+ return -1;
+ }
+ if (ret == 0) {
+ mail_storage_set_error(ibox->box.storage,
+ "Timeout while waiting for lock");
+ return 0;
+ }
+ if (mbox_file_open_latest(ctx, lock_type) < 0)
+ return -1;
+ return 1;
+}
+
#ifdef HAVE_FLOCK
-static int mbox_lock_flock(struct index_mailbox *ibox, int lock_type,
+static int mbox_lock_flock(struct mbox_lock_context *ctx, int lock_type,
time_t max_wait_time)
{
time_t now, last_notify;
+ if (mbox_file_open_latest(ctx, lock_type) < 0)
+ return -1;
+
+ if (lock_type == F_UNLCK && ctx->ibox->mbox_fd == -1)
+ return 1;
+
if (lock_type == F_WRLCK)
lock_type = LOCK_EX;
else if (lock_type == F_RDLCK)
@@ -149,9 +253,9 @@
lock_type = LOCK_UN;
last_notify = 0;
- while (flock(ibox->mbox_fd, lock_type | LOCK_NB) < 0) {
+ while (flock(ctx->ibox->mbox_fd, lock_type | LOCK_NB) < 0) {
if (errno != EWOULDBLOCK) {
- mbox_set_syscall_error(ibox, "flock()");
+ mbox_set_syscall_error(ctx->ibox, "flock()");
return -1;
}
@@ -163,7 +267,7 @@
return 0;
if (now != last_notify) {
- index_storage_lock_notify(ibox,
+ index_storage_lock_notify(ctx->ibox,
MAILBOX_LOCK_NOTIFY_MAILBOX_ABORT,
max_wait_time - now);
}
@@ -176,20 +280,26 @@
#endif
#ifdef HAVE_LOCKF
-static int mbox_lock_lockf(struct index_mailbox *ibox, int lock_type,
+static int mbox_lock_lockf(struct mbox_lock_context *ctx, int lock_type,
time_t max_wait_time)
{
time_t now, last_notify;
+ if (mbox_file_open_latest(ctx, lock_type) < 0)
+ return -1;
+
+ if (lock_type == F_UNLCK && ctx->ibox->mbox_fd == -1)
+ return 1;
+
if (lock_type != F_UNLCK)
lock_type = F_TLOCK;
else
lock_type = F_ULOCK;
last_notify = 0;
- while (lockf(ibox->mbox_fd, lock_type, 0) < 0) {
+ while (lockf(ctx->ibox->mbox_fd, lock_type, 0) < 0) {
if (errno != EAGAIN) {
- mbox_set_syscall_error(ibox, "lockf()");
+ mbox_set_syscall_error(ctx->ibox, "lockf()");
return -1;
}
@@ -201,7 +311,7 @@
return 0;
if (now != last_notify) {
- index_storage_lock_notify(ibox,
+ index_storage_lock_notify(ctx->ibox,
MAILBOX_LOCK_NOTIFY_MAILBOX_ABORT,
max_wait_time - now);
}
@@ -213,13 +323,19 @@
}
#endif
-static int mbox_lock_fcntl(struct index_mailbox *ibox, int lock_type,
+static int mbox_lock_fcntl(struct mbox_lock_context *ctx, int lock_type,
time_t max_wait_time)
{
struct flock fl;
time_t now;
int wait_type;
+ if (mbox_file_open_latest(ctx, lock_type) < 0)
+ return -1;
+
+ if (lock_type == F_UNLCK && ctx->ibox->mbox_fd == -1)
+ return 1;
+
memset(&fl, 0, sizeof(fl));
fl.l_type = lock_type;
fl.l_whence = SEEK_SET;
@@ -227,10 +343,10 @@
fl.l_len = 0;
wait_type = max_wait_time == 0 ? F_SETLK : F_SETLKW;
- while (fcntl(ibox->mbox_fd, wait_type, &fl) < 0) {
+ while (fcntl(ctx->ibox->mbox_fd, wait_type, &fl) < 0) {
if (errno != EINTR) {
if (errno != EAGAIN && errno != EACCES)
- mbox_set_syscall_error(ibox, "fcntl()");
+ mbox_set_syscall_error(ctx->ibox, "fcntl()");
return -1;
}
@@ -238,7 +354,7 @@
if (max_wait_time != 0 && now >= max_wait_time)
return 0;
- index_storage_lock_notify(ibox,
+ index_storage_lock_notify(ctx->ibox,
MAILBOX_LOCK_NOTIFY_MAILBOX_ABORT,
max_wait_time - now);
}
@@ -246,82 +362,37 @@
return 1;
}
-static int mbox_file_locks(struct index_mailbox *ibox, int lock_type,
- time_t max_wait_time)
+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;
- struct stat st;
- int i, ret;
-
- /* now we need to have the file itself locked. open it if needed. */
- if (stat(ibox->path, &st) < 0) {
- mbox_set_syscall_error(ibox, "stat()");
- return -1;
- }
-
- if (st.st_ino != ibox->mbox_ino ||
- !CMP_DEV_T(st.st_dev, ibox->mbox_dev))
- mbox_file_close(ibox);
+ enum mbox_lock_type type;
+ int i, ret = 0, lock_status;
- if (ibox->mbox_fd == -1) {
- if (mbox_file_open(ibox) < 0) {
- (void)mbox_unlock_files(ibox);
- return -1;
- }
- }
+ ctx->lock_type = lock_type;
- lock_types = lock_type == F_WRLCK ? write_locks : read_locks;
- for (i = 0; lock_types[i] != (enum mbox_lock_type)-1; i++) {
- if (lock_data[lock_types[i]].type != MBOX_LOCK_DOTLOCK) {
- ret = lock_data[lock_types[i]].func(ibox, lock_type,
- max_wait_time);
- if (ret <= 0)
- return ret;
- }
- }
- return 1;
-}
+ lock_types = lock_type == F_WRLCK ||
+ (lock_type == F_UNLCK && ctx->ibox->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;
-static int mbox_file_unlock(struct index_mailbox *ibox)
-{
- enum mbox_lock_type *lock_types;
- int i, ret = 0;
+ if (ctx->lock_status[type] == lock_status)
+ continue;
+ ctx->lock_status[type] = lock_status;
- lock_types = ibox->mbox_lock_type == F_WRLCK ? write_locks : read_locks;
- for (i = 0; lock_types[i] != (enum mbox_lock_type)-1; i++) {
- if (lock_data[lock_types[i]].type != MBOX_LOCK_DOTLOCK) {
- if (lock_data[lock_types[i]].func(ibox, F_UNLCK, 0) < 0)
- ret = -1;
- }
+ ret = lock_data[type].func(ctx, lock_type, max_wait_time);
+ if (ret <= 0)
+ break;
}
-
return ret;
}
-static int dotlock_callback(unsigned int secs_left, int stale, void *context)
-{
- struct dotlock_context *ctx = context;
-
- if (stale && !ctx->last_stale) {
- if (mbox_file_locks(ctx->ibox, ctx->lock_type, 0) <= 0) {
- /* we couldn't get fcntl/flock - it's really locked */
- ctx->last_stale = TRUE;
- return FALSE;
- }
- (void)mbox_file_unlock(ctx->ibox);
- }
- ctx->last_stale = stale;
-
- index_storage_lock_notify(ctx->ibox, stale ?
- MAILBOX_LOCK_NOTIFY_MAILBOX_OVERRIDE :
- MAILBOX_LOCK_NOTIFY_MAILBOX_ABORT,
- secs_left);
- return TRUE;
-}
-
int mbox_lock(struct index_mailbox *ibox, int lock_type,
unsigned int *lock_id_r)
{
+ struct mbox_lock_context ctx;
time_t max_wait_time;
int ret;
@@ -342,36 +413,13 @@
max_wait_time = time(NULL) + lock_timeout;
- /* make .lock file first to protect overwriting the file */
- if (((lock_type == F_RDLCK && read_locks[0] == MBOX_LOCK_DOTLOCK) ||
- (lock_type == F_WRLCK && write_locks[0] == MBOX_LOCK_DOTLOCK)) &&
- ibox->mbox_dotlock.ino == 0) {
- struct dotlock_context ctx;
-
- ctx.ibox = ibox;
- ctx.lock_type = lock_type;
- ctx.last_stale = -1;
-
- ret = file_lock_dotlock(ibox->path, NULL, FALSE, lock_timeout,
- dotlock_change_timeout, 0,
- dotlock_callback, &ctx,
- &ibox->mbox_dotlock);
-
- if (ret < 0) {
- mbox_set_syscall_error(ibox, "file_lock_dotlock()");
- return -1;
- }
- if (ret == 0) {
- mail_storage_set_error(ibox->box.storage,
- "Timeout while waiting for lock");
- return 0;
- }
- }
+ memset(&ctx, 0, sizeof(ctx));
+ ctx.ibox = ibox;
ibox->mbox_lock_type = lock_type;
- ret = mbox_file_locks(ibox, ibox->mbox_lock_type, max_wait_time);
+ ret = mbox_lock_list(&ctx, ibox->mbox_lock_type, max_wait_time, 0);
if (ret <= 0) {
- (void)mbox_unlock_files(ibox);
+ (void)mbox_unlock_files(&ctx);
if (ret == 0) {
mail_storage_set_error(ibox->box.storage,
"Timeout while waiting for lock");
@@ -384,38 +432,37 @@
return 1;
}
-static int mbox_unlock_files(struct index_mailbox *ibox)
+static int mbox_unlock_files(struct mbox_lock_context *ctx)
{
int ret = 0;
- if (ibox->mbox_fd != -1) {
- if (mbox_file_unlock(ibox) < 0)
- ret = -1;
- }
-
- if (ibox->mbox_dotlock.ino != 0) {
- if (file_unlock_dotlock(ibox->path, &ibox->mbox_dotlock) <= 0) {
- mbox_set_syscall_error(ibox, "file_unlock_dotlock()");
- ret = -1;
- }
- ibox->mbox_dotlock.ino = 0;
- }
+ if (mbox_lock_list(ctx, F_UNLCK, 0, 0) < 0)
+ ret = -1;
/* make sure we don't keep mmap() between locks */
- mbox_file_close_stream(ibox);
+ mbox_file_close_stream(ctx->ibox);
- ibox->mbox_lock_id++;
- ibox->mbox_lock_type = F_UNLCK;
+ ctx->ibox->mbox_lock_id++;
+ ctx->ibox->mbox_lock_type = F_UNLCK;
return ret;
}
int mbox_unlock(struct index_mailbox *ibox, unsigned int lock_id)
{
+ struct mbox_lock_context ctx;
+ int i;
+
i_assert(ibox->mbox_locks > 0);
i_assert(ibox->mbox_lock_id == lock_id);
if (--ibox->mbox_locks > 0)
return 0;
- return mbox_unlock_files(ibox);
+ memset(&ctx, 0, sizeof(ctx));
+ ctx.ibox = ibox;
+
+ for (i = 0; i < MBOX_LOCK_COUNT; i++)
+ ctx.lock_status[i] = 1;
+
+ return mbox_unlock_files(&ctx);
}
More information about the dovecot-cvs
mailing list