diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 9c7e85caea..13affc1f35 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -1642,18 +1642,15 @@ static bool virtio_net_can_receive(NetClientState *nc)
 static int virtio_net_has_buffers(VirtIONetQueue *q, int bufsize)
 {
     VirtIONet *n = q->n;
-    if (virtio_queue_empty(q->rx_vq) ||
-        (n->mergeable_rx_bufs &&
-         !virtqueue_avail_bytes(q->rx_vq, bufsize, 0))) {
-        virtio_queue_set_notification(q->rx_vq, 1);
-
-        /* To avoid a race condition where the guest has made some buffers
-         * available after the above check but before notification was
-         * enabled, check for available buffers again.
-         */
-        if (virtio_queue_empty(q->rx_vq) ||
+
+    while (virtio_queue_empty(q->rx_vq) ||
             (n->mergeable_rx_bufs &&
-             !virtqueue_avail_bytes(q->rx_vq, bufsize, 0))) {
+            !virtqueue_avail_bytes(q->rx_vq, bufsize, 0))) {
+        /* guest may have made some buf, try again */
+        if (virtio_queue_set_notification(q->rx_vq, 1)) {
+            virtio_queue_set_notification(q->rx_vq, 0);
+            continue;
+        } else {
             return 0;
         }
     }
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 893a072c9d..3e9b8b0d29 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -507,10 +507,13 @@ static inline void vring_set_avail_event(VirtQueue *vq, uint16_t val)
     address_space_cache_invalidate(&caches->used, pa, sizeof(val));
 }
 
-static void virtio_queue_split_set_notification(VirtQueue *vq, int enable)
+static bool virtio_queue_split_set_notification(VirtQueue *vq, int enable)
 {
+    uint16_t shadow_idx;
+
     RCU_READ_LOCK_GUARD();
 
+    shadow_idx = vq->shadow_avail_idx;
     if (virtio_vdev_has_feature(vq->vdev, VIRTIO_RING_F_EVENT_IDX)) {
         vring_set_avail_event(vq, vring_avail_idx(vq));
     } else if (enable) {
@@ -521,10 +524,14 @@ static void virtio_queue_split_set_notification(VirtQueue *vq, int enable)
     if (enable) {
         /* Expose avail event/used flags before caller checks the avail idx. */
         smp_mb();
+
+        return shadow_idx != vring_avail_idx(vq);
     }
+
+    return false;
 }
 
-static void virtio_queue_packed_set_notification(VirtQueue *vq, int enable)
+static bool virtio_queue_packed_set_notification(VirtQueue *vq, int enable)
 {
     uint16_t off_wrap;
     VRingPackedDescEvent e;
@@ -533,7 +540,7 @@ static void virtio_queue_packed_set_notification(VirtQueue *vq, int enable)
     RCU_READ_LOCK_GUARD();
     caches = vring_get_region_caches(vq);
     if (!caches) {
-        return;
+        return false;
     }
 
     vring_packed_event_read(vq->vdev, &caches->used, &e);
@@ -555,6 +562,8 @@ static void virtio_queue_packed_set_notification(VirtQueue *vq, int enable)
         /* Expose avail event/used flags before caller checks the avail idx. */
         smp_mb();
     }
+
+    return false;
 }
 
 bool virtio_queue_get_notification(VirtQueue *vq)
@@ -562,18 +571,18 @@ bool virtio_queue_get_notification(VirtQueue *vq)
     return vq->notification;
 }
 
-void virtio_queue_set_notification(VirtQueue *vq, int enable)
+bool virtio_queue_set_notification(VirtQueue *vq, int enable)
 {
     vq->notification = enable;
 
     if (!vq->vring.desc) {
-        return;
+        return false;
     }
 
     if (virtio_vdev_has_feature(vq->vdev, VIRTIO_F_RING_PACKED)) {
-        virtio_queue_packed_set_notification(vq, enable);
+        return virtio_queue_packed_set_notification(vq, enable);
     } else {
-        virtio_queue_split_set_notification(vq, enable);
+        return virtio_queue_split_set_notification(vq, enable);
     }
 }
 
diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
index 7d5ffdc145..e1a1621e2d 100644
--- a/include/hw/virtio/virtio.h
+++ b/include/hw/virtio/virtio.h
@@ -301,7 +301,7 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id);
 void virtio_notify_config(VirtIODevice *vdev);
 
 bool virtio_queue_get_notification(VirtQueue *vq);
-void virtio_queue_set_notification(VirtQueue *vq, int enable);
+bool virtio_queue_set_notification(VirtQueue *vq, int enable);
 
 int virtio_queue_ready(VirtQueue *vq);
 
