summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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 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);
diff --git a/include/linux/ceph/osd_client.h b/include/linux/ceph/osd_client.h
index ffaf9076fdc..5ee1a3776b4 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);
extern void osd_req_op_extent_init(struct ceph_osd_req_op *op, u16 opcode,
u64 offset, u64 length,
u64 truncate_size, u32 truncate_seq);
+extern void osd_req_op_extent_update(struct ceph_osd_req_op *op, u64 length);
extern void osd_req_op_cls_init(struct ceph_osd_req_op *op, u16 opcode,
const char *class, const char *method,
const void *request_data,
diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c
index 9ca693d0df1..426ca1f2a72 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,
}
EXPORT_SYMBOL(osd_req_op_extent_init);
+void osd_req_op_extent_update(struct ceph_osd_req_op *op, u64 length)
+{
+ u64 previous = op->extent.length;
+
+ if (length == previous)
+ return; /* Nothing to do */
+ BUG_ON(length > previous);
+
+ op->extent.length = length;
+ op->payload_len -= previous - length;
+}
+EXPORT_SYMBOL(osd_req_op_extent_update);
+
void osd_req_op_cls_init(struct ceph_osd_req_op *op, u16 opcode,
const char *class, const char *method,
const void *request_data, size_t request_data_size)