+
+ OBD_ALLOC_PTR_ARRAY(update_bufs, update_buf_count);
+ if (update_bufs == NULL)
+ RETURN(err_serious(-ENOMEM));
+
+ if (ouh->ouh_inline_length > 0) {
+ update_bufs[0] = ouh->ouh_inline_data;
+ } else {
+ struct out_update_buffer *tmp;
+ int page_count = 0;
+
+ oub = req_capsule_client_get(pill, &RMF_OUT_UPDATE_BUF);
+ if (oub == NULL)
+ GOTO(out_free, rc = err_serious(-EPROTO));
+
+ for (i = 0; i < update_buf_count; i++)
+ /* First *and* last might be partial pages, hence +1 */
+ page_count += DIV_ROUND_UP(oub[i].oub_size,
+ PAGE_SIZE) + 1;
+
+ desc = ptlrpc_prep_bulk_exp(pill->rc_req, page_count,
+ PTLRPC_BULK_OPS_COUNT,
+ PTLRPC_BULK_GET_SINK,
+ MDS_BULK_PORTAL,
+ &ptlrpc_bulk_kiov_nopin_ops);
+ if (desc == NULL)
+ GOTO(out_free, rc = err_serious(-ENOMEM));
+
+ tmp = oub;
+ for (i = 0; i < update_buf_count; i++, tmp++) {
+ if (tmp->oub_size >= OUT_MAXREQSIZE)
+ GOTO(out_free, rc = err_serious(-EPROTO));
+
+ OBD_ALLOC_LARGE(update_bufs[i], tmp->oub_size);
+ if (update_bufs[i] == NULL)
+ GOTO(out_free, rc = err_serious(-ENOMEM));
+
+ desc->bd_frag_ops->add_iov_frag(desc, update_bufs[i],
+ tmp->oub_size);
+ }
+
+ pill->rc_req->rq_bulk_write = 1;
+ rc = sptlrpc_svc_prep_bulk(pill->rc_req, desc);
+ if (rc != 0)
+ GOTO(out_free, rc = err_serious(rc));
+
+ rc = target_bulk_io(pill->rc_req->rq_export, desc);
+ if (rc < 0)
+ GOTO(out_free, rc = err_serious(rc));
+ }
+ /* validate the request and calculate the total update count and
+ * set it to reply */
+ reply_size = 0;
+ updates = 0;
+ for (i = 0; i < update_buf_count; i++) {
+ struct object_update_request *our;
+ int j;
+
+ our = update_bufs[i];
+ if (req_capsule_req_need_swab(pill))
+ lustre_swab_object_update_request(our, 0);
+
+ if (our->ourq_magic != UPDATE_REQUEST_MAGIC) {
+ CERROR("%s: invalid update buffer magic %x"
+ " expect %x: rc = %d\n",
+ tgt_name(tsi->tsi_tgt), our->ourq_magic,
+ UPDATE_REQUEST_MAGIC, -EPROTO);
+ GOTO(out_free, rc = err_serious(-EPROTO));
+ }
+ updates += our->ourq_count;
+
+ /* need to calculate reply size */
+ for (j = 0; j < our->ourq_count; j++) {
+ update = object_update_request_get(our, j, NULL);
+ if (update == NULL)
+ GOTO(out, rc = err_serious(-EPROTO));
+ if (req_capsule_req_need_swab(pill))
+ lustre_swab_object_update(update);
+
+ if (!fid_is_sane(&update->ou_fid)) {
+ CERROR("%s: invalid FID "DFID": rc = %d\n",
+ tgt_name(tsi->tsi_tgt),
+ PFID(&update->ou_fid), -EPROTO);
+ GOTO(out, rc = err_serious(-EPROTO));
+ }
+
+ /* XXX: what ou_result_size can be considered safe? */
+
+ reply_size += sizeof(reply->ourp_lens[0]);
+ reply_size += sizeof(struct object_update_result);
+ reply_size += update->ou_result_size;
+ }
+ }
+ reply_size += sizeof(*reply);
+
+ if (unlikely(reply_size > ouh->ouh_reply_size)) {
+ CERROR("%s: too small reply buf %u for %u, need %u at least\n",
+ tgt_name(tsi->tsi_tgt), ouh->ouh_reply_size,
+ updates, reply_size);
+ GOTO(out_free, rc = err_serious(-EPROTO));