Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

nfs: page group syncing in write path

Operations that modify state for a whole page must be syncronized across
all requests within a page group. In the write path, this is calling
end_page_writeback and removing the head request from an inode.
Both of these operations should not be called until all requests
in a page group have reached the point where they would call them.

This patch should have no effect yet since all page groups currently
have one request, but will come into play when pg_test functions are
modified to split pages into sub-page regions.

Signed-off-by: Weston Andros Adamson <dros@primarydata.com>
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>

authored by

Weston Andros Adamson and committed by
Trond Myklebust
20633f04 67d0338e

+24 -12
+2
fs/nfs/pagelist.c
··· 397 397 WARN_ON_ONCE(test_bit(PG_TEARDOWN, &req->wb_flags)); 398 398 WARN_ON_ONCE(test_bit(PG_UNLOCKPAGE, &req->wb_flags)); 399 399 WARN_ON_ONCE(test_bit(PG_UPTODATE, &req->wb_flags)); 400 + WARN_ON_ONCE(test_bit(PG_WB_END, &req->wb_flags)); 401 + WARN_ON_ONCE(test_bit(PG_REMOVE, &req->wb_flags)); 400 402 401 403 /* Release struct file and open context */ 402 404 nfs_clear_request(req);
+20 -12
fs/nfs/write.c
··· 201 201 } 202 202 } 203 203 204 - static void nfs_end_page_writeback(struct page *page) 204 + static void nfs_end_page_writeback(struct nfs_page *req) 205 205 { 206 - struct inode *inode = page_file_mapping(page)->host; 206 + struct inode *inode = page_file_mapping(req->wb_page)->host; 207 207 struct nfs_server *nfss = NFS_SERVER(inode); 208 208 209 - end_page_writeback(page); 209 + if (!nfs_page_group_sync_on_bit(req, PG_WB_END)) 210 + return; 211 + 212 + end_page_writeback(req->wb_page); 210 213 if (atomic_long_dec_return(&nfss->writeback) < NFS_CONGESTION_OFF_THRESH) 211 214 clear_bdi_congested(&nfss->backing_dev_info, BLK_RW_ASYNC); 212 215 } ··· 400 397 { 401 398 struct inode *inode = req->wb_context->dentry->d_inode; 402 399 struct nfs_inode *nfsi = NFS_I(inode); 400 + struct nfs_page *head; 403 401 404 - spin_lock(&inode->i_lock); 405 - if (likely(!PageSwapCache(req->wb_page))) { 406 - set_page_private(req->wb_page, 0); 407 - ClearPagePrivate(req->wb_page); 408 - clear_bit(PG_MAPPED, &req->wb_flags); 402 + if (nfs_page_group_sync_on_bit(req, PG_REMOVE)) { 403 + head = req->wb_head; 404 + 405 + spin_lock(&inode->i_lock); 406 + if (likely(!PageSwapCache(head->wb_page))) { 407 + set_page_private(head->wb_page, 0); 408 + ClearPagePrivate(head->wb_page); 409 + clear_bit(PG_MAPPED, &head->wb_flags); 410 + } 411 + nfsi->npages--; 412 + spin_unlock(&inode->i_lock); 409 413 } 410 - nfsi->npages--; 411 - spin_unlock(&inode->i_lock); 412 414 nfs_release_request(req); 413 415 } 414 416 ··· 607 599 nfs_inode_remove_request(req); 608 600 next: 609 601 nfs_unlock_request(req); 610 - nfs_end_page_writeback(req->wb_page); 602 + nfs_end_page_writeback(req); 611 603 do_destroy = !test_bit(NFS_IOHDR_NEED_COMMIT, &hdr->flags); 612 604 nfs_release_request(req); 613 605 } ··· 972 964 { 973 965 nfs_mark_request_dirty(req); 974 966 nfs_unlock_request(req); 975 - nfs_end_page_writeback(req->wb_page); 967 + nfs_end_page_writeback(req); 976 968 nfs_release_request(req); 977 969 } 978 970
+2
include/linux/nfs_page.h
··· 31 31 PG_TEARDOWN, /* page group sync for destroy */ 32 32 PG_UNLOCKPAGE, /* page group sync bit in read path */ 33 33 PG_UPTODATE, /* page group sync bit in read path */ 34 + PG_WB_END, /* page group sync bit in write path */ 35 + PG_REMOVE, /* page group sync bit in write path */ 34 36 }; 35 37 36 38 struct nfs_inode;