summaryrefslogtreecommitdiff
path: root/fs/ceph
diff options
context:
space:
mode:
authorAlex Elder <elder@inktank.com>2013-03-14 14:09:05 -0500
committerSage Weil <sage@inktank.com>2013-05-01 21:18:02 -0700
commite5975c7c8eb6aeab8d2f76a98c368081082795e0 (patch)
tree438c42affdf77297070e981eba8a96ff0ee3bbdb /fs/ceph
parent02ee07d3002e6c0b0c4ea1982cd7e6aeca203ed6 (diff)
downloadlinux-3.10-e5975c7c8eb6aeab8d2f76a98c368081082795e0.tar.gz
linux-3.10-e5975c7c8eb6aeab8d2f76a98c368081082795e0.tar.bz2
linux-3.10-e5975c7c8eb6aeab8d2f76a98c368081082795e0.zip
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/ceph')
-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 0a3d2ce8966..5d8ce79385e 100644
--- a/fs/ceph/addr.c
+++ b/fs/ceph/addr.c
@@ -737,10 +737,14 @@ retry:
while (!done && index <= end) {
struct ceph_osd_req_op ops[2];
+ int num_ops = do_sync ? 2 : 1;
+ struct ceph_vino vino;
unsigned i;
int first;
pgoff_t next;
int pvec_pages, locked_pages;
+ struct page **pages = NULL;
+ mempool_t *pool = NULL; /* Becomes non-null if mempool used */
struct page *page;
int want;
u64 offset, len;
@@ -824,16 +828,19 @@ get_more_pages:
break;
}
- /* ok */
+ /*
+ * We have something to write. If this is
+ * the first locked page this time through,
+ * allocate an osd request and a page array
+ * that it will use.
+ */
if (locked_pages == 0) {
- struct ceph_vino vino;
- int num_ops = do_sync ? 2 : 1;
size_t size;
- struct page **pages;
- mempool_t *pool = NULL;
+
+ BUG_ON(pages);
/* prepare async write request */
- offset = (u64) page_offset(page);
+ offset = (u64)page_offset(page);
len = wsize;
req = ceph_writepages_osd_request(inode,
offset, &len, snapc,
@@ -845,11 +852,6 @@ get_more_pages:
break;
}
- vino = ceph_vino(inode);
- ceph_osdc_build_request(req, offset,
- num_ops, ops, snapc, vino.snap,
- &inode->i_mtime);
-
req->r_callback = writepages_finish;
req->r_inode = inode;
@@ -858,16 +860,9 @@ get_more_pages:
pages = kmalloc(size, GFP_NOFS);
if (!pages) {
pool = fsc->wb_pagevec_pool;
-
pages = mempool_alloc(pool, GFP_NOFS);
- WARN_ON(!pages);
+ BUG_ON(!pages);
}
-
- req->r_data_out.pages = pages;
- req->r_data_out.pages_from_pool = !!pool;
- req->r_data_out.type = CEPH_OSD_DATA_TYPE_PAGES;
- req->r_data_out.length = len;
- req->r_data_out.alignment = 0;
}
/* note position of first page in pvec */
@@ -885,7 +880,7 @@ get_more_pages:
}
set_page_writeback(page);
- req->r_data_out.pages[locked_pages] = page;
+ pages[locked_pages] = page;
locked_pages++;
next = page->index + 1;
}
@@ -914,18 +909,30 @@ get_more_pages:
pvec.nr -= i-first;
}
- /* submit the write */
- offset = page_offset(req->r_data_out.pages[0]);
+ /* Format the osd request message and submit the write */
+
+ offset = page_offset(pages[0]);
len = min((snap_size ? snap_size : i_size_read(inode)) - offset,
(u64)locked_pages << PAGE_CACHE_SHIFT);
dout("writepages got %d pages at %llu~%llu\n",
locked_pages, offset, len);
- /* revise final length, page count */
+ req->r_data_out.type = CEPH_OSD_DATA_TYPE_PAGES;
+ req->r_data_out.pages = pages;
req->r_data_out.length = len;
- req->r_request_ops[0].extent.length = cpu_to_le64(len);
- req->r_request_ops[0].payload_len = cpu_to_le32(len);
- req->r_request->hdr.data_len = cpu_to_le32(len);
+ req->r_data_out.alignment = 0;
+ req->r_data_out.pages_from_pool = !!pool;
+
+ pages = NULL; /* request message now owns the pages array */
+ pool = NULL;
+
+ /* Update the write op length in case we changed it */
+
+ osd_req_op_extent_update(&ops[0], len);
+
+ vino = ceph_vino(inode);
+ ceph_osdc_build_request(req, offset, num_ops, ops,
+ snapc, vino.snap, &inode->i_mtime);
rc = ceph_osdc_start_request(&fsc->client->osdc, req, true);
BUG_ON(rc);