]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-storage: When index dir rmdir() fails with ENOTEMPTY, retry it for 1 second
authorTimo Sirainen <timo.sirainen@dovecot.fi>
Thu, 13 Jul 2017 23:11:56 +0000 (02:11 +0300)
committerTimo Sirainen <timo.sirainen@dovecot.fi>
Thu, 13 Jul 2017 23:11:56 +0000 (02:11 +0300)
This helps to avoid leaving those index directories lying around with NFS.
Hopefully within the 1 second any existing processes that have been keeping those
files open have finished their task. Especially IMAP IDLE will take 0.5 seconds
to start syncing indexes and realize that they're deleted.

src/lib-storage/list/mailbox-list-delete.c

index 49ef84bb49361486f278f4032d63e4a33fea02cf..637ecc38dc8bcdf697d88c5f2cefba288a5c34b7 100644 (file)
@@ -206,6 +206,9 @@ int mailbox_list_delete_mailbox_nonrecursive(struct mailbox_list *list,
                        mailbox_list_set_critical(list,
                                "unlink(%s) failed: %m", str_c(full_path));
                        ret = -1;
+               } else {
+                       /* child directories still exist */
+                       rmdir_path = FALSE;
                }
        }
        if (errno != 0) {
@@ -221,6 +224,17 @@ int mailbox_list_delete_mailbox_nonrecursive(struct mailbox_list *list,
                return -1;
 
        if (rmdir_path) {
+               unsigned int try_count = 0;
+               int ret = rmdir(path);
+               while (ret < 0 && errno == ENOTEMPTY && try_count++ < 10) {
+                       /* We didn't see any child directories, so this is
+                          either a race condition or .nfs* files were left
+                          lying around. In case it's .nfs* files, retry after
+                          waiting a bit. Hopefully all processes keeping those
+                          files open will have closed them by then. */
+                       usleep(100000);
+                       ret = rmdir(path);
+               }
                if (rmdir(path) == 0)
                        unlinked_something = TRUE;
                else if (errno == ENOENT) {