diff --git a/drivers/virtio-blk.cc b/drivers/virtio-blk.cc index 1074856808a4940d2dad7d29c0b114faec3e30cf..49e161a310db69990aafff36f6752eabcd78d42f 100644 --- a/drivers/virtio-blk.cc +++ b/drivers/virtio-blk.cc @@ -171,6 +171,13 @@ void virtio_blk::response_worker() { delete req; queue->get_buf_finalize(); } + + // wake up the requesting thread in case the ring was full before + _request_thread_lock.lock(); + if (_waiting_request_thread) { + _waiting_request_thread->wake(); + } + _request_thread_lock.unlock(); } } @@ -195,12 +202,6 @@ int virtio_blk::make_virtio_request(struct bio* bio) } vring* queue = get_virt_queue(0); - if (!queue->avail_ring_not_empty()) { - virtio_w("Warn: No space on ring"); - biodone(bio, false); - return ENOMEM; - } - virtio_blk_request_type type; switch (bio->bio_cmd) { @@ -251,10 +252,13 @@ int virtio_blk::make_virtio_request(struct bio* bio) req->res.status = 0; queue->_sg_vec.push_back(vring::sg_node(mmu::virt_to_phys(&req->res), sizeof (struct virtio_blk_res), vring_desc::VRING_DESC_F_WRITE)); - if (!queue->add_buf(req)) { - biodone(bio, false); - delete req; - return EBUSY; + while (!queue->add_buf(req)) { + _waiting_request_thread = sched::thread::current(); + std::atomic_thread_fence(std::memory_order_seq_cst); + sched::thread::wait_until([queue] {queue->get_buf_gc(); return queue->avail_ring_has_room(queue->_sg_vec.size());}); + _request_thread_lock.lock(); + _waiting_request_thread = nullptr; + _request_thread_lock.unlock(); } queue->kick(); // should be out of the loop but I like plenty of irqs for the test diff --git a/drivers/virtio-blk.hh b/drivers/virtio-blk.hh index 605124616004f8daccb4ec73be3ba2ff0258ed47..ae548ba66b8b1008a37fe64135023a812a9936dc 100644 --- a/drivers/virtio-blk.hh +++ b/drivers/virtio-blk.hh @@ -178,7 +178,10 @@ namespace virtio { bool _ro; // This mutex protects parallel make_request invocations mutex _lock; - + sched::thread* _waiting_request_thread = nullptr; + // The mutex protects the above thread ptr from going away of + // the waker + mutex _request_thread_lock; };