bool write_request)
 {
        struct rbd_img_request *img_request = obj_request->img_request;
+       struct ceph_osd_request *osd_req = obj_request->osd_req;
+       struct ceph_osd_data *osd_data = NULL;
        struct ceph_snap_context *snapc = NULL;
        u64 snap_id = CEPH_NOSNAP;
        struct timespec *mtime = NULL;
        struct timespec now;
 
-       rbd_assert(obj_request->osd_req != NULL);
+       rbd_assert(osd_req != NULL);
 
        if (write_request) {
+               osd_data = &osd_req->r_data_out;
                now = CURRENT_TIME;
                mtime = &now;
                if (img_request)
                        snapc = img_request->snapc;
-       } else if (img_request) {
-               snap_id = img_request->snap_id;
+       } else {
+               osd_data = &osd_req->r_data_in;
+               if (img_request)
+                       snap_id = img_request->snap_id;
        }
+       if (obj_request->type != OBJ_REQUEST_NODATA) {
+               struct ceph_osd_req_op *op = &obj_request->osd_req->r_ops[0];
 
-       ceph_osdc_build_request(obj_request->osd_req, obj_request->offset,
+               /*
+                * If it has data, it's either a object class method
+                * call (cls) or it's an extent operation.
+                */
+               if (op->op == CEPH_OSD_OP_CALL)
+                       osd_req_op_cls_response_data(op, osd_data);
+               else
+                       osd_req_op_extent_osd_data(op, osd_data);
+       }
+       ceph_osdc_build_request(osd_req, obj_request->offset,
                        snapc, snap_id, mtime);
 }
 
 
                }
                pages[i] = page;
        }
-       ceph_osd_data_pages_init(&req->r_data_in, pages, len, 0,
+       BUG_ON(req->r_ops[0].extent.osd_data != &req->r_data_in);
+       ceph_osd_data_pages_init(req->r_ops[0].extent.osd_data, pages, len, 0,
                                        false, false);
        req->r_callback = finish_read;
        req->r_inode = inode;
                dout("writepages got %d pages at %llu~%llu\n",
                     locked_pages, offset, len);
 
-               ceph_osd_data_pages_init(&req->r_data_out, pages, len, 0,
-                                               !!pool, false);
+               BUG_ON(req->r_ops[0].extent.osd_data != &req->r_data_out);
+               ceph_osd_data_pages_init(req->r_ops[0].extent.osd_data, pages,
+                                               len, 0, !!pool, false);
 
                pages = NULL;   /* request message now owns the pages array */
                pool = NULL;
 
                        own_pages = true;
                }
        }
-       ceph_osd_data_pages_init(&req->r_data_out, pages, len, page_align,
-                                       false, own_pages);
+       BUG_ON(req->r_ops[0].extent.osd_data != &req->r_data_out);
+       ceph_osd_data_pages_init(req->r_ops[0].extent.osd_data, pages, len,
+                                       page_align, false, own_pages);
 
        /* BUG_ON(vino.snap != CEPH_NOSNAP); */
        ceph_osdc_build_request(req, pos, snapc, vino.snap, &mtime);
 
                        u64 offset, length;
                        u64 truncate_size;
                        u32 truncate_seq;
+                       struct ceph_osd_data *osd_data;
                } extent;
                struct {
                        const char *class_name;
                        const char *method_name;
                        const void *request_data;
                        u32 request_data_len;
+                       struct ceph_osd_data *response_data;
                        __u8 class_len;
                        __u8 method_len;
                        __u8 argc;
                                        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_extent_osd_data(struct ceph_osd_req_op *op,
+                                       struct ceph_osd_data *osd_data);
 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,
                                        size_t request_data_size);
+extern void osd_req_op_cls_response_data(struct ceph_osd_req_op *op,
+                                       struct ceph_osd_data *response_data);
 extern void osd_req_op_watch_init(struct ceph_osd_req_op *op, u16 opcode,
                                        u64 cookie, u64 version, int flag);
 
 
 }
 EXPORT_SYMBOL(osd_req_op_extent_update);
 
+void osd_req_op_extent_osd_data(struct ceph_osd_req_op *op,
+                               struct ceph_osd_data *osd_data)
+{
+       op->extent.osd_data = osd_data;
+}
+EXPORT_SYMBOL(osd_req_op_extent_osd_data);
+
 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)
 }
 EXPORT_SYMBOL(osd_req_op_cls_init);
 
+void osd_req_op_cls_response_data(struct ceph_osd_req_op *op,
+                               struct ceph_osd_data *response_data)
+{
+       op->cls.response_data = response_data;
+}
+EXPORT_SYMBOL(osd_req_op_cls_response_data);
+
 void osd_req_op_watch_init(struct ceph_osd_req_op *op, u16 opcode,
                                u64 cookie, u64 version, int flag)
 {
                        cpu_to_le64(src->extent.truncate_size);
                dst->extent.truncate_seq =
                        cpu_to_le32(src->extent.truncate_seq);
+               if (src->op == CEPH_OSD_OP_WRITE)
+                       WARN_ON(src->extent.osd_data != &req->r_data_out);
+               else
+                       WARN_ON(src->extent.osd_data != &req->r_data_in);
                break;
        case CEPH_OSD_OP_CALL:
                pagelist = kmalloc(sizeof (*pagelist), GFP_NOFS);
                                     src->cls.method_len);
                ceph_pagelist_append(pagelist, src->cls.request_data,
                                     src->cls.request_data_len);
-
                ceph_osd_data_pagelist_init(&req->r_data_out, pagelist);
+
+               WARN_ON(src->cls.response_data != &req->r_data_in);
                request_data_len = pagelist->length;
                break;
        case CEPH_OSD_OP_STARTSYNC:
                                               bool use_mempool)
 {
        struct ceph_osd_request *req;
+       struct ceph_osd_data *osd_data;
        struct ceph_osd_req_op *op;
        u64 objnum = 0;
        u64 objoff = 0;
                                        GFP_NOFS);
        if (!req)
                return ERR_PTR(-ENOMEM);
+       osd_data = opcode == CEPH_OSD_OP_WRITE ? &req->r_data_out
+                                              : &req->r_data_in;
 
        req->r_flags = flags;
 
        op = &req->r_ops[0];
        osd_req_op_extent_init(op, opcode, objoff, objlen,
                                truncate_size, truncate_seq);
+       osd_req_op_extent_osd_data(op, osd_data);
+
        /*
         * A second op in the ops array means the caller wants to
         * also issue a include a 'startsync' command so that the