Commit 6edf9609 authored by Trond Myklebust's avatar Trond Myklebust

NFS: Don't mark the data cache as invalid if it has been flushed

Now that we have functions such as nfs_write_pageuptodate() that use
the cache_validity flags to check if the data cache is valid or not,
it is a little more important to keep the flags in sync with the
state of the data cache.
In particular, we'd like to ensure that if the data cache is empty, we
don't start marking it as needing revalidation.
Reported-by: default avatarScott Mayhew <smayhew@redhat.com>
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@primarydata.com>
parent f2467b6f
...@@ -147,6 +147,17 @@ int nfs_sync_mapping(struct address_space *mapping) ...@@ -147,6 +147,17 @@ int nfs_sync_mapping(struct address_space *mapping)
return ret; return ret;
} }
static void nfs_set_cache_invalid(struct inode *inode, unsigned long flags)
{
struct nfs_inode *nfsi = NFS_I(inode);
if (inode->i_mapping->nrpages == 0)
flags &= ~NFS_INO_INVALID_DATA;
nfsi->cache_validity |= flags;
if (flags & NFS_INO_INVALID_DATA)
nfs_fscache_invalidate(inode);
}
/* /*
* Invalidate the local caches * Invalidate the local caches
*/ */
...@@ -162,17 +173,16 @@ static void nfs_zap_caches_locked(struct inode *inode) ...@@ -162,17 +173,16 @@ static void nfs_zap_caches_locked(struct inode *inode)
memset(NFS_I(inode)->cookieverf, 0, sizeof(NFS_I(inode)->cookieverf)); memset(NFS_I(inode)->cookieverf, 0, sizeof(NFS_I(inode)->cookieverf));
if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) { if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) {
nfs_fscache_invalidate(inode); nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR
nfsi->cache_validity |= NFS_INO_INVALID_ATTR
| NFS_INO_INVALID_DATA | NFS_INO_INVALID_DATA
| NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACCESS
| NFS_INO_INVALID_ACL | NFS_INO_INVALID_ACL
| NFS_INO_REVAL_PAGECACHE; | NFS_INO_REVAL_PAGECACHE);
} else } else
nfsi->cache_validity |= NFS_INO_INVALID_ATTR nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR
| NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACCESS
| NFS_INO_INVALID_ACL | NFS_INO_INVALID_ACL
| NFS_INO_REVAL_PAGECACHE; | NFS_INO_REVAL_PAGECACHE);
nfs_zap_label_cache_locked(nfsi); nfs_zap_label_cache_locked(nfsi);
} }
...@@ -187,8 +197,7 @@ void nfs_zap_mapping(struct inode *inode, struct address_space *mapping) ...@@ -187,8 +197,7 @@ void nfs_zap_mapping(struct inode *inode, struct address_space *mapping)
{ {
if (mapping->nrpages != 0) { if (mapping->nrpages != 0) {
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
NFS_I(inode)->cache_validity |= NFS_INO_INVALID_DATA; nfs_set_cache_invalid(inode, NFS_INO_INVALID_DATA);
nfs_fscache_invalidate(inode);
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
} }
} }
...@@ -209,7 +218,7 @@ EXPORT_SYMBOL_GPL(nfs_zap_acl_cache); ...@@ -209,7 +218,7 @@ EXPORT_SYMBOL_GPL(nfs_zap_acl_cache);
void nfs_invalidate_atime(struct inode *inode) void nfs_invalidate_atime(struct inode *inode)
{ {
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATIME; nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATIME);
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
} }
EXPORT_SYMBOL_GPL(nfs_invalidate_atime); EXPORT_SYMBOL_GPL(nfs_invalidate_atime);
...@@ -369,7 +378,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr, st ...@@ -369,7 +378,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr, st
inode->i_mode = fattr->mode; inode->i_mode = fattr->mode;
if ((fattr->valid & NFS_ATTR_FATTR_MODE) == 0 if ((fattr->valid & NFS_ATTR_FATTR_MODE) == 0
&& nfs_server_capable(inode, NFS_CAP_MODE)) && nfs_server_capable(inode, NFS_CAP_MODE))
nfsi->cache_validity |= NFS_INO_INVALID_ATTR; nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR);
/* Why so? Because we want revalidate for devices/FIFOs, and /* Why so? Because we want revalidate for devices/FIFOs, and
* that's precisely what we have in nfs_file_inode_operations. * that's precisely what we have in nfs_file_inode_operations.
*/ */
...@@ -415,36 +424,36 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr, st ...@@ -415,36 +424,36 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr, st
if (fattr->valid & NFS_ATTR_FATTR_ATIME) if (fattr->valid & NFS_ATTR_FATTR_ATIME)
inode->i_atime = fattr->atime; inode->i_atime = fattr->atime;
else if (nfs_server_capable(inode, NFS_CAP_ATIME)) else if (nfs_server_capable(inode, NFS_CAP_ATIME))
nfsi->cache_validity |= NFS_INO_INVALID_ATTR; nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR);
if (fattr->valid & NFS_ATTR_FATTR_MTIME) if (fattr->valid & NFS_ATTR_FATTR_MTIME)
inode->i_mtime = fattr->mtime; inode->i_mtime = fattr->mtime;
else if (nfs_server_capable(inode, NFS_CAP_MTIME)) else if (nfs_server_capable(inode, NFS_CAP_MTIME))
nfsi->cache_validity |= NFS_INO_INVALID_ATTR; nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR);
if (fattr->valid & NFS_ATTR_FATTR_CTIME) if (fattr->valid & NFS_ATTR_FATTR_CTIME)
inode->i_ctime = fattr->ctime; inode->i_ctime = fattr->ctime;
else if (nfs_server_capable(inode, NFS_CAP_CTIME)) else if (nfs_server_capable(inode, NFS_CAP_CTIME))
nfsi->cache_validity |= NFS_INO_INVALID_ATTR; nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR);
if (fattr->valid & NFS_ATTR_FATTR_CHANGE) if (fattr->valid & NFS_ATTR_FATTR_CHANGE)
inode->i_version = fattr->change_attr; inode->i_version = fattr->change_attr;
else if (nfs_server_capable(inode, NFS_CAP_CHANGE_ATTR)) else if (nfs_server_capable(inode, NFS_CAP_CHANGE_ATTR))
nfsi->cache_validity |= NFS_INO_INVALID_ATTR; nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR);
if (fattr->valid & NFS_ATTR_FATTR_SIZE) if (fattr->valid & NFS_ATTR_FATTR_SIZE)
inode->i_size = nfs_size_to_loff_t(fattr->size); inode->i_size = nfs_size_to_loff_t(fattr->size);
else else
nfsi->cache_validity |= NFS_INO_INVALID_ATTR nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR
| NFS_INO_REVAL_PAGECACHE; | NFS_INO_REVAL_PAGECACHE);
if (fattr->valid & NFS_ATTR_FATTR_NLINK) if (fattr->valid & NFS_ATTR_FATTR_NLINK)
set_nlink(inode, fattr->nlink); set_nlink(inode, fattr->nlink);
else if (nfs_server_capable(inode, NFS_CAP_NLINK)) else if (nfs_server_capable(inode, NFS_CAP_NLINK))
nfsi->cache_validity |= NFS_INO_INVALID_ATTR; nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR);
if (fattr->valid & NFS_ATTR_FATTR_OWNER) if (fattr->valid & NFS_ATTR_FATTR_OWNER)
inode->i_uid = fattr->uid; inode->i_uid = fattr->uid;
else if (nfs_server_capable(inode, NFS_CAP_OWNER)) else if (nfs_server_capable(inode, NFS_CAP_OWNER))
nfsi->cache_validity |= NFS_INO_INVALID_ATTR; nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR);
if (fattr->valid & NFS_ATTR_FATTR_GROUP) if (fattr->valid & NFS_ATTR_FATTR_GROUP)
inode->i_gid = fattr->gid; inode->i_gid = fattr->gid;
else if (nfs_server_capable(inode, NFS_CAP_OWNER_GROUP)) else if (nfs_server_capable(inode, NFS_CAP_OWNER_GROUP))
nfsi->cache_validity |= NFS_INO_INVALID_ATTR; nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR);
if (fattr->valid & NFS_ATTR_FATTR_BLOCKS_USED) if (fattr->valid & NFS_ATTR_FATTR_BLOCKS_USED)
inode->i_blocks = fattr->du.nfs2.blocks; inode->i_blocks = fattr->du.nfs2.blocks;
if (fattr->valid & NFS_ATTR_FATTR_SPACE_USED) { if (fattr->valid & NFS_ATTR_FATTR_SPACE_USED) {
...@@ -550,6 +559,9 @@ static int nfs_vmtruncate(struct inode * inode, loff_t offset) ...@@ -550,6 +559,9 @@ static int nfs_vmtruncate(struct inode * inode, loff_t offset)
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
i_size_write(inode, offset); i_size_write(inode, offset);
/* Optimisation */
if (offset == 0)
NFS_I(inode)->cache_validity &= ~NFS_INO_INVALID_DATA;
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
truncate_pagecache(inode, offset); truncate_pagecache(inode, offset);
...@@ -578,7 +590,8 @@ void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr) ...@@ -578,7 +590,8 @@ void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr)
inode->i_uid = attr->ia_uid; inode->i_uid = attr->ia_uid;
if ((attr->ia_valid & ATTR_GID) != 0) if ((attr->ia_valid & ATTR_GID) != 0)
inode->i_gid = attr->ia_gid; inode->i_gid = attr->ia_gid;
NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; nfs_set_cache_invalid(inode, NFS_INO_INVALID_ACCESS
| NFS_INO_INVALID_ACL);
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
} }
if ((attr->ia_valid & ATTR_SIZE) != 0) { if ((attr->ia_valid & ATTR_SIZE) != 0) {
...@@ -1101,7 +1114,7 @@ static unsigned long nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr ...@@ -1101,7 +1114,7 @@ static unsigned long nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr
&& inode->i_version == fattr->pre_change_attr) { && inode->i_version == fattr->pre_change_attr) {
inode->i_version = fattr->change_attr; inode->i_version = fattr->change_attr;
if (S_ISDIR(inode->i_mode)) if (S_ISDIR(inode->i_mode))
nfsi->cache_validity |= NFS_INO_INVALID_DATA; nfs_set_cache_invalid(inode, NFS_INO_INVALID_DATA);
ret |= NFS_INO_INVALID_ATTR; ret |= NFS_INO_INVALID_ATTR;
} }
/* If we have atomic WCC data, we may update some attributes */ /* If we have atomic WCC data, we may update some attributes */
...@@ -1117,7 +1130,7 @@ static unsigned long nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr ...@@ -1117,7 +1130,7 @@ static unsigned long nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr
&& timespec_equal(&inode->i_mtime, &fattr->pre_mtime)) { && timespec_equal(&inode->i_mtime, &fattr->pre_mtime)) {
memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime)); memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
if (S_ISDIR(inode->i_mode)) if (S_ISDIR(inode->i_mode))
nfsi->cache_validity |= NFS_INO_INVALID_DATA; nfs_set_cache_invalid(inode, NFS_INO_INVALID_DATA);
ret |= NFS_INO_INVALID_ATTR; ret |= NFS_INO_INVALID_ATTR;
} }
if ((fattr->valid & NFS_ATTR_FATTR_PRESIZE) if ((fattr->valid & NFS_ATTR_FATTR_PRESIZE)
...@@ -1128,9 +1141,6 @@ static unsigned long nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr ...@@ -1128,9 +1141,6 @@ static unsigned long nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr
ret |= NFS_INO_INVALID_ATTR; ret |= NFS_INO_INVALID_ATTR;
} }
if (nfsi->cache_validity & NFS_INO_INVALID_DATA)
nfs_fscache_invalidate(inode);
return ret; return ret;
} }
...@@ -1189,7 +1199,7 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat ...@@ -1189,7 +1199,7 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat
invalid |= NFS_INO_INVALID_ATIME; invalid |= NFS_INO_INVALID_ATIME;
if (invalid != 0) if (invalid != 0)
nfsi->cache_validity |= invalid; nfs_set_cache_invalid(inode, invalid);
nfsi->read_cache_jiffies = fattr->time_start; nfsi->read_cache_jiffies = fattr->time_start;
return 0; return 0;
...@@ -1402,13 +1412,11 @@ EXPORT_SYMBOL_GPL(nfs_refresh_inode); ...@@ -1402,13 +1412,11 @@ EXPORT_SYMBOL_GPL(nfs_refresh_inode);
static int nfs_post_op_update_inode_locked(struct inode *inode, struct nfs_fattr *fattr) static int nfs_post_op_update_inode_locked(struct inode *inode, struct nfs_fattr *fattr)
{ {
struct nfs_inode *nfsi = NFS_I(inode); unsigned long invalid = NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE; if (S_ISDIR(inode->i_mode))
if (S_ISDIR(inode->i_mode)) { invalid |= NFS_INO_INVALID_DATA;
nfsi->cache_validity |= NFS_INO_INVALID_DATA; nfs_set_cache_invalid(inode, invalid);
nfs_fscache_invalidate(inode);
}
if ((fattr->valid & NFS_ATTR_FATTR) == 0) if ((fattr->valid & NFS_ATTR_FATTR) == 0)
return 0; return 0;
return nfs_refresh_inode_locked(inode, fattr); return nfs_refresh_inode_locked(inode, fattr);
...@@ -1703,10 +1711,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) ...@@ -1703,10 +1711,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
invalid &= ~NFS_INO_INVALID_DATA; invalid &= ~NFS_INO_INVALID_DATA;
if (!NFS_PROTO(inode)->have_delegation(inode, FMODE_READ) || if (!NFS_PROTO(inode)->have_delegation(inode, FMODE_READ) ||
(save_cache_validity & NFS_INO_REVAL_FORCED)) (save_cache_validity & NFS_INO_REVAL_FORCED))
nfsi->cache_validity |= invalid; nfs_set_cache_invalid(inode, invalid);
if (invalid & NFS_INO_INVALID_DATA)
nfs_fscache_invalidate(inode);
return 0; return 0;
out_err: out_err:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment