annotate src/lib/nfs-workarounds.c @ 5970:a290b84d144a HEAD

Added nfs_flush_attr_cache() and nfs_flush_read_cache().
author Timo Sirainen <tss@iki.fi>
date Thu, 12 Jul 2007 23:54:13 +0300
parents 885ed4d5c51d
children 6a64e64fa3a3
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
5970
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
1 /* Copyright (c) 2006-2007 Timo Sirainen */
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
2
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
3 /*
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
4 These tests were done with various Linux 2.6 kernels, FreeBSD 6.2 and
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
5 Solaris 8 and 10.
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
6
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
7 Attribute cache is usually flushed with chown()ing or fchown()ing the file.
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
8 The safest way would be to use uid=-1 gid=-1, but this doesn't work with
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
9 Linux (it does with FreeBSD 6.2 and Solaris). So we'll first get the
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
10 file's owner and use it. As long as we're not root the file's owner can't
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
11 change accidentally. If would be possible to also use chmod()/fchmod(), but
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
12 that's riskier since it could actually cause an unwanted change.
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
13
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
14 Write cache can be flushed with fdatasync(). It's all we need, but other
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
15 tested alternatives are: fcntl locking (Linux 2.6, Solaris),
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
16 fchown() (Solaris) and dup()+close() (Linux 2.6, Solaris).
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
17
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
18 Read cache flushing is more problematic. There's no universal way to do it.
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
19 The working methods are:
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
20
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
21 Linux 2.6: fcntl(), O_DIRECT
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
22 Solaris: fchown(), fcntl(), dup()+close()
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
23 FreeBSD 6.2: fchown()
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
24
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
25 fchown() can be easily used for Solaris and FreeBSD, but Linux requires
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
26 playing with locks. O_DIRECT requires CONFIG_NFS_DIRECTIO to be enabled, so
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
27 we can't always use it.
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
28 */
4071
cd3d26cf124a Renamed safe-open.* to nfs-workarounds.*, safe_open() to nfs_safe_open() and
Timo Sirainen <tss@iki.fi>
parents:
diff changeset
29
cd3d26cf124a Renamed safe-open.* to nfs-workarounds.*, safe_open() to nfs_safe_open() and
Timo Sirainen <tss@iki.fi>
parents:
diff changeset
30 #include "lib.h"
cd3d26cf124a Renamed safe-open.* to nfs-workarounds.*, safe_open() to nfs_safe_open() and
Timo Sirainen <tss@iki.fi>
parents:
diff changeset
31 #include "nfs-workarounds.h"
cd3d26cf124a Renamed safe-open.* to nfs-workarounds.*, safe_open() to nfs_safe_open() and
Timo Sirainen <tss@iki.fi>
parents:
diff changeset
32
cd3d26cf124a Renamed safe-open.* to nfs-workarounds.*, safe_open() to nfs_safe_open() and
Timo Sirainen <tss@iki.fi>
parents:
diff changeset
33 #include <fcntl.h>
cd3d26cf124a Renamed safe-open.* to nfs-workarounds.*, safe_open() to nfs_safe_open() and
Timo Sirainen <tss@iki.fi>
parents:
diff changeset
34 #include <unistd.h>
cd3d26cf124a Renamed safe-open.* to nfs-workarounds.*, safe_open() to nfs_safe_open() and
Timo Sirainen <tss@iki.fi>
parents:
diff changeset
35 #include <sys/stat.h>
cd3d26cf124a Renamed safe-open.* to nfs-workarounds.*, safe_open() to nfs_safe_open() and
Timo Sirainen <tss@iki.fi>
parents:
diff changeset
36
5970
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
37 #ifdef __linux__
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
38 # define READ_CACHE_FLUSH_FCNTL
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
39 #endif
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
40
4225
abdef9d86a94 Added nfs_safe_stat() to transparently work around ESTALE with stat().
Timo Sirainen <timo.sirainen@movial.fi>
parents: 4071
diff changeset
41 static int
abdef9d86a94 Added nfs_safe_stat() to transparently work around ESTALE with stat().
Timo Sirainen <timo.sirainen@movial.fi>
parents: 4071
diff changeset
42 nfs_safe_do(const char *path, int (*callback)(const char *path, void *context),
abdef9d86a94 Added nfs_safe_stat() to transparently work around ESTALE with stat().
Timo Sirainen <timo.sirainen@movial.fi>
parents: 4071
diff changeset
43 void *context)
4071
cd3d26cf124a Renamed safe-open.* to nfs-workarounds.*, safe_open() to nfs_safe_open() and
Timo Sirainen <tss@iki.fi>
parents:
diff changeset
44 {
cd3d26cf124a Renamed safe-open.* to nfs-workarounds.*, safe_open() to nfs_safe_open() and
Timo Sirainen <tss@iki.fi>
parents:
diff changeset
45 const char *dir = NULL;
cd3d26cf124a Renamed safe-open.* to nfs-workarounds.*, safe_open() to nfs_safe_open() and
Timo Sirainen <tss@iki.fi>
parents:
diff changeset
46 struct stat st;
cd3d26cf124a Renamed safe-open.* to nfs-workarounds.*, safe_open() to nfs_safe_open() and
Timo Sirainen <tss@iki.fi>
parents:
diff changeset
47 unsigned int i;
4225
abdef9d86a94 Added nfs_safe_stat() to transparently work around ESTALE with stat().
Timo Sirainen <timo.sirainen@movial.fi>
parents: 4071
diff changeset
48 int ret;
4071
cd3d26cf124a Renamed safe-open.* to nfs-workarounds.*, safe_open() to nfs_safe_open() and
Timo Sirainen <tss@iki.fi>
parents:
diff changeset
49
cd3d26cf124a Renamed safe-open.* to nfs-workarounds.*, safe_open() to nfs_safe_open() and
Timo Sirainen <tss@iki.fi>
parents:
diff changeset
50 t_push();
cd3d26cf124a Renamed safe-open.* to nfs-workarounds.*, safe_open() to nfs_safe_open() and
Timo Sirainen <tss@iki.fi>
parents:
diff changeset
51 for (i = 1;; i++) {
4225
abdef9d86a94 Added nfs_safe_stat() to transparently work around ESTALE with stat().
Timo Sirainen <timo.sirainen@movial.fi>
parents: 4071
diff changeset
52 ret = callback(path, context);
abdef9d86a94 Added nfs_safe_stat() to transparently work around ESTALE with stat().
Timo Sirainen <timo.sirainen@movial.fi>
parents: 4071
diff changeset
53 if (ret == 0 || errno != ESTALE || i == NFS_ESTALE_RETRY_COUNT)
4071
cd3d26cf124a Renamed safe-open.* to nfs-workarounds.*, safe_open() to nfs_safe_open() and
Timo Sirainen <tss@iki.fi>
parents:
diff changeset
54 break;
cd3d26cf124a Renamed safe-open.* to nfs-workarounds.*, safe_open() to nfs_safe_open() and
Timo Sirainen <tss@iki.fi>
parents:
diff changeset
55
cd3d26cf124a Renamed safe-open.* to nfs-workarounds.*, safe_open() to nfs_safe_open() and
Timo Sirainen <tss@iki.fi>
parents:
diff changeset
56 /* ESTALE: Some operating systems may fail with this if they
cd3d26cf124a Renamed safe-open.* to nfs-workarounds.*, safe_open() to nfs_safe_open() and
Timo Sirainen <tss@iki.fi>
parents:
diff changeset
57 can't internally revalidating the NFS handle. It may also
cd3d26cf124a Renamed safe-open.* to nfs-workarounds.*, safe_open() to nfs_safe_open() and
Timo Sirainen <tss@iki.fi>
parents:
diff changeset
58 happen if the parent directory has been deleted. If the
cd3d26cf124a Renamed safe-open.* to nfs-workarounds.*, safe_open() to nfs_safe_open() and
Timo Sirainen <tss@iki.fi>
parents:
diff changeset
59 directory still exists, try reopening the file. */
cd3d26cf124a Renamed safe-open.* to nfs-workarounds.*, safe_open() to nfs_safe_open() and
Timo Sirainen <tss@iki.fi>
parents:
diff changeset
60 if (dir == NULL) {
cd3d26cf124a Renamed safe-open.* to nfs-workarounds.*, safe_open() to nfs_safe_open() and
Timo Sirainen <tss@iki.fi>
parents:
diff changeset
61 dir = strrchr(path, '/');
cd3d26cf124a Renamed safe-open.* to nfs-workarounds.*, safe_open() to nfs_safe_open() and
Timo Sirainen <tss@iki.fi>
parents:
diff changeset
62 if (dir == NULL)
cd3d26cf124a Renamed safe-open.* to nfs-workarounds.*, safe_open() to nfs_safe_open() and
Timo Sirainen <tss@iki.fi>
parents:
diff changeset
63 break;
cd3d26cf124a Renamed safe-open.* to nfs-workarounds.*, safe_open() to nfs_safe_open() and
Timo Sirainen <tss@iki.fi>
parents:
diff changeset
64 dir = t_strdup_until(path, dir);
cd3d26cf124a Renamed safe-open.* to nfs-workarounds.*, safe_open() to nfs_safe_open() and
Timo Sirainen <tss@iki.fi>
parents:
diff changeset
65 }
cd3d26cf124a Renamed safe-open.* to nfs-workarounds.*, safe_open() to nfs_safe_open() and
Timo Sirainen <tss@iki.fi>
parents:
diff changeset
66 if (stat(dir, &st) < 0) {
cd3d26cf124a Renamed safe-open.* to nfs-workarounds.*, safe_open() to nfs_safe_open() and
Timo Sirainen <tss@iki.fi>
parents:
diff changeset
67 /* maybe it's gone or something else bad happened to
cd3d26cf124a Renamed safe-open.* to nfs-workarounds.*, safe_open() to nfs_safe_open() and
Timo Sirainen <tss@iki.fi>
parents:
diff changeset
68 it. in any case we can't open the file, so fail
cd3d26cf124a Renamed safe-open.* to nfs-workarounds.*, safe_open() to nfs_safe_open() and
Timo Sirainen <tss@iki.fi>
parents:
diff changeset
69 with the original ESTALE error and let our caller
cd3d26cf124a Renamed safe-open.* to nfs-workarounds.*, safe_open() to nfs_safe_open() and
Timo Sirainen <tss@iki.fi>
parents:
diff changeset
70 handle it. */
cd3d26cf124a Renamed safe-open.* to nfs-workarounds.*, safe_open() to nfs_safe_open() and
Timo Sirainen <tss@iki.fi>
parents:
diff changeset
71 errno = ESTALE;
cd3d26cf124a Renamed safe-open.* to nfs-workarounds.*, safe_open() to nfs_safe_open() and
Timo Sirainen <tss@iki.fi>
parents:
diff changeset
72 break;
cd3d26cf124a Renamed safe-open.* to nfs-workarounds.*, safe_open() to nfs_safe_open() and
Timo Sirainen <tss@iki.fi>
parents:
diff changeset
73 }
cd3d26cf124a Renamed safe-open.* to nfs-workarounds.*, safe_open() to nfs_safe_open() and
Timo Sirainen <tss@iki.fi>
parents:
diff changeset
74
cd3d26cf124a Renamed safe-open.* to nfs-workarounds.*, safe_open() to nfs_safe_open() and
Timo Sirainen <tss@iki.fi>
parents:
diff changeset
75 /* directory still exists, try reopening */
cd3d26cf124a Renamed safe-open.* to nfs-workarounds.*, safe_open() to nfs_safe_open() and
Timo Sirainen <tss@iki.fi>
parents:
diff changeset
76 }
cd3d26cf124a Renamed safe-open.* to nfs-workarounds.*, safe_open() to nfs_safe_open() and
Timo Sirainen <tss@iki.fi>
parents:
diff changeset
77 t_pop();
4225
abdef9d86a94 Added nfs_safe_stat() to transparently work around ESTALE with stat().
Timo Sirainen <timo.sirainen@movial.fi>
parents: 4071
diff changeset
78 return ret;
abdef9d86a94 Added nfs_safe_stat() to transparently work around ESTALE with stat().
Timo Sirainen <timo.sirainen@movial.fi>
parents: 4071
diff changeset
79 }
abdef9d86a94 Added nfs_safe_stat() to transparently work around ESTALE with stat().
Timo Sirainen <timo.sirainen@movial.fi>
parents: 4071
diff changeset
80
abdef9d86a94 Added nfs_safe_stat() to transparently work around ESTALE with stat().
Timo Sirainen <timo.sirainen@movial.fi>
parents: 4071
diff changeset
81 struct nfs_safe_open_context {
abdef9d86a94 Added nfs_safe_stat() to transparently work around ESTALE with stat().
Timo Sirainen <timo.sirainen@movial.fi>
parents: 4071
diff changeset
82 int flags;
abdef9d86a94 Added nfs_safe_stat() to transparently work around ESTALE with stat().
Timo Sirainen <timo.sirainen@movial.fi>
parents: 4071
diff changeset
83 int fd;
abdef9d86a94 Added nfs_safe_stat() to transparently work around ESTALE with stat().
Timo Sirainen <timo.sirainen@movial.fi>
parents: 4071
diff changeset
84 };
abdef9d86a94 Added nfs_safe_stat() to transparently work around ESTALE with stat().
Timo Sirainen <timo.sirainen@movial.fi>
parents: 4071
diff changeset
85
abdef9d86a94 Added nfs_safe_stat() to transparently work around ESTALE with stat().
Timo Sirainen <timo.sirainen@movial.fi>
parents: 4071
diff changeset
86 static int nfs_safe_open_callback(const char *path, void *context)
abdef9d86a94 Added nfs_safe_stat() to transparently work around ESTALE with stat().
Timo Sirainen <timo.sirainen@movial.fi>
parents: 4071
diff changeset
87 {
abdef9d86a94 Added nfs_safe_stat() to transparently work around ESTALE with stat().
Timo Sirainen <timo.sirainen@movial.fi>
parents: 4071
diff changeset
88 struct nfs_safe_open_context *ctx = context;
abdef9d86a94 Added nfs_safe_stat() to transparently work around ESTALE with stat().
Timo Sirainen <timo.sirainen@movial.fi>
parents: 4071
diff changeset
89
abdef9d86a94 Added nfs_safe_stat() to transparently work around ESTALE with stat().
Timo Sirainen <timo.sirainen@movial.fi>
parents: 4071
diff changeset
90 ctx->fd = open(path, ctx->flags);
abdef9d86a94 Added nfs_safe_stat() to transparently work around ESTALE with stat().
Timo Sirainen <timo.sirainen@movial.fi>
parents: 4071
diff changeset
91 return ctx->fd == -1 ? -1 : 0;
4071
cd3d26cf124a Renamed safe-open.* to nfs-workarounds.*, safe_open() to nfs_safe_open() and
Timo Sirainen <tss@iki.fi>
parents:
diff changeset
92 }
4225
abdef9d86a94 Added nfs_safe_stat() to transparently work around ESTALE with stat().
Timo Sirainen <timo.sirainen@movial.fi>
parents: 4071
diff changeset
93
abdef9d86a94 Added nfs_safe_stat() to transparently work around ESTALE with stat().
Timo Sirainen <timo.sirainen@movial.fi>
parents: 4071
diff changeset
94 int nfs_safe_open(const char *path, int flags)
abdef9d86a94 Added nfs_safe_stat() to transparently work around ESTALE with stat().
Timo Sirainen <timo.sirainen@movial.fi>
parents: 4071
diff changeset
95 {
abdef9d86a94 Added nfs_safe_stat() to transparently work around ESTALE with stat().
Timo Sirainen <timo.sirainen@movial.fi>
parents: 4071
diff changeset
96 struct nfs_safe_open_context ctx;
abdef9d86a94 Added nfs_safe_stat() to transparently work around ESTALE with stat().
Timo Sirainen <timo.sirainen@movial.fi>
parents: 4071
diff changeset
97
abdef9d86a94 Added nfs_safe_stat() to transparently work around ESTALE with stat().
Timo Sirainen <timo.sirainen@movial.fi>
parents: 4071
diff changeset
98 i_assert((flags & O_CREAT) == 0);
abdef9d86a94 Added nfs_safe_stat() to transparently work around ESTALE with stat().
Timo Sirainen <timo.sirainen@movial.fi>
parents: 4071
diff changeset
99
abdef9d86a94 Added nfs_safe_stat() to transparently work around ESTALE with stat().
Timo Sirainen <timo.sirainen@movial.fi>
parents: 4071
diff changeset
100 ctx.flags = flags;
abdef9d86a94 Added nfs_safe_stat() to transparently work around ESTALE with stat().
Timo Sirainen <timo.sirainen@movial.fi>
parents: 4071
diff changeset
101 if (nfs_safe_do(path, nfs_safe_open_callback, &ctx) < 0)
abdef9d86a94 Added nfs_safe_stat() to transparently work around ESTALE with stat().
Timo Sirainen <timo.sirainen@movial.fi>
parents: 4071
diff changeset
102 return -1;
abdef9d86a94 Added nfs_safe_stat() to transparently work around ESTALE with stat().
Timo Sirainen <timo.sirainen@movial.fi>
parents: 4071
diff changeset
103
abdef9d86a94 Added nfs_safe_stat() to transparently work around ESTALE with stat().
Timo Sirainen <timo.sirainen@movial.fi>
parents: 4071
diff changeset
104 return ctx.fd;
abdef9d86a94 Added nfs_safe_stat() to transparently work around ESTALE with stat().
Timo Sirainen <timo.sirainen@movial.fi>
parents: 4071
diff changeset
105 }
abdef9d86a94 Added nfs_safe_stat() to transparently work around ESTALE with stat().
Timo Sirainen <timo.sirainen@movial.fi>
parents: 4071
diff changeset
106
abdef9d86a94 Added nfs_safe_stat() to transparently work around ESTALE with stat().
Timo Sirainen <timo.sirainen@movial.fi>
parents: 4071
diff changeset
107 static int nfs_safe_stat_callback(const char *path, void *context)
abdef9d86a94 Added nfs_safe_stat() to transparently work around ESTALE with stat().
Timo Sirainen <timo.sirainen@movial.fi>
parents: 4071
diff changeset
108 {
abdef9d86a94 Added nfs_safe_stat() to transparently work around ESTALE with stat().
Timo Sirainen <timo.sirainen@movial.fi>
parents: 4071
diff changeset
109 struct stat *buf = context;
abdef9d86a94 Added nfs_safe_stat() to transparently work around ESTALE with stat().
Timo Sirainen <timo.sirainen@movial.fi>
parents: 4071
diff changeset
110
abdef9d86a94 Added nfs_safe_stat() to transparently work around ESTALE with stat().
Timo Sirainen <timo.sirainen@movial.fi>
parents: 4071
diff changeset
111 return stat(path, buf);
abdef9d86a94 Added nfs_safe_stat() to transparently work around ESTALE with stat().
Timo Sirainen <timo.sirainen@movial.fi>
parents: 4071
diff changeset
112 }
abdef9d86a94 Added nfs_safe_stat() to transparently work around ESTALE with stat().
Timo Sirainen <timo.sirainen@movial.fi>
parents: 4071
diff changeset
113
abdef9d86a94 Added nfs_safe_stat() to transparently work around ESTALE with stat().
Timo Sirainen <timo.sirainen@movial.fi>
parents: 4071
diff changeset
114 int nfs_safe_stat(const char *path, struct stat *buf)
abdef9d86a94 Added nfs_safe_stat() to transparently work around ESTALE with stat().
Timo Sirainen <timo.sirainen@movial.fi>
parents: 4071
diff changeset
115 {
abdef9d86a94 Added nfs_safe_stat() to transparently work around ESTALE with stat().
Timo Sirainen <timo.sirainen@movial.fi>
parents: 4071
diff changeset
116 return nfs_safe_do(path, nfs_safe_stat_callback, buf);
abdef9d86a94 Added nfs_safe_stat() to transparently work around ESTALE with stat().
Timo Sirainen <timo.sirainen@movial.fi>
parents: 4071
diff changeset
117 }
5968
885ed4d5c51d Added nfs_safe_lstat()
Timo Sirainen <tss@iki.fi>
parents: 4225
diff changeset
118
885ed4d5c51d Added nfs_safe_lstat()
Timo Sirainen <tss@iki.fi>
parents: 4225
diff changeset
119 static int nfs_safe_lstat_callback(const char *path, void *context)
885ed4d5c51d Added nfs_safe_lstat()
Timo Sirainen <tss@iki.fi>
parents: 4225
diff changeset
120 {
885ed4d5c51d Added nfs_safe_lstat()
Timo Sirainen <tss@iki.fi>
parents: 4225
diff changeset
121 struct stat *buf = context;
885ed4d5c51d Added nfs_safe_lstat()
Timo Sirainen <tss@iki.fi>
parents: 4225
diff changeset
122
885ed4d5c51d Added nfs_safe_lstat()
Timo Sirainen <tss@iki.fi>
parents: 4225
diff changeset
123 return lstat(path, buf);
885ed4d5c51d Added nfs_safe_lstat()
Timo Sirainen <tss@iki.fi>
parents: 4225
diff changeset
124 }
885ed4d5c51d Added nfs_safe_lstat()
Timo Sirainen <tss@iki.fi>
parents: 4225
diff changeset
125
885ed4d5c51d Added nfs_safe_lstat()
Timo Sirainen <tss@iki.fi>
parents: 4225
diff changeset
126 int nfs_safe_lstat(const char *path, struct stat *buf)
885ed4d5c51d Added nfs_safe_lstat()
Timo Sirainen <tss@iki.fi>
parents: 4225
diff changeset
127 {
885ed4d5c51d Added nfs_safe_lstat()
Timo Sirainen <tss@iki.fi>
parents: 4225
diff changeset
128 return nfs_safe_do(path, nfs_safe_lstat_callback, buf);
885ed4d5c51d Added nfs_safe_lstat()
Timo Sirainen <tss@iki.fi>
parents: 4225
diff changeset
129 }
5970
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
130
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
131 static void nfs_flush_fchown_uid(const char *path, int fd)
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
132 {
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
133 struct stat st;
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
134
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
135 if (fstat(fd, &st) < 0) {
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
136 if (errno == ESTALE) {
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
137 /* ESTALE causes the OS to flush the attr cache */
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
138 return;
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
139 }
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
140 i_error("nfs_flush_fchown_uid: fstat(%s) failed: %m", path);
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
141 return;
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
142 }
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
143 if (fchown(fd, st.st_uid, (gid_t)-1) < 0) {
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
144 if (errno == ESTALE || errno == EACCES || errno == EPERM) {
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
145 /* attr cache is flushed */
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
146 return;
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
147 }
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
148
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
149 i_error("nfs_flush_fchown_uid: fchown(%s) failed: %m", path);
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
150 }
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
151 }
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
152
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
153 static void nfs_flush_chown_uid(const char *path)
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
154 {
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
155 struct stat st;
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
156
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
157 if (stat(path, &st) < 0) {
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
158 if (errno == ESTALE) {
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
159 /* ESTALE causes the OS to flush the attr cache */
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
160 return;
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
161 }
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
162 if (errno != ENOENT) {
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
163 i_error("nfs_flush_chown_uid: stat(%s) failed: %m",
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
164 path);
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
165 return;
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
166 }
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
167
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
168 /* flush a negative cache entry. use effective UID to chown.
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
169 it probably doesn't really matter what UID is used, because
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
170 as long as we're not root we don't have permission to really
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
171 change it anyway */
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
172 st.st_uid = geteuid();
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
173 }
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
174 if (chown(path, st.st_uid, (gid_t)-1) < 0) {
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
175 if (errno == ESTALE || errno == EACCES ||
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
176 errno == EPERM || errno == ENOENT) {
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
177 /* attr cache is flushed */
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
178 return;
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
179 }
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
180 i_error("nfs_flush_chown_uid: chown(%s) failed: %m", path);
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
181 }
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
182 }
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
183
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
184 #ifdef READ_CACHE_FLUSH_FCNTL
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
185 static void nfs_flush_fcntl(const char *path, int fd, int old_lock_type)
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
186 {
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
187 struct flock fl;
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
188 int ret;
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
189
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
190 /* If the file was already locked, we'll just get the same lock
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
191 again. It should succeed just fine. If was was unlocked, we'll
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
192 have to get a lock and then unlock it. Linux 2.6 flushes read cache
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
193 only when read/write locking succeeded. */
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
194 fl.l_type = old_lock_type != F_UNLCK ? old_lock_type : F_RDLCK;
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
195 fl.l_whence = SEEK_SET;
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
196 fl.l_start = 0;
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
197 fl.l_len = 0;
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
198
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
199 alarm(60);
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
200 ret = fcntl(fd, F_SETLKW, &fl);
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
201 alarm(0);
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
202
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
203 if (ret < 0) {
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
204 i_error("nfs_flush_fcntl: fcntl(%s, F_RDLCK) failed: %m", path);
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
205 return;
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
206 }
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
207
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
208 if (old_lock_type == F_UNLCK) {
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
209 fl.l_type = F_UNLCK;
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
210 (void)fcntl(fd, F_SETLKW, &fl);
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
211 }
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
212 }
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
213 #endif
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
214
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
215 void nfs_flush_attr_cache(const char *path)
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
216 {
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
217 nfs_flush_chown_uid(path);
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
218 }
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
219
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
220 void nfs_flush_attr_cache_fd(const char *path, int fd)
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
221 {
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
222 nfs_flush_fchown_uid(path, fd);
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
223 }
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
224
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
225 void nfs_flush_read_cache(const char *path, int fd,
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
226 int lock_type __attr_unused__,
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
227 bool just_locked __attr_unused__)
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
228 {
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
229 #ifdef READ_CACHE_FLUSH_FCNTL
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
230 if (!just_locked)
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
231 nfs_flush_fcntl(path, fd, lock_type);
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
232 #else
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
233 /* FreeBSD, Solaris */
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
234 nfs_flush_fchown_uid(path, fd);
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
235 #endif
a290b84d144a Added nfs_flush_attr_cache() and nfs_flush_read_cache().
Timo Sirainen <tss@iki.fi>
parents: 5968
diff changeset
236 }