From 6f366bb5e02140bce2a8543c130e4b874804c15b Mon Sep 17 00:00:00 2001
Message-Id: <6f366bb5e02140bce2a8543c130e4b874804c15b.1430412215.git.jen@redhat.com>
From: Amos Kong <akong@redhat.com>
Date: Wed, 1 Apr 2015 08:30:16 -0500
Subject: [CHANGE] virtio-pci: avoid repeatedly deassigning notifers of vhost
 device
To: rhvirt-patches@redhat.com,
    jen@redhat.com

RH-Author: Amos Kong <akong@redhat.com>
Message-id: <1427877016-13288-1-git-send-email-akong@redhat.com>
Patchwork-id: 64660
O-Subject: [RHEL-6.7 qemu-kvm PATCH v2] virtio-pci: avoid repeatedly deassigning notifers of vhost device
Bugzilla: 1124311
RH-Acked-by: Marcel Apfelbaum <marcel@redhat.com>
RH-Acked-by: Vlad Yasevich <vyasevic@redhat.com>
RH-Acked-by: Juan Quintela <quintela@redhat.com>

Bugzilla: 1124311
Brew: http://brewweb.devel.redhat.com/brew/taskinfo?taskID=8932591
Upstream: only for rhel6, upstream uses new memory API, that's fine.

Launch guest with 232 virtio nics (vhost=on), we will see two errors,
kernel doesn't have enough ioeventfd and return ENOSPC error, the opened
file descriptors might also reach to the MAX number of open file for single
process in userspace.

The notifiers will be deassigned after ENOSPC error. The second error
will cause vhost device fails to start, then repeatedly deassign notifiers
and get EMFILE error. The notifiers will be redisabled in vhost_net_stop()
when guest exits or device is hotunplugged.

So we should avoid repeat deassign notifiers of vhost device. Upstream uses
new memory API, it didn't check deassign result.

Signed-off-by: Amos Kong <akong@redhat.com>
---
v2: remove redundant variable init (Fam)
---
 hw/event_notifier.c |    2 ++
 hw/virtio-pci.c     |    4 ++++
 2 files changed, 6 insertions(+), 0 deletions(-)

Signed-off-by: Jeff E. Nelson <jen@redhat.com>
---
 hw/event_notifier.c | 2 ++
 hw/virtio-pci.c     | 4 ++++
 2 files changed, 6 insertions(+)

diff --git a/hw/event_notifier.c b/hw/event_notifier.c
index 10ffb65..d02ae90 100644
--- a/hw/event_notifier.c
+++ b/hw/event_notifier.c
@@ -18,6 +18,7 @@
 
 int event_notifier_init(EventNotifier *e, int active)
 {
+	e->fd = -1;
 #ifdef CONFIG_EVENTFD
 	int fd = eventfd(!!active, EFD_NONBLOCK | EFD_CLOEXEC);
 	if (fd < 0)
@@ -32,6 +33,7 @@ int event_notifier_init(EventNotifier *e, int active)
 void event_notifier_cleanup(EventNotifier *e)
 {
 	close(e->fd);
+	e->fd = -1;
 }
 
 int event_notifier_get_fd(EventNotifier *e)
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index 15b1d67..3a72e1e 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -212,6 +212,10 @@ static int virtio_pci_set_host_notifier_internal(VirtIOPCIProxy *proxy,
             event_notifier_cleanup(notifier);
         }
     } else {
+        /* Skip repeat deassigning of notifier */
+        if (event_notifier_get_fd(notifier) == -1) {
+            return 0;
+        }
         r = kvm_set_ioeventfd_pio_word(event_notifier_get_fd(notifier),
                                        proxy->addr + VIRTIO_PCI_QUEUE_NOTIFY,
                                        n, assign);
-- 
2.1.0

