aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--fs/ceph/addr.c59
-rw-r--r--include/linux/ceph/osd_client.h1
-rw-r--r--net/ceph/osd_client.c13
3 files changed, 47 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);
diff --git a/include/linux/ceph/osd_client.h b/include/linux/ceph/osd_client.h
index ffaf9076fdc4..5ee1a3776b4b 100644
--- a/include/linux/ceph/osd_client.h
+++ b/include/linux/ceph/osd_client.h
@@ -234,6 +234,7 @@ extern void osd_req_op_init(struct ceph_osd_req_op *op, u16 opcode);
234extern void osd_req_op_extent_init(struct ceph_osd_req_op *op, u16 opcode, 234extern void osd_req_op_extent_init(struct ceph_osd_req_op *op, u16 opcode,
235 u64 offset, u64 length, 235 u64 offset, u64 length,
236 u64 truncate_size, u32 truncate_seq); 236 u64 truncate_size, u32 truncate_seq);
237extern void osd_req_op_extent_update(struct ceph_osd_req_op *op, u64 length);
237extern void osd_req_op_cls_init(struct ceph_osd_req_op *op, u16 opcode, 238extern void osd_req_op_cls_init(struct ceph_osd_req_op *op, u16 opcode,
238 const char *class, const char *method, 239 const char *class, const char *method,
239 const void *request_data, 240 const void *request_data,
diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c
index 9ca693d0df19..426ca1f2a721 100644
--- a/net/ceph/osd_client.c
+++ b/net/ceph/osd_client.c
@@ -296,6 +296,19 @@ void osd_req_op_extent_init(struct ceph_osd_req_op *op, u16 opcode,
296} 296}
297EXPORT_SYMBOL(osd_req_op_extent_init); 297EXPORT_SYMBOL(osd_req_op_extent_init);
298 298
299void osd_req_op_extent_update(struct ceph_osd_req_op *op, u64 length)
300{
301 u64 previous = op->extent.length;
302
303 if (length == previous)
304 return; /* Nothing to do */
305 BUG_ON(length > previous);
306
307 op->extent.length = length;
308 op->payload_len -= previous - length;
309}
310EXPORT_SYMBOL(osd_req_op_extent_update);
311
299void osd_req_op_cls_init(struct ceph_osd_req_op *op, u16 opcode, 312void osd_req_op_cls_init(struct ceph_osd_req_op *op, u16 opcode,
300 const char *class, const char *method, 313 const char *class, const char *method,
301 const void *request_data, size_t request_data_size) 314 const void *request_data, size_t request_data_size)