Commit 15820773 authored by Trond Myklebust's avatar Trond Myklebust

NFSv2/v3/v4: Fix a slowdown of O_SYNC and O_DIRECT writes that resulted

from over-aggressive attribute cache revalidation.
parent a9156c09
......@@ -337,8 +337,7 @@ nfs_direct_write_seg(struct inode *inode, struct file *file,
VERF_SIZE) != 0)
goto sync_retry;
}
nfs_end_data_update(inode);
NFS_FLAGS(inode) |= NFS_INO_INVALID_DATA;
nfs_end_data_update_defer(inode);
return tot_bytes;
......@@ -397,10 +396,6 @@ nfs_direct_write(struct inode *inode, struct file *file,
if (result < size)
break;
}
/* Zap the page cache if we managed to write */
if (tot_bytes > 0)
invalidate_remote_inode(inode);
return tot_bytes;
}
......
......@@ -1012,6 +1012,8 @@ void nfs_begin_data_update(struct inode *inode)
* nfs_end_data_update
* @inode - pointer to inode
* Declare end of the operations that will update file data
* This will mark the inode as immediately needing revalidation
* of its attribute cache.
*/
void nfs_end_data_update(struct inode *inode)
{
......@@ -1026,6 +1028,27 @@ void nfs_end_data_update(struct inode *inode)
atomic_dec(&nfsi->data_updates);
}
/**
* nfs_end_data_update_defer
* @inode - pointer to inode
* Declare end of the operations that will update file data
* This will defer marking the inode as needing revalidation
* unless there are no other pending updates.
*/
void nfs_end_data_update_defer(struct inode *inode)
{
struct nfs_inode *nfsi = NFS_I(inode);
if (atomic_dec_and_test(&nfsi->data_updates)) {
/* Mark the attribute cache for revalidation */
nfsi->flags |= NFS_INO_INVALID_ATTR;
/* Directories and symlinks: invalidate page cache too */
if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))
nfsi->flags |= NFS_INO_INVALID_DATA;
nfsi->cache_change_attribute ++;
}
}
/**
* nfs_refresh_inode - verify consistency of the inode attribute cache
* @inode - pointer to inode
......
......@@ -233,7 +233,7 @@ static int nfs_writepage_sync(struct file *file, struct inode *inode,
ClearPageError(page);
io_error:
nfs_end_data_update(inode);
nfs_end_data_update_defer(inode);
if (wdata.cred)
put_rpccred(wdata.cred);
......@@ -404,7 +404,7 @@ nfs_inode_remove_request(struct nfs_page *req)
nfsi->npages--;
if (!nfsi->npages) {
spin_unlock(&nfs_wreq_lock);
nfs_end_data_update(inode);
nfs_end_data_update_defer(inode);
iput(inode);
} else
spin_unlock(&nfs_wreq_lock);
......
......@@ -277,6 +277,7 @@ 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 *);
extern void nfs_end_data_update_defer(struct inode *);
/* linux/net/ipv4/ipconfig.c: trims ip addr off front of name, too. */
extern u32 root_nfs_parse_addr(char *name); /*__init*/
......
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