mirror of
https://github.com/scylladb/scylladb.git
synced 2026-04-22 09:30:45 +00:00
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.
This commit is contained in:
@@ -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<buffer_chain> 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();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user