+ switch (m->lm_magic) {
+ case LUSTRE_MSG_MAGIC_V1:
+ case LUSTRE_MSG_MAGIC_V1_SWABBED:
+ return lustre_msg_buf_v1(m, n - 1, min_size);
+ case LUSTRE_MSG_MAGIC_V2:
+ case LUSTRE_MSG_MAGIC_V2_SWABBED:
+ return lustre_msg_buf_v2(m, n, min_size);
+ default:
+ LASSERTF(0, "incorrect message magic: %08x\n", m->lm_magic);
+ return NULL;
+ }
+}
+
+void lustre_shrink_reply_v1(struct ptlrpc_request *req, int segment,
+ unsigned int newlen, int move_data)
+{
+ struct lustre_msg_v1 *msg = (struct lustre_msg_v1 *)req->rq_repmsg;
+ char *tail = NULL, *newpos;
+ int tail_len = 0, n;
+
+ LASSERT(req->rq_reply_state);
+ LASSERT(msg);
+ LASSERT(segment >= 0);
+ LASSERT(msg->lm_bufcount > segment);
+ LASSERT(msg->lm_buflens[segment] >= newlen);
+
+ if (msg->lm_buflens[segment] == newlen)
+ return;
+
+ if (move_data && msg->lm_bufcount > segment + 1) {
+ tail = lustre_msg_buf_v1(msg, segment + 1, 0);
+ for (n = segment + 1; n < msg->lm_bufcount; n++)
+ tail_len += size_round(msg->lm_buflens[n]);
+ }
+
+ msg->lm_buflens[segment] = newlen;
+
+ if (tail && tail_len) {
+ newpos = lustre_msg_buf_v1(msg, segment + 1, 0);
+ LASSERT(newpos <= tail);
+ if (newpos != tail)
+ memcpy(newpos, tail, tail_len);
+ }
+
+ if (newlen == 0 && msg->lm_bufcount > segment + 1) {
+ memmove(&msg->lm_buflens[segment], &msg->lm_buflens[segment + 1],
+ (msg->lm_bufcount - segment - 1) * sizeof(__u32));
+ msg->lm_buflens[msg->lm_bufcount - 1] = 0;
+ }
+
+ req->rq_replen = lustre_msg_size_v1(msg->lm_bufcount, msg->lm_buflens);
+}
+
+void lustre_shrink_reply_v2(struct ptlrpc_request *req, int segment,
+ unsigned int newlen, int move_data)
+{
+ struct lustre_msg_v2 *msg = req->rq_repmsg;
+ char *tail = NULL, *newpos;
+ int tail_len = 0, n;
+
+ LASSERT(req->rq_reply_state);
+ LASSERT(msg);
+ LASSERT(msg->lm_bufcount > segment);
+ LASSERT(msg->lm_buflens[segment] >= newlen);
+
+ if (msg->lm_buflens[segment] == newlen)
+ return;
+
+ if (move_data && msg->lm_bufcount > segment + 1) {
+ tail = lustre_msg_buf_v2(msg, segment + 1, 0);
+ for (n = segment + 1; n < msg->lm_bufcount; n++)
+ tail_len += size_round(msg->lm_buflens[n]);
+ }
+
+ msg->lm_buflens[segment] = newlen;
+
+ if (tail && tail_len) {
+ newpos = lustre_msg_buf_v2(msg, segment + 1, 0);
+ LASSERT(newpos <= tail);
+ if (newpos != tail)
+ memcpy(newpos, tail, tail_len);
+ }
+
+ if (newlen == 0 && msg->lm_bufcount > segment + 1) {
+ memmove(&msg->lm_buflens[segment], &msg->lm_buflens[segment + 1],
+ (msg->lm_bufcount - segment - 1) * sizeof(__u32));
+ msg->lm_buflens[msg->lm_bufcount - 1] = 0;
+ }
+
+ req->rq_replen = lustre_msg_size_v2(msg->lm_bufcount, msg->lm_buflens);
+}
+
+/*
+ * shrink @segment to size @newlen. if @move_data is non-zero, we also move
+ * data forward from @segment + 1.
+ *
+ * if @newlen == 0, we remove the segment completely, but we still keep the
+ * totally bufcount the same to save possible data moving. this will leave a
+ * unused segment with size 0 at the tail, but that's ok.
+ *
+ * CAUTION:
+ * + if any buffers higher than @segment has been filled in, must call shrink
+ * with non-zero @move_data.
+ * + caller should NOT keep pointers to msg buffers which higher than @segment
+ * after call shrink.
+ */
+void lustre_shrink_reply(struct ptlrpc_request *req, int segment,
+ unsigned int newlen, int move_data)
+{
+ switch (req->rq_repmsg->lm_magic) {
+ case LUSTRE_MSG_MAGIC_V1:
+ lustre_shrink_reply_v1(req, segment - 1, newlen, move_data);
+ return;
+ case LUSTRE_MSG_MAGIC_V2:
+ lustre_shrink_reply_v2(req, segment, newlen, move_data);
+ return;
+ default:
+ LASSERTF(0, "incorrect message magic: %08x\n",
+ req->rq_repmsg->lm_magic);
+ }
+}
+
+void lustre_free_reply_state(struct ptlrpc_reply_state *rs)
+{
+ PTLRPC_RS_DEBUG_LRU_DEL(rs);
+
+ LASSERT (atomic_read(&rs->rs_refcount) == 0);
+ LASSERT (!rs->rs_difficult || rs->rs_handled);
+ LASSERT (!rs->rs_on_net);
+ LASSERT (!rs->rs_scheduled);
+ LASSERT (rs->rs_export == NULL);
+ LASSERT (rs->rs_nlocks == 0);
+ LASSERT (list_empty(&rs->rs_exp_list));
+ LASSERT (list_empty(&rs->rs_obd_list));
+
+ if (unlikely(rs->rs_prealloc)) {
+ struct ptlrpc_service *svc = rs->rs_service;
+
+ spin_lock(&svc->srv_lock);
+ list_add(&rs->rs_list,
+ &svc->srv_free_rs_list);
+ spin_unlock(&svc->srv_lock);
+ cfs_waitq_signal(&svc->srv_free_rs_waitq);
+ } else {
+ OBD_FREE(rs, rs->rs_size);
+ }
+}
+
+int lustre_unpack_msg_v1(void *msg, int len)
+{
+ struct lustre_msg_v1 *m = (struct lustre_msg_v1 *)msg;
+ int flipped, required_len, i;