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, ...@@ -337,8 +337,7 @@ nfs_direct_write_seg(struct inode *inode, struct file *file,
VERF_SIZE) != 0) VERF_SIZE) != 0)
goto sync_retry; goto sync_retry;
} }
nfs_end_data_update(inode); nfs_end_data_update_defer(inode);
NFS_FLAGS(inode) |= NFS_INO_INVALID_DATA;
return tot_bytes; return tot_bytes;
...@@ -397,10 +396,6 @@ nfs_direct_write(struct inode *inode, struct file *file, ...@@ -397,10 +396,6 @@ nfs_direct_write(struct inode *inode, struct file *file,
if (result < size) if (result < size)
break; break;
} }
/* Zap the page cache if we managed to write */
if (tot_bytes > 0)
invalidate_remote_inode(inode);
return tot_bytes; return tot_bytes;
} }
......
...@@ -1012,6 +1012,8 @@ void nfs_begin_data_update(struct inode *inode) ...@@ -1012,6 +1012,8 @@ void nfs_begin_data_update(struct inode *inode)
* nfs_end_data_update * nfs_end_data_update
* @inode - pointer to inode * @inode - pointer to inode
* Declare end of the operations that will update file data * 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) void nfs_end_data_update(struct inode *inode)
{ {
...@@ -1026,6 +1028,27 @@ 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); 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 * nfs_refresh_inode - verify consistency of the inode attribute cache
* @inode - pointer to inode * @inode - pointer to inode
......
...@@ -233,7 +233,7 @@ static int nfs_writepage_sync(struct file *file, struct inode *inode, ...@@ -233,7 +233,7 @@ static int nfs_writepage_sync(struct file *file, struct inode *inode,
ClearPageError(page); ClearPageError(page);
io_error: io_error:
nfs_end_data_update(inode); nfs_end_data_update_defer(inode);
if (wdata.cred) if (wdata.cred)
put_rpccred(wdata.cred); put_rpccred(wdata.cred);
...@@ -404,7 +404,7 @@ nfs_inode_remove_request(struct nfs_page *req) ...@@ -404,7 +404,7 @@ nfs_inode_remove_request(struct nfs_page *req)
nfsi->npages--; nfsi->npages--;
if (!nfsi->npages) { if (!nfsi->npages) {
spin_unlock(&nfs_wreq_lock); spin_unlock(&nfs_wreq_lock);
nfs_end_data_update(inode); nfs_end_data_update_defer(inode);
iput(inode); iput(inode);
} else } else
spin_unlock(&nfs_wreq_lock); spin_unlock(&nfs_wreq_lock);
......
...@@ -277,6 +277,7 @@ extern void nfs_begin_attr_update(struct inode *); ...@@ -277,6 +277,7 @@ extern void nfs_begin_attr_update(struct inode *);
extern void nfs_end_attr_update(struct inode *); extern void nfs_end_attr_update(struct inode *);
extern void nfs_begin_data_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(struct inode *);
extern void nfs_end_data_update_defer(struct inode *);
/* linux/net/ipv4/ipconfig.c: trims ip addr off front of name, too. */ /* linux/net/ipv4/ipconfig.c: trims ip addr off front of name, too. */
extern u32 root_nfs_parse_addr(char *name); /*__init*/ 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