nfs-workarounds.c revision 023ed67920a771de3b34b242c13a422eec6a2e01
bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2006-2008 Dovecot authors, see the included COPYING file */
f877ee033a0737100c2f661a7ca4c559ea2ddb8aTimo Sirainen These tests were done with various Linux 2.6 kernels, FreeBSD 6.2 and
f877ee033a0737100c2f661a7ca4c559ea2ddb8aTimo Sirainen Solaris 8 and 10.
f877ee033a0737100c2f661a7ca4c559ea2ddb8aTimo Sirainen Attribute cache is usually flushed with chown()ing or fchown()ing the file.
f877ee033a0737100c2f661a7ca4c559ea2ddb8aTimo Sirainen The safest way would be to use uid=-1 gid=-1, but this doesn't work with
f877ee033a0737100c2f661a7ca4c559ea2ddb8aTimo Sirainen Linux (it does with FreeBSD 6.2 and Solaris). So we'll first get the
f877ee033a0737100c2f661a7ca4c559ea2ddb8aTimo Sirainen file's owner and use it. As long as we're not root the file's owner can't
f877ee033a0737100c2f661a7ca4c559ea2ddb8aTimo Sirainen change accidentally. If would be possible to also use chmod()/fchmod(), but
f877ee033a0737100c2f661a7ca4c559ea2ddb8aTimo Sirainen that's riskier since it could actually cause an unwanted change.
f877ee033a0737100c2f661a7ca4c559ea2ddb8aTimo Sirainen Write cache can be flushed with fdatasync(). It's all we need, but other
f877ee033a0737100c2f661a7ca4c559ea2ddb8aTimo Sirainen tested alternatives are: fcntl locking (Linux 2.6, Solaris),
f877ee033a0737100c2f661a7ca4c559ea2ddb8aTimo Sirainen fchown() (Solaris) and dup()+close() (Linux 2.6, Solaris).
f877ee033a0737100c2f661a7ca4c559ea2ddb8aTimo Sirainen Read cache flushing is more problematic. There's no universal way to do it.
f877ee033a0737100c2f661a7ca4c559ea2ddb8aTimo Sirainen The working methods are:
f877ee033a0737100c2f661a7ca4c559ea2ddb8aTimo Sirainen Linux 2.6: fcntl(), O_DIRECT
f877ee033a0737100c2f661a7ca4c559ea2ddb8aTimo Sirainen Solaris: fchown(), fcntl(), dup()+close()
f877ee033a0737100c2f661a7ca4c559ea2ddb8aTimo Sirainen FreeBSD 6.2: fchown()
f877ee033a0737100c2f661a7ca4c559ea2ddb8aTimo Sirainen fchown() can be easily used for Solaris and FreeBSD, but Linux requires
f877ee033a0737100c2f661a7ca4c559ea2ddb8aTimo Sirainen playing with locks. O_DIRECT requires CONFIG_NFS_DIRECTIO to be enabled, so
f877ee033a0737100c2f661a7ca4c559ea2ddb8aTimo Sirainen we can't always use it.
f877ee033a0737100c2f661a7ca4c559ea2ddb8aTimo Sirainenstatic void nfs_flush_file_handle_cache_parent_dir(const char *path);
f877ee033a0737100c2f661a7ca4c559ea2ddb8aTimo Sirainennfs_safe_do(const char *path, int (*callback)(const char *path, void *context),
f877ee033a0737100c2f661a7ca4c559ea2ddb8aTimo Sirainen unsigned int i;
f877ee033a0737100c2f661a7ca4c559ea2ddb8aTimo Sirainen for (i = 1;; i++) {
f877ee033a0737100c2f661a7ca4c559ea2ddb8aTimo Sirainen if (ret == 0 || errno != ESTALE || i == NFS_ESTALE_RETRY_COUNT)
f877ee033a0737100c2f661a7ca4c559ea2ddb8aTimo Sirainen /* ESTALE: Some operating systems may fail with this if they
f877ee033a0737100c2f661a7ca4c559ea2ddb8aTimo Sirainen can't internally revalidate the NFS file handle. Flush the
f877ee033a0737100c2f661a7ca4c559ea2ddb8aTimo Sirainen file handle and try again */
f877ee033a0737100c2f661a7ca4c559ea2ddb8aTimo Sirainenstatic int nfs_safe_open_callback(const char *path, void *context)
3efdcb59492bd1e0602340a4204003a32b34654aTimo Sirainen if (nfs_safe_do(path, nfs_safe_open_callback, &ctx) < 0)
if (!links1) {
#ifndef __FreeBSD__
#ifdef ATTRCACHE_FLUSH_CHOWN_UID_1
#ifdef __FreeBSD__
#ifndef ATTRCACHE_FLUSH_CHOWN_UID_1
return FALSE;
path);
return TRUE;
return FALSE;
return TRUE;
path);
return TRUE;
#ifdef READ_CACHE_FLUSH_FCNTL
int ret;
alarm(0);
int fd;
#ifdef __FreeBSD__
return TRUE;
#ifdef __linux__
return FALSE;
return TRUE;
if (p == NULL)
else T_FRAME(
#ifdef READ_CACHE_FLUSH_FCNTL
/* we can only hope that underlying filesystem uses micro/nanosecond
#ifdef READ_CACHE_FLUSH_FCNTL