Skip to content

Commit

Permalink
NFSv4: Fix handling of non-atomic change attrbute updates
Browse files Browse the repository at this point in the history
[ Upstream commit 20cf7d4 ]

If the change attribute update is declared to be non-atomic by the
server, or our cached value does not match the server's value before the
operation was performed, then we should declare the inode cache invalid.

On the other hand, if the change to the directory raced with a lookup or
getattr which already updated the change attribute, then optimise away
the revalidation.

Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
  • Loading branch information
Trond Myklebust authored and gregkh committed Jul 20, 2021
1 parent 357d881 commit cdc0073
Showing 1 changed file with 15 additions and 18 deletions.
33 changes: 15 additions & 18 deletions fs/nfs/nfs4proc.c
Expand Up @@ -1205,37 +1205,34 @@ nfs4_update_changeattr_locked(struct inode *inode,
u64 change_attr = inode_peek_iversion_raw(inode);

cache_validity |= NFS_INO_INVALID_CTIME | NFS_INO_INVALID_MTIME;
if (S_ISDIR(inode->i_mode))
cache_validity |= NFS_INO_INVALID_DATA;

switch (NFS_SERVER(inode)->change_attr_type) {
case NFS4_CHANGE_TYPE_IS_UNDEFINED:
break;
case NFS4_CHANGE_TYPE_IS_TIME_METADATA:
if ((s64)(change_attr - cinfo->after) > 0)
if (cinfo->after == change_attr)
goto out;
break;
default:
if ((s64)(change_attr - cinfo->after) >= 0)
goto out;
}

if (cinfo->atomic && cinfo->before == change_attr) {
nfsi->attrtimeo_timestamp = jiffies;
} else {
if (S_ISDIR(inode->i_mode)) {
cache_validity |= NFS_INO_INVALID_DATA;
inode_set_iversion_raw(inode, cinfo->after);
if (!cinfo->atomic || cinfo->before != change_attr) {
if (S_ISDIR(inode->i_mode))
nfs_force_lookup_revalidate(inode);
} else {
if (!NFS_PROTO(inode)->have_delegation(inode,
FMODE_READ))
cache_validity |= NFS_INO_REVAL_PAGECACHE;
}

if (cinfo->before != change_attr)
cache_validity |= NFS_INO_INVALID_ACCESS |
NFS_INO_INVALID_ACL |
NFS_INO_INVALID_XATTR;
if (!NFS_PROTO(inode)->have_delegation(inode, FMODE_READ))
cache_validity |=
NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL |
NFS_INO_INVALID_SIZE | NFS_INO_INVALID_OTHER |
NFS_INO_INVALID_BLOCKS | NFS_INO_INVALID_NLINK |
NFS_INO_INVALID_MODE | NFS_INO_INVALID_XATTR |
NFS_INO_REVAL_PAGECACHE;
nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
}
inode_set_iversion_raw(inode, cinfo->after);
nfsi->attrtimeo_timestamp = jiffies;
nfsi->read_cache_jiffies = timestamp;
nfsi->attr_gencount = nfs_inc_attr_generation_counter();
nfsi->cache_validity &= ~NFS_INO_INVALID_CHANGE;
Expand Down

0 comments on commit cdc0073

Please sign in to comment.