[PATCH] rtas_errd: Add support for hotplugging qemu pci devices via RTAS event

Tyrel Datwyler <[email protected]> Thu, 20 Feb 2014 15:44:12 -0800
Newsgroups gmane.linux.tools.diag.devel
Message-ID <[email protected]>
QEMU uses the newly defined hotplug event in librtasevent to initiate hotplug
of virtio pci devices in a pseries guest. This patch catches hotplug events and
invokes the drmgr commad with the necessary parameters to fufill the hotplug
request. Current support is limited to pci devices identified by a drc-index.

Signed-off-by: Tyrel Datwyler <[email protected]>
---
 rtas_errd/Makefile    |  2 +-
 rtas_errd/hotplug.c   | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++
 rtas_errd/rtas_errd.c |  5 +++
 rtas_errd/rtas_errd.h |  3 ++
 4 files changed, 108 insertions(+), 1 deletion(-)
 create mode 100644 rtas_errd/hotplug.c

diff --git a/rtas_errd/Makefile b/rtas_errd/Makefile
index d5427d5..d2a366f 100644
--- a/rtas_errd/Makefile
+++ b/rtas_errd/Makefile
@@ -10,7 +10,7 @@ PRRN_HOTPLUG = prrn_hotplug
 
 RTAS_ERRD_OBJS = rtas_errd.o epow.o dump.o guard.o eeh.o update.o \
 		 files.o config.o diag_support.o ela.o v6ela.o servicelog.o \
-		 signal.o prrn.o
+		 signal.o prrn.o hotplug.o
 
 RTAS_ERRD_LIBS = -lrtas -lrtasevent -lservicelog -lsqlite3
 
diff --git a/rtas_errd/hotplug.c b/rtas_errd/hotplug.c
new file mode 100644
index 0000000..298d1a4
--- /dev/null
+++ b/rtas_errd/hotplug.c
@@ -0,0 +1,99 @@
+/**
+ * @file hotplug.c
+ *
+ * Copyright (C) 2013 IBM Corporation
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/wait.h>
+
+#include <librtas.h>
+#include "rtas_errd.h"
+
+#define DRMGR_PROGRAM           "/usr/sbin/drmgr"
+#define DRMGR_PROGRAM_NOPATH    "drmgr"
+
+void handle_hotplug_event(struct event *re)
+{
+        struct rtas_event_hdr *rtas_hdr = re->rtas_hdr;
+        struct rtas_hotplug_scn *hotplug;
+        pid_t child;
+        int status, rc;
+        char drc_index[11];
+        char *drmgr_args[] = { DRMGR_PROGRAM_NOPATH, "-c", NULL, NULL, NULL,
+                        NULL, NULL, "-d4", "-V", NULL};
+
+        /* Retrieve Hotplug section */
+        if (rtas_hdr->version >= 6) {
+	        hotplug = rtas_get_hotplug_scn(re->rtas_event);
+
+                /* Build drmgr argument list */
+                dbg("Build drmgr command\n");
+
+                switch (hotplug->type) {
+                        case RTAS_HP_TYPE_PCI:
+                                drmgr_args[2] = "pci";
+                                drmgr_args[6] = "-n";
+                                break;
+                        default:
+                                dbg("Unknown or unsupported hotplug type %d\n",
+					hotplug->type);
+                                return;
+                }
+
+                switch (hotplug->action) {
+                        case RTAS_HP_ACTION_ADD:
+                                drmgr_args[3] = "-a";
+                                break;
+                        case RTAS_HP_ACTION_REMOVE:
+                                drmgr_args[3] = "-r";
+                                break;
+                        default:
+                                dbg("Unknown hotplug action %d\n", hotplug->action);
+                                return;
+                }
+
+                switch (hotplug->identifier) {
+                        case RTAS_HP_ID_DRC_INDEX:
+                                drmgr_args[4] = "-s";
+                                snprintf(drc_index, 11, "%#x", hotplug->u1.drc_index);
+                                drmgr_args[5] = drc_index;
+                                break;
+                        default:
+                                dbg("Unknown or unsupported hotplug identifier %d\n",
+					hotplug->identifier);
+                                return;
+                }
+ 
+
+                dbg("run: %s %s %s %s %s %s %s\n", drmgr_args[0],
+                        drmgr_args[1], drmgr_args[2], drmgr_args[3],
+                        drmgr_args[4], drmgr_args[5], drmgr_args[6]);
+
+                /* invoke drmgr */
+                dbg("Invoke drmgr command\n");
+
+                child = fork();
+                if (child == -1) {
+                        log_msg(NULL, "%s cannot be run to handle a hotplug event, %s",
+                                DRMGR_PROGRAM, strerror(errno));
+                        return;
+                } else if (child == 0) {
+                        /* child process */
+                        rc = execv(DRMGR_PROGRAM, drmgr_args);
+
+                        /* shouldn't get here */
+                        log_msg(NULL, "Couldn not exec %s in response to hotplug event, %s",
+                                DRMGR_PROGRAM, strerror(errno));
+                        exit(1);
+                }
+
+                child = waitpid(child, &status, 0);
+
+                dbg("drmgr call exited with %d\n", WEXITSTATUS(status));
+        }
+}
diff --git a/rtas_errd/rtas_errd.c b/rtas_errd/rtas_errd.c
index c911641..e94d1a8 100644
--- a/rtas_errd/rtas_errd.c
+++ b/rtas_errd/rtas_errd.c
@@ -160,6 +160,11 @@ handle_rtas_event(struct event *event)
 		 */
 		return 0;
 
+	    case RTAS_HDR_TYPE_HOTPLUG:
+		dbg("Entering Hotplug handler");
+		handle_hotplug_event(event);
+		break;
+
 	    default:
 		/* Nothing to do for this event */
 		break;
diff --git a/rtas_errd/rtas_errd.h b/rtas_errd/rtas_errd.h
index c59255d..f7b2e8e 100644
--- a/rtas_errd/rtas_errd.h
+++ b/rtas_errd/rtas_errd.h
@@ -169,4 +169,7 @@ void setup_sigchld_handler(void);
 /* prrn.c */
 void handle_prrn_event(struct event *);
 
+/* hotplug.c */
+void handle_hotplug_event(struct event *);
+
 #endif /* _RTAS_ERRD_H */
-- 
1.7.12.2


------------------------------------------------------------------------------
Managing the Performance of Cloud-Based Applications
Take advantage of what the Cloud has to offer - Avoid Common Pitfalls.
Read the Whitepaper.
http://pubads.g.doubleclick.net/gampad/clk?id=121054471&iu=/4140/ostg.clktrk