Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 70ca8852 authored by Trond Myklebust's avatar Trond Myklebust
Browse files

NFS: Fake up 'wcc' attributes to prevent cache invalidation after write



NFSv2 and v4 don't offer weak cache consistency attributes on WRITE calls.
In NFSv3, returning wcc data is optional. In all cases, we want to prevent
the client from invalidating our cached data whenever ->write_done()
attempts to update the inode attributes.

Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent b64e8a5e
Loading
Loading
Loading
Loading
+34 −0
Original line number Diff line number Diff line
@@ -793,6 +793,12 @@ static void nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr)
{
	struct nfs_inode *nfsi = NFS_I(inode);

	if ((fattr->valid & NFS_ATTR_WCC_V4) != 0 &&
			nfsi->change_attr == fattr->pre_change_attr) {
		nfsi->change_attr = fattr->change_attr;
		if (S_ISDIR(inode->i_mode))
			nfsi->cache_validity |= NFS_INO_INVALID_DATA;
	}
	/* If we have atomic WCC data, we may update some attributes */
	if ((fattr->valid & NFS_ATTR_WCC) != 0) {
		if (timespec_equal(&inode->i_ctime, &fattr->pre_ctime))
@@ -923,6 +929,34 @@ int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr)
	return status;
}

/**
 * nfs_post_op_update_inode_force_wcc - try to update the inode attribute cache
 * @inode - pointer to inode
 * @fattr - updated attributes
 *
 * After an operation that has changed the inode metadata, mark the
 * attribute cache as being invalid, then try to update it. Fake up
 * weak cache consistency data, if none exist.
 *
 * This function is mainly designed to be used by the ->write_done() functions.
 */
int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr)
{
	if ((fattr->valid & NFS_ATTR_FATTR_V4) != 0 &&
			(fattr->valid & NFS_ATTR_WCC_V4) == 0) {
		fattr->pre_change_attr = NFS_I(inode)->change_attr;
		fattr->valid |= NFS_ATTR_WCC_V4;
	}
	if ((fattr->valid & NFS_ATTR_FATTR) != 0 &&
			(fattr->valid & NFS_ATTR_WCC) == 0) {
		memcpy(&fattr->pre_ctime, &inode->i_ctime, sizeof(fattr->pre_ctime));
		memcpy(&fattr->pre_mtime, &inode->i_mtime, sizeof(fattr->pre_mtime));
		fattr->pre_size = inode->i_size;
		fattr->valid |= NFS_ATTR_WCC;
	}
	return nfs_post_op_update_inode(inode, fattr);
}

/*
 * Many nfs protocol calls return the new file attributes after
 * an operation.  Here we update the inode to reflect the state
+1 −1
Original line number Diff line number Diff line
@@ -750,7 +750,7 @@ static int nfs3_write_done(struct rpc_task *task, struct nfs_write_data *data)
	if (nfs3_async_handle_jukebox(task, data->inode))
		return -EAGAIN;
	if (task->tk_status >= 0)
		nfs_post_op_update_inode(data->inode, data->res.fattr);
		nfs_post_op_update_inode_force_wcc(data->inode, data->res.fattr);
	return 0;
}

+1 −1
Original line number Diff line number Diff line
@@ -2427,7 +2427,7 @@ static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data)
	}
	if (task->tk_status >= 0) {
		renew_lease(NFS_SERVER(inode), data->timestamp);
		nfs_post_op_update_inode(inode, data->res.fattr);
		nfs_post_op_update_inode_force_wcc(inode, data->res.fattr);
	}
	return 0;
}
+1 −1
Original line number Diff line number Diff line
@@ -579,7 +579,7 @@ static void nfs_proc_read_setup(struct nfs_read_data *data)
static int nfs_write_done(struct rpc_task *task, struct nfs_write_data *data)
{
	if (task->tk_status >= 0)
		nfs_post_op_update_inode(data->inode, data->res.fattr);
		nfs_post_op_update_inode_force_wcc(data->inode, data->res.fattr);
	return 0;
}

+1 −0
Original line number Diff line number Diff line
@@ -293,6 +293,7 @@ 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_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr);
extern int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr);
extern int nfs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
extern int nfs_permission(struct inode *, int, struct nameidata *);
extern int nfs_open(struct inode *, struct file *);
Loading