aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/write.c
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2008-06-13 13:25:22 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2008-07-09 12:09:24 -0400
commite468bae97d243fe0e1515abaa1f7d0edf1476ad0 (patch)
tree42bbbfe8d6dfc60bcaaaa1a7164ba75dc1060050 /fs/nfs/write.c
parente7d39069e387a12d4c57f4067d9f48c1d29ea900 (diff)
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: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/write.c')
-rw-r--r--fs/nfs/write.c65
1 files changed, 32 insertions, 33 deletions
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 04f51e52e184..feca8c648766 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -242,12 +242,9 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio,
242 return ret; 242 return ret;
243 spin_lock(&inode->i_lock); 243 spin_lock(&inode->i_lock);
244 } 244 }
245 if (test_bit(PG_NEED_COMMIT, &req->wb_flags)) { 245 if (test_bit(PG_CLEAN, &req->wb_flags)) {
246 /* This request is marked for commit */
247 spin_unlock(&inode->i_lock); 246 spin_unlock(&inode->i_lock);
248 nfs_clear_page_tag_locked(req); 247 BUG();
249 nfs_pageio_complete(pgio);
250 return 0;
251 } 248 }
252 if (nfs_set_page_writeback(page) != 0) { 249 if (nfs_set_page_writeback(page) != 0) {
253 spin_unlock(&inode->i_lock); 250 spin_unlock(&inode->i_lock);
@@ -391,19 +388,6 @@ nfs_mark_request_dirty(struct nfs_page *req)
391 __set_page_dirty_nobuffers(req->wb_page); 388 __set_page_dirty_nobuffers(req->wb_page);
392} 389}
393 390
394/*
395 * Check if a request is dirty
396 */
397static inline int
398nfs_dirty_request(struct nfs_page *req)
399{
400 struct page *page = req->wb_page;
401
402 if (page == NULL || test_bit(PG_NEED_COMMIT, &req->wb_flags))
403 return 0;
404 return !PageWriteback(page);
405}
406
407#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) 391#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
408/* 392/*
409 * Add a request to the inode's commit list. 393 * Add a request to the inode's commit list.
@@ -416,7 +400,7 @@ nfs_mark_request_commit(struct nfs_page *req)
416 400
417 spin_lock(&inode->i_lock); 401 spin_lock(&inode->i_lock);
418 nfsi->ncommit++; 402 nfsi->ncommit++;
419 set_bit(PG_NEED_COMMIT, &(req)->wb_flags); 403 set_bit(PG_CLEAN, &(req)->wb_flags);
420 radix_tree_tag_set(&nfsi->nfs_page_tree, 404 radix_tree_tag_set(&nfsi->nfs_page_tree,
421 req->wb_index, 405 req->wb_index,
422 NFS_PAGE_TAG_COMMIT); 406 NFS_PAGE_TAG_COMMIT);
@@ -426,6 +410,19 @@ nfs_mark_request_commit(struct nfs_page *req)
426 __mark_inode_dirty(inode, I_DIRTY_DATASYNC); 410 __mark_inode_dirty(inode, I_DIRTY_DATASYNC);
427} 411}
428 412
413static int
414nfs_clear_request_commit(struct nfs_page *req)
415{
416 struct page *page = req->wb_page;
417
418 if (test_and_clear_bit(PG_CLEAN, &(req)->wb_flags)) {
419 dec_zone_page_state(page, NR_UNSTABLE_NFS);
420 dec_bdi_stat(page->mapping->backing_dev_info, BDI_RECLAIMABLE);
421 return 1;
422 }
423 return 0;
424}
425
429static inline 426static inline
430int nfs_write_need_commit(struct nfs_write_data *data) 427int nfs_write_need_commit(struct nfs_write_data *data)
431{ 428{
@@ -435,7 +432,7 @@ int nfs_write_need_commit(struct nfs_write_data *data)
435static inline 432static inline
436int nfs_reschedule_unstable_write(struct nfs_page *req) 433int nfs_reschedule_unstable_write(struct nfs_page *req)
437{ 434{
438 if (test_bit(PG_NEED_COMMIT, &req->wb_flags)) { 435 if (test_and_clear_bit(PG_NEED_COMMIT, &req->wb_flags)) {
439 nfs_mark_request_commit(req); 436 nfs_mark_request_commit(req);
440 return 1; 437 return 1;
441 } 438 }
@@ -451,6 +448,12 @@ nfs_mark_request_commit(struct nfs_page *req)
451{ 448{
452} 449}
453 450
451static inline int
452nfs_clear_request_commit(struct nfs_page *req)
453{
454 return 0;
455}
456
454static inline 457static inline
455int nfs_write_need_commit(struct nfs_write_data *data) 458int nfs_write_need_commit(struct nfs_write_data *data)
456{ 459{
@@ -508,11 +511,8 @@ static void nfs_cancel_commit_list(struct list_head *head)
508 511
509 while(!list_empty(head)) { 512 while(!list_empty(head)) {
510 req = nfs_list_entry(head->next); 513 req = nfs_list_entry(head->next);
511 dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
512 dec_bdi_stat(req->wb_page->mapping->backing_dev_info,
513 BDI_RECLAIMABLE);
514 nfs_list_remove_request(req); 514 nfs_list_remove_request(req);
515 clear_bit(PG_NEED_COMMIT, &(req)->wb_flags); 515 nfs_clear_request_commit(req);
516 nfs_inode_remove_request(req); 516 nfs_inode_remove_request(req);
517 nfs_unlock_request(req); 517 nfs_unlock_request(req);
518 } 518 }
@@ -584,8 +584,7 @@ static struct nfs_page *nfs_try_to_update_request(struct inode *inode,
584 * Note: nfs_flush_incompatible() will already 584 * Note: nfs_flush_incompatible() will already
585 * have flushed out requests having wrong owners. 585 * have flushed out requests having wrong owners.
586 */ 586 */
587 if (!nfs_dirty_request(req) 587 if (offset > rqend
588 || offset > rqend
589 || end < req->wb_offset) 588 || end < req->wb_offset)
590 goto out_flushme; 589 goto out_flushme;
591 590
@@ -601,6 +600,10 @@ static struct nfs_page *nfs_try_to_update_request(struct inode *inode,
601 spin_lock(&inode->i_lock); 600 spin_lock(&inode->i_lock);
602 } 601 }
603 602
603 if (nfs_clear_request_commit(req))
604 radix_tree_tag_clear(&NFS_I(inode)->nfs_page_tree,
605 req->wb_index, NFS_PAGE_TAG_COMMIT);
606
604 /* Okay, the request matches. Update the region */ 607 /* Okay, the request matches. Update the region */
605 if (offset < req->wb_offset) { 608 if (offset < req->wb_offset) {
606 req->wb_offset = offset; 609 req->wb_offset = offset;
@@ -682,8 +685,7 @@ int nfs_flush_incompatible(struct file *file, struct page *page)
682 req = nfs_page_find_request(page); 685 req = nfs_page_find_request(page);
683 if (req == NULL) 686 if (req == NULL)
684 return 0; 687 return 0;
685 do_flush = req->wb_page != page || req->wb_context != ctx 688 do_flush = req->wb_page != page || req->wb_context != ctx;
686 || !nfs_dirty_request(req);
687 nfs_release_request(req); 689 nfs_release_request(req);
688 if (!do_flush) 690 if (!do_flush)
689 return 0; 691 return 0;
@@ -1288,10 +1290,7 @@ static void nfs_commit_release(void *calldata)
1288 while (!list_empty(&data->pages)) { 1290 while (!list_empty(&data->pages)) {
1289 req = nfs_list_entry(data->pages.next); 1291 req = nfs_list_entry(data->pages.next);
1290 nfs_list_remove_request(req); 1292 nfs_list_remove_request(req);
1291 clear_bit(PG_NEED_COMMIT, &(req)->wb_flags); 1293 nfs_clear_request_commit(req);
1292 dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
1293 dec_bdi_stat(req->wb_page->mapping->backing_dev_info,
1294 BDI_RECLAIMABLE);
1295 1294
1296 dprintk("NFS: commit (%s/%lld %d@%lld)", 1295 dprintk("NFS: commit (%s/%lld %d@%lld)",
1297 req->wb_context->path.dentry->d_inode->i_sb->s_id, 1296 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 req = nfs_page_find_request(page); 1466 req = nfs_page_find_request(page);
1468 if (req == NULL) 1467 if (req == NULL)
1469 goto out; 1468 goto out;
1470 if (test_bit(PG_NEED_COMMIT, &req->wb_flags)) { 1469 if (test_bit(PG_CLEAN, &req->wb_flags)) {
1471 nfs_release_request(req); 1470 nfs_release_request(req);
1472 break; 1471 break;
1473 } 1472 }