dovecot: NFS attribute cache flushing fixes. nfs_flush_attr_cach...

dovecot at dovecot.org dovecot at dovecot.org
Wed Nov 14 23:52:40 EET 2007


details:   http://hg.dovecot.org/dovecot/rev/a59deefc552f
changeset: 6797:a59deefc552f
user:      Timo Sirainen <tss at iki.fi>
date:      Wed Nov 14 23:52:33 2007 +0200
description:
NFS attribute cache flushing fixes. nfs_flush_attr_cache() takes now
flush_dir parameter and nfs_flush_attr_cache_fd() returns FALSE if file
handle is already stale.

diffstat:

11 files changed, 83 insertions(+), 36 deletions(-)
src/lib-index/mail-hash.c                        |    2 -
src/lib-index/mail-index.c                       |   28 ++++++++++-----
src/lib-index/mail-transaction-log-file.c        |    2 -
src/lib-index/mail-transaction-log.c             |    9 +++--
src/lib-index/mailbox-list-index.c               |    2 -
src/lib-storage/index/maildir/maildir-keywords.c |    2 -
src/lib-storage/index/maildir/maildir-uidlist.c  |   22 ++++++++++--
src/lib-storage/index/mbox/mbox-lock.c           |    2 -
src/lib/file-dotlock.c                           |    4 +-
src/lib/nfs-workarounds.c                        |   39 +++++++++++++++-------
src/lib/nfs-workarounds.h                        |    7 ++-

diffs (truncated from 319 to 300 lines):

