[Dovecot] windows live mail + dovecot and nfs
Hi all. My clients have got problem accessing dovecot by "Windows live mail (Windows 7)" client. The problem is that users can't delete two or more folders one-by-one.
There is no errors deleting first folder (new dir /storage/vol1/mail/domain/user/Maildir/..DOVECOT-TRASHED appeared and wasn't deleted). If I try to delete second one, error occurs (user, domain, IP address changed):
dovecot: IMAP(user@domain): unlink_directory(/storage/vol1/mail/domain/user/Maildir/..DOVECOT-TRASHED) failed: Directory not empty
I'm using dovecot 1.2.10 @FreeBSD 7.2-RELEASE-p1 amd64 and NFS storage backend.
dovecot -n # 1.2.10: /usr/local/etc/dovecot.conf # OS: FreeBSD 7.2-RELEASE-p1 amd64 syslog_facility: local7 protocols: imap imaps pop3 pop3s ssl_cert_file: /etc/ssl/1.crt ssl_key_file: /etc/ssl/1.key.unsec disable_plaintext_auth: no verbose_ssl: yes shutdown_clients: no login_dir: /var/run/dovecot/login login_executable(default): /usr/local/libexec/dovecot/imap-login login_executable(imap): /usr/local/libexec/dovecot/imap-login login_executable(pop3): /usr/local/libexec/dovecot/pop3-login login_greeting: mail server ready. login_process_per_connection: no login_process_size: 512 login_processes_count: 60 login_max_processes_count: 256 login_max_connections: 100 max_mail_processes: 4096 mail_max_userip_connections(default): 50 mail_max_userip_connections(imap): 50 mail_max_userip_connections(pop3): 30 verbose_proctitle: yes first_valid_uid: 90 last_valid_uid: 90 first_valid_gid: 90 last_valid_gid: 90 mail_privileged_group: mail mail_location: maildir:%h/Maildir mmap_disable: yes mail_nfs_storage: yes mail_nfs_index: yes lock_method: dotlock maildir_copy_preserve_filename: yes mail_executable(default): /usr/local/libexec/dovecot/imap mail_executable(imap): /usr/local/libexec/dovecot/imap mail_executable(pop3): /usr/local/libexec/dovecot/pop3 mail_process_size: 128 mail_plugins(default): quota imap_quota mail_plugins(imap): quota imap_quota mail_plugins(pop3): quota mail_plugin_dir(default): /usr/local/lib/dovecot/imap mail_plugin_dir(imap): /usr/local/lib/dovecot/imap mail_plugin_dir(pop3): /usr/local/lib/dovecot/pop3 imap_client_workarounds(default): delay-newmail outlook-idle netscape-eoh tb-extra-mailbox-sep imap_client_workarounds(imap): delay-newmail outlook-idle netscape-eoh tb-extra-mailbox-sep imap_client_workarounds(pop3): pop3_client_workarounds(default): pop3_client_workarounds(imap): pop3_client_workarounds(pop3): outlook-no-nuls oe-ns-eoh lda: postmaster_address: postmaster@domain.ru mail_plugins: quota sendmail_path: /usr/sbin/sendmail log_path: /var/log/dovecot/deliver.log info_log_path: /var/log/dovecot/deliver.log auth default: mechanisms: plain login cram-md5 cache_size: 262144 cache_ttl: 180 cache_negative_ttl: 60 failure_delay: 1 worker_max_count: 2000 process_size: 512 passdb: driver: sql args: /usr/local/etc/dovecot-sql.conf userdb: driver: prefetch userdb: driver: sql args: /usr/local/etc/dovecot-sql.conf socket: type: listen master: path: /var/run/dovecot/auth-master mode: 384 user: user group: domain plugin: quota: maildir:Quota
Here is listing of ..DOVECOT-TRASHED:
ls -la /storage/vol1/mail/domain/user/Maildir/..DOVECOT-TRASHED: total 16 drwx------ 2 user user 4096 Apr 9 11:32 . drwx------ 27 user user 8192 Apr 9 11:41 .. -rw------- 1 user user 156 Apr 9 11:32 .nfs.014cd02e.ffffd11b4.4 -rw------- 1 user user 17 Apr 9 11:32 .nfs.014cd031.ffffd11b4.4
fstat output:
[root@ /storage/vol1/mail/domain/user/Maildir/..DOVECOT-TRASHED]# fstat .*
USER CMD PID FD MOUNT INUM MODE SZ|DV R/W NAME
root fstat 82081 wd /storage/vol1 32454159 drwx------
4096 r .
user imap 53042 7 /storage/vol1 40573622 -rw------- 156 rw
.nfs.014cd02e.ffffd11b4.4
user imap 53042 9 /storage/vol1 40573631 -rw------- 17
rw .nfs.014cd031.ffffd11b4.4
root bash 22223 wd /storage/vol1 32454159 drwx------
4096 r .
# ps uxwa|grep user
user 53042 0.0 0.1 9812 2400 ?? S 11:31AM 0:00.02 imap [user@domain 1.1.1.1] user 53650 0.0 0.1 10836 2908 ?? S 11:32AM 0:00.05 imap [user@domain 1.1.1.1]
It seems like first imap process locked ..DOVECOT-TRASHED.
Best regards Anes Muhametoc.
On Fri, 2010-04-09 at 12:11 +0400, Anes Muhametov wrote:
dovecot: IMAP(user@domain): unlink_directory(/storage/vol1/mail/domain/user/Maildir/..DOVECOT-TRASHED) failed: Directory not empty
Yeah, unfortunately this happens with NFS. Hmm. I fixed this now in v2.0: http://hg.dovecot.org/dovecot-2.0/rev/c2f00a85a177
A similar fix could probably be written for v1.2 (maildir-storage.c: maildir_list_delete_mailbox()) but I'm trying to avoid adding any non-critical changes to v1.2.
Thanks, Timo! I've made similar fix for 1.2.11. Seems like it works correctly. Check it for errors if you can, please:) Timo Sirainen wrote:
On Fri, 2010-04-09 at 12:11 +0400, Anes Muhametov wrote:
dovecot: IMAP(user@domain): unlink_directory(/storage/vol1/mail/domain/user/Maildir/..DOVECOT-TRASHED) failed: Directory not empty
Yeah, unfortunately this happens with NFS. Hmm. I fixed this now in v2.0: http://hg.dovecot.org/dovecot-2.0/rev/c2f00a85a177
A similar fix could probably be written for v1.2 (maildir-storage.c: maildir_list_delete_mailbox()) but I'm trying to avoid adding any non-critical changes to v1.2.
--- src/lib-storage/index/maildir/maildir-storage.c.orig 2010-04-17 13:17:10.000000000 +0400 +++ src/lib-storage/index/maildir/maildir-storage.c 2010-04-17 13:17:19.000000000 +0400 @@ -5,6 +5,9 @@ #include "array.h" #include "hostpid.h" #include "str.h" +#include "hex-binary.h" +#include "hostpid.h" +#include "randgen.h" #include "mkdir-parents.h" #include "eacces-error.h" #include "unlink-directory.h" @@ -59,6 +62,16 @@ enum mailbox_list_file_type type, enum mailbox_info_flags *flags_r); +static const char *unique_fname(void) +{ + unsigned char randbuf[8]; + + random_fill_weak(randbuf, sizeof(randbuf)); + return t_strdup_printf("%s.%s.%s", my_hostname, my_pid, + binary_to_hex(randbuf, sizeof(randbuf))); + +} + static int maildir_get_list_settings(struct mailbox_list_settings *list_set, const char *data, struct mail_storage *storage, @@ -770,7 +783,7 @@ { struct maildir_storage *storage = MAILDIR_LIST_CONTEXT(list); struct stat st; - const char *src, *dest, *base; + const char *src, *dest, *base, *trash_dest; int count; /* Make sure the indexes are closed before trying to delete the @@ -825,29 +838,48 @@ marks it as being deleted. If we die before deleting the ..DOVECOT-TRASH directory, it gets deleted the next time mailbox listing sees it. */ - count = 0; - while (rename(src, dest) < 0) { + count = 0; trash_dest = dest; + for (; rename(src, trash_dest) < 0; count++) { if (errno == ENOENT) { /* it was just deleted under us by another process */ + if (trash_dest != dest && count < 5) { + /* either the source was just deleted or + the trash dir was deleted. */ + trash_dest = dest; + continue; + } mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND, T_MAIL_ERR_MAILBOX_NOT_FOUND(name)); return -1; } if (!EDESTDIREXISTS(errno)) { mailbox_list_set_critical(list, - "rename(%s, %s) failed: %m", src, dest); + "rename(%s, %s) failed: %m", src, trash_dest); return -1; } /* already existed, delete it and try again */ - if (unlink_directory(dest, TRUE) < 0 && - (errno != ENOTEMPTY || count >= 5)) { + /* trash dir already exists. the reasons for this are: + + a) another process is in the middle of deleting it + b) previous process crashed and didn't delete it + c) NFS: mailbox was recently deleted, but some connection + still has that mailbox open. the directory contains .nfs* + files that can't be deleted until the mailbox is closed. + + Because of c) we'll first try to rename the mailbox under + the trash directory and only later try to delete the entire + trash directory. */ + if (dest == trash_dest) { + trash_dest = t_strconcat(dest, "/", + unique_fname(), NULL); + } else if (unlink_directory(trash_dest, TRUE) < 0 && + (errno != ENOTEMPTY || count >= 5)) { mailbox_list_set_critical(list, - "unlink_directory(%s) failed: %m", dest); + "unlink_directory(%s) failed: %m", trash_dest); return -1; } - count++; } if (unlink_directory(dest, TRUE) < 0 && errno != ENOTEMPTY) {
participants (2)
-
Anes Muhametov
-
Timo Sirainen