mbox-lock.c revision 6ef7e31619edfaa17ed044b45861d106a86191ef
8c294c1cd4d721818a59684cf7f2b36123f79163Stephen Gallagher/* Copyright (C) 2002 Timo Sirainen */
8c294c1cd4d721818a59684cf7f2b36123f79163Stephen Gallagher
8c294c1cd4d721818a59684cf7f2b36123f79163Stephen Gallagher#include "lib.h"
8c294c1cd4d721818a59684cf7f2b36123f79163Stephen Gallagher#include "mail-index-private.h"
8c294c1cd4d721818a59684cf7f2b36123f79163Stephen Gallagher#include "mbox-storage.h"
c252d148fa8ab50aaaa8bbae7beb4d208025171dNikolai Kondrashov#include "mbox-file.h"
9542512d7be40f2000298c86d3d2b728f4f0f65aStephen Gallagher#include "mbox-lock.h"
9542512d7be40f2000298c86d3d2b728f4f0f65aStephen Gallagher
9542512d7be40f2000298c86d3d2b728f4f0f65aStephen Gallagher#include <time.h>
c6e39e15178675d0779e0ae855245774a09b4eb5Nikolai Kondrashov#include <stdlib.h>
c6e39e15178675d0779e0ae855245774a09b4eb5Nikolai Kondrashov#include <unistd.h>
c6e39e15178675d0779e0ae855245774a09b4eb5Nikolai Kondrashov#include <fcntl.h>
c6e39e15178675d0779e0ae855245774a09b4eb5Nikolai Kondrashov#include <sys/stat.h>
c6e39e15178675d0779e0ae855245774a09b4eb5Nikolai Kondrashov
29c5542feb4c45865ea61be97e0e84a1d1f04918Jakub Hrozek#ifdef HAVE_FLOCK
29c5542feb4c45865ea61be97e0e84a1d1f04918Jakub Hrozek# include <sys/file.h>
fd5a4eacd56700ffb08a73121aeacdc806cb0132Sumit Bose#endif
8b1f525acd20f36c836e827de3c251088961c5d9Stephen Gallagher
8b1f525acd20f36c836e827de3c251088961c5d9Stephen Gallagher/* 0.1 .. 0.2msec */
8b1f525acd20f36c836e827de3c251088961c5d9Stephen Gallagher#define LOCK_RANDOM_USLEEP_TIME (100000 + (unsigned int)rand() % 100000)
8b1f525acd20f36c836e827de3c251088961c5d9Stephen Gallagher
8b1f525acd20f36c836e827de3c251088961c5d9Stephen Gallagher/* lock methods to use in wanted order */
84ae5edab16ad6be5e3be956cb6fa031c1428eb5Stephen Gallagher#define DEFAULT_READ_LOCK_METHODS "fcntl"
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov#define DEFAULT_WRITE_LOCK_METHODS "dotlock fcntl"
428db8a58c0c149d5efccc6d788f70916c1d34d7Jakub Hrozek/* lock timeout */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#define DEFAULT_LOCK_TIMEOUT (10*60)
df4cc3a83c5d6700b6a09ff96cb4a6b1949b1aa9Stephen Gallagher/* assume stale dotlock if mbox file hasn't changed for n seconds */
df4cc3a83c5d6700b6a09ff96cb4a6b1949b1aa9Stephen Gallagher#define DEFAULT_DOTLOCK_CHANGE_TIMEOUT (5*60)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherenum mbox_lock_type {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher MBOX_LOCK_DOTLOCK,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher MBOX_LOCK_FCNTL,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher MBOX_LOCK_FLOCK,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher MBOX_LOCK_LOCKF,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher MBOX_LOCK_COUNT
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher};
59744cff6edb106ae799b2321cb8731edadf409aStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstruct mbox_lock_context {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct mbox_mailbox *mbox;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher int lock_status[MBOX_LOCK_COUNT];
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher bool checked_file;
8a5e793a0576250da80371e53aa3e7eba15cdb63Sumit Bose
8a5e793a0576250da80371e53aa3e7eba15cdb63Sumit Bose int lock_type;
8a5e793a0576250da80371e53aa3e7eba15cdb63Sumit Bose bool dotlock_last_stale;
90fd1bbd6035cdab46faa3a695a2fb2be6508b17Sumit Bose};
90fd1bbd6035cdab46faa3a695a2fb2be6508b17Sumit Bose
90fd1bbd6035cdab46faa3a695a2fb2be6508b17Sumit Bosestruct mbox_lock_data {
af4ffe1001adcc0a96897e426d26444f07af9aa1Benjamin Franzke enum mbox_lock_type type;
af4ffe1001adcc0a96897e426d26444f07af9aa1Benjamin Franzke const char *name;
af4ffe1001adcc0a96897e426d26444f07af9aa1Benjamin Franzke int (*func)(struct mbox_lock_context *ctx, int lock_type,
1d1a0a019d8d4d9ab0f51ada03604cd2cada287eSumit Bose time_t max_wait_time);
1d1a0a019d8d4d9ab0f51ada03604cd2cada287eSumit Bose};
1d1a0a019d8d4d9ab0f51ada03604cd2cada287eSumit Bose
f3c85d900c4663854cc7bbae7d9f77867ed1f69bSumit Bosestatic int mbox_lock_dotlock(struct mbox_lock_context *ctx, int lock_type,
f3c85d900c4663854cc7bbae7d9f77867ed1f69bSumit Bose time_t max_wait_time);
f3c85d900c4663854cc7bbae7d9f77867ed1f69bSumit Bosestatic int mbox_lock_fcntl(struct mbox_lock_context *ctx, int lock_type,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher time_t max_wait_time);
2a552e43581c74f51205c7141ec9f6e9542509f8Stephen Gallagher#ifdef HAVE_FLOCK
2a552e43581c74f51205c7141ec9f6e9542509f8Stephen Gallagherstatic int mbox_lock_flock(struct mbox_lock_context *ctx, int lock_type,
41291f19dbc5bf14f20729959b852fa605fcc02dJakub Hrozek time_t max_wait_time);
8214510f125879c3b1d247f2ce981ee20b5375d1Jakub Hrozek#else
1a59af8245f183f22d87d067a90197d8e2ea958dJakub Hrozek# define mbox_lock_flock NULL
a5bb518446d5ce565d7ba819590a009cabb0b0b4Jakub Hrozek#endif
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce#ifdef HAVE_LOCKF
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic int mbox_lock_lockf(struct mbox_lock_context *ctx, int lock_type,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher time_t max_wait_time);
d921c1eba437662437847279f251a0a5d8f70127Maxim#else
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek# define mbox_lock_lockf NULL
b9c8ce2bdd4045782c243605a1b999098bedcffcNoam Meltzer#endif
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstruct mbox_lock_data lock_data[] = {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher { MBOX_LOCK_DOTLOCK, "dotlock", mbox_lock_dotlock },
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher { MBOX_LOCK_FCNTL, "fcntl", mbox_lock_fcntl },
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher { MBOX_LOCK_FLOCK, "flock", mbox_lock_flock },
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce { MBOX_LOCK_LOCKF, "lockf", mbox_lock_lockf },
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher { 0, NULL, NULL }
2a5790216f57e9bdfb2930d52860bb5300366536Jakub Hrozek};
5377441d7a846461c2d9a7a870cea711360a529aNikolai Kondrashov
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic bool lock_settings_initialized = FALSE;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic enum mbox_lock_type read_locks[MBOX_LOCK_COUNT+1];
32381402a4a9afc003782c9e2301fc59c9bda2a9Yassir Elleystatic enum mbox_lock_type write_locks[MBOX_LOCK_COUNT+1];
dbfc407eef1d9ba2469687c3ffbe7fd8bb111d94Jakub Hrozekstatic int lock_timeout, dotlock_change_timeout;
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher
4b6a0d0b3d42e5fdb457f47d9adfa5e66b160256Stephen Gallagherstatic int mbox_lock_list(struct mbox_lock_context *ctx, int lock_type,
e124844907ed6973915e4d56f5442ecd07535a12Jakub Hrozek time_t max_wait_time, int idx);
5484044ea7bb632b915f706685fce509f6eacc48Jakub Hrozekstatic int mbox_unlock_files(struct mbox_lock_context *ctx);
59744cff6edb106ae799b2321cb8731edadf409aStephen Gallagher
6dcbfe52d5e64205c0d922f3e89add066b42c496Jakub Hrozekstatic void mbox_read_lock_methods(const char *str, const char *env,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher enum mbox_lock_type *locks)
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce{
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce enum mbox_lock_type type;
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher const char *const *lock;
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher int i, dest;
87d3b47abba6a40fcf809c85a2b138bc1013d9c5Jakub Hrozek
bc13c352ba9c2877f1e9bc62e55ad60fc000a55dJakub Hrozek for (lock = t_strsplit(str, " "), dest = 0; *lock != NULL; lock++) {
bc13c352ba9c2877f1e9bc62e55ad60fc000a55dJakub Hrozek for (type = 0; lock_data[type].name != NULL; type++) {
bc13c352ba9c2877f1e9bc62e55ad60fc000a55dJakub Hrozek if (strcasecmp(*lock, lock_data[type].name) == 0) {
bc13c352ba9c2877f1e9bc62e55ad60fc000a55dJakub Hrozek type = lock_data[type].type;
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce break;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (lock_data[type].name == NULL)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("%s: Invalid value %s", env, *lock);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (lock_data[type].func == NULL) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("%s: Support for lock type %s "
054b5d4bb98973698f74d66b14ccd14394b53f10Lukas Slebodnik "not compiled into binary", env, *lock);
054b5d4bb98973698f74d66b14ccd14394b53f10Lukas Slebodnik }
62bda5f75bda6b77aea30d708c74efaf725d9367Lukas Slebodnik
a3d176d116ceccd6a7547c128fab5df5cdd2c2b6Michal Zidek for (i = 0; i < dest; i++) {
a3d176d116ceccd6a7547c128fab5df5cdd2c2b6Michal Zidek if (locks[i] == type)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("%s: Duplicated value %s", env, *lock);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
4f6931e854c698dcb1c09f99eb330ce2fb97e7c6Lukas Slebodnik
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher /* @UNSAFE */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher locks[dest++] = type;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
558998ce664055a75595371118f818084d8f2b23Jan Cholasta locks[dest] = (enum mbox_lock_type)-1;
558998ce664055a75595371118f818084d8f2b23Jan Cholasta}
9a3e40dc49c1e38bf58e45be5adff37615f3910bJan Cholasta
9a3e40dc49c1e38bf58e45be5adff37615f3910bJan Cholastastatic void mbox_init_lock_settings(void)
558998ce664055a75595371118f818084d8f2b23Jan Cholasta{
558998ce664055a75595371118f818084d8f2b23Jan Cholasta const char *str;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher int r, w;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher str = getenv("MBOX_READ_LOCKS");
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (str == NULL) str = DEFAULT_READ_LOCK_METHODS;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher mbox_read_lock_methods(str, "MBOX_READ_LOCKS", read_locks);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher str = getenv("MBOX_WRITE_LOCKS");
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (str == NULL) str = DEFAULT_WRITE_LOCK_METHODS;
c737e1444fb186e349e59bfa9dac4995b720b4b1Jan Zeleny mbox_read_lock_methods(str, "MBOX_WRITE_LOCKS", write_locks);
f1828234a850dd28465425248a83a993f262918fPavel Březina
6ea6ec5cb7d9985e2730fb9d4657624d10aed4d8Nick Guay /* check that read/write list orders match. write_locks must contain
b69cb1787209e85cc246eb9a944242689bfe0c46Pavel Březina at least read_locks and possibly more. */
b69cb1787209e85cc246eb9a944242689bfe0c46Pavel Březina for (r = w = 0; write_locks[w] != (enum mbox_lock_type)-1; w++) {
e157b9f6cb370e1b94bcac2044d26ad66d640fbaPavel Březina if (read_locks[r] == (enum mbox_lock_type)-1)
b69cb1787209e85cc246eb9a944242689bfe0c46Pavel Březina break;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (read_locks[r] == write_locks[w])
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher r++;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (read_locks[r] != (enum mbox_lock_type)-1) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("mbox read/write lock list settings are invalid. "
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher "Lock ordering must be the same with both, "
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher "and write locks must contain all read locks "
1746e8b8399da2a7a8da4aace186f66055ccfec1Jakub Hrozek "(and possibly more)");
1746e8b8399da2a7a8da4aace186f66055ccfec1Jakub Hrozek }
1746e8b8399da2a7a8da4aace186f66055ccfec1Jakub Hrozek
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina str = getenv("MBOX_LOCK_TIMEOUT");
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina lock_timeout = str == NULL ? DEFAULT_LOCK_TIMEOUT : atoi(str);
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina
9e80079370ff3b943832adc3c5ef430e64be0a0cJakub Hrozek str = getenv("MBOX_DOTLOCK_CHANGE_TIMEOUT");
9e80079370ff3b943832adc3c5ef430e64be0a0cJakub Hrozek dotlock_change_timeout = str == NULL ?
9e80079370ff3b943832adc3c5ef430e64be0a0cJakub Hrozek DEFAULT_DOTLOCK_CHANGE_TIMEOUT : atoi(str);
e7311aec8d691e5427317442387af1bc8fff3742Jan Cholasta
e7311aec8d691e5427317442387af1bc8fff3742Jan Cholasta lock_settings_initialized = TRUE;
e7311aec8d691e5427317442387af1bc8fff3742Jan Cholasta}
cb4d5b588e704114b7090678752d33512baa718eJakub Hrozek
cb4d5b588e704114b7090678752d33512baa718eJakub Hrozekstatic int mbox_file_open_latest(struct mbox_lock_context *ctx, int lock_type)
cb4d5b588e704114b7090678752d33512baa718eJakub Hrozek{
19d3aba12c70528708be9440aca66038a291f29eYassir Elley struct mbox_mailbox *mbox = ctx->mbox;
19d3aba12c70528708be9440aca66038a291f29eYassir Elley struct stat st;
19d3aba12c70528708be9440aca66038a291f29eYassir Elley
f3a25949de81f80c136bb073e4a8f504b080c20cJakub Hrozek if (ctx->checked_file || lock_type == F_UNLCK)
f3a25949de81f80c136bb073e4a8f504b080c20cJakub Hrozek return 0;
f3a25949de81f80c136bb073e4a8f504b080c20cJakub Hrozek
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose if (mbox->mbox_fd != -1) {
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose if (stat(mbox->path, &st) < 0) {
3be9e26dcd169d44ae105f1b8a0674464c700b77Sumit Bose mbox_set_syscall_error(mbox, "stat()");
5484044ea7bb632b915f706685fce509f6eacc48Jakub Hrozek return -1;
5484044ea7bb632b915f706685fce509f6eacc48Jakub Hrozek }
3be9e26dcd169d44ae105f1b8a0674464c700b77Sumit Bose
3be9e26dcd169d44ae105f1b8a0674464c700b77Sumit Bose if (st.st_ino != mbox->mbox_ino ||
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose !CMP_DEV_T(st.st_dev, mbox->mbox_dev))
5484044ea7bb632b915f706685fce509f6eacc48Jakub Hrozek mbox_file_close(mbox);
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce }
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce if (mbox->mbox_fd == -1) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (mbox_file_open(mbox) < 0)
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose return -1;
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose }
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose ctx->checked_file = TRUE;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return 0;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher}
36ccdecd053a9ad88dce86b8c84770dc2aa11d21Simo Sorce
4b39208286ca0351ee76d4e64e077e7ad5ca8568Jakub Hrozekstatic bool dotlock_callback(unsigned int secs_left, bool stale, void *context)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct mbox_lock_context *ctx = context;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher enum mbox_lock_type *lock_types;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher int i;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (stale && !ctx->dotlock_last_stale) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* get next index we wish to try locking. it's the one after
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher dotlocking. */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher lock_types = ctx->lock_type == F_WRLCK ||
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher (ctx->lock_type == F_UNLCK &&
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher ctx->mbox->mbox_lock_type == F_WRLCK) ?
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek write_locks : read_locks;
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher
fe60346714a73ac3987f786731389320633dd245Pavel Březina for (i = 0; lock_types[i] != (enum mbox_lock_type)-1; i++) {
a6098862048d4bb469130b9ff21be3020d6f2c54Sumit Bose if (lock_types[i] == MBOX_LOCK_DOTLOCK)
2d257ccf620ce1b611f89cec8f0a94c88c2f2881Sumit Bose break;
b9d8c6172e48a2633ebe196b2e88bebdf9523c20Stef Walter }
4bd20c075f0f187db0181dc53d00ab6cd47fdb4dJakub Hrozek
e5e8252ec48bfdd4e7529debc705c8e090264b9aSumit Bose if (lock_types[i] != (enum mbox_lock_type)-1 &&
71e7918be3ca5d38794a16a17f6b4f19a24d51fcPavel Březina lock_types[i+1] != (enum mbox_lock_type)-1) {
8359bf07a2e6c0181251ce8d5d9160dc57546c55Stephen Gallagher i++;
71e7918be3ca5d38794a16a17f6b4f19a24d51fcPavel Březina if (mbox_lock_list(ctx, ctx->lock_type, 0, i) <= 0) {
71e7918be3ca5d38794a16a17f6b4f19a24d51fcPavel Březina /* we couldn't get fd lock -
bbaba8b3ef9bc101863b8687f234f4ee956caacdPavel Březina it's really locked */
80314a6f3ea8d81abe73d501d5b953a256cb2167Pavel Březina ctx->dotlock_last_stale = TRUE;
80314a6f3ea8d81abe73d501d5b953a256cb2167Pavel Březina return FALSE;
bbaba8b3ef9bc101863b8687f234f4ee956caacdPavel Březina }
bbaba8b3ef9bc101863b8687f234f4ee956caacdPavel Březina (void)mbox_lock_list(ctx, F_UNLCK, 0, i);
80314a6f3ea8d81abe73d501d5b953a256cb2167Pavel Březina }
4bd20c075f0f187db0181dc53d00ab6cd47fdb4dJakub Hrozek }
4bd20c075f0f187db0181dc53d00ab6cd47fdb4dJakub Hrozek ctx->dotlock_last_stale = stale;
4bd20c075f0f187db0181dc53d00ab6cd47fdb4dJakub Hrozek
4bd20c075f0f187db0181dc53d00ab6cd47fdb4dJakub Hrozek index_storage_lock_notify(&ctx->mbox->ibox, stale ?
4bd20c075f0f187db0181dc53d00ab6cd47fdb4dJakub Hrozek MAILBOX_LOCK_NOTIFY_MAILBOX_OVERRIDE :
4bd20c075f0f187db0181dc53d00ab6cd47fdb4dJakub Hrozek MAILBOX_LOCK_NOTIFY_MAILBOX_ABORT,
4bd20c075f0f187db0181dc53d00ab6cd47fdb4dJakub Hrozek secs_left);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return TRUE;
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek}
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek
2dcf7b9b65df21f2aee6cdf051a7fbdef6dfe034Jakub Hrozekstatic int mbox_lock_dotlock(struct mbox_lock_context *ctx, int lock_type,
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh time_t max_wait_time __attr_unused__)
2a9af1f71887f02935e2fb6ad5023afba5b6d43eSumit Bose{
d00ffd2cb4e2f17c75b466178bb645b5c9317909Pallavi Jha struct mbox_mailbox *mbox = ctx->mbox;
461da2984c747708e8badd27fa55ef879f40e712Pallavi Jha struct dotlock_settings set;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek int ret;
777374243e15c53e7b0a7345e190c1018920be18Jakub Hrozek
d064fef06dcbcb5f6c1be03e286b1a3433d6dfd7Sumit Bose if (lock_type == F_UNLCK) {
3432a503c714732407ea18b2dd32f4f432a6c545Jakub Hrozek if (!mbox->mbox_dotlocked)
939246537b0b9a4af6862c513d3919501ad57d92Sumit Bose return 1;
f69f3581658351003a6d9245045e41d0efb85022Sumit Bose
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozek if (file_dotlock_delete(&mbox->mbox_dotlock) <= 0) {
90afedb00608547ae1f32aa7aafd552c4b306909Jakub Hrozek mbox_set_syscall_error(mbox, "file_dotlock_delete()");
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek ret = -1;
0161a3c5637a0c0092bf54c436bb3d6508d7df26Jakub Hrozek }
f43c6a9ae2aea13b7a83fd932139f9352efbfcadPavel Březina mbox->mbox_dotlocked = FALSE;
e592d5f157be869151983bd1b46d6f4f7a29daafJakub Hrozek return 1;
50b8a36b0932a510e825ed1ad8103f81ead2b7d8Pavel Reichl }
50b8a36b0932a510e825ed1ad8103f81ead2b7d8Pavel Reichl
e592d5f157be869151983bd1b46d6f4f7a29daafJakub Hrozek if (mbox->mbox_dotlocked)
d36f4db9bb5efc63b94190cca25adb08ee56971cJakub Hrozek return 1;
6ea6662287147308b81b9c9f2f1f3c992d01bc50Jakub Hrozek
526a15438525417cd701f837d7085b7f8c8a6325Jakub Hrozek ctx->dotlock_last_stale = -1;
27a7dedb0ee4d4b51ca4c196aa894ad30cb3e821Petr Cech
1d93029624d708119bbf803e6647a2cbb271f001Sumit Bose memset(&set, 0, sizeof(set));
a5623363d6042290fe652a1ca5ce5a85a821236fPavel Březina set.timeout = lock_timeout;
802385896dc1c4e7b8bbd40dcfe3cd131f68e696Sumit Bose set.stale_timeout = dotlock_change_timeout;
a0ab15ceb80290db80c2052520830a95390de385Sumit Bose set.callback = dotlock_callback;
e00c2b5ac4963de9521599c88597b7fb97339d0eJakub Hrozek set.context = ctx;
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina ret = file_dotlock_create(&set, mbox->path, 0, &mbox->mbox_dotlock);
8df69bbc58c2f4d3f0b34be9756d9ddf24b1db6dJakub Hrozek if (ret < 0) {
2b62d5a414b8b7dba4f714dc5033e28dc4b1f4feJakub Hrozek mbox_set_syscall_error(mbox, "file_lock_dotlock()");
89ddc9ed474e9ac2b1e7bccb0a58610babf26cf8Jakub Hrozek return -1;
b590f44c06158485357d69cc5b24d5af05f1bb95Petr Cech }
01ec08efd0e166ac6f390f8627c6d08dcc63ccc4Jakub Hrozek if (ret == 0) {
bf01e8179cbb2be476805340636098deda7e1366Sumit Bose mail_storage_set_error(STORAGE(mbox->storage),
338af078fcc18126df939f20182acea7a646b7c8Michal Zidek "Timeout while waiting for lock");
99c5f2f6ba0af6ce52be0d82ec2794bacc215742Jakub Hrozek return 0;
b9d83e10cec267ae11fee64a30f42a12bbf7abe4Pavel Březina }
49c467733ca65c9b77b9c33f38cdc223a99562e1Pavel Reichl mbox->mbox_dotlocked = TRUE;
62370340092503baeaf6587d7ffe4fe25bd9582dPavel Reichl
b407fe0474a674bb42f0f42ab47c7f530a07a367Pavel Březina if (mbox_file_open_latest(ctx, lock_type) < 0)
583c1b9a052f4eb5ba046c5f2b7d2ed2a81b6d66Jakub Hrozek return -1;
e592d5f157be869151983bd1b46d6f4f7a29daafJakub Hrozek return 1;
f92ace4a52602e8c38a34f2392bec3deeac2ddddJakub Hrozek}
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek#ifdef HAVE_FLOCK
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozekstatic int mbox_lock_flock(struct mbox_lock_context *ctx, int lock_type,
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek time_t max_wait_time)
f92ace4a52602e8c38a34f2392bec3deeac2ddddJakub Hrozek{
f92ace4a52602e8c38a34f2392bec3deeac2ddddJakub Hrozek time_t now, last_notify;
f92ace4a52602e8c38a34f2392bec3deeac2ddddJakub Hrozek
f92ace4a52602e8c38a34f2392bec3deeac2ddddJakub Hrozek if (mbox_file_open_latest(ctx, lock_type) < 0)
a2e417f38c57ed87c956ddcecf4dafca93842b65Lukas Slebodnik return -1;
99f8be128274eba264ea1434a7eb2800bced5902Lukas Slebodnik
99f8be128274eba264ea1434a7eb2800bced5902Lukas Slebodnik if (lock_type == F_UNLCK && ctx->mbox->mbox_fd == -1)
91d312000e6ded4a93327c137b10c5beda55f65cSumit Bose return 1;
91d312000e6ded4a93327c137b10c5beda55f65cSumit Bose
91d312000e6ded4a93327c137b10c5beda55f65cSumit Bose if (lock_type == F_WRLCK)
91d312000e6ded4a93327c137b10c5beda55f65cSumit Bose lock_type = LOCK_EX;
a2e417f38c57ed87c956ddcecf4dafca93842b65Lukas Slebodnik else if (lock_type == F_RDLCK)
a2e417f38c57ed87c956ddcecf4dafca93842b65Lukas Slebodnik lock_type = LOCK_SH;
f92ace4a52602e8c38a34f2392bec3deeac2ddddJakub Hrozek else
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek lock_type = LOCK_UN;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher last_notify = 0;
f232789430a080384188d5da89b19d874cf17513Jakub Hrozek while (flock(ctx->mbox->mbox_fd, lock_type | LOCK_NB) < 0) {
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek if (errno != EWOULDBLOCK) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher mbox_set_syscall_error(ctx->mbox, "flock()");
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return -1;
9f521c61c17cecd9625ebc1b33c666fa3488622cJakub Hrozek }
fb3c5cdfcda069a5fbeb7b9d200c0881911364b8Jakub Hrozek
9f521c61c17cecd9625ebc1b33c666fa3488622cJakub Hrozek now = time(NULL);
9f521c61c17cecd9625ebc1b33c666fa3488622cJakub Hrozek if (now >= max_wait_time)
bf5a808fa92007c325c3996e79694badfab201d4Stephen Gallagher return 0;
bf5a808fa92007c325c3996e79694badfab201d4Stephen Gallagher
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik if (now != last_notify) {
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik index_storage_lock_notify(&ctx->mbox->ibox,
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik MAILBOX_LOCK_NOTIFY_MAILBOX_ABORT,
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik max_wait_time - now);
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik }
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik usleep(LOCK_RANDOM_USLEEP_TIME);
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik }
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik return 1;
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik}
bf5a808fa92007c325c3996e79694badfab201d4Stephen Gallagher#endif
bf5a808fa92007c325c3996e79694badfab201d4Stephen Gallagher
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik#ifdef HAVE_LOCKF
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic int mbox_lock_lockf(struct mbox_lock_context *ctx, int lock_type,
bf5a808fa92007c325c3996e79694badfab201d4Stephen Gallagher time_t max_wait_time)
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek{
cbff3fcdce5b0377a62fbe74f32e476efbf7ca9cNikolai Kondrashov time_t now, last_notify;
cbff3fcdce5b0377a62fbe74f32e476efbf7ca9cNikolai Kondrashov
cbff3fcdce5b0377a62fbe74f32e476efbf7ca9cNikolai Kondrashov if (mbox_file_open_latest(ctx, lock_type) < 0)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return -1;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (lock_type == F_UNLCK && ctx->mbox->mbox_fd == -1)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return 1;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (lock_type != F_UNLCK)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher lock_type = F_TLOCK;
a2e417f38c57ed87c956ddcecf4dafca93842b65Lukas Slebodnik else
a2e417f38c57ed87c956ddcecf4dafca93842b65Lukas Slebodnik lock_type = F_ULOCK;
a2e417f38c57ed87c956ddcecf4dafca93842b65Lukas Slebodnik
a2e417f38c57ed87c956ddcecf4dafca93842b65Lukas Slebodnik last_notify = 0;
a2e417f38c57ed87c956ddcecf4dafca93842b65Lukas Slebodnik while (lockf(ctx->mbox->mbox_fd, lock_type, 0) < 0) {
a2e417f38c57ed87c956ddcecf4dafca93842b65Lukas Slebodnik if (errno != EAGAIN) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher mbox_set_syscall_error(ctx->mbox, "lockf()");
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return -1;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher now = time(NULL);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (now >= max_wait_time)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return 0;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
8a5e793a0576250da80371e53aa3e7eba15cdb63Sumit Bose if (now != last_notify) {
8a5e793a0576250da80371e53aa3e7eba15cdb63Sumit Bose index_storage_lock_notify(&ctx->mbox->ibox,
8a5e793a0576250da80371e53aa3e7eba15cdb63Sumit Bose MAILBOX_LOCK_NOTIFY_MAILBOX_ABORT,
8a5e793a0576250da80371e53aa3e7eba15cdb63Sumit Bose max_wait_time - now);
8a5e793a0576250da80371e53aa3e7eba15cdb63Sumit Bose }
90fd1bbd6035cdab46faa3a695a2fb2be6508b17Sumit Bose
90fd1bbd6035cdab46faa3a695a2fb2be6508b17Sumit Bose usleep(LOCK_RANDOM_USLEEP_TIME);
90fd1bbd6035cdab46faa3a695a2fb2be6508b17Sumit Bose }
90fd1bbd6035cdab46faa3a695a2fb2be6508b17Sumit Bose
90fd1bbd6035cdab46faa3a695a2fb2be6508b17Sumit Bose return 1;
af4ffe1001adcc0a96897e426d26444f07af9aa1Benjamin Franzke}
af4ffe1001adcc0a96897e426d26444f07af9aa1Benjamin Franzke#endif
af4ffe1001adcc0a96897e426d26444f07af9aa1Benjamin Franzke
af4ffe1001adcc0a96897e426d26444f07af9aa1Benjamin Franzkestatic int mbox_lock_fcntl(struct mbox_lock_context *ctx, int lock_type,
af4ffe1001adcc0a96897e426d26444f07af9aa1Benjamin Franzke time_t max_wait_time)
1d1a0a019d8d4d9ab0f51ada03604cd2cada287eSumit Bose{
1d1a0a019d8d4d9ab0f51ada03604cd2cada287eSumit Bose struct flock fl;
1d1a0a019d8d4d9ab0f51ada03604cd2cada287eSumit Bose time_t now;
1d1a0a019d8d4d9ab0f51ada03604cd2cada287eSumit Bose unsigned int next_alarm;
1d1a0a019d8d4d9ab0f51ada03604cd2cada287eSumit Bose int wait_type;
1d1a0a019d8d4d9ab0f51ada03604cd2cada287eSumit Bose
96453f402831275a39d5fb89c33c9776e148d03fStephen Gallagher if (mbox_file_open_latest(ctx, lock_type) < 0)
96453f402831275a39d5fb89c33c9776e148d03fStephen Gallagher return -1;
25d4435998d0446f7699e7ab0874c7a6f610ab58Lukas Slebodnik
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (lock_type == F_UNLCK && ctx->mbox->mbox_fd == -1)
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik return 1;
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik memset(&fl, 0, sizeof(fl));
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik fl.l_type = lock_type;
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik fl.l_whence = SEEK_SET;
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik fl.l_start = 0;
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik fl.l_len = 0;
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik if (max_wait_time == 0) {
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik /* usually we're waiting here, but if we came from
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik mbox_lock_dotlock(), we just want to try locking */
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik wait_type = F_SETLK;
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik } else {
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik wait_type = F_SETLKW;
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik now = time(NULL);
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik if (now >= max_wait_time)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher alarm(1);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher else
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher alarm(I_MIN(max_wait_time - now, 5));
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
1467daed400d6c186bd0c99c057c42e764309ff3Stephen Gallagher while (fcntl(ctx->mbox->mbox_fd, wait_type, &fl) < 0) {
1467daed400d6c186bd0c99c057c42e764309ff3Stephen Gallagher if (errno != EINTR) {
15b266d9f14dad26da8678a79019749d0f69532eStephen Gallagher mbox_set_syscall_error(ctx->mbox, "fcntl()");
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik alarm(0);
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik return -1;
1467daed400d6c186bd0c99c057c42e764309ff3Stephen Gallagher }
b97595ae059c69b1960a6e7e56d74660388a683bJan Zeleny
6a6a821866091e0f722808566c25b951aa346d7cStephen Gallagher now = time(NULL);
48d7840cae22c5ff4d786149b0d8ecee7efb8306Lukas Slebodnik if (now >= max_wait_time) {
3ce85a5f5264e7118beb6524e120fd8b53a13da4Nikolai Kondrashov alarm(0);
3ce85a5f5264e7118beb6524e120fd8b53a13da4Nikolai Kondrashov return 0;
3ce85a5f5264e7118beb6524e120fd8b53a13da4Nikolai Kondrashov }
3ce85a5f5264e7118beb6524e120fd8b53a13da4Nikolai Kondrashov
60e51fd2764291df2332f36ff478777627d92b57Sumit Bose /* notify locks once every 5 seconds.
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik try to use rounded values. */
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik next_alarm = (max_wait_time - now) % 5;
51d65c4ad15c2cc23f38fa09dd6efeb15e4f3e86Jakub Hrozek if (next_alarm == 0)
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik next_alarm = 5;
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik alarm(next_alarm);
51d65c4ad15c2cc23f38fa09dd6efeb15e4f3e86Jakub Hrozek
cbff3fcdce5b0377a62fbe74f32e476efbf7ca9cNikolai Kondrashov index_storage_lock_notify(&ctx->mbox->ibox,
7bb9ba8688ec1ca930d693eea05e936bc38f6d1bSumit Bose MAILBOX_LOCK_NOTIFY_MAILBOX_ABORT,
51d65c4ad15c2cc23f38fa09dd6efeb15e4f3e86Jakub Hrozek max_wait_time - now);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
84ae5edab16ad6be5e3be956cb6fa031c1428eb5Stephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher alarm(0);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return 1;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher}
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic int mbox_lock_list(struct mbox_lock_context *ctx, int lock_type,
17f08cbd0f909181536b93d6c12c7cd69995f09eSumit Bose time_t max_wait_time, int idx)
3ce85a5f5264e7118beb6524e120fd8b53a13da4Nikolai Kondrashov{
3ce85a5f5264e7118beb6524e120fd8b53a13da4Nikolai Kondrashov enum mbox_lock_type *lock_types;
3ce85a5f5264e7118beb6524e120fd8b53a13da4Nikolai Kondrashov enum mbox_lock_type type;
3ce85a5f5264e7118beb6524e120fd8b53a13da4Nikolai Kondrashov int i, ret = 0, lock_status;
3ce85a5f5264e7118beb6524e120fd8b53a13da4Nikolai Kondrashov
6398f22526303343193a18e514602f1af6fb29cbNikolai Kondrashov ctx->lock_type = lock_type;
6398f22526303343193a18e514602f1af6fb29cbNikolai Kondrashov
a8d887323f83984679a7d9b827a70146656bb7b2Sumit Bose lock_types = lock_type == F_WRLCK ||
a8d887323f83984679a7d9b827a70146656bb7b2Sumit Bose (lock_type == F_UNLCK && ctx->mbox->mbox_lock_type == F_WRLCK) ?
29c5542feb4c45865ea61be97e0e84a1d1f04918Jakub Hrozek write_locks : read_locks;
6398f22526303343193a18e514602f1af6fb29cbNikolai Kondrashov for (i = idx; lock_types[i] != (enum mbox_lock_type)-1; i++) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher type = lock_types[i];
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher lock_status = lock_type != F_UNLCK;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (ctx->lock_status[type] == lock_status)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher continue;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ctx->lock_status[type] = lock_status;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ret = lock_data[type].func(ctx, lock_type, max_wait_time);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (ret <= 0)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher break;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return ret;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher}
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic int mbox_update_locking(struct mbox_mailbox *mbox, int lock_type)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct mbox_lock_context ctx;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher time_t max_wait_time;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher int ret, i;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher bool drop_locks;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher index_storage_lock_notify_reset(&mbox->ibox);
bfbf5cb0f00c60c0f000f56c282377b13b9a89abSumit Bose
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher if (!lock_settings_initialized)
77c0d1f6074059dafd2293f9c42ea0f9d60f8aadJakub Hrozek mbox_init_lock_settings();
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (mbox->mbox_fd == -1 && mbox->mbox_file_stream != NULL) {
a5bb518446d5ce565d7ba819590a009cabb0b0b4Jakub Hrozek /* read-only mbox stream. no need to lock. */
eaaeaa7e00c3d4bfa792cc4d3c6770dc1e28ef0cSumit Bose i_assert(mbox->mbox_readonly);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher mbox->mbox_lock_type = lock_type;
c42ca36247022490ad65a33c453cb5e43900dbe9Lukas Slebodnik return 1;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
59744cff6edb106ae799b2321cb8731edadf409aStephen Gallagher max_wait_time = time(NULL) + lock_timeout;
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher memset(&ctx, 0, sizeof(ctx));
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ctx.mbox = mbox;
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (mbox->mbox_lock_type == F_WRLCK) {
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce /* dropping to shared lock. first drop those that we
0ef783e186ef1c9f60e61a4e8e54c44cb366fdfePavel Březina don't remove completely. */
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek for (i = 0; i < MBOX_LOCK_COUNT; i++)
e7311aec8d691e5427317442387af1bc8fff3742Jan Cholasta ctx.lock_status[i] = 1;
50c9d542e8bf641412debaa82a4dcf67ddb72258Lukas Slebodnik for (i = 0; read_locks[i] != (enum mbox_lock_type)-1; i++)
50c9d542e8bf641412debaa82a4dcf67ddb72258Lukas Slebodnik ctx.lock_status[read_locks[i]] = 0;
50c9d542e8bf641412debaa82a4dcf67ddb72258Lukas Slebodnik drop_locks = TRUE;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher } else {
b3b6189850d50c656d62efbd498789124c033b00Lukas Slebodnik drop_locks = FALSE;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
e7ccfb139388c947ec2dee16cfe3005f5643b90dPetr Cech mbox->mbox_lock_type = lock_type;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ret = mbox_lock_list(&ctx, lock_type, max_wait_time, 0);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (ret <= 0) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (!drop_locks)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher (void)mbox_unlock_files(&ctx);
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny if (ret == 0) {
769347ad4d35d43488eb98f980143495b0db415dStef Walter mail_storage_set_error(STORAGE(mbox->storage),
115de6d50f0d0bdd5745a5d8eb0d067be9128528Sumit Bose "Timeout while waiting for lock");
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina }
83a79d93035c2d75a1941f3b54426119174044a0Pavel Březina return ret;
83a79d93035c2d75a1941f3b54426119174044a0Pavel Březina }
769347ad4d35d43488eb98f980143495b0db415dStef Walter
769347ad4d35d43488eb98f980143495b0db415dStef Walter if (drop_locks) {
376eaf187c13c2a1eaea0ffbdd970b6b563ab74cPetr Cech /* dropping to shared lock: drop the locks that are only
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher in write list */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher memset(ctx.lock_status, 0, sizeof(ctx.lock_status));
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher for (i = 0; write_locks[i] != (enum mbox_lock_type)-1; i++)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ctx.lock_status[write_locks[i]] = 1;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher for (i = 0; read_locks[i] != (enum mbox_lock_type)-1; i++)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ctx.lock_status[read_locks[i]] = 0;
284937e6b5b0c9d7a1d3382d0d2820d1168842fbPavel Březina
aea1d5c0ca9bb1470759b024c8b97b6c1f577193Pavel Březina mbox->mbox_lock_type = F_WRLCK;
d2d8f342cd5e90bb9fd947c448492225f959aa86Pavel Březina (void)mbox_lock_list(&ctx, F_UNLCK, 0, 0);
284937e6b5b0c9d7a1d3382d0d2820d1168842fbPavel Březina mbox->mbox_lock_type = F_RDLCK;
284937e6b5b0c9d7a1d3382d0d2820d1168842fbPavel Březina }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
543676afec3c08fdc0a5a794976adc8dfdca974bJakub Hrozek return 1;
543676afec3c08fdc0a5a794976adc8dfdca974bJakub Hrozek}
543676afec3c08fdc0a5a794976adc8dfdca974bJakub Hrozek
543676afec3c08fdc0a5a794976adc8dfdca974bJakub Hrozekint mbox_lock(struct mbox_mailbox *mbox, int lock_type,
543676afec3c08fdc0a5a794976adc8dfdca974bJakub Hrozek unsigned int *lock_id_r)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
ca261795ce61c41d7e62217ccb2ee913923040ffPavel Březina int ret;
ca261795ce61c41d7e62217ccb2ee913923040ffPavel Březina
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* allow only unlock -> shared/exclusive or exclusive -> shared */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_assert(lock_type == F_RDLCK || lock_type == F_WRLCK);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_assert(lock_type == F_RDLCK || mbox->mbox_lock_type != F_RDLCK);
77d165f0629966db65753a3aee84a8b4971673afPavel Březina
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* mbox must be locked before index */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_assert(mbox->ibox.index->lock_type != F_WRLCK);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (mbox->mbox_lock_type == F_UNLCK) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ret = mbox_update_locking(mbox, lock_type);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (ret <= 0)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return ret;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher mbox->mbox_lock_id += 2;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (lock_type == F_RDLCK) {
126c9338cf12a3e4404c36bbe4ec14b18f23537cMaxim mbox->mbox_shared_locks++;
6499d0b915209b670f8e337c4fe76a8be9fa6576Simo Sorce *lock_id_r = mbox->mbox_lock_id;
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher } else {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher mbox->mbox_excl_locks++;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher *lock_id_r = mbox->mbox_lock_id + 1;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return 1;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher}
4e0404ca1b19830dc0f729e59efd5bbd0a9d6103Lukas Slebodnik
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic int mbox_unlock_files(struct mbox_lock_context *ctx)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
eaa723b4d06b4c1e588df67bef44a84bbfaebf1aLukas Slebodnik int ret = 0;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (mbox_lock_list(ctx, F_UNLCK, 0, 0) < 0)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ret = -1;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (ctx->mbox->ibox.mail_read_mmaped) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* make sure we don't keep mmap() between locks */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher mbox_file_close_stream(ctx->mbox);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
bfbf5cb0f00c60c0f000f56c282377b13b9a89abSumit Bose ctx->mbox->mbox_lock_id += 2;
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher ctx->mbox->mbox_lock_type = F_UNLCK;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return ret;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher}
2e6087c6cc903d5164b9a1d5e3d791fd046001d9Jakub Hrozek
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherint mbox_unlock(struct mbox_mailbox *mbox, unsigned int lock_id)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct mbox_lock_context ctx;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher int i;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek i_assert(mbox->mbox_lock_id == (lock_id & ~1));
bf01e8179cbb2be476805340636098deda7e1366Sumit Bose
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (lock_id & 1) {
558ec7d717735bb16c210c675c2cc5bee1da4576Lukas Slebodnik /* dropping exclusive lock */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_assert(mbox->mbox_excl_locks > 0);
3a4186ae40d0c3b7be46a4c973166f6048fcfe38Lukas Slebodnik if (--mbox->mbox_excl_locks > 0)
8bcabb97d988d1602882a1f036aac2eaf5e09234Simo Sorce return 0;
b9d8c6172e48a2633ebe196b2e88bebdf9523c20Stef Walter if (mbox->mbox_shared_locks > 0) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* drop to shared lock */
46e36286953de4e5af5e4289b90a529929bdd17cPetr Cech if (mbox_update_locking(mbox, F_RDLCK) < 0)
1658c567191c35beaddffafdb079abe33248037bLukas Slebodnik return -1;
29be7d76c949b82350c7603cfd362a1fcb47eb1bJan Zeleny return 0;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
72e60fd4eabcfbcdbfe01e8c38b94052bc6c2067Jakub Hrozek } else {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* dropping shared lock */
823a5b3f4375f12b6edae4dd5169ee01771baebeJan Zeleny i_assert(mbox->mbox_shared_locks > 0);
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce if (--mbox->mbox_shared_locks > 0)
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher return 0;
748ba184db97b7534254f97018fa04e8aa458faeJan Cholasta if (mbox->mbox_excl_locks > 0)
7de6e3534fd61c7619ed34a6b1afe7230b5e6504Ondrej Kos return 0;
701f13b5c8e27bcbfc79e77ce7c76d9f768a448cLukas Slebodnik }
3fc158e59eebbc2f538fe0076a03928d0d4eab9fPavel Březina /* all locks gone */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher memset(&ctx, 0, sizeof(ctx));
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ctx.mbox = mbox;
5a70b84cb66fb8c7a3fce0e3f2e4b61e0b2ea9d4Simo Sorce
5f90993426fa2bdc3b3d994c9e85e0805bb92bbcSimo Sorce for (i = 0; i < MBOX_LOCK_COUNT; i++)
9959c512ac3ba36f7a0db7614f0357ce0bae748fJakub Hrozek ctx.lock_status[i] = 1;
7452f1b637276ce582b120f8f5482ae7f3b6bd47Jakub Hrozek
918b2a5a91f1c551d48f4bffed2a28c36fdb4be1Simo Sorce return mbox_unlock_files(&ctx);
bc052ea17d858c19f9cb9c9e2bc602e754f68831Sumit Bose}
2fa8d6655ac37f9bdeb34420000052d921f4a543Michal Zidek