summaryrefslogtreecommitdiff
path: root/include/linux
diff options
context:
space:
mode:
authorTrond Myklebust <trond.myklebust@fys.uio.no>2004-03-13 11:25:33 -0500
committerTrond Myklebust <trond.myklebust@fys.uio.no>2004-03-13 11:25:33 -0500
commitca9268fe3ddd075714005adecd4afbd7f9ab87d0 (patch)
tree2192fe3e38f7f96186786138073f1c3d818ba226 /include/linux
parent9bf35f8c7949be067d90db1af39b5ac1a03bd5ce (diff)
NFSv2/v3/v4: New attribute revalidation code that no
longer relies on ctime for correctness in avoiding update races. VFS: allow filesystems to disable inode_update_time() on a per-inode basis.
Diffstat (limited to 'include/linux')
-rw-r--r--include/linux/fs.h2
-rw-r--r--include/linux/nfs_fs.h97
2 files changed, 72 insertions, 27 deletions
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 661e12c67875..9468e5d98ead 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -138,6 +138,7 @@ extern int leases_enable, dir_notify_enable, lease_break_time;
#define S_DEAD 32 /* removed, but still open directory */
#define S_NOQUOTA 64 /* Inode is not counted to quota */
#define S_DIRSYNC 128 /* Directory modifications are synchronous */
+#define S_NOCMTIME 256 /* Do not update file c/mtime */
/*
* Note that nosuid etc flags are inode-specific: setting some file-system
@@ -171,6 +172,7 @@ extern int leases_enable, dir_notify_enable, lease_break_time;
#define IS_ONE_SECOND(inode) __IS_FLG(inode, MS_ONE_SECOND)
#define IS_DEADDIR(inode) ((inode)->i_flags & S_DEAD)
+#define IS_NOCMTIME(inode) ((inode)->i_flags & S_NOCMTIME)
/* the read-only stuff doesn't really belong here, but any other place is
probably as bad and I don't want to create yet another include file. */
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 524eb6d04d7b..eb39e0513bb3 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -99,7 +99,7 @@ struct nfs_inode {
/*
* Various flags
*/
- unsigned short flags;
+ unsigned int flags;
/*
* read_cache_jiffies is when we started read-caching this inode,
@@ -118,19 +118,22 @@ struct nfs_inode {
*
* mtime != read_cache_mtime
*/
+ unsigned long readdir_timestamp;
unsigned long read_cache_jiffies;
- struct timespec read_cache_ctime;
- struct timespec read_cache_mtime;
- __u64 read_cache_isize;
unsigned long attrtimeo;
unsigned long attrtimeo_timestamp;
__u64 change_attr; /* v4 only */
+ /* "Generation counter" for the attribute cache. This is
+ * bumped whenever we update the metadata on the
+ * server.
+ */
+ unsigned long cache_change_attribute;
/*
- * Timestamp that dates the change made to read_cache_mtime.
- * This is of use for dentry revalidation
+ * Counter indicating the number of outstanding requests that
+ * will cause a file data update.
*/
- unsigned long cache_mtime_jiffies;
+ atomic_t data_updates;
struct nfs_access_cache cache_access;
@@ -170,7 +173,9 @@ struct nfs_inode {
#define NFS_INO_STALE 0x0001 /* possible stale inode */
#define NFS_INO_ADVISE_RDPLUS 0x0002 /* advise readdirplus */
#define NFS_INO_REVALIDATING 0x0004 /* revalidating attrs */
-#define NFS_INO_FLUSH 0x0008 /* inode is due for flushing */
+#define NFS_INO_INVALID_ATTR 0x0008 /* cached attrs are invalid */
+#define NFS_INO_INVALID_DATA 0x0010 /* cached data is invalid */
+#define NFS_INO_INVALID_ATIME 0x0020 /* cached atime is invalid */
#define NFS_INO_FAKE_ROOT 0x0080 /* root inode placeholder */
static inline struct nfs_inode *NFS_I(struct inode *inode)
@@ -186,15 +191,7 @@ static inline struct nfs_inode *NFS_I(struct inode *inode)
#define NFS_ADDR(inode) (RPC_PEERADDR(NFS_CLIENT(inode)))
#define NFS_COOKIEVERF(inode) (NFS_I(inode)->cookieverf)
#define NFS_READTIME(inode) (NFS_I(inode)->read_cache_jiffies)
-#define NFS_MTIME_UPDATE(inode) (NFS_I(inode)->cache_mtime_jiffies)
-#define NFS_CACHE_CTIME(inode) (NFS_I(inode)->read_cache_ctime)
-#define NFS_CACHE_MTIME(inode) (NFS_I(inode)->read_cache_mtime)
-#define NFS_CACHE_ISIZE(inode) (NFS_I(inode)->read_cache_isize)
#define NFS_CHANGE_ATTR(inode) (NFS_I(inode)->change_attr)
-#define NFS_CACHEINV(inode) \
-do { \
- NFS_READTIME(inode) = jiffies - NFS_MAXATTRTIMEO(inode) - 1; \
-} while (0)
#define NFS_ATTRTIMEO(inode) (NFS_I(inode)->attrtimeo)
#define NFS_MINATTRTIMEO(inode) \
(S_ISDIR(inode->i_mode)? NFS_SERVER(inode)->acdirmin \
@@ -211,6 +208,17 @@ do { \
#define NFS_FILEID(inode) (NFS_I(inode)->fileid)
+static inline int nfs_caches_unstable(struct inode *inode)
+{
+ return atomic_read(&NFS_I(inode)->data_updates) != 0;
+}
+
+static inline void NFS_CACHEINV(struct inode *inode)
+{
+ if (!nfs_caches_unstable(inode))
+ NFS_FLAGS(inode) |= NFS_INO_INVALID_ATTR;
+}
+
static inline int nfs_server_capable(struct inode *inode, int cap)
{
return NFS_SERVER(inode)->caps & cap;
@@ -227,13 +235,37 @@ loff_t page_offset(struct page *page)
return ((loff_t)page->index) << PAGE_CACHE_SHIFT;
}
+/**
+ * nfs_save_change_attribute - Returns the inode attribute change cookie
+ * @inode - pointer to inode
+ * The "change attribute" is updated every time we finish an operation
+ * that will result in a metadata change on the server.
+ */
+static inline long nfs_save_change_attribute(struct inode *inode)
+{
+ return NFS_I(inode)->cache_change_attribute;
+}
+
+/**
+ * nfs_verify_change_attribute - Detects NFS inode cache updates
+ * @inode - pointer to inode
+ * @chattr - previously saved change attribute
+ * Return "false" if metadata has been updated (or is in the process of
+ * being updated) since the change attribute was saved.
+ */
+static inline int nfs_verify_change_attribute(struct inode *inode, unsigned long chattr)
+{
+ return !nfs_caches_unstable(inode)
+ && chattr == NFS_I(inode)->cache_change_attribute;
+}
+
/*
* linux/fs/nfs/inode.c
*/
extern void nfs_zap_caches(struct inode *);
extern struct inode *nfs_fhget(struct super_block *, struct nfs_fh *,
struct nfs_fattr *);
-extern int __nfs_refresh_inode(struct inode *, struct nfs_fattr *);
+extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *);
extern int nfs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
extern int nfs_permission(struct inode *, int, struct nameidata *);
extern void nfs_set_mmcred(struct inode *, struct rpc_cred *);
@@ -241,6 +273,10 @@ extern int nfs_open(struct inode *, struct file *);
extern int nfs_release(struct inode *, struct file *);
extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *);
extern int nfs_setattr(struct dentry *, struct iattr *);
+extern void nfs_begin_attr_update(struct inode *);
+extern void nfs_end_attr_update(struct inode *);
+extern void nfs_begin_data_update(struct inode *);
+extern void nfs_end_data_update(struct inode *);
/*
* linux/fs/nfs/file.c
@@ -383,20 +419,27 @@ extern int nfsroot_mount(struct sockaddr_in *, char *, struct nfs_fh *,
/*
* inline functions
*/
-static inline int
-nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
+
+static inline int nfs_attribute_timeout(struct inode *inode)
{
- if (time_before(jiffies, NFS_READTIME(inode)+NFS_ATTRTIMEO(inode)))
- return NFS_STALE(inode) ? -ESTALE : 0;
- return __nfs_revalidate_inode(server, inode);
+ struct nfs_inode *nfsi = NFS_I(inode);
+
+ return time_after(jiffies, nfsi->read_cache_jiffies+nfsi->attrtimeo);
}
-static inline int
-nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
+/**
+ * nfs_revalidate_inode - Revalidate the inode attributes
+ * @server - pointer to nfs_server struct
+ * @inode - pointer to inode struct
+ *
+ * Updates inode attribute information by retrieving the data from the server.
+ */
+static inline int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
{
- if ((fattr->valid & NFS_ATTR_FATTR) == 0)
- return 0;
- return __nfs_refresh_inode(inode,fattr);
+ if (!(NFS_FLAGS(inode) & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA))
+ && !nfs_attribute_timeout(inode))
+ return NFS_STALE(inode) ? -ESTALE : 0;
+ return __nfs_revalidate_inode(server, inode);
}
static inline loff_t