Discussion:
[Linux-diag-devel] [PATCH] rtas_errd: Add support for hotplugging qemu pci devices via RTAS event
Tyrel Datwyler
2014-02-20 23:44:12 UTC
Permalink
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 <***@linux.vnet.ibm.com>
---
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
Nathan Fontenot
2014-02-21 16:28:16 UTC
Permalink
Post by Tyrel Datwyler
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.
---
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 @@
+/**
+ *
+ * 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) {
+ drmgr_args[2] = "pci";
+ drmgr_args[6] = "-n";
+ break;
+ dbg("Unknown or unsupported hotplug type %d\n",
+ hotplug->type);
+ return;
+ }
+
+ switch (hotplug->action) {
+ drmgr_args[3] = "-a";
+ break;
+ drmgr_args[3] = "-r";
+ break;
+ dbg("Unknown hotplug action %d\n", hotplug->action);
+ return;
+ }
+
+ switch (hotplug->identifier) {
+ drmgr_args[4] = "-s";
+ snprintf(drc_index, 11, "%#x", hotplug->u1.drc_index);
+ drmgr_args[5] = drc_index;
+ break;
+ 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;
+ dbg("Entering Hotplug handler");
+ handle_hotplug_event(event);
+ break;
+
/* 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 */
Loading...