From 7c7eebbab4e860c95e68ba042d4c334e389c6481 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Thu, 11 Sep 2014 13:03:59 +0300 Subject: [PATCH] virtio: fix overzealous vring completion The complete() function loops around, waiting for notifications and cleaning up the ring when they happen. However, we also call it opportunistically from produce(), and each time this happens, it starts another loop in the background, leaking memory. Fix by splitting complete() into do_complete(), which doesn't loop, and complete(), which does, and only call do_complete() from the produce() loop. --- net/virtio.cc | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/net/virtio.cc b/net/virtio.cc index b28d5b03c4..76df719a3a 100644 --- a/net/virtio.cc +++ b/net/virtio.cc @@ -174,6 +174,8 @@ public: void disable_interrupts(); void enable_interrupts(); private: + void produce(); + void do_complete(); size_t mask() { return size() - 1; } size_t masked(size_t idx) { return idx & mask(); } size_t available(); @@ -226,6 +228,11 @@ void vring::setup() { } void vring::run() { + produce(); + complete(); +} + +void vring::produce() { _producer(_available_descriptors).then([this] (std::vector vbc) { for (auto&& bc: vbc) { bool has_prev = false; @@ -248,12 +255,12 @@ void vring::run() { } _avail._shared->_idx.store(_avail._head, std::memory_order_release); _kick.signal(1); - complete(); - run(); + do_complete(); + produce(); }); } -void vring::complete() { +void vring::do_complete() { auto used_head = _used._shared->_idx.load(std::memory_order_acquire); while (used_head != _used._tail) { auto ue = _used._shared->_used_elements[masked(_used._tail++)]; @@ -268,6 +275,10 @@ void vring::complete() { id = next; } } +} + +void vring::complete() { + do_complete(); _notified.wait().then([this] (size_t ignore) { complete(); });