diff -r 587a9d3054c1 -r a59deefc552f src/lib-index/mail-hash.c
--- a/src/lib-index/mail-hash.c	Wed Nov 14 23:43:42 2007 +0200
+++ b/src/lib-index/mail-hash.c	Wed Nov 14 23:52:33 2007 +0200
@@ -653,7 +653,7 @@ static int mail_hash_reopen_if_needed(st
 		return mail_hash_reopen(hash);
 
 	if (hash->index->nfs_flush)
-		nfs_flush_attr_cache(hash->filepath);
+		nfs_flush_attr_cache(hash->filepath, TRUE);
 
 	if (nfs_safe_stat(hash->filepath, &st) < 0) {
 		if (errno == ENOENT)
diff -r 587a9d3054c1 -r a59deefc552f src/lib-index/mail-index.c
--- a/src/lib-index/mail-index.c	Wed Nov 14 23:43:42 2007 +0200
+++ b/src/lib-index/mail-index.c	Wed Nov 14 23:52:33 2007 +0200
@@ -248,6 +248,9 @@ int mail_index_try_open_only(struct mail
 	i_assert(index->fd == -1);
 	i_assert(!MAIL_INDEX_IS_IN_MEMORY(index));
 
+	if (index->nfs_flush)
+		nfs_flush_attr_cache(index->filepath, TRUE);
+
         /* Note that our caller must close index->fd by itself. */
 	if (index->readonly)
 		errno = EACCES;
@@ -470,6 +473,22 @@ int mail_index_reopen_if_changed(struct 
 	if (index->fd == -1)
 		return mail_index_try_open_only(index);
 
+	if (index->nfs_flush)
+		nfs_flush_attr_cache(index->filepath, TRUE);
+	if (nfs_safe_stat(index->filepath, &st2) < 0) {
+		if (errno == ENOENT)
+			return 0;
+
+		return mail_index_set_syscall_error(index, "stat()");
+	}
+
+	if (index->nfs_flush) {
+		if (!nfs_flush_attr_cache_fd(index->filepath, index->fd)) {
+			/* deleted/recreated, reopen */
+			mail_index_close_file(index);
+			return mail_index_try_open_only(index);
+		}
+	}
 	if (fstat(index->fd, &st1) < 0) {
 		if (errno != ESTALE)
 			return mail_index_set_syscall_error(index, "fstat()");
@@ -478,15 +497,6 @@ int mail_index_reopen_if_changed(struct 
 		return mail_index_try_open_only(index);
 	}
 
-	if (index->nfs_flush)
-		nfs_flush_attr_cache(index->filepath);
-	if (nfs_safe_stat(index->filepath, &st2) < 0) {
-		if (errno == ENOENT)
-			return 0;
-
-		return mail_index_set_syscall_error(index, "stat()");
-	}
-
 	if (st1.st_ino == st2.st_ino && CMP_DEV_T(st1.st_dev, st2.st_dev)) {
 		/* the same file */
 		return 1;
diff -r 587a9d3054c1 -r a59deefc552f src/lib-index/mail-transaction-log-file.c
--- a/src/lib-index/mail-transaction-log-file.c	Wed Nov 14 23:43:42 2007 +0200
+++ b/src/lib-index/mail-transaction-log-file.c	Wed Nov 14 23:52:33 2007 +0200
@@ -435,7 +435,7 @@ mail_transaction_log_file_create2(struct
 	bool rename_existing;
 
 	if (index->nfs_flush)
-		nfs_flush_attr_cache(file->filepath);
+		nfs_flush_attr_cache(file->filepath, TRUE);
 
 	/* log creation is locked now - see if someone already created it.
 	   note that if we're rotating, we need to keep the log locked until
diff -r 587a9d3054c1 -r a59deefc552f src/lib-index/mail-transaction-log.c
--- a/src/lib-index/mail-transaction-log.c	Wed Nov 14 23:43:42 2007 +0200
+++ b/src/lib-index/mail-transaction-log.c	Wed Nov 14 23:52:33 2007 +0200
@@ -279,7 +279,7 @@ static int mail_transaction_log_refresh(
 	path = t_strconcat(log->index->filepath,
 			   MAIL_TRANSACTION_LOG_SUFFIX, NULL);
 	if (log->index->nfs_flush)
-		nfs_flush_attr_cache(path);
+		nfs_flush_attr_cache(path, TRUE);
 	if (nfs_safe_stat(path, &st) < 0) {
 		if (errno != ENOENT) {
 			mail_index_file_set_syscall_error(log->index, path,
@@ -299,8 +299,11 @@ static int mail_transaction_log_refresh(
 	} else {
 		if (log->head->st_ino == st.st_ino &&
 		    CMP_DEV_T(log->head->st_dev, st.st_dev)) {
-			/* same file */
-			return 0;
+			/* same file? */
+			if (nfs_flush_attr_cache_fd(log->head->filepath,
+						    log->head->fd))
+				return 0;
+			/* nope */
 		}
 	}
 
diff -r 587a9d3054c1 -r a59deefc552f src/lib-index/mailbox-list-index.c
--- a/src/lib-index/mailbox-list-index.c	Wed Nov 14 23:43:42 2007 +0200
+++ b/src/lib-index/mailbox-list-index.c	Wed Nov 14 23:52:33 2007 +0200
@@ -229,7 +229,7 @@ static int mailbox_list_index_is_recreat
 		return 1;
 
 	if (index->mail_index->nfs_flush)
-		nfs_flush_attr_cache(index->filepath);
+		nfs_flush_attr_cache(index->filepath, TRUE);
 
 	if (nfs_safe_stat(index->filepath, &st1) < 0) {
 		if (errno == ENOENT)
diff -r 587a9d3054c1 -r a59deefc552f src/lib-storage/index/maildir/maildir-keywords.c
--- a/src/lib-storage/index/maildir/maildir-keywords.c	Wed Nov 14 23:43:42 2007 +0200
+++ b/src/lib-storage/index/maildir/maildir-keywords.c	Wed Nov 14 23:52:33 2007 +0200
@@ -118,7 +118,7 @@ static int maildir_keywords_sync(struct 
            errors. */
 
 	if ((mk->storage->flags & MAIL_STORAGE_FLAG_NFS_FLUSH_STORAGE) != 0)
-		nfs_flush_attr_cache(mk->path);
+		nfs_flush_attr_cache(mk->path, TRUE);
 
 	if (nfs_safe_stat(mk->path, &st) < 0) {
 		if (errno == ENOENT) {
diff -r 587a9d3054c1 -r a59deefc552f src/lib-storage/index/maildir/maildir-uidlist.c
--- a/src/lib-storage/index/maildir/maildir-uidlist.c	Wed Nov 14 23:43:42 2007 +0200
+++ b/src/lib-storage/index/maildir/maildir-uidlist.c	Wed Nov 14 23:52:33 2007 +0200
@@ -631,7 +631,7 @@ maildir_uidlist_has_changed(struct maild
 	*recreated_r = FALSE;
 
 	if ((storage->flags & MAIL_STORAGE_FLAG_NFS_FLUSH_STORAGE) != 0)
-		nfs_flush_attr_cache(uidlist->path);
+		nfs_flush_attr_cache(uidlist->path, TRUE);
 
 	if (nfs_safe_stat(uidlist->path, &st) < 0) {
 		if (errno != ENOENT) {
@@ -647,7 +647,17 @@ maildir_uidlist_has_changed(struct maild
 		/* file recreated */
 		*recreated_r = TRUE;
 		return 1;
-	} else if (st.st_size != uidlist->fd_size) {
+	}
+
+	/* either the file hasn't been changed, or it has already been deleted
+	   and the inodes just happen to be the same. check if the fd is still
+	   valid. */
+	if (!nfs_flush_attr_cache_fd(uidlist->path, uidlist->fd)) {
+		*recreated_r = TRUE;
+		return 1;
+	}
+
+	if (st.st_size != uidlist->fd_size) {
 		/* file modified but not recreated */
 		return 1;
 	} else {
@@ -658,6 +668,7 @@ maildir_uidlist_has_changed(struct maild
 
 int maildir_uidlist_refresh(struct maildir_uidlist *uidlist)
 {
+	struct mail_storage *storage = uidlist->ibox->box.storage;
         unsigned int i;
         bool retry, recreated;
         int ret;
@@ -669,6 +680,9 @@ int maildir_uidlist_refresh(struct maild
 
 		if (recreated)
 			maildir_uidlist_close(uidlist);
+	} else {
+		if ((storage->flags & MAIL_STORAGE_FLAG_NFS_FLUSH_STORAGE) != 0)
+			nfs_flush_attr_cache(uidlist->path, TRUE);
 	}
 
         for (i = 0; ; i++) {
@@ -676,7 +690,9 @@ int maildir_uidlist_refresh(struct maild
 						i < UIDLIST_ESTALE_RETRY_COUNT);
 		if (!retry)
 			break;
-                /* ESTALE - try reopening and rereading */
+		/* ESTALE - try reopening and rereading */
+		maildir_uidlist_close(uidlist);
+		nfs_flush_attr_cache(uidlist->path, TRUE);
         }
 	if (ret >= 0)
 		uidlist->initial_read = TRUE;
diff -r 587a9d3054c1 -r a59deefc552f src/lib-storage/index/mbox/mbox-lock.c
--- a/src/lib-storage/index/mbox/mbox-lock.c	Wed Nov 14 23:43:42 2007 +0200
+++ b/src/lib-storage/index/mbox/mbox-lock.c	Wed Nov 14 23:52:33 2007 +0200
@@ -173,7 +173,7 @@ static int mbox_file_open_latest(struct 
 	if (mbox->mbox_fd != -1) {
 		if ((mbox->storage->storage.flags &
 		     MAIL_STORAGE_FLAG_NFS_FLUSH_STORAGE) != 0)
-			nfs_flush_attr_cache(mbox->path);
+			nfs_flush_attr_cache(mbox->path, TRUE);
 		if (nfs_safe_stat(mbox->path, &st) < 0) {
 			mbox_set_syscall_error(mbox, "stat()");
 			return -1;
diff -r 587a9d3054c1 -r a59deefc552f src/lib/file-dotlock.c
--- a/src/lib/file-dotlock.c	Wed Nov 14 23:43:42 2007 +0200
+++ b/src/lib/file-dotlock.c	Wed Nov 14 23:52:33 2007 +0200
@@ -156,7 +156,7 @@ static int update_lock_info(time_t now, 
 	struct stat st;
 
 	if (lock_info->set->nfs_flush)
-		nfs_flush_attr_cache(lock_info->lock_path);
+		nfs_flush_attr_cache(lock_info->lock_path, TRUE);
 	if (nfs_safe_lstat(lock_info->lock_path, &st) < 0) {
 		if (errno != ENOENT) {
 			i_error("lstat(%s) failed: %m", lock_info->lock_path);
@@ -244,7 +244,7 @@ static int check_lock(time_t now, struct
 		/* possibly stale lock file. check also the timestamp of the
 		   file we're protecting. */
 		if (lock_info->set->nfs_flush)
-			nfs_flush_attr_cache(lock_info->path);
+			nfs_flush_attr_cache(lock_info->path, TRUE);
 		if (nfs_safe_stat(lock_info->path, &st) < 0) {
 			if (errno == ENOENT) {
 				/* file doesn't exist. treat it as if
diff -r 587a9d3054c1 -r a59deefc552f src/lib/nfs-workarounds.c
--- a/src/lib/nfs-workarounds.c	Wed Nov 14 23:43:42 2007 +0200
+++ b/src/lib/nfs-workarounds.c	Wed Nov 14 23:52:33 2007 +0200
@@ -62,7 +62,8 @@ nfs_safe_do(const char *path, int (*call
                         if (dir == NULL)
                                 break;
                         dir = t_strdup_until(path, dir);
-                }
+		}
+		nfs_flush_attr_cache(dir, FALSE);
                 if (stat(dir, &st) < 0) {
                         /* maybe it's gone or something else bad happened to
                            it. in any case we can't open the file, so fail
@@ -128,26 +129,30 @@ int nfs_safe_lstat(const char *path, str
 	return nfs_safe_do(path, nfs_safe_lstat_callback, buf);
 }
 
-static void nfs_flush_fchown_uid(const char *path, int fd)
+static bool nfs_flush_fchown_uid(const char *path, int fd)
 {
 	struct stat st;
 
 	if (fstat(fd, &st) < 0) {
 		if (errno == ESTALE) {
 			/* ESTALE causes the OS to flush the attr cache */
-			return;
+			return FALSE;
 		}
 		i_error("nfs_flush_fchown_uid: fstat(%s) failed: %m", path);
-		return;
+		return TRUE;
 	}
 	if (fchown(fd, st.st_uid, (gid_t)-1) < 0) {
-		if (errno == ESTALE || errno == EACCES || errno == EPERM) {
+		if (errno == ESTALE) {
+			return FALSE;
+		}
+		if (errno == EACCES || errno == EPERM) {
 			/* attr cache is flushed */
-			return;
+			return TRUE;
 		}
 
 		i_error("nfs_flush_fchown_uid: fchown(%s) failed: %m", path);
 	}
+	return TRUE;
 }
 
 static void nfs_flush_chown_uid(const char *path)
@@ -212,14 +217,26 @@ static void nfs_flush_fcntl(const char *
 }
 #endif
 
-void nfs_flush_attr_cache(const char *path)
-{
+void nfs_flush_attr_cache(const char *path, bool flush_dir)
+{
+	const char *p;
+
+	if (flush_dir) {
+		p = strrchr(path, '/');
+		if (p == NULL)
+			nfs_flush_chown_uid(".");
+		else {
+			t_push();
+			nfs_flush_chown_uid(t_strdup_until(path, p));
+			t_pop();
+		}
+	}
 	nfs_flush_chown_uid(path);
 }
 
-void nfs_flush_attr_cache_fd(const char *path, int fd)
-{
-	nfs_flush_fchown_uid(path, fd);
+bool nfs_flush_attr_cache_fd(const char *path, int fd)
+{
+	return nfs_flush_fchown_uid(path, fd);
 }
 
 void nfs_flush_read_cache(const char *path, int fd,


More information about the dovecot-cvs mailing list