提交 e468bae9 编写于 作者: T Trond Myklebust

NFS: Allow redirtying of a completed unstable write.

Currently, if an unstable write completes, we cannot redirty the page in
order to reflect a new change in the page data until after we've sent a
COMMIT request.

This patch allows a page rewrite to proceed without the unnecessary COMMIT
step, putting it immediately back onto the dirty page list, undoing the
VM unstable write accounting, and removing the NFS_PAGE_TAG_COMMIT tag from
the NFS radix tree.
Signed-off-by: NTrond Myklebust <Trond.Myklebust@netapp.com>
上级 e7d39069
...@@ -242,12 +242,9 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, ...@@ -242,12 +242,9 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio,
return ret; return ret;
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
} }
if (test_bit(PG_NEED_COMMIT, &req->wb_flags)) { if (test_bit(PG_CLEAN, &req->wb_flags)) {
/* This request is marked for commit */
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
nfs_clear_page_tag_locked(req); BUG();
nfs_pageio_complete(pgio);
return 0;
} }
if (nfs_set_page_writeback(page) != 0) { if (nfs_set_page_writeback(page) != 0) {
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
...@@ -391,19 +388,6 @@ nfs_mark_request_dirty(struct nfs_page *req) ...@@ -391,19 +388,6 @@ nfs_mark_request_dirty(struct nfs_page *req)
__set_page_dirty_nobuffers(req->wb_page); __set_page_dirty_nobuffers(req->wb_page);
} }
/*
* Check if a request is dirty
*/
static inline int
nfs_dirty_request(struct nfs_page *req)
{
struct page *page = req->wb_page;
if (page == NULL || test_bit(PG_NEED_COMMIT, &req->wb_flags))
return 0;
return !PageWriteback(page);
}
#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
/* /*
* Add a request to the inode's commit list. * Add a request to the inode's commit list.
...@@ -416,7 +400,7 @@ nfs_mark_request_commit(struct nfs_page *req) ...@@ -416,7 +400,7 @@ nfs_mark_request_commit(struct nfs_page *req)
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
nfsi->ncommit++; nfsi->ncommit++;
set_bit(PG_NEED_COMMIT, &(req)->wb_flags); set_bit(PG_CLEAN, &(req)->wb_flags);
radix_tree_tag_set(&nfsi->nfs_page_tree, radix_tree_tag_set(&nfsi->nfs_page_tree,
req->wb_index, req->wb_index,
NFS_PAGE_TAG_COMMIT); NFS_PAGE_TAG_COMMIT);
...@@ -426,6 +410,19 @@ nfs_mark_request_commit(struct nfs_page *req) ...@@ -426,6 +410,19 @@ nfs_mark_request_commit(struct nfs_page *req)
__mark_inode_dirty(inode, I_DIRTY_DATASYNC); __mark_inode_dirty(inode, I_DIRTY_DATASYNC);
} }
static int
nfs_clear_request_commit(struct nfs_page *req)
{
struct page *page = req->wb_page;
if (test_and_clear_bit(PG_CLEAN, &(req)->wb_flags)) {
dec_zone_page_state(page, NR_UNSTABLE_NFS);
dec_bdi_stat(page->mapping->backing_dev_info, BDI_RECLAIMABLE);
return 1;
}
return 0;
}
static inline static inline
int nfs_write_need_commit(struct nfs_write_data *data) int nfs_write_need_commit(struct nfs_write_data *data)
{ {
...@@ -435,7 +432,7 @@ int nfs_write_need_commit(struct nfs_write_data *data) ...@@ -435,7 +432,7 @@ int nfs_write_need_commit(struct nfs_write_data *data)
static inline static inline
int nfs_reschedule_unstable_write(struct nfs_page *req) int nfs_reschedule_unstable_write(struct nfs_page *req)
{ {
if (test_bit(PG_NEED_COMMIT, &req->wb_flags)) { if (test_and_clear_bit(PG_NEED_COMMIT, &req->wb_flags)) {
nfs_mark_request_commit(req); nfs_mark_request_commit(req);
return 1; return 1;
} }
...@@ -451,6 +448,12 @@ nfs_mark_request_commit(struct nfs_page *req) ...@@ -451,6 +448,12 @@ nfs_mark_request_commit(struct nfs_page *req)
{ {
} }
static inline int
nfs_clear_request_commit(struct nfs_page *req)
{
return 0;
}
static inline static inline
int nfs_write_need_commit(struct nfs_write_data *data) int nfs_write_need_commit(struct nfs_write_data *data)
{ {
...@@ -508,11 +511,8 @@ static void nfs_cancel_commit_list(struct list_head *head) ...@@ -508,11 +511,8 @@ static void nfs_cancel_commit_list(struct list_head *head)
while(!list_empty(head)) { while(!list_empty(head)) {
req = nfs_list_entry(head->next); req = nfs_list_entry(head->next);
dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
dec_bdi_stat(req->wb_page->mapping->backing_dev_info,
BDI_RECLAIMABLE);
nfs_list_remove_request(req); nfs_list_remove_request(req);
clear_bit(PG_NEED_COMMIT, &(req)->wb_flags); nfs_clear_request_commit(req);
nfs_inode_remove_request(req); nfs_inode_remove_request(req);
nfs_unlock_request(req); nfs_unlock_request(req);
} }
...@@ -584,8 +584,7 @@ static struct nfs_page *nfs_try_to_update_request(struct inode *inode, ...@@ -584,8 +584,7 @@ static struct nfs_page *nfs_try_to_update_request(struct inode *inode,
* Note: nfs_flush_incompatible() will already * Note: nfs_flush_incompatible() will already
* have flushed out requests having wrong owners. * have flushed out requests having wrong owners.
*/ */
if (!nfs_dirty_request(req) if (offset > rqend
|| offset > rqend
|| end < req->wb_offset) || end < req->wb_offset)
goto out_flushme; goto out_flushme;
...@@ -601,6 +600,10 @@ static struct nfs_page *nfs_try_to_update_request(struct inode *inode, ...@@ -601,6 +600,10 @@ static struct nfs_page *nfs_try_to_update_request(struct inode *inode,
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
} }
if (nfs_clear_request_commit(req))
radix_tree_tag_clear(&NFS_I(inode)->nfs_page_tree,
req->wb_index, NFS_PAGE_TAG_COMMIT);
/* Okay, the request matches. Update the region */ /* Okay, the request matches. Update the region */
if (offset < req->wb_offset) { if (offset < req->wb_offset) {
req->wb_offset = offset; req->wb_offset = offset;
...@@ -682,8 +685,7 @@ int nfs_flush_incompatible(struct file *file, struct page *page) ...@@ -682,8 +685,7 @@ int nfs_flush_incompatible(struct file *file, struct page *page)
req = nfs_page_find_request(page); req = nfs_page_find_request(page);
if (req == NULL) if (req == NULL)
return 0; return 0;
do_flush = req->wb_page != page || req->wb_context != ctx do_flush = req->wb_page != page || req->wb_context != ctx;
|| !nfs_dirty_request(req);
nfs_release_request(req); nfs_release_request(req);
if (!do_flush) if (!do_flush)
return 0; return 0;
...@@ -1288,10 +1290,7 @@ static void nfs_commit_release(void *calldata) ...@@ -1288,10 +1290,7 @@ static void nfs_commit_release(void *calldata)
while (!list_empty(&data->pages)) { while (!list_empty(&data->pages)) {
req = nfs_list_entry(data->pages.next); req = nfs_list_entry(data->pages.next);
nfs_list_remove_request(req); nfs_list_remove_request(req);
clear_bit(PG_NEED_COMMIT, &(req)->wb_flags); nfs_clear_request_commit(req);
dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
dec_bdi_stat(req->wb_page->mapping->backing_dev_info,
BDI_RECLAIMABLE);
dprintk("NFS: commit (%s/%lld %d@%lld)", dprintk("NFS: commit (%s/%lld %d@%lld)",
req->wb_context->path.dentry->d_inode->i_sb->s_id, req->wb_context->path.dentry->d_inode->i_sb->s_id,
...@@ -1467,7 +1466,7 @@ int nfs_wb_page_cancel(struct inode *inode, struct page *page) ...@@ -1467,7 +1466,7 @@ int nfs_wb_page_cancel(struct inode *inode, struct page *page)
req = nfs_page_find_request(page); req = nfs_page_find_request(page);
if (req == NULL) if (req == NULL)
goto out; goto out;
if (test_bit(PG_NEED_COMMIT, &req->wb_flags)) { if (test_bit(PG_CLEAN, &req->wb_flags)) {
nfs_release_request(req); nfs_release_request(req);
break; break;
} }
......
...@@ -27,9 +27,12 @@ ...@@ -27,9 +27,12 @@
/* /*
* Valid flags for a dirty buffer * Valid flags for a dirty buffer
*/ */
#define PG_BUSY 0 enum {
#define PG_NEED_COMMIT 1 PG_BUSY = 0,
#define PG_NEED_RESCHED 2 PG_CLEAN,
PG_NEED_COMMIT,
PG_NEED_RESCHED,
};
struct nfs_inode; struct nfs_inode;
struct nfs_page { struct nfs_page {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册