From: Anthony Liguori <aliguori@us.ibm.com>
To: qemu-devel@nongnu.org
Cc: Anthony Liguori <aliguori@us.ibm.com>
Subject: [Qemu-devel] [PATCH 17/21] qom: add CharDriver class
Date: Sun, 24 Jul 2011 20:44:49 -0500 [thread overview]
Message-ID: <1311558293-5855-18-git-send-email-aliguori@us.ibm.com> (raw)
In-Reply-To: <1311558293-5855-1-git-send-email-aliguori@us.ibm.com>
The CharDriver type replaces the CharDriverState in QEMU today. Here's how
everything matches up:
1) qemu_chr_open() no longer exists. This function used to act as a factory
and used parsing of the filename to determine which type to create. A newer
version using QemuOpts was introduced, qemu_chr_open_opts() which eliminates
the filename in favor of typed key value pairs.
Now, plug_create() can be used to create CharDrivers using an explicit
type that subclasses CharDriver.
2) query-chardev is deprecated. This is replaced by
plug_list(type=char-driver) and plug_list_props().
3) We can now dynamically add and remove new CharDrivers
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
Makefile.qom | 3 +
Qconfig | 1 +
chrdrv/Makefile | 1 +
chrdrv/Qconfig | 5 +
chrdrv/chrdrv.c | 229 ++++++++++++++++++++++++++++++++++++++++
configure | 2 +-
include/qemu/chrdrv.h | 281 +++++++++++++++++++++++++++++++++++++++++++++++++
7 files changed, 521 insertions(+), 1 deletions(-)
create mode 100644 chrdrv/Makefile
create mode 100644 chrdrv/Qconfig
create mode 100644 chrdrv/chrdrv.c
create mode 100644 include/qemu/chrdrv.h
diff --git a/Makefile.qom b/Makefile.qom
index c694cbb..02a5ca5 100644
--- a/Makefile.qom
+++ b/Makefile.qom
@@ -16,3 +16,6 @@ common-obj-y += $(addprefix qom/,$(qom-obj-y))
include $(SRC_PATH)/devices/Makefile
common-obj-y += $(addprefix devices/,$(devices-obj-y))
+include $(SRC_PATH)/chrdrv/Makefile
+common-obj-y += $(addprefix chrdrv/,$(chrdrv-obj-y))
+
diff --git a/Qconfig b/Qconfig
index 03f2a87..57c1c7d 100644
--- a/Qconfig
+++ b/Qconfig
@@ -1,3 +1,4 @@
source qapi/Qconfig
source qom/Qconfig
source devices/Qconfig
+source chrdrv/Qconfig
diff --git a/chrdrv/Makefile b/chrdrv/Makefile
new file mode 100644
index 0000000..43a51e7
--- /dev/null
+++ b/chrdrv/Makefile
@@ -0,0 +1 @@
+chrdrv-obj-$(CONFIG_CHRDRV) := chrdrv.o
diff --git a/chrdrv/Qconfig b/chrdrv/Qconfig
new file mode 100644
index 0000000..845c205
--- /dev/null
+++ b/chrdrv/Qconfig
@@ -0,0 +1,5 @@
+config CHRDRV
+ bool "QEMU Character Drivers"
+ default y
+ help
+ Character layer
diff --git a/chrdrv/chrdrv.c b/chrdrv/chrdrv.c
new file mode 100644
index 0000000..a9b8dc2
--- /dev/null
+++ b/chrdrv/chrdrv.c
@@ -0,0 +1,229 @@
+#include "qemu/chrdrv.h"
+
+int char_driver_write(CharDriver *s, const uint8_t *buf, int len)
+{
+ CharDriverClass *cdc = CHAR_DRIVER_GET_CLASS(s);
+
+ return cdc->write(s, buf, len);
+}
+
+int char_driver_ioctl(CharDriver *s, int cmd, void *arg)
+{
+ CharDriverClass *cdc = CHAR_DRIVER_GET_CLASS(s);
+
+ return cdc->ioctl(s, cmd, arg);
+}
+
+int char_driver_get_msgfd(CharDriver *s)
+{
+ CharDriverClass *cdc = CHAR_DRIVER_GET_CLASS(s);
+
+ return cdc->get_msgfd(s);
+}
+
+void char_driver_send_event(CharDriver *s, int event)
+{
+ CharDriverClass *cdc = CHAR_DRIVER_GET_CLASS(s);
+
+ cdc->send_event(s, event);
+}
+
+void char_driver_accept_input(CharDriver *s)
+{
+ CharDriverClass *cdc = CHAR_DRIVER_GET_CLASS(s);
+
+ cdc->accept_input(s);
+}
+
+void char_driver_set_echo(CharDriver *s, bool echo)
+{
+ CharDriverClass *cdc = CHAR_DRIVER_GET_CLASS(s);
+
+ cdc->set_echo(s, echo);
+}
+
+void char_driver_guest_open(CharDriver *s)
+{
+ CharDriverClass *cdc = CHAR_DRIVER_GET_CLASS(s);
+
+ cdc->guest_open(s);
+}
+
+void char_driver_guest_close(CharDriver *s)
+{
+ CharDriverClass *cdc = CHAR_DRIVER_GET_CLASS(s);
+
+ cdc->guest_close(s);
+}
+
+static int char_driver_def_write(CharDriver *s, const uint8_t *buf, int len)
+{
+ return -ENOTSUP;
+}
+
+static void char_driver_def_update_read_handler(CharDriver *s)
+{
+}
+
+static int char_driver_def_ioctl(CharDriver *s, int cmd, void *arg)
+{
+ return -ENOTSUP;
+}
+
+static int char_driver_def_get_msgfd(CharDriver *s)
+{
+ return -1;
+}
+
+static void char_driver_def_send_event(CharDriver *chr, int event)
+{
+}
+
+static void char_driver_def_close(CharDriver *chr)
+{
+ char_driver_send_event(chr, CHR_EVENT_CLOSED);
+}
+
+static void char_driver_def_accept_input(CharDriver *chr)
+{
+}
+
+static void char_driver_def_set_echo(CharDriver *chr, bool echo)
+{
+}
+
+static void char_driver_def_guest_open(CharDriver *chr)
+{
+}
+
+static void char_driver_def_guest_close(CharDriver *chr)
+{
+}
+
+static void char_driver_def_open(CharDriver *chr, Error **errp)
+{
+}
+
+static void char_driver_realize(Plug *plug)
+{
+ CharDriver *chr = CHAR_DRIVER(plug);
+ CharDriverClass *cdc = CHAR_DRIVER_GET_CLASS(chr);
+
+ cdc->open(chr, NULL);
+}
+
+int char_driver_can_read(CharDriver *chr)
+{
+ if (!chr->chr_can_read) {
+ return 1024;
+ }
+
+ return chr->chr_can_read(chr->handler_opaque);
+}
+
+void char_driver_read(CharDriver *chr, uint8_t *buf, int len)
+{
+ if (!chr->chr_read) {
+ return;
+ }
+
+ chr->chr_read(chr->handler_opaque, buf, len);
+}
+
+void char_driver_event(CharDriver *chr, int event)
+{
+ /* Keep track if the char device is open */
+ switch (event) {
+ case CHR_EVENT_OPENED:
+ chr->opened = 1;
+ break;
+ case CHR_EVENT_CLOSED:
+ chr->opened = 0;
+ break;
+ }
+
+ if (!chr->chr_event) {
+ return;
+ }
+
+ chr->chr_event(chr->handler_opaque, event);
+}
+
+static void char_driver_class_init(TypeClass *class)
+{
+ PlugClass *pc = PLUG_CLASS(class);
+ CharDriverClass *cdc = CHAR_DRIVER_CLASS(class);
+
+ pc->realize = char_driver_realize;
+ cdc->write = char_driver_def_write;
+ cdc->ioctl = char_driver_def_ioctl;
+ cdc->get_msgfd = char_driver_def_get_msgfd;
+ cdc->send_event = char_driver_def_send_event;
+ cdc->close = char_driver_def_close;
+ cdc->accept_input = char_driver_def_accept_input;
+ cdc->set_echo = char_driver_def_set_echo;
+ cdc->guest_open = char_driver_def_guest_open;
+ cdc->guest_close = char_driver_def_guest_close;
+ cdc->open = char_driver_def_open;
+ cdc->update_read_handler = char_driver_def_update_read_handler;
+
+}
+
+static void char_driver_generic_open(CharDriver *s)
+{
+ char_driver_event(s, CHR_EVENT_OPENED);
+}
+
+void char_driver_add_handlers(CharDriver *s,
+ IOCanReadHandler *fd_can_read,
+ IOReadHandler *fd_read,
+ IOEventHandler *fd_event,
+ void *opaque)
+{
+ CharDriverClass *cdc = CHAR_DRIVER_GET_CLASS(s);
+
+ if (!opaque && !fd_can_read && !fd_read && !fd_event) {
+ /* chr driver being released. */
+ ++s->avail_connections;
+ }
+ s->chr_can_read = fd_can_read;
+ s->chr_read = fd_read;
+ s->chr_event = fd_event;
+ s->handler_opaque = opaque;
+ if (cdc->update_read_handler) {
+ cdc->update_read_handler(s);
+ }
+
+ /* We're connecting to an already opened device, so let's make sure we
+ also get the open event */
+ if (s->opened) {
+ char_driver_generic_open(s);
+ }
+}
+
+static void char_driver_fini(TypeInstance *inst)
+{
+ CharDriver *chr = CHAR_DRIVER(inst);
+ CharDriverClass *cdc = CHAR_DRIVER_GET_CLASS(chr);
+
+ if (cdc->close) {
+ cdc->close(chr);
+ }
+}
+
+static TypeInfo chrdrv_type_info = {
+ .name = TYPE_CHAR_DRIVER,
+ .parent = TYPE_PLUG,
+ .instance_size = sizeof(CharDriver),
+ .instance_finalize = char_driver_fini,
+ .class_size = sizeof(CharDriverClass),
+ .class_init = char_driver_class_init,
+ .abstract = true,
+};
+
+static void register_backends(void)
+{
+ type_register_static(&chrdrv_type_info);
+}
+
+device_init(register_backends);
diff --git a/configure b/configure
index 6ec1020..63c62b0 100755
--- a/configure
+++ b/configure
@@ -3516,7 +3516,7 @@ DIRS="$DIRS pc-bios/spapr-rtas"
DIRS="$DIRS roms/seabios roms/vgabios"
DIRS="$DIRS fsdev ui"
DIRS="$DIRS qapi"
-DIRS="$DIRS qga qom devices"
+DIRS="$DIRS qga qom devices chrdrv"
FILES="Makefile tests/Makefile"
FILES="$FILES tests/cris/Makefile tests/cris/.gdbinit"
FILES="$FILES pc-bios/optionrom/Makefile pc-bios/keymaps"
diff --git a/include/qemu/chrdrv.h b/include/qemu/chrdrv.h
new file mode 100644
index 0000000..075b589
--- /dev/null
+++ b/include/qemu/chrdrv.h
@@ -0,0 +1,281 @@
+#ifndef QEMU_CHAR_DRIVER
+#define QEMU_CHAR_DRIVER
+
+#include "qemu/plug.h"
+
+/* Temporarily for a couple of enum */
+#include "qemu-char.h"
+
+/**
+ * @CharDriver
+ *
+ * A streaming data connection, typically used to transfer data from a @Device
+ * to some process on the host.
+ *
+ * A @CharDriver subclass implements the driver. Typically, this is the host
+ * routine and may include a TCP, stdio, or fd transport. The @Device that is
+ * interacting with the driver is the client. This is typically a device that
+ * looks like a serial port including UARTs, virtio-serial, etc.
+ *
+ * @CharDriver also supports by direction messaging. These messages carry no
+ * data though.
+ */
+typedef struct CharDriver
+{
+ Plug parent;
+
+ /* Public */
+
+ /**
+ * @avail_connection used by qdev to keep track of how "connections" are
+ * available in the @CharDriver verses how many qdev are using. This is
+ * meant to ensure that the same @CharDriver isn't connected to multiple
+ * sockets at the same time.
+ *
+ * It's not well thought through though as there are other things that can
+ * use a @CharDriver and the attempt at supporting mux drivers results in
+ * this value just being ignored for mux (although not predictably).
+ *
+ * Sufficed to say, this needs to go away.
+ */
+ int avail_connections;
+
+ /**
+ * @opened despite what the name implies, this doesn't correspond to whether
+ * the @CharDriver is opened. @CharDriver doesn't have a notion of opened,
+ * instead, @opened tracks whether the CHR_EVENT_OPEN event has been
+ * generated. The CHR_EVENT_CLOSED event will clear the @opened flag.
+ *
+ * The primary purpose of this flag is to ensure the CHR_EVENT_OPEN event is
+ * not generated twice in a row.
+ */
+ int opened;
+
+ /* Private */
+
+ /**
+ * @chr_can_read when a client has added its handlers to a @CharDriver, this
+ * contains the can read callback for the client.
+ */
+ IOCanReadHandler *chr_can_read;
+
+ /**
+ * @chr_read when a client has added its handlers to a @CharDriver, this
+ * contains the read callback for the client.
+ */
+ IOReadHandler *chr_read;
+
+ /**
+ * @chr_event when a client has added its handlers to a @CharDriver, this
+ * contains the event callback for the client.
+ */
+ IOEventHandler *chr_event;
+
+ /**
+ * @handler_opaque when a client has added its handlers to a @CharDriver,
+ * this contains the opaque associated with the callbacks for the client.
+ */
+ void *handler_opaque;
+} CharDriver;
+
+typedef struct CharDriverClass
+{
+ PlugClass parent_class;
+
+ /* Public */
+ int (*write)(CharDriver *s, const uint8_t *buf, int len);
+ int (*ioctl)(CharDriver *s, int cmd, void *arg);
+ int (*get_msgfd)(CharDriver *s);
+ void (*send_event)(CharDriver *chr, int event);
+ void (*accept_input)(CharDriver *chr);
+ void (*set_echo)(CharDriver *chr, bool echo);
+ void (*guest_open)(CharDriver *chr);
+ void (*guest_close)(CharDriver *chr);
+
+ /* Protected */
+ /**
+ * @open:
+ *
+ * This is called during realize to initialize the object. At this point,
+ * all of the properties should have been set.
+ */
+ void (*open)(CharDriver *s, Error **errp);
+
+ /**
+ * @update_read_handler:
+ *
+ * This is called after @char_driver_add_handlers is called to allow sub-
+ * classes to re-register their callbacks if necessary.
+ */
+ void (*update_read_handler)(CharDriver *s);
+
+ /**
+ * @close:
+ *
+ * Called during the finalize path. The default behavior sends a
+ * CHR_EVENT_CLOSED. It's generally better to use the classes destructor to
+ * implement driver specific cleanup.
+ */
+ void (*close)(CharDriver *chr);
+} CharDriverClass;
+
+#define TYPE_CHAR_DRIVER "char-driver"
+#define CHAR_DRIVER(obj) TYPE_CHECK(CharDriver, obj, TYPE_CHAR_DRIVER)
+#define CHAR_DRIVER_CLASS(class) \
+ TYPE_CLASS_CHECK(CharDriverClass, class, TYPE_CHAR_DRIVER)
+#define CHAR_DRIVER_GET_CLASS(obj) \
+ TYPE_GET_CLASS(CharDriverClass, obj, TYPE_CHAR_DRIVER)
+
+/**
+ * @char_driver_write:
+ *
+ * Write data to a @CharDriver
+ *
+ * @buf The data to write
+ * @len The size of the data in buf
+ *
+ * Returns: The number of bytes written to the device
+ *
+ * Notes: Each backend deals with flow control on its own. Depending on the
+ * driver, this function may block execution or silently drop data.
+ *
+ * Dropping data may also occur if the backend uses a connection
+ * oriented transport and the transport is disconnected.
+ *
+ * The caller receives no indication that data was dropped. This
+ * function may return a partial write result.
+ */
+int char_driver_write(CharDriver *s, const uint8_t *buf, int len);
+
+/**
+ * @char_driver_ioctl:
+ *
+ * Performs a device specific ioctl.
+ *
+ * @cmd an ioctl, see CHR_IOCTL_*
+ * @arg values depends on @cmd
+ *
+ * Returns: The result of this depends on the @cmd. If @cmd is not supported
+ * by this device, -ENOTSUP.
+ */
+int char_driver_ioctl(CharDriver *s, int cmd, void *arg);
+
+/**
+ * @char_driver_get_msgfd:
+ *
+ * If the driver has received a file descriptor through its transport, this
+ * function will return the file descriptor.
+ *
+ * Returns: The file descriptor or -1 if transport doesn't support file
+ * descriptor passing or doesn't currently have a file descriptor.
+ */
+int char_driver_get_msgfd(CharDriver *s);
+
+/**
+ * @char_driver_send_event:
+ *
+ * Raise an event to a driver.
+ *
+ * @event see CHR_EVENT_*
+ *
+ * Notes: There is no way to determine if the driver successfully handled the
+ * event.
+ */
+void char_driver_send_event(CharDriver *chr, int event);
+
+/**
+ * @char_driver_accept_input:
+ *
+ * I honestly can't tell what this function is meant to do.
+ */
+void char_driver_accept_input(CharDriver *chr);
+
+/**
+ * @char_driver_set_echo:
+ *
+ * Requests to override the backends use of echo. This is really only
+ * applicable to the stdio backend but is a generic interface today.
+ *
+ * @echo true to enable echo
+ */
+void char_driver_set_echo(CharDriver *chr, bool echo);
+
+/**
+ * @char_driver_guest_open:
+ *
+ * If the client has a notion of a connection, this is invoked when the
+ * connection is created.
+ *
+ * Note: There is no way to determine if a client has the notion of a
+ * connection. A driver cannot rely on this function ever being called.
+ */
+void char_driver_guest_open(CharDriver *chr);
+
+/**
+ * @char_driver_guest_close:
+ *
+ * If the client has a notion of a connection, this is invoked when the
+ * connection is closed.
+ *
+ * Note: There is no way to determine if a client has the notion of a
+ * connection. A driver cannot rely on this function ever being called.
+ */
+void char_driver_guest_close(CharDriver *chr);
+
+/**
+ * @char_driver_can_read:
+ *
+ * Returns: The maximum number of bytes the client connected to the driver can
+ * receive at the moment.
+ */
+int char_driver_can_read(CharDriver *chr);
+
+/**
+ * @char_driver_read:
+ *
+ * This function transfers the contents of buf to the client.
+ *
+ * @buf the buffer to write to the client
+ * @len the number of bytes to write
+ *
+ * Notes: This function should only be invoked after receiving a non-zero
+ * value from @char_driver_can_read. @len may be larger than the return
+ * value but the results are undefined. It may result in the entire
+ * message being dropped or the message being truncated.
+ */
+void char_driver_read(CharDriver *chr, uint8_t *buf, int len);
+
+/**
+ * @char_driver_event:
+ *
+ * Sends an event to the client of a driver.
+ *
+ * @event the CHR_EVENT_* to send to the client
+ */
+void char_driver_event(CharDriver *chr, int event);
+
+/**
+ * @char_driver_add_handlers:
+ *
+ * Connect a client to a @CharDriver. A connected client may send data to the
+ * driver by using the @char_driver_write function. Data is received from the
+ * driver to the client using the callbacks registered in this function.
+ *
+ * @fd_can_read This callback returns the maximum amount of data the client is
+ * prepared to receive from the driver.
+ *
+ * @fd_read This callback is used by the driver to pass data to the client.
+ *
+ * @fd_event This callback is used to send events from the driver to the
+ * client.
+ *
+ * @opaque An opaque value that is passed with the registered callbacks to
+ * form a closure.
+ */
+void char_driver_add_handlers(CharDriver *s,
+ IOCanReadHandler *fd_can_read,
+ IOReadHandler *fd_read,
+ IOEventHandler *fd_event,
+ void *opaque);
+
+#endif
--
1.7.4.1
next prev parent reply other threads:[~2011-07-25 1:45 UTC|newest]
Thread overview: 52+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-07-25 1:44 [Qemu-devel] [RFC][PATCH 0/21] QEMU Object Model Anthony Liguori
2011-07-25 1:44 ` [Qemu-devel] [PATCH 01/21] qom: add make infrastructure Anthony Liguori
2011-07-25 1:44 ` [Qemu-devel] [PATCH 02/21] qom: convert QAPI to use Qconfig build system Anthony Liguori
2011-07-25 1:44 ` [Qemu-devel] [PATCH 03/21] qom: Add core type system Anthony Liguori
2011-07-25 1:44 ` [Qemu-devel] [PATCH 04/21] qom: add Plug class Anthony Liguori
2011-07-25 1:44 ` [Qemu-devel] [PATCH 05/21] plug: add Plug property type Anthony Liguori
2011-07-25 1:44 ` [Qemu-devel] [PATCH 06/21] plug: add socket " Anthony Liguori
2011-07-25 1:44 ` [Qemu-devel] [PATCH 07/21] plug: add generated property types Anthony Liguori
2011-07-25 1:44 ` [Qemu-devel] [PATCH 08/21] qom: add plug_create QMP command Anthony Liguori
2011-07-25 1:44 ` [Qemu-devel] [PATCH 09/21] qom: add plug_list " Anthony Liguori
2011-07-25 1:44 ` [Qemu-devel] [PATCH 10/21] qom: add plug_get " Anthony Liguori
2011-07-25 1:44 ` [Qemu-devel] [PATCH 11/21] qom: add plug_set " Anthony Liguori
2011-07-25 1:44 ` [Qemu-devel] [PATCH 12/21] qom: add plug_list_props " Anthony Liguori
2011-07-25 1:44 ` [Qemu-devel] [PATCH 13/21] qom: add plug_destroy command Anthony Liguori
2011-07-25 1:44 ` [Qemu-devel] [PATCH 14/21] qom: add example qsh command Anthony Liguori
2011-07-25 1:44 ` [Qemu-devel] [PATCH 15/21] qom: add Device class Anthony Liguori
2011-07-27 15:10 ` Peter Maydell
2011-07-27 16:07 ` Anthony Liguori
2011-07-25 1:44 ` [Qemu-devel] [PATCH 16/21] qom-devices: add a Pin class Anthony Liguori
2011-07-25 1:44 ` Anthony Liguori [this message]
2011-07-25 1:44 ` [Qemu-devel] [PATCH 18/21] qom-chrdrv: add memory character driver Anthony Liguori
2011-07-25 1:44 ` [Qemu-devel] [PATCH 19/21] qom-chrdrv: add Socket base class Anthony Liguori
2011-07-25 1:44 ` [Qemu-devel] [PATCH 20/21] qom-chrdrv: add TCPServer class Anthony Liguori
2011-07-25 1:44 ` [Qemu-devel] [PATCH 21/21] qom-chrdrv: add UnixServer Anthony Liguori
2011-07-25 11:21 ` [Qemu-devel] [RFC][PATCH 0/21] QEMU Object Model Kevin Wolf
2011-07-25 12:45 ` Anthony Liguori
2011-07-25 13:08 ` Kevin Wolf
2011-07-25 13:10 ` Anthony Liguori
2011-07-26 12:59 ` Paolo Bonzini
2011-07-26 14:02 ` Anthony Liguori
2011-07-26 14:35 ` Paolo Bonzini
2011-07-26 15:34 ` Anthony Liguori
2011-07-26 18:26 ` Paolo Bonzini
2011-07-26 19:23 ` Anthony Liguori
2011-07-27 8:55 ` Paolo Bonzini
2011-07-27 12:48 ` Anthony Liguori
2011-07-27 15:33 ` Paolo Bonzini
2011-07-27 16:19 ` Anthony Liguori
2011-07-27 16:28 ` Anthony Liguori
2011-07-27 18:51 ` Paolo Bonzini
2011-07-27 20:01 ` Anthony Liguori
2011-07-28 7:36 ` Paolo Bonzini
2011-07-28 12:46 ` Anthony Liguori
2011-07-28 13:50 ` Paolo Bonzini
2011-07-28 14:03 ` Anthony Liguori
2011-07-28 14:41 ` Paolo Bonzini
2011-07-28 15:04 ` Anthony Liguori
2011-07-28 15:47 ` Paolo Bonzini
2011-07-28 17:59 ` Anthony Liguori
2011-07-29 7:19 ` Paolo Bonzini
2011-07-27 21:33 ` Peter Maydell
2011-07-27 22:31 ` Anthony Liguori
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1311558293-5855-18-git-send-email-aliguori@us.ibm.com \
--to=aliguori@us.ibm.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).