aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorAlex Elder <elder@inktank.com>2013-03-14 15:09:05 -0400
committerSage Weil <sage@inktank.com>2013-05-02 00:18:02 -0400
commite5975c7c8eb6aeab8d2f76a98c368081082795e0 (patch)
tree438c42affdf77297070e981eba8a96ff0ee3bbdb /fs
parent02ee07d3002e6c0b0c4ea1982cd7e6aeca203ed6 (diff)
ceph: build osd request message later for writepages
Hold off building the osd request message in ceph_writepages_start() until just before it will be submitted to the osd client for execution. We'll still create the request and allocate the page pointer array after we learn we have at least one page to write. A local variable will be used to keep track of the allocated array of pages. Wait until just before submitting the request for assigning that page array pointer to the request message. Create ands use a new function osd_req_op_extent_update() whose purpose is to serve this one spot where the length value supplied when an osd request's op was initially formatted might need to get changed (reduced, never increased) before submitting the request. Previously, ceph_writepages_start() assigned the message header's data length because of this update. That's no longer necessary, because ceph_osdc_build_request() will recalculate the right value to use based on the content of the ops in the request. Signed-off-by: Alex Elder <elder@inktank.com> Reviewed-by: Josh Durgin <josh.durgin@inktank.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/ceph/addr.c59
1 files changed, 33 insertions, 26 deletions
diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c
index 0a3d2ce89660..5d8ce79385ed 100644
--- a/fs/ceph/addr.c
+++ b/fs/ceph/addr.c
@@ -737,10 +737,14 @@ retry:
737 737
738 while (!done && index <= end) { 738 while (!done && index <= end) {
739 struct ceph_osd_req_op ops[2]; 739 struct ceph_osd_req_op ops[2];
740 int num_ops = do_sync ? 2 : 1;
741 struct ceph_vino vino;
740 unsigned i; 742 unsigned i;
741 int first; 743 int first;
742 pgoff_t next; 744 pgoff_t next;
743 int pvec_pages, locked_pages; 745 int pvec_pages, locked_pages;
746 struct page **pages = NULL;
747 mempool_t *pool = NULL; /* Becomes non-null if mempool used */
744 struct page *page; 748 struct page *page;
745 int want; 749 int want;
746 u64 offset, len; 750 u64 offset, len;
@@ -824,16 +828,19 @@ get_more_pages:
824 break; 828 break;
825 } 829 }
826 830
827 /* ok */ 831 /*
832 * We have something to write. If this is
833 * the first locked page this time through,
834 * allocate an osd request and a page array
835 * that it will use.
836 */
828 if (locked_pages == 0) { 837 if (locked_pages == 0) {
829 struct ceph_vino vino;
830 int num_ops = do_sync ? 2 : 1;
831 size_t size; 838 size_t size;
832 struct page **pages; 839
833 mempool_t *pool = NULL; 840 BUG_ON(pages);
834 841
835 /* prepare async write request */ 842 /* prepare async write request */
836 offset = (u64) page_offset(page); 843 offset = (u64)page_offset(page);
837 len = wsize; 844 len = wsize;
838 req = ceph_writepages_osd_request(inode, 845 req = ceph_writepages_osd_request(inode,
839 offset, &len, snapc, 846 offset, &len, snapc,
@@ -845,11 +852,6 @@ get_more_pages:
845 break; 852 break;
846 } 853 }
847 854
848 vino = ceph_vino(inode);
849 ceph_osdc_build_request(req, offset,
850 num_ops, ops, snapc, vino.snap,
851 &inode->i_mtime);
852
853 req->r_callback = writepages_finish; 855 req->r_callback = writepages_finish;
854 req->r_inode = inode; 856 req->r_inode = inode;
855 857
@@ -858,16 +860,9 @@ get_more_pages:
858 pages = kmalloc(size, GFP_NOFS); 860 pages = kmalloc(size, GFP_NOFS);
859 if (!pages) { 861 if (!pages) {
860 pool = fsc->wb_pagevec_pool; 862 pool = fsc->wb_pagevec_pool;
861
862 pages = mempool_alloc(pool, GFP_NOFS); 863 pages = mempool_alloc(pool, GFP_NOFS);
863 WARN_ON(!pages); 864 BUG_ON(!pages);
864 } 865 }
865
866 req->r_data_out.pages = pages;
867 req->r_data_out.pages_from_pool = !!pool;
868 req->r_data_out.type = CEPH_OSD_DATA_TYPE_PAGES;
869 req->r_data_out.length = len;
870 req->r_data_out.alignment = 0;
871 } 866 }
872 867
873 /* note position of first page in pvec */ 868 /* note position of first page in pvec */
@@ -885,7 +880,7 @@ get_more_pages:
885 } 880 }
886 881
887 set_page_writeback(page); 882 set_page_writeback(page);
888 req->r_data_out.pages[locked_pages] = page; 883 pages[locked_pages] = page;
889 locked_pages++; 884 locked_pages++;
890 next = page->index + 1; 885 next = page->index + 1;
891 } 886 }
@@ -914,18 +909,30 @@ get_more_pages:
914 pvec.nr -= i-first; 909 pvec.nr -= i-first;
915 } 910 }
916 911
917 /* submit the write */ 912 /* Format the osd request message and submit the write */
918 offset = page_offset(req->r_data_out.pages[0]); 913
914 offset = page_offset(pages[0]);
919 len = min((snap_size ? snap_size : i_size_read(inode)) - offset, 915 len = min((snap_size ? snap_size : i_size_read(inode)) - offset,
920 (u64)locked_pages << PAGE_CACHE_SHIFT); 916 (u64)locked_pages << PAGE_CACHE_SHIFT);
921 dout("writepages got %d pages at %llu~%llu\n", 917 dout("writepages got %d pages at %llu~%llu\n",
922 locked_pages, offset, len); 918 locked_pages, offset, len);
923 919
924 /* revise final length, page count */ 920 req->r_data_out.type = CEPH_OSD_DATA_TYPE_PAGES;
921 req->r_data_out.pages = pages;
925 req->r_data_out.length = len; 922 req->r_data_out.length = len;
926 req->r_request_ops[0].extent.length = cpu_to_le64(len); 923 req->r_data_out.alignment = 0;
927 req->r_request_ops[0].payload_len = cpu_to_le32(len); 924 req->r_data_out.pages_from_pool = !!pool;
928 req->r_request->hdr.data_len = cpu_to_le32(len); 925
926 pages = NULL; /* request message now owns the pages array */
927 pool = NULL;
928
929 /* Update the write op length in case we changed it */
930
931 osd_req_op_extent_update(&ops[0], len);
932
933 vino = ceph_vino(inode);
934 ceph_osdc_build_request(req, offset, num_ops, ops,
935 snapc, vino.snap, &inode->i_mtime);
929 936
930 rc = ceph_osdc_start_request(&fsc->client->osdc, req, true); 937 rc = ceph_osdc_start_request(&fsc->client->osdc, req, true);
931 BUG_ON(rc); 938 BUG_ON(rc);