summaryrefslogtreecommitdiffstats
path: root/fs/nfs/write.c
diff options
context:
space:
mode:
authorTrond Myklebust <trond.myklebust@primarydata.com>2017-07-18 15:22:12 -0400
committerTrond Myklebust <trond.myklebust@primarydata.com>2017-08-15 11:54:47 -0400
commitb66aaa8dfeda7b5c7df513cf3b36e1290fa84055 (patch)
tree1e998c046a8313506772867245816cc5c1a38d48 /fs/nfs/write.c
parent31a01f093edbc687e783a4c8adcd76d3cc91a559 (diff)
NFS: Fix the inode request accounting when pages have subrequests
Both nfs_destroy_unlinked_subrequests() and nfs_lock_and_join_requests() manipulate the inode flags adjusting the NFS_I(inode)->nrequests. Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Diffstat (limited to 'fs/nfs/write.c')
-rw-r--r--fs/nfs/write.c27
1 files changed, 15 insertions, 12 deletions
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index bb38c881fc48..ee981353d4aa 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -418,7 +418,8 @@ nfs_unroll_locks_and_wait(struct inode *inode, struct nfs_page *head,
418 */ 418 */
419static void 419static void
420nfs_destroy_unlinked_subrequests(struct nfs_page *destroy_list, 420nfs_destroy_unlinked_subrequests(struct nfs_page *destroy_list,
421 struct nfs_page *old_head) 421 struct nfs_page *old_head,
422 struct inode *inode)
422{ 423{
423 while (destroy_list) { 424 while (destroy_list) {
424 struct nfs_page *subreq = destroy_list; 425 struct nfs_page *subreq = destroy_list;
@@ -443,9 +444,12 @@ nfs_destroy_unlinked_subrequests(struct nfs_page *destroy_list,
443 nfs_page_group_clear_bits(subreq); 444 nfs_page_group_clear_bits(subreq);
444 445
445 /* release the PG_INODE_REF reference */ 446 /* release the PG_INODE_REF reference */
446 if (test_and_clear_bit(PG_INODE_REF, &subreq->wb_flags)) 447 if (test_and_clear_bit(PG_INODE_REF, &subreq->wb_flags)) {
447 nfs_release_request(subreq); 448 nfs_release_request(subreq);
448 else 449 spin_lock(&inode->i_lock);
450 NFS_I(inode)->nrequests--;
451 spin_unlock(&inode->i_lock);
452 } else
449 WARN_ON_ONCE(1); 453 WARN_ON_ONCE(1);
450 } else { 454 } else {
451 WARN_ON_ONCE(test_bit(PG_CLEAN, &subreq->wb_flags)); 455 WARN_ON_ONCE(test_bit(PG_CLEAN, &subreq->wb_flags));
@@ -572,25 +576,24 @@ try_again:
572 head->wb_bytes = total_bytes; 576 head->wb_bytes = total_bytes;
573 } 577 }
574 578
579 /* Postpone destruction of this request */
580 if (test_and_clear_bit(PG_REMOVE, &head->wb_flags)) {
581 set_bit(PG_INODE_REF, &head->wb_flags);
582 kref_get(&head->wb_kref);
583 NFS_I(inode)->nrequests++;
584 }
585
575 /* 586 /*
576 * prepare head request to be added to new pgio descriptor 587 * prepare head request to be added to new pgio descriptor
577 */ 588 */
578 nfs_page_group_clear_bits(head); 589 nfs_page_group_clear_bits(head);
579 590
580 /*
581 * some part of the group was still on the inode list - otherwise
582 * the group wouldn't be involved in async write.
583 * grab a reference for the head request, iff it needs one.
584 */
585 if (!test_and_set_bit(PG_INODE_REF, &head->wb_flags))
586 kref_get(&head->wb_kref);
587
588 nfs_page_group_unlock(head); 591 nfs_page_group_unlock(head);
589 592
590 /* drop lock to clean uprequests on destroy list */ 593 /* drop lock to clean uprequests on destroy list */
591 spin_unlock(&inode->i_lock); 594 spin_unlock(&inode->i_lock);
592 595
593 nfs_destroy_unlinked_subrequests(destroy_list, head); 596 nfs_destroy_unlinked_subrequests(destroy_list, head, inode);
594 597
595 /* still holds ref on head from nfs_page_find_head_request_locked 598 /* still holds ref on head from nfs_page_find_head_request_locked
596 * and still has lock on head from lock loop */ 599 * and still has lock on head from lock loop */