]> 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>
Fri, 14 Jul 2017 07:49:46 +0000 (10:49 +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 4fa15af9848ef06f25f48a1c7ed16b57185f26d8..37f7a19bff0fc6b621d1f6c5813e51e62ef785c4 100644 (file)
@@ -205,6 +205,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) {
@@ -220,6 +223,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) {