int vmbus_chan_recv(struct vmbus_channel *chan, void *data, int *dlen0, uint64_t *xactid) { struct vmbus_chanpkt_hdr pkt; int error, dlen, hlen; error = vmbus_rxbr_peek(&chan->ch_rxbr, &pkt, sizeof(pkt)); if (error) return error; hlen = VMBUS_CHANPKT_GETLEN(pkt.cph_hlen); dlen = VMBUS_CHANPKT_GETLEN(pkt.cph_tlen) - hlen; if (*dlen0 < dlen) { /* Return the size of this packet's data. */ *dlen0 = dlen; return ENOBUFS; } *xactid = pkt.cph_xactid; *dlen0 = dlen; /* Skip packet header */ error = vmbus_rxbr_read(&chan->ch_rxbr, data, dlen, hlen); KASSERT(!error, ("vmbus_rxbr_read failed")); return 0; }
int vmbus_chan_recv_pkt(struct vmbus_channel *chan, struct vmbus_chanpkt_hdr *pkt0, int *pktlen0) { struct vmbus_chanpkt_hdr pkt; int error, pktlen; error = vmbus_rxbr_peek(&chan->ch_rxbr, &pkt, sizeof(pkt)); if (error) return error; pktlen = VMBUS_CHANPKT_GETLEN(pkt.cph_tlen); if (*pktlen0 < pktlen) { /* Return the size of this packet. */ *pktlen0 = pktlen; return ENOBUFS; } *pktlen0 = pktlen; /* Include packet header */ error = vmbus_rxbr_read(&chan->ch_rxbr, pkt0, pktlen, 0); KASSERT(!error, ("vmbus_rxbr_read failed")); return 0; }
static int vmbus_read_and_signal(struct vmbus_channel *chan, void *data, size_t dlen, size_t skip) { struct vmbus_br *rbr = &chan->rxbr; uint32_t write_sz, pending_sz, bytes_read; int error; /* Record where host was when we started read (for debug) */ rbr->windex = rbr->vbr->windex; /* Read data and skip packet header */ error = vmbus_rxbr_read(rbr, data, dlen, skip); if (error) return error; /* No need for signaling on older versions */ if (!rbr->vbr->feature_bits.feat_pending_send_sz) return 0; /* Make sure reading of pending happens after new read index */ rte_mb(); pending_sz = rbr->vbr->pending_send; if (!pending_sz) return 0; rte_smp_rmb(); write_sz = vmbus_br_availwrite(rbr, rbr->vbr->windex); bytes_read = dlen + skip + sizeof(uint64_t); /* If there was space before then host was not blocked */ if (write_sz - bytes_read > pending_sz) return 0; /* If pending write will not fit */ if (write_sz <= pending_sz) return 0; vmbus_set_event(chan->device, chan); return 0; }