# HG changeset patch # User Timo Sirainen # Date 1195077153 -7200 # Node ID a59deefc552fc0e7c68d262e7ea310156bc94169 # Parent 587a9d3054c11b6f0aac295757733c0982141611 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. 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ } 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 @@ 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 @@ 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 @@ *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 @@ /* 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ /* 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 @@ 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 @@ 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 @@ } #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) +bool nfs_flush_attr_cache_fd(const char *path, int fd) { - nfs_flush_fchown_uid(path, fd); + return nfs_flush_fchown_uid(path, fd); } void nfs_flush_read_cache(const char *path, int fd, diff -r 587a9d3054c1 -r a59deefc552f src/lib/nfs-workarounds.h --- a/src/lib/nfs-workarounds.h Wed Nov 14 23:43:42 2007 +0200 +++ b/src/lib/nfs-workarounds.h Wed Nov 14 23:52:33 2007 +0200 @@ -15,11 +15,12 @@ int nfs_safe_stat(const char *path, struct stat *buf); int nfs_safe_lstat(const char *path, struct stat *buf); -/* Flush attribute cache for given path */ -void nfs_flush_attr_cache(const char *path); +/* Flush attribute cache for given path. If flush_dir is TRUE, also the + directory's cache is flushed. */ +void nfs_flush_attr_cache(const char *path, bool flush_dir); /* Flush attribute cache for given file descriptor. The given path is used only for logging. */ -void nfs_flush_attr_cache_fd(const char *path, int fd); +bool nfs_flush_attr_cache_fd(const char *path, int fd); /* Flush read cache for given fd. lock_type must be set to the file's current fcntl locking state (F_UNLCK, F_RDLCK, F_WRLCK). Set just_locked=TRUE if the file was locked at the same time as read cache flush was wanted (to avoid