提交 b7d3a7e1 编写于 作者: G Gerd Hoffmann

ehci: fix fetch qtd race

The token field contains the (guest-filled) state of the qtd, which
indicates whenever the other fields are valid or not.  So make sure
we read the token first, otherwise we may end up with an stale next
pointer:

  (1) ehci reads next
  (2) guest writes next
  (3) guest writes token
  (4) ehci reads token
  (5) ehci operates with stale next.

Typical effect is that qemu doesn't notice that the guest appends new
qtds to the end of the queue.  Looks like the usb device stopped
responding.  Linux can recover from that, but leaves a message in the
kernel log that it did reset the usb device in question.
Signed-off-by: NGerd Hoffmann <kraxel@redhat.com>
Message-id: 20181126100836.8805-1-kraxel@redhat.com
上级 5621d045
...@@ -1783,9 +1783,17 @@ static int ehci_state_fetchqtd(EHCIQueue *q) ...@@ -1783,9 +1783,17 @@ static int ehci_state_fetchqtd(EHCIQueue *q)
EHCIqtd qtd; EHCIqtd qtd;
EHCIPacket *p; EHCIPacket *p;
int again = 1; int again = 1;
uint32_t addr;
if (get_dwords(q->ehci, NLPTR_GET(q->qtdaddr), (uint32_t *) &qtd, addr = NLPTR_GET(q->qtdaddr);
sizeof(EHCIqtd) >> 2) < 0) { if (get_dwords(q->ehci, addr + 8, &qtd.token, 1) < 0) {
return 0;
}
barrier();
if (get_dwords(q->ehci, addr + 0, &qtd.next, 1) < 0 ||
get_dwords(q->ehci, addr + 4, &qtd.altnext, 1) < 0 ||
get_dwords(q->ehci, addr + 12, qtd.bufptr,
ARRAY_SIZE(qtd.bufptr)) < 0) {
return 0; return 0;
} }
ehci_trace_qtd(q, NLPTR_GET(q->qtdaddr), &qtd); ehci_trace_qtd(q, NLPTR_GET(q->qtdaddr), &qtd);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册