mbox-lock.c revision c000c8eca8f24b2a0c76393ec4bbf76a505a4983
f209d63a97a8a2df5324608fee7b0d7a494d69ebS.Çağlar Onur/* Copyright (c) 2002-2010 Dovecot authors, see the included COPYING file */
95ee490bbdb97ab2b4f1dfa63a0a26e0dd1c2f17Stéphane Graber/* 0.1 .. 0.2msec */
95ee490bbdb97ab2b4f1dfa63a0a26e0dd1c2f17Stéphane Graber#define LOCK_RANDOM_USLEEP_TIME (100000 + (unsigned int)rand() % 100000)
293ec758831aa307d834aa6dc1bee36bc604e674Dwight Engen const char *name;
293ec758831aa307d834aa6dc1bee36bc604e674Dwight Engen int (*func)(struct mbox_lock_context *ctx, int lock_type,
beb6d93ee2b449ae2ea53125be2f198d15d8f8e8Dwight Engenstatic int mbox_lock_dotlock(struct mbox_lock_context *ctx, int lock_type,
beb6d93ee2b449ae2ea53125be2f198d15d8f8e8Dwight Engenstatic int mbox_lock_dotlock_try(struct mbox_lock_context *ctx, int lock_type,
103a2fc0729727d74470a366a1ea942d2cda2326Serge Hallynstatic int mbox_lock_fcntl(struct mbox_lock_context *ctx, int lock_type,
f209d63a97a8a2df5324608fee7b0d7a494d69ebS.Çağlar Onurstatic int mbox_lock_flock(struct mbox_lock_context *ctx, int lock_type,
beb6d93ee2b449ae2ea53125be2f198d15d8f8e8Dwight Engenstatic int mbox_lock_lockf(struct mbox_lock_context *ctx, int lock_type,
f209d63a97a8a2df5324608fee7b0d7a494d69ebS.Çağlar Onur { MBOX_LOCK_DOTLOCK, "dotlock", mbox_lock_dotlock },
beb6d93ee2b449ae2ea53125be2f198d15d8f8e8Dwight Engen { MBOX_LOCK_DOTLOCK_TRY, "dotlock_try", mbox_lock_dotlock_try },
d028235de9ec7664e1c2c904c541a447a768997aStéphane Graberstatic int mbox_lock_list(struct mbox_lock_context *ctx, int lock_type,
36eaa694151aff72a74987034d5f0eeb4261951cDwight Engenstatic int mbox_unlock_files(struct mbox_lock_context *ctx);
f209d63a97a8a2df5324608fee7b0d7a494d69ebS.Çağlar Onurstatic void mbox_read_lock_methods(const char *str, const char *env,
f209d63a97a8a2df5324608fee7b0d7a494d69ebS.Çağlar Onur const char *const *lock;
f209d63a97a8a2df5324608fee7b0d7a494d69ebS.Çağlar Onur for (lock = t_strsplit(str, " "), dest = 0; *lock != NULL; lock++) {
540f932aeb28274e8e7ea1e8f3a8e5889b88e1d6Stéphane Graber for (type = 0; lock_data[type].name != NULL; type++) {
f209d63a97a8a2df5324608fee7b0d7a494d69ebS.Çağlar Onur if (strcasecmp(*lock, lock_data[type].name) == 0) {
f209d63a97a8a2df5324608fee7b0d7a494d69ebS.Çağlar Onur for (i = 0; i < dest; i++) {
f209d63a97a8a2df5324608fee7b0d7a494d69ebS.Çağlar Onur i_fatal("%s: Duplicated value %s", env, *lock);
b130964dd7faf19abc7afde7eebe7905a0fe8661S.Çağlar Onur /* @UNSAFE */
f209d63a97a8a2df5324608fee7b0d7a494d69ebS.Çağlar Onurstatic void mbox_init_lock_settings(struct mbox_storage *storage)
f209d63a97a8a2df5324608fee7b0d7a494d69ebS.Çağlar Onur enum mbox_lock_type read_locks[MBOX_LOCK_COUNT+1];
f209d63a97a8a2df5324608fee7b0d7a494d69ebS.Çağlar Onur enum mbox_lock_type write_locks[MBOX_LOCK_COUNT+1];
f209d63a97a8a2df5324608fee7b0d7a494d69ebS.Çağlar Onur mbox_read_lock_methods(storage->set->mbox_read_locks,
f209d63a97a8a2df5324608fee7b0d7a494d69ebS.Çağlar Onur mbox_read_lock_methods(storage->set->mbox_write_locks,
f209d63a97a8a2df5324608fee7b0d7a494d69ebS.Çağlar Onur /* check that read/write list orders match. write_locks must contain
f209d63a97a8a2df5324608fee7b0d7a494d69ebS.Çağlar Onur at least read_locks and possibly more. */
beb6d93ee2b449ae2ea53125be2f198d15d8f8e8Dwight Engen for (r = w = 0; write_locks[w] != (enum mbox_lock_type)-1; w++) {
beb6d93ee2b449ae2ea53125be2f198d15d8f8e8Dwight Engen if (read_locks[r] != (enum mbox_lock_type)-1) {
f209d63a97a8a2df5324608fee7b0d7a494d69ebS.Çağlar Onur i_fatal("mbox read/write lock list settings are invalid. "
f209d63a97a8a2df5324608fee7b0d7a494d69ebS.Çağlar Onur "Lock ordering must be the same with both, "
beb6d93ee2b449ae2ea53125be2f198d15d8f8e8Dwight Engen "and write locks must contain all read locks "
f209d63a97a8a2df5324608fee7b0d7a494d69ebS.Çağlar Onur "(and possibly more)");
f209d63a97a8a2df5324608fee7b0d7a494d69ebS.Çağlar Onur storage->read_locks = p_new(storage->storage.pool,
f209d63a97a8a2df5324608fee7b0d7a494d69ebS.Çağlar Onur sizeof(*storage->read_locks) * (MBOX_LOCK_COUNT+1));
f209d63a97a8a2df5324608fee7b0d7a494d69ebS.Çağlar Onur storage->write_locks = p_new(storage->storage.pool,
beb6d93ee2b449ae2ea53125be2f198d15d8f8e8Dwight Engen sizeof(*storage->write_locks) * (MBOX_LOCK_COUNT+1));
beb6d93ee2b449ae2ea53125be2f198d15d8f8e8Dwight Engenstatic int mbox_file_open_latest(struct mbox_lock_context *ctx, int lock_type)
beb6d93ee2b449ae2ea53125be2f198d15d8f8e8Dwight Engen /* we could flush NFS file handle cache here if we wanted to
d028235de9ec7664e1c2c904c541a447a768997aStéphane Graber be sure that the file is latest, but mbox files get rarely
d028235de9ec7664e1c2c904c541a447a768997aStéphane Graber deleted and the flushing might cause errors (e.g. EBUSY for
d028235de9ec7664e1c2c904c541a447a768997aStéphane Graber trying to flush a /var/mail mountpoint) */
293ec758831aa307d834aa6dc1bee36bc604e674Dwight Engen if (nfs_safe_stat(mailbox_get_path(&mbox->box), &st) < 0) {
beb6d93ee2b449ae2ea53125be2f198d15d8f8e8Dwight Engenstatic bool dotlock_callback(unsigned int secs_left, bool stale, void *context)
beb6d93ee2b449ae2ea53125be2f198d15d8f8e8Dwight Engen /* get next index we wish to try locking. it's the one after
585ed6b1b64083e11f2196bc5913b096428dacc2Stéphane Graber dotlocking. */
beb6d93ee2b449ae2ea53125be2f198d15d8f8e8Dwight Engen for (i = 0; lock_types[i] != (enum mbox_lock_type)-1; i++) {
beb6d93ee2b449ae2ea53125be2f198d15d8f8e8Dwight Engen if (lock_types[i] != (enum mbox_lock_type)-1 &&
beb6d93ee2b449ae2ea53125be2f198d15d8f8e8Dwight Engen if (mbox_lock_list(ctx, ctx->lock_type, 0, i) <= 0) {
beb6d93ee2b449ae2ea53125be2f198d15d8f8e8Dwight Engen /* we couldn't get fd lock -
beb6d93ee2b449ae2ea53125be2f198d15d8f8e8Dwight Engen it's really locked */
beb6d93ee2b449ae2ea53125be2f198d15d8f8e8Dwight Engen index_storage_lock_notify(&ctx->mbox->box, stale ?
beb6d93ee2b449ae2ea53125be2f198d15d8f8e8Dwight Engen /* shouldn't get here */
f209d63a97a8a2df5324608fee7b0d7a494d69ebS.Çağlar Onurstatic int mbox_dotlock_privileged_op(struct mbox_mailbox *mbox,
fname++;
if (restrict_access_use_priv_gid() < 0) {
switch (op) {
case MBOX_DOTLOCK_OP_LOCK:
if (ret > 0)
const char *errmsg =
fname);
case MBOX_DOTLOCK_OP_UNLOCK:
if (ret < 0)
case MBOX_DOTLOCK_OP_TOUCH:
if (ret < 0)
return ret;
int ret;
if (ret >= 0) {
if (ret < 0) {
if (ret == 0) {
#ifdef HAVE_FLOCK
unsigned int next_alarm;
if (max_wait_time == 0) {
alarm(0);
alarm(0);
if (next_alarm == 0)
alarm(0);
#ifdef HAVE_LOCKF
unsigned int next_alarm;
else if (max_wait_time == 0) {
max_wait_time == 0) {
alarm(0);
alarm(0);
if (next_alarm == 0)
alarm(0);
unsigned int next_alarm;
int wait_type;
if (max_wait_time == 0) {
alarm(0);
alarm(0);
if (next_alarm == 0)
alarm(0);
if (ret <= 0)
return ret;
bool *fcntl_locked_r)
int ret, i;
bool drop_locks;
for (i = 0; i < MBOX_LOCK_COUNT; i++)
if (ret <= 0) {
if (!drop_locks)
if (ret == 0) {
return ret;
if (drop_locks) {
unsigned int *lock_id_r)
bool fcntl_locked;
int ret;
if (ret <= 0)
return ret;
if (fcntl_locked) {
int ret = 0;
return ret;
bool fcntl_locked;
&fcntl_locked) < 0)
for (i = 0; i < MBOX_LOCK_COUNT; i++)