All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/11] (v6) virtio: console: Fixes, new way of discovering ports
@ 2010-04-08 14:49 Amit Shah
  2010-04-08 14:49 ` [PATCH 01/11] Revert "virtio: disable multiport console support." Amit Shah
  0 siblings, 1 reply; 13+ messages in thread
From: Amit Shah @ 2010-04-08 14:49 UTC (permalink / raw)
  To: Virtualization List; +Cc: Amit Shah, Juan Quintela, Michael S. Tsirkin

Hello,

This series reworks the ABI to allow port discovery (only) via the
control queue and enable multiport again.

In addition, it adds support for non-blocking write() support, which
means no spinning. This works fine with the recent patches that are on
qemu-devel.

Also included is removal of hvc_remove() as removing one such console
port causes other console ports (registered with hvc) to stall. This
has to be debugged in the hvc_console.c file, I'll do that later, but
we have a nice workaround for this: returning -EPIPE on any hvc
operations will make the hvc console core perform any cleanups for the
removed ports. Looks like we don't lose much by removing hvc_remove().

New in this version:
- Locking for the out_vq. Slightly changed version compared to the
  diff I sent earlier in that I don't lock inside
  reclaim_used_buffers() now, letting us use spin_lock_irq() instead
  of spin_lock_irqsave() from non-irq contexts.
- Remove extra line spotted by Rusty

Rusty, please apply for -next if all is well.

Amit Shah (11):
  Revert "virtio: disable multiport console support."
  virtio: console: Add a __send_control_msg() that can send messages
    without a valid port
  virtio: console: Let host know of port or device add failures
  virtio: console: Return -EPIPE to hvc_console if we lost the
    connection
  virtio: console: Don't call hvc_remove() on unplugging console ports
  virtio: console: Remove config work handler
  virtio: console: Move code around for future patches
  virtio: console: Use a control message to add ports
  virtio: console: Don't always create a port 0 if using multiport
  virtio: console: Rename wait_is_over() to will_read_block()
  virtio: console: Add support for nonblocking write()s

 drivers/char/virtio_console.c  |  605 ++++++++++++++++++++--------------------
 include/linux/virtio_console.h |   25 ++
 2 files changed, 334 insertions(+), 296 deletions(-)

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH 01/11] Revert "virtio: disable multiport console support."
  2010-04-08 14:49 [PATCH 00/11] (v6) virtio: console: Fixes, new way of discovering ports Amit Shah
@ 2010-04-08 14:49 ` Amit Shah
  2010-04-08 14:49   ` [PATCH 02/11] virtio: console: Add a __send_control_msg() that can send messages without a valid port Amit Shah
  0 siblings, 1 reply; 13+ messages in thread
From: Amit Shah @ 2010-04-08 14:49 UTC (permalink / raw)
  To: Virtualization List; +Cc: Amit Shah, Juan Quintela, Michael S. Tsirkin

This reverts commit b7a413015d2986edf020fba765c906cc9cbcbfc9.

Multiport support was disabled for 2.6.34 because we wanted to introduce
a new ABI and since we didn't have any released kernel with the older
ABI and were out of the merge window, it didn't make sense keeping the
older ABI around.

Now we revert the patch disabling multiport and rework the ABI in the
following patches.
---
 drivers/char/virtio_console.c  |   49 ++++++---------------------------------
 include/linux/virtio_console.h |   23 ++++++++++++++++++
 2 files changed, 31 insertions(+), 41 deletions(-)

diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 196428c..86e9011 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -33,35 +33,6 @@
 #include <linux/workqueue.h>
 #include "hvc_console.h"
 
-/* Moved here from .h file in order to disable MULTIPORT. */
-#define VIRTIO_CONSOLE_F_MULTIPORT 1	/* Does host provide multiple ports? */
-
-struct virtio_console_multiport_conf {
-	struct virtio_console_config config;
-	/* max. number of ports this device can hold */
-	__u32 max_nr_ports;
-	/* number of ports added so far */
-	__u32 nr_ports;
-} __attribute__((packed));
-
-/*
- * A message that's passed between the Host and the Guest for a
- * particular port.
- */
-struct virtio_console_control {
-	__u32 id;		/* Port number */
-	__u16 event;		/* The kind of control event (see below) */
-	__u16 value;		/* Extra information for the key */
-};
-
-/* Some events for control messages */
-#define VIRTIO_CONSOLE_PORT_READY	0
-#define VIRTIO_CONSOLE_CONSOLE_PORT	1
-#define VIRTIO_CONSOLE_RESIZE		2
-#define VIRTIO_CONSOLE_PORT_OPEN	3
-#define VIRTIO_CONSOLE_PORT_NAME	4
-#define VIRTIO_CONSOLE_PORT_REMOVE	5
-
 /*
  * This is a global struct for storing common data for all the devices
  * this driver handles.
@@ -150,7 +121,7 @@ struct ports_device {
 	spinlock_t cvq_lock;
 
 	/* The current config space is stored here */
-	struct virtio_console_multiport_conf config;
+	struct virtio_console_config config;
 
 	/* The virtio device we're associated with */
 	struct virtio_device *vdev;
@@ -1243,7 +1214,7 @@ fail:
  */
 static void config_work_handler(struct work_struct *work)
 {
-	struct virtio_console_multiport_conf virtconconf;
+	struct virtio_console_config virtconconf;
 	struct ports_device *portdev;
 	struct virtio_device *vdev;
 	int err;
@@ -1252,8 +1223,7 @@ static void config_work_handler(struct work_struct *work)
 
 	vdev = portdev->vdev;
 	vdev->config->get(vdev,
-			  offsetof(struct virtio_console_multiport_conf,
-				   nr_ports),
+			  offsetof(struct virtio_console_config, nr_ports),
 			  &virtconconf.nr_ports,
 			  sizeof(virtconconf.nr_ports));
 
@@ -1445,19 +1415,16 @@ static int __devinit virtcons_probe(struct virtio_device *vdev)
 	multiport = false;
 	portdev->config.nr_ports = 1;
 	portdev->config.max_nr_ports = 1;
-#if 0 /* Multiport is not quite ready yet --RR */
 	if (virtio_has_feature(vdev, VIRTIO_CONSOLE_F_MULTIPORT)) {
 		multiport = true;
 		vdev->features[0] |= 1 << VIRTIO_CONSOLE_F_MULTIPORT;
 
-		vdev->config->get(vdev,
-				  offsetof(struct virtio_console_multiport_conf,
-					   nr_ports),
+		vdev->config->get(vdev, offsetof(struct virtio_console_config,
+						 nr_ports),
 				  &portdev->config.nr_ports,
 				  sizeof(portdev->config.nr_ports));
-		vdev->config->get(vdev,
-				  offsetof(struct virtio_console_multiport_conf,
-					   max_nr_ports),
+		vdev->config->get(vdev, offsetof(struct virtio_console_config,
+						 max_nr_ports),
 				  &portdev->config.max_nr_ports,
 				  sizeof(portdev->config.max_nr_ports));
 		if (portdev->config.nr_ports > portdev->config.max_nr_ports) {
@@ -1473,7 +1440,6 @@ static int __devinit virtcons_probe(struct virtio_device *vdev)
 
 	/* Let the Host know we support multiple ports.*/
 	vdev->config->finalize_features(vdev);
-#endif
 
 	err = init_vqs(portdev);
 	if (err < 0) {
@@ -1556,6 +1522,7 @@ static struct virtio_device_id id_table[] = {
 
 static unsigned int features[] = {
 	VIRTIO_CONSOLE_F_SIZE,
+	VIRTIO_CONSOLE_F_MULTIPORT,
 };
 
 static struct virtio_driver virtio_console = {
diff --git a/include/linux/virtio_console.h b/include/linux/virtio_console.h
index 92228a8..ae4f039 100644
--- a/include/linux/virtio_console.h
+++ b/include/linux/virtio_console.h
@@ -12,14 +12,37 @@
 
 /* Feature bits */
 #define VIRTIO_CONSOLE_F_SIZE	0	/* Does host provide console size? */
+#define VIRTIO_CONSOLE_F_MULTIPORT 1	/* Does host provide multiple ports? */
 
 struct virtio_console_config {
 	/* colums of the screens */
 	__u16 cols;
 	/* rows of the screens */
 	__u16 rows;
+	/* max. number of ports this device can hold */
+	__u32 max_nr_ports;
+	/* number of ports added so far */
+	__u32 nr_ports;
 } __attribute__((packed));
 
+/*
+ * A message that's passed between the Host and the Guest for a
+ * particular port.
+ */
+struct virtio_console_control {
+	__u32 id;		/* Port number */
+	__u16 event;		/* The kind of control event (see below) */
+	__u16 value;		/* Extra information for the key */
+};
+
+/* Some events for control messages */
+#define VIRTIO_CONSOLE_PORT_READY	0
+#define VIRTIO_CONSOLE_CONSOLE_PORT	1
+#define VIRTIO_CONSOLE_RESIZE		2
+#define VIRTIO_CONSOLE_PORT_OPEN	3
+#define VIRTIO_CONSOLE_PORT_NAME	4
+#define VIRTIO_CONSOLE_PORT_REMOVE	5
+
 #ifdef __KERNEL__
 int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int));
 #endif /* __KERNEL__ */
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 02/11] virtio: console: Add a __send_control_msg() that can send messages without a valid port
  2010-04-08 14:49 ` [PATCH 01/11] Revert "virtio: disable multiport console support." Amit Shah
@ 2010-04-08 14:49   ` Amit Shah
  2010-04-08 14:49     ` [PATCH 03/11] virtio: console: Let host know of port or device add failures Amit Shah
  0 siblings, 1 reply; 13+ messages in thread
From: Amit Shah @ 2010-04-08 14:49 UTC (permalink / raw)
  To: Virtualization List; +Cc: Amit Shah, Juan Quintela, Michael S. Tsirkin

We will introduce control messages that operate on the device as a whole
rather than just ports. Make send_control_msg() a wrapper around
__send_control_msg() which does not need a valid port.

Signed-off-by: Amit Shah <amit.shah@redhat.com>
---
 drivers/char/virtio_console.c |   16 +++++++++++-----
 1 files changed, 11 insertions(+), 5 deletions(-)

diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 86e9011..cfd6aa9 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -374,22 +374,22 @@ out:
 	return ret;
 }
 
-static ssize_t send_control_msg(struct port *port, unsigned int event,
-				unsigned int value)
+static ssize_t __send_control_msg(struct ports_device *portdev, u32 port_id,
+				  unsigned int event, unsigned int value)
 {
 	struct scatterlist sg[1];
 	struct virtio_console_control cpkt;
 	struct virtqueue *vq;
 	unsigned int len;
 
-	if (!use_multiport(port->portdev))
+	if (!use_multiport(portdev))
 		return 0;
 
-	cpkt.id = port->id;
+	cpkt.id = port_id;
 	cpkt.event = event;
 	cpkt.value = value;
 
-	vq = port->portdev->c_ovq;
+	vq = portdev->c_ovq;
 
 	sg_init_one(sg, &cpkt, sizeof(cpkt));
 	if (vq->vq_ops->add_buf(vq, sg, 1, 0, &cpkt) >= 0) {
@@ -400,6 +400,12 @@ static ssize_t send_control_msg(struct port *port, unsigned int event,
 	return 0;
 }
 
+static ssize_t send_control_msg(struct port *port, unsigned int event,
+				unsigned int value)
+{
+	return __send_control_msg(port->portdev, port->id, event, value);
+}
+
 static ssize_t send_buf(struct port *port, void *in_buf, size_t in_count)
 {
 	struct scatterlist sg[1];
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 03/11] virtio: console: Let host know of port or device add failures
  2010-04-08 14:49   ` [PATCH 02/11] virtio: console: Add a __send_control_msg() that can send messages without a valid port Amit Shah
@ 2010-04-08 14:49     ` Amit Shah
  2010-04-08 14:49       ` [PATCH 04/11] virtio: console: Return -EPIPE to hvc_console if we lost the connection Amit Shah
  0 siblings, 1 reply; 13+ messages in thread
From: Amit Shah @ 2010-04-08 14:49 UTC (permalink / raw)
  To: Virtualization List; +Cc: Amit Shah, Juan Quintela, Michael S. Tsirkin

The host may want to know and let management apps notify of port or
device add failures. Send a control message saying the device or port is
not ready in this case.

Signed-off-by: Amit Shah <amit.shah@redhat.com>
---
 drivers/char/virtio_console.c  |    5 +++++
 include/linux/virtio_console.h |    3 +++
 2 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index cfd6aa9..5aa1891 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -1210,6 +1210,8 @@ free_cdev:
 free_port:
 	kfree(port);
 fail:
+	/* The host might want to notify management sw about port add failure */
+	send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 0);
 	return err;
 }
 
@@ -1488,6 +1490,9 @@ free_chrdev:
 free:
 	kfree(portdev);
 fail:
+	/* The host might want to notify mgmt sw about device add failure */
+	__send_control_msg(portdev, VIRTIO_CONSOLE_BAD_ID,
+			   VIRTIO_CONSOLE_DEVICE_READY, 0);
 	return err;
 }
 
diff --git a/include/linux/virtio_console.h b/include/linux/virtio_console.h
index ae4f039..0157361 100644
--- a/include/linux/virtio_console.h
+++ b/include/linux/virtio_console.h
@@ -14,6 +14,8 @@
 #define VIRTIO_CONSOLE_F_SIZE	0	/* Does host provide console size? */
 #define VIRTIO_CONSOLE_F_MULTIPORT 1	/* Does host provide multiple ports? */
 
+#define VIRTIO_CONSOLE_BAD_ID		(~(u32)0)
+
 struct virtio_console_config {
 	/* colums of the screens */
 	__u16 cols;
@@ -42,6 +44,7 @@ struct virtio_console_control {
 #define VIRTIO_CONSOLE_PORT_OPEN	3
 #define VIRTIO_CONSOLE_PORT_NAME	4
 #define VIRTIO_CONSOLE_PORT_REMOVE	5
+#define VIRTIO_CONSOLE_DEVICE_READY	6
 
 #ifdef __KERNEL__
 int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int));
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 04/11] virtio: console: Return -EPIPE to hvc_console if we lost the connection
  2010-04-08 14:49     ` [PATCH 03/11] virtio: console: Let host know of port or device add failures Amit Shah
@ 2010-04-08 14:49       ` Amit Shah
  2010-04-08 14:49         ` [PATCH 05/11] virtio: console: Don't call hvc_remove() on unplugging console ports Amit Shah
  0 siblings, 1 reply; 13+ messages in thread
From: Amit Shah @ 2010-04-08 14:49 UTC (permalink / raw)
  To: Virtualization List; +Cc: Amit Shah, Juan Quintela, Michael S. Tsirkin

hvc_console handles -EPIPE properly when the connection to the host is
lost.

Signed-off-by: Amit Shah <amit.shah@redhat.com>
---
 drivers/char/virtio_console.c |    8 ++++++--
 1 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 5aa1891..24fa759 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -653,7 +653,7 @@ static int put_chars(u32 vtermno, const char *buf, int count)
 
 	port = find_port_by_vtermno(vtermno);
 	if (!port)
-		return 0;
+		return -EPIPE;
 
 	return send_buf(port, (void *)buf, count);
 }
@@ -669,9 +669,13 @@ static int get_chars(u32 vtermno, char *buf, int count)
 {
 	struct port *port;
 
+	/* If we've not set up the port yet, we have no input to give. */
+	if (unlikely(early_put_chars))
+		return 0;
+
 	port = find_port_by_vtermno(vtermno);
 	if (!port)
-		return 0;
+		return -EPIPE;
 
 	/* If we don't have an input queue yet, we can't get input. */
 	BUG_ON(!port->in_vq);
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 05/11] virtio: console: Don't call hvc_remove() on unplugging console ports
  2010-04-08 14:49       ` [PATCH 04/11] virtio: console: Return -EPIPE to hvc_console if we lost the connection Amit Shah
@ 2010-04-08 14:49         ` Amit Shah
  2010-04-08 14:49           ` [PATCH 06/11] virtio: console: Remove config work handler Amit Shah
  0 siblings, 1 reply; 13+ messages in thread
From: Amit Shah @ 2010-04-08 14:49 UTC (permalink / raw)
  To: Virtualization List; +Cc: Amit Shah, Juan Quintela, Michael S. Tsirkin

hvc_remove() has some bug which freezes other active hvc ports when one
port is removed.

So disable calling of hvc_remove() which deregisters a port with the
hvc_console.

If the hvc_console code calls into our get_chars() routine as a result
of a poll operation, we will return -EPIPE and the hvc_console code will
then do the necessary cleanup.

This call will be restored when the bug in hvc_remove() is found and
fixed.

Signed-off-by: Amit Shah <amit.shah@redhat.com>
---
 drivers/char/virtio_console.c |   11 +++++++++++
 1 files changed, 11 insertions(+), 0 deletions(-)

diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 24fa759..6adde65 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -869,7 +869,18 @@ static int remove_port(struct port *port)
 		spin_lock_irq(&pdrvdata_lock);
 		list_del(&port->cons.list);
 		spin_unlock_irq(&pdrvdata_lock);
+#if 0
+		/*
+		 * hvc_remove() not called as removing one hvc port
+		 * results in other hvc ports getting frozen.
+		 *
+		 * Once this is resolved in hvc, this functionality
+		 * will be enabled.  Till that is done, the -EPIPE
+		 * return from get_chars() above will help
+		 * hvc_console.c to clean up on ports we remove here.
+		 */
 		hvc_remove(port->cons.hvc);
+#endif
 	}
 	if (port->guest_connected)
 		send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 0);
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 06/11] virtio: console: Remove config work handler
  2010-04-08 14:49         ` [PATCH 05/11] virtio: console: Don't call hvc_remove() on unplugging console ports Amit Shah
@ 2010-04-08 14:49           ` Amit Shah
  2010-04-08 14:49             ` [PATCH 07/11] virtio: console: Move code around for future patches Amit Shah
  0 siblings, 1 reply; 13+ messages in thread
From: Amit Shah @ 2010-04-08 14:49 UTC (permalink / raw)
  To: Virtualization List; +Cc: Amit Shah, Juan Quintela, Michael S. Tsirkin

We're going to switch to using control messages for port hot-plug and
initial port discovery. Remove the config work handler which handled
port hot-plug so far.

Signed-off-by: Amit Shah <amit.shah@redhat.com>
---
 drivers/char/virtio_console.c |   64 +----------------------------------------
 1 files changed, 1 insertions(+), 63 deletions(-)

diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 6adde65..003fe6a 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -110,7 +110,6 @@ struct ports_device {
 	 * notification
 	 */
 	struct work_struct control_work;
-	struct work_struct config_work;
 
 	struct list_head ports;
 
@@ -1084,10 +1083,7 @@ static void config_intr(struct virtio_device *vdev)
 	struct ports_device *portdev;
 
 	portdev = vdev->priv;
-	if (use_multiport(portdev)) {
-		/* Handle port hot-add */
-		schedule_work(&portdev->config_work);
-	}
+
 	/*
 	 * We'll use this way of resizing only for legacy support.
 	 * For newer userspace (VIRTIO_CONSOLE_F_MULTPORT+), use
@@ -1230,62 +1226,6 @@ fail:
 	return err;
 }
 
-/*
- * The workhandler for config-space updates.
- *
- * This is called when ports are hot-added.
- */
-static void config_work_handler(struct work_struct *work)
-{
-	struct virtio_console_config virtconconf;
-	struct ports_device *portdev;
-	struct virtio_device *vdev;
-	int err;
-
-	portdev = container_of(work, struct ports_device, config_work);
-
-	vdev = portdev->vdev;
-	vdev->config->get(vdev,
-			  offsetof(struct virtio_console_config, nr_ports),
-			  &virtconconf.nr_ports,
-			  sizeof(virtconconf.nr_ports));
-
-	if (portdev->config.nr_ports == virtconconf.nr_ports) {
-		/*
-		 * Port 0 got hot-added.  Since we already did all the
-		 * other initialisation for it, just tell the Host
-		 * that the port is ready if we find the port.  In
-		 * case the port was hot-removed earlier, we call
-		 * add_port to add the port.
-		 */
-		struct port *port;
-
-		port = find_port_by_id(portdev, 0);
-		if (!port)
-			add_port(portdev, 0);
-		else
-			send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1);
-		return;
-	}
-	if (virtconconf.nr_ports > portdev->config.max_nr_ports) {
-		dev_warn(&vdev->dev,
-			 "More ports specified (%u) than allowed (%u)",
-			 portdev->config.nr_ports + 1,
-			 portdev->config.max_nr_ports);
-		return;
-	}
-	if (virtconconf.nr_ports < portdev->config.nr_ports)
-		return;
-
-	/* Hot-add ports */
-	while (virtconconf.nr_ports - portdev->config.nr_ports) {
-		err = add_port(portdev, portdev->config.nr_ports);
-		if (err)
-			break;
-		portdev->config.nr_ports++;
-	}
-}
-
 static int init_vqs(struct ports_device *portdev)
 {
 	vq_callback_t **io_callbacks;
@@ -1478,7 +1418,6 @@ static int __devinit virtcons_probe(struct virtio_device *vdev)
 
 		spin_lock_init(&portdev->cvq_lock);
 		INIT_WORK(&portdev->control_work, &control_work_handler);
-		INIT_WORK(&portdev->config_work, &config_work_handler);
 
 		nr_added_bufs = fill_queue(portdev->c_ivq, &portdev->cvq_lock);
 		if (!nr_added_bufs) {
@@ -1521,7 +1460,6 @@ static void virtcons_remove(struct virtio_device *vdev)
 	portdev = vdev->priv;
 
 	cancel_work_sync(&portdev->control_work);
-	cancel_work_sync(&portdev->config_work);
 
 	list_for_each_entry_safe(port, port2, &portdev->ports, list)
 		remove_port(port);
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 07/11] virtio: console: Move code around for future patches
  2010-04-08 14:49           ` [PATCH 06/11] virtio: console: Remove config work handler Amit Shah
@ 2010-04-08 14:49             ` Amit Shah
  2010-04-08 14:49               ` [PATCH 08/11] virtio: console: Use a control message to add ports Amit Shah
  0 siblings, 1 reply; 13+ messages in thread
From: Amit Shah @ 2010-04-08 14:49 UTC (permalink / raw)
  To: Virtualization List; +Cc: Amit Shah, Juan Quintela, Michael S. Tsirkin

We're going to use add_port() from handle_control_message() in the next
patch.

Move the add_port() and fill_queue(), which depends on it, above
handle_control_message() to avoid forward declarations.

Signed-off-by: Amit Shah <amit.shah@redhat.com>
---
 drivers/char/virtio_console.c |  264 ++++++++++++++++++++---------------------
 1 files changed, 131 insertions(+), 133 deletions(-)

diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 003fe6a..f155de9 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -855,6 +855,137 @@ static const struct file_operations port_debugfs_ops = {
 	.read  = debugfs_read,
 };
 
+static unsigned int fill_queue(struct virtqueue *vq, spinlock_t *lock)
+{
+	struct port_buffer *buf;
+	unsigned int nr_added_bufs;
+	int ret;
+
+	nr_added_bufs = 0;
+	do {
+		buf = alloc_buf(PAGE_SIZE);
+		if (!buf)
+			break;
+
+		spin_lock_irq(lock);
+		ret = add_inbuf(vq, buf);
+		if (ret < 0) {
+			spin_unlock_irq(lock);
+			free_buf(buf);
+			break;
+		}
+		nr_added_bufs++;
+		spin_unlock_irq(lock);
+	} while (ret > 0);
+
+	return nr_added_bufs;
+}
+
+static int add_port(struct ports_device *portdev, u32 id)
+{
+	char debugfs_name[16];
+	struct port *port;
+	struct port_buffer *buf;
+	dev_t devt;
+	unsigned int nr_added_bufs;
+	int err;
+
+	port = kmalloc(sizeof(*port), GFP_KERNEL);
+	if (!port) {
+		err = -ENOMEM;
+		goto fail;
+	}
+
+	port->portdev = portdev;
+	port->id = id;
+
+	port->name = NULL;
+	port->inbuf = NULL;
+	port->cons.hvc = NULL;
+
+	port->host_connected = port->guest_connected = false;
+
+	port->in_vq = portdev->in_vqs[port->id];
+	port->out_vq = portdev->out_vqs[port->id];
+
+	cdev_init(&port->cdev, &port_fops);
+
+	devt = MKDEV(portdev->chr_major, id);
+	err = cdev_add(&port->cdev, devt, 1);
+	if (err < 0) {
+		dev_err(&port->portdev->vdev->dev,
+			"Error %d adding cdev for port %u\n", err, id);
+		goto free_port;
+	}
+	port->dev = device_create(pdrvdata.class, &port->portdev->vdev->dev,
+				  devt, port, "vport%up%u",
+				  port->portdev->drv_index, id);
+	if (IS_ERR(port->dev)) {
+		err = PTR_ERR(port->dev);
+		dev_err(&port->portdev->vdev->dev,
+			"Error %d creating device for port %u\n",
+			err, id);
+		goto free_cdev;
+	}
+
+	spin_lock_init(&port->inbuf_lock);
+	init_waitqueue_head(&port->waitqueue);
+
+	/* Fill the in_vq with buffers so the host can send us data. */
+	nr_added_bufs = fill_queue(port->in_vq, &port->inbuf_lock);
+	if (!nr_added_bufs) {
+		dev_err(port->dev, "Error allocating inbufs\n");
+		err = -ENOMEM;
+		goto free_device;
+	}
+
+	/*
+	 * If we're not using multiport support, this has to be a console port
+	 */
+	if (!use_multiport(port->portdev)) {
+		err = init_port_console(port);
+		if (err)
+			goto free_inbufs;
+	}
+
+	spin_lock_irq(&portdev->ports_lock);
+	list_add_tail(&port->list, &port->portdev->ports);
+	spin_unlock_irq(&portdev->ports_lock);
+
+	/*
+	 * Tell the Host we're set so that it can send us various
+	 * configuration parameters for this port (eg, port name,
+	 * caching, whether this is a console port, etc.)
+	 */
+	send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1);
+
+	if (pdrvdata.debugfs_dir) {
+		/*
+		 * Finally, create the debugfs file that we can use to
+		 * inspect a port's state at any time
+		 */
+		sprintf(debugfs_name, "vport%up%u",
+			port->portdev->drv_index, id);
+		port->debugfs_file = debugfs_create_file(debugfs_name, 0444,
+							 pdrvdata.debugfs_dir,
+							 port,
+							 &port_debugfs_ops);
+	}
+	return 0;
+
+free_inbufs:
+	while ((buf = port->in_vq->vq_ops->detach_unused_buf(port->in_vq)))
+		free_buf(buf);
+free_device:
+	device_destroy(pdrvdata.class, port->dev->devt);
+free_cdev:
+	cdev_del(&port->cdev);
+free_port:
+	kfree(port);
+fail:
+	return err;
+}
+
 /* Remove all port-specific data. */
 static int remove_port(struct port *port)
 {
@@ -1093,139 +1224,6 @@ static void config_intr(struct virtio_device *vdev)
 	resize_console(find_port_by_id(portdev, 0));
 }
 
-static unsigned int fill_queue(struct virtqueue *vq, spinlock_t *lock)
-{
-	struct port_buffer *buf;
-	unsigned int nr_added_bufs;
-	int ret;
-
-	nr_added_bufs = 0;
-	do {
-		buf = alloc_buf(PAGE_SIZE);
-		if (!buf)
-			break;
-
-		spin_lock_irq(lock);
-		ret = add_inbuf(vq, buf);
-		if (ret < 0) {
-			spin_unlock_irq(lock);
-			free_buf(buf);
-			break;
-		}
-		nr_added_bufs++;
-		spin_unlock_irq(lock);
-	} while (ret > 0);
-
-	return nr_added_bufs;
-}
-
-static int add_port(struct ports_device *portdev, u32 id)
-{
-	char debugfs_name[16];
-	struct port *port;
-	struct port_buffer *buf;
-	dev_t devt;
-	unsigned int nr_added_bufs;
-	int err;
-
-	port = kmalloc(sizeof(*port), GFP_KERNEL);
-	if (!port) {
-		err = -ENOMEM;
-		goto fail;
-	}
-
-	port->portdev = portdev;
-	port->id = id;
-
-	port->name = NULL;
-	port->inbuf = NULL;
-	port->cons.hvc = NULL;
-
-	port->host_connected = port->guest_connected = false;
-
-	port->in_vq = portdev->in_vqs[port->id];
-	port->out_vq = portdev->out_vqs[port->id];
-
-	cdev_init(&port->cdev, &port_fops);
-
-	devt = MKDEV(portdev->chr_major, id);
-	err = cdev_add(&port->cdev, devt, 1);
-	if (err < 0) {
-		dev_err(&port->portdev->vdev->dev,
-			"Error %d adding cdev for port %u\n", err, id);
-		goto free_port;
-	}
-	port->dev = device_create(pdrvdata.class, &port->portdev->vdev->dev,
-				  devt, port, "vport%up%u",
-				  port->portdev->drv_index, id);
-	if (IS_ERR(port->dev)) {
-		err = PTR_ERR(port->dev);
-		dev_err(&port->portdev->vdev->dev,
-			"Error %d creating device for port %u\n",
-			err, id);
-		goto free_cdev;
-	}
-
-	spin_lock_init(&port->inbuf_lock);
-	init_waitqueue_head(&port->waitqueue);
-
-	/* Fill the in_vq with buffers so the host can send us data. */
-	nr_added_bufs = fill_queue(port->in_vq, &port->inbuf_lock);
-	if (!nr_added_bufs) {
-		dev_err(port->dev, "Error allocating inbufs\n");
-		err = -ENOMEM;
-		goto free_device;
-	}
-
-	/*
-	 * If we're not using multiport support, this has to be a console port
-	 */
-	if (!use_multiport(port->portdev)) {
-		err = init_port_console(port);
-		if (err)
-			goto free_inbufs;
-	}
-
-	spin_lock_irq(&portdev->ports_lock);
-	list_add_tail(&port->list, &port->portdev->ports);
-	spin_unlock_irq(&portdev->ports_lock);
-
-	/*
-	 * Tell the Host we're set so that it can send us various
-	 * configuration parameters for this port (eg, port name,
-	 * caching, whether this is a console port, etc.)
-	 */
-	send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1);
-
-	if (pdrvdata.debugfs_dir) {
-		/*
-		 * Finally, create the debugfs file that we can use to
-		 * inspect a port's state at any time
-		 */
-		sprintf(debugfs_name, "vport%up%u",
-			port->portdev->drv_index, id);
-		port->debugfs_file = debugfs_create_file(debugfs_name, 0444,
-							 pdrvdata.debugfs_dir,
-							 port,
-							 &port_debugfs_ops);
-	}
-	return 0;
-
-free_inbufs:
-	while ((buf = port->in_vq->vq_ops->detach_unused_buf(port->in_vq)))
-		free_buf(buf);
-free_device:
-	device_destroy(pdrvdata.class, port->dev->devt);
-free_cdev:
-	cdev_del(&port->cdev);
-free_port:
-	kfree(port);
-fail:
-	/* The host might want to notify management sw about port add failure */
-	send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 0);
-	return err;
-}
-
 static int init_vqs(struct ports_device *portdev)
 {
 	vq_callback_t **io_callbacks;
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 08/11] virtio: console: Use a control message to add ports
  2010-04-08 14:49             ` [PATCH 07/11] virtio: console: Move code around for future patches Amit Shah
@ 2010-04-08 14:49               ` Amit Shah
  2010-04-08 14:49                 ` [PATCH 09/11] virtio: console: Don't always create a port 0 if using multiport Amit Shah
  0 siblings, 1 reply; 13+ messages in thread
From: Amit Shah @ 2010-04-08 14:49 UTC (permalink / raw)
  To: Virtualization List; +Cc: Amit Shah, Juan Quintela, Michael S. Tsirkin

Instead of the host and guest independently enumerating ports, switch to
a control message to add ports where the host supplies the port number
so there's no ambiguity or a possibility of a race between the host and
the guest port numbers.

We now no longer need the 'nr_ports' config value. Since no kernel has
been released with the MULTIPORT changes yet, we have a chance to fiddle
with the config space without adding compatibility features.

This is beneficial for management software, which would now be able to
instantiate ports at known locations and avoid problems that arise with
implicit numbering in the host and the guest. This removes the 'guessing
game' part of it, and management software can now actually indicate
which id to spawn a particular port on.

Signed-off-by: Amit Shah <amit.shah@redhat.com>
---
 drivers/char/virtio_console.c  |   77 +++++++++++++++++-----------------------
 include/linux/virtio_console.h |   17 ++++-----
 2 files changed, 41 insertions(+), 53 deletions(-)

diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index f155de9..4087248 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -1046,7 +1046,7 @@ static void handle_control_message(struct ports_device *portdev,
 	cpkt = (struct virtio_console_control *)(buf->buf + buf->offset);
 
 	port = find_port_by_id(portdev, cpkt->id);
-	if (!port) {
+	if (!port && cpkt->event != VIRTIO_CONSOLE_PORT_ADD) {
 		/* No valid header at start of buffer.  Drop it. */
 		dev_dbg(&portdev->vdev->dev,
 			"Invalid index %u in control packet\n", cpkt->id);
@@ -1054,6 +1054,30 @@ static void handle_control_message(struct ports_device *portdev,
 	}
 
 	switch (cpkt->event) {
+	case VIRTIO_CONSOLE_PORT_ADD:
+		if (port) {
+			/*
+			 * This can happen for port 0: we have to
+			 * create a console port during probe() as was
+			 * the behaviour before the MULTIPORT feature.
+			 * On a newer host, when the host tells us
+			 * that a port 0 is available, we should just
+			 * say we have the port all set up.
+			 */
+			send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1);
+			break;
+		}
+		if (cpkt->id >= portdev->config.max_nr_ports) {
+			dev_warn(&portdev->vdev->dev,
+				"Request for adding port with out-of-bound id %u, max. supported id: %u\n",
+				cpkt->id, portdev->config.max_nr_ports - 1);
+			break;
+		}
+		add_port(portdev, cpkt->id);
+		break;
+	case VIRTIO_CONSOLE_PORT_REMOVE:
+		remove_port(port);
+		break;
 	case VIRTIO_CONSOLE_CONSOLE_PORT:
 		if (!cpkt->value)
 			break;
@@ -1112,32 +1136,6 @@ static void handle_control_message(struct ports_device *portdev,
 			kobject_uevent(&port->dev->kobj, KOBJ_CHANGE);
 		}
 		break;
-	case VIRTIO_CONSOLE_PORT_REMOVE:
-		/*
-		 * Hot unplug the port.  We don't decrement nr_ports
-		 * since we don't want to deal with extra complexities
-		 * of using the lowest-available port id: We can just
-		 * pick up the nr_ports number as the id and not have
-		 * userspace send it to us.  This helps us in two
-		 * ways:
-		 *
-		 * - We don't need to have a 'port_id' field in the
-		 *   config space when a port is hot-added.  This is a
-		 *   good thing as we might queue up multiple hotplug
-		 *   requests issued in our workqueue.
-		 *
-		 * - Another way to deal with this would have been to
-		 *   use a bitmap of the active ports and select the
-		 *   lowest non-active port from that map.  That
-		 *   bloats the already tight config space and we
-		 *   would end up artificially limiting the
-		 *   max. number of ports to sizeof(bitmap).  Right
-		 *   now we can support 2^32 ports (as the port id is
-		 *   stored in a u32 type).
-		 *
-		 */
-		remove_port(port);
-		break;
 	}
 }
 
@@ -1345,7 +1343,6 @@ static const struct file_operations portdev_fops = {
 static int __devinit virtcons_probe(struct virtio_device *vdev)
 {
 	struct ports_device *portdev;
-	u32 i;
 	int err;
 	bool multiport;
 
@@ -1374,29 +1371,15 @@ static int __devinit virtcons_probe(struct virtio_device *vdev)
 	}
 
 	multiport = false;
-	portdev->config.nr_ports = 1;
 	portdev->config.max_nr_ports = 1;
 	if (virtio_has_feature(vdev, VIRTIO_CONSOLE_F_MULTIPORT)) {
 		multiport = true;
 		vdev->features[0] |= 1 << VIRTIO_CONSOLE_F_MULTIPORT;
 
 		vdev->config->get(vdev, offsetof(struct virtio_console_config,
-						 nr_ports),
-				  &portdev->config.nr_ports,
-				  sizeof(portdev->config.nr_ports));
-		vdev->config->get(vdev, offsetof(struct virtio_console_config,
 						 max_nr_ports),
 				  &portdev->config.max_nr_ports,
 				  sizeof(portdev->config.max_nr_ports));
-		if (portdev->config.nr_ports > portdev->config.max_nr_ports) {
-			dev_warn(&vdev->dev,
-				 "More ports (%u) specified than allowed (%u). Will init %u ports.",
-				 portdev->config.nr_ports,
-				 portdev->config.max_nr_ports,
-				 portdev->config.max_nr_ports);
-
-			portdev->config.nr_ports = portdev->config.max_nr_ports;
-		}
 	}
 
 	/* Let the Host know we support multiple ports.*/
@@ -1426,11 +1409,17 @@ static int __devinit virtcons_probe(struct virtio_device *vdev)
 		}
 	}
 
-	for (i = 0; i < portdev->config.nr_ports; i++)
-		add_port(portdev, i);
+	/*
+	 * For backward compatibility: if we're running on an older
+	 * host, we always want to create a console port.
+	 */
+	add_port(portdev, 0);
 
 	/* Start using the new console output. */
 	early_put_chars = NULL;
+
+	__send_control_msg(portdev, VIRTIO_CONSOLE_BAD_ID,
+			   VIRTIO_CONSOLE_DEVICE_READY, 1);
 	return 0;
 
 free_vqs:
diff --git a/include/linux/virtio_console.h b/include/linux/virtio_console.h
index 0157361..a85064d 100644
--- a/include/linux/virtio_console.h
+++ b/include/linux/virtio_console.h
@@ -23,8 +23,6 @@ struct virtio_console_config {
 	__u16 rows;
 	/* max. number of ports this device can hold */
 	__u32 max_nr_ports;
-	/* number of ports added so far */
-	__u32 nr_ports;
 } __attribute__((packed));
 
 /*
@@ -38,13 +36,14 @@ struct virtio_console_control {
 };
 
 /* Some events for control messages */
-#define VIRTIO_CONSOLE_PORT_READY	0
-#define VIRTIO_CONSOLE_CONSOLE_PORT	1
-#define VIRTIO_CONSOLE_RESIZE		2
-#define VIRTIO_CONSOLE_PORT_OPEN	3
-#define VIRTIO_CONSOLE_PORT_NAME	4
-#define VIRTIO_CONSOLE_PORT_REMOVE	5
-#define VIRTIO_CONSOLE_DEVICE_READY	6
+#define VIRTIO_CONSOLE_DEVICE_READY	0
+#define VIRTIO_CONSOLE_PORT_ADD		1
+#define VIRTIO_CONSOLE_PORT_REMOVE	2
+#define VIRTIO_CONSOLE_PORT_READY	3
+#define VIRTIO_CONSOLE_CONSOLE_PORT	4
+#define VIRTIO_CONSOLE_RESIZE		5
+#define VIRTIO_CONSOLE_PORT_OPEN	6
+#define VIRTIO_CONSOLE_PORT_NAME	7
 
 #ifdef __KERNEL__
 int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int));
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 09/11] virtio: console: Don't always create a port 0 if using multiport
  2010-04-08 14:49               ` [PATCH 08/11] virtio: console: Use a control message to add ports Amit Shah
@ 2010-04-08 14:49                 ` Amit Shah
  2010-04-08 14:49                   ` [PATCH 10/11] virtio: console: Rename wait_is_over() to will_read_block() Amit Shah
  2010-04-10  7:19                   ` [PATCH 09/11] virtio: console: Don't always create a port 0 if using multiport Amit Shah
  0 siblings, 2 replies; 13+ messages in thread
From: Amit Shah @ 2010-04-08 14:49 UTC (permalink / raw)
  To: Virtualization List; +Cc: Amit Shah, Juan Quintela, Michael S. Tsirkin

If we're using multiport, there's no point in always creating a console
port. Create the console port only if the host doesn't support
multiport.

Signed-off-by: Amit Shah <amit.shah@redhat.com>
---
 drivers/char/virtio_console.c |   26 +++++++++-----------------
 1 files changed, 9 insertions(+), 17 deletions(-)

diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 4087248..567acbd 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -784,6 +784,13 @@ int init_port_console(struct port *port)
 	spin_unlock_irq(&pdrvdata_lock);
 	port->guest_connected = true;
 
+	/*
+	 * Start using the new console output if this is the first
+	 * console to come up.
+	 */
+	if (early_put_chars)
+		early_put_chars = NULL;
+
 	/* Notify host of port being opened */
 	send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 1);
 
@@ -1056,14 +1063,8 @@ static void handle_control_message(struct ports_device *portdev,
 	switch (cpkt->event) {
 	case VIRTIO_CONSOLE_PORT_ADD:
 		if (port) {
-			/*
-			 * This can happen for port 0: we have to
-			 * create a console port during probe() as was
-			 * the behaviour before the MULTIPORT feature.
-			 * On a newer host, when the host tells us
-			 * that a port 0 is available, we should just
-			 * say we have the port all set up.
-			 */
+			dev_dbg(&portdev->vdev->dev,
+				"Port %u already added\n", port->id);
 			send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1);
 			break;
 		}
@@ -1409,15 +1410,6 @@ static int __devinit virtcons_probe(struct virtio_device *vdev)
 		}
 	}
 
-	/*
-	 * For backward compatibility: if we're running on an older
-	 * host, we always want to create a console port.
-	 */
-	add_port(portdev, 0);
-
-	/* Start using the new console output. */
-	early_put_chars = NULL;
-
 	__send_control_msg(portdev, VIRTIO_CONSOLE_BAD_ID,
 			   VIRTIO_CONSOLE_DEVICE_READY, 1);
 	return 0;
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 10/11] virtio: console: Rename wait_is_over() to will_read_block()
  2010-04-08 14:49                 ` [PATCH 09/11] virtio: console: Don't always create a port 0 if using multiport Amit Shah
@ 2010-04-08 14:49                   ` Amit Shah
  2010-04-08 14:49                     ` [PATCH 11/11] virtio: console: Add support for nonblocking write()s Amit Shah
  2010-04-10  7:19                   ` [PATCH 09/11] virtio: console: Don't always create a port 0 if using multiport Amit Shah
  1 sibling, 1 reply; 13+ messages in thread
From: Amit Shah @ 2010-04-08 14:49 UTC (permalink / raw)
  To: Virtualization List; +Cc: Amit Shah, Juan Quintela, Michael S. Tsirkin

We'll introduce a function that checks if write will block.  Have
function names that are similar for the two cases.

Signed-off-by: Amit Shah <amit.shah@redhat.com>
---
 drivers/char/virtio_console.c |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 567acbd..03d9229 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -479,9 +479,9 @@ static ssize_t fill_readbuf(struct port *port, char *out_buf, size_t out_count,
 }
 
 /* The condition that must be true for polling to end */
-static bool wait_is_over(struct port *port)
+static bool will_read_block(struct port *port)
 {
-	return port_has_data(port) || !port->host_connected;
+	return !port_has_data(port) && port->host_connected;
 }
 
 static ssize_t port_fops_read(struct file *filp, char __user *ubuf,
@@ -504,7 +504,7 @@ static ssize_t port_fops_read(struct file *filp, char __user *ubuf,
 			return -EAGAIN;
 
 		ret = wait_event_interruptible(port->waitqueue,
-					       wait_is_over(port));
+					       !will_read_block(port));
 		if (ret < 0)
 			return ret;
 	}
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 11/11] virtio: console: Add support for nonblocking write()s
  2010-04-08 14:49                   ` [PATCH 10/11] virtio: console: Rename wait_is_over() to will_read_block() Amit Shah
@ 2010-04-08 14:49                     ` Amit Shah
  0 siblings, 0 replies; 13+ messages in thread
From: Amit Shah @ 2010-04-08 14:49 UTC (permalink / raw)
  To: Virtualization List; +Cc: Amit Shah, Juan Quintela, Michael S. Tsirkin

If the host port is not open, a write() should either just return if the
file is opened in non-blocking mode, or block till the host port is
opened.

Also, don't spin till host consumes data for nonblocking ports. For
non-blocking ports, we can do away with the spinning and reclaim the
buffers consumed by the host on the next write call or on the condition
that'll make poll return.

Signed-off-by: Amit Shah <amit.shah@redhat.com>
---
 drivers/char/virtio_console.c |  119 ++++++++++++++++++++++++++++++++++++++---
 1 files changed, 111 insertions(+), 8 deletions(-)

diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 03d9229..2a4e4e1 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -159,6 +159,9 @@ struct port {
 	 */
 	spinlock_t inbuf_lock;
 
+	/* Protect the operations on the out_vq. */
+	spinlock_t outvq_lock;
+
 	/* The IO vqs for this port */
 	struct virtqueue *in_vq, *out_vq;
 
@@ -184,6 +187,8 @@ struct port {
 	/* The 'id' to identify the port with the Host */
 	u32 id;
 
+	bool outvq_full;
+
 	/* Is the host device open */
 	bool host_connected;
 
@@ -405,15 +410,33 @@ static ssize_t send_control_msg(struct port *port, unsigned int event,
 	return __send_control_msg(port->portdev, port->id, event, value);
 }
 
-static ssize_t send_buf(struct port *port, void *in_buf, size_t in_count)
+/* Callers must take the port->outvq_lock */
+static void reclaim_consumed_buffers(struct port *port)
+{
+	void *buf;
+	unsigned int len;
+
+	while ((buf = port->out_vq->vq_ops->get_buf(port->out_vq, &len))) {
+		kfree(buf);
+		port->outvq_full = false;
+	}
+}
+
+static ssize_t send_buf(struct port *port, void *in_buf, size_t in_count,
+			bool nonblock)
 {
 	struct scatterlist sg[1];
 	struct virtqueue *out_vq;
 	ssize_t ret;
+	unsigned long flags;
 	unsigned int len;
 
 	out_vq = port->out_vq;
 
+	spin_lock_irqsave(&port->outvq_lock, flags);
+
+	reclaim_consumed_buffers(port);
+
 	sg_init_one(sg, in_buf, in_count);
 	ret = out_vq->vq_ops->add_buf(out_vq, sg, 1, 0, in_buf);
 
@@ -422,14 +445,29 @@ static ssize_t send_buf(struct port *port, void *in_buf, size_t in_count)
 
 	if (ret < 0) {
 		in_count = 0;
-		goto fail;
+		goto done;
 	}
 
-	/* Wait till the host acknowledges it pushed out the data we sent. */
+	if (ret == 0)
+		port->outvq_full = true;
+
+	if (nonblock)
+		goto done;
+
+	/*
+	 * Wait till the host acknowledges it pushed out the data we
+	 * sent.  This is done for ports in blocking mode or for data
+	 * from the hvc_console; the tty operations are performed with
+	 * spinlocks held so we can't sleep here.
+	 */
 	while (!out_vq->vq_ops->get_buf(out_vq, &len))
 		cpu_relax();
-fail:
-	/* We're expected to return the amount of data we wrote */
+done:
+	spin_unlock_irqrestore(&port->outvq_lock, flags);
+	/*
+	 * We're expected to return the amount of data we wrote -- all
+	 * of it
+	 */
 	return in_count;
 }
 
@@ -484,6 +522,25 @@ static bool will_read_block(struct port *port)
 	return !port_has_data(port) && port->host_connected;
 }
 
+static bool will_write_block(struct port *port)
+{
+	bool ret;
+
+	if (!port->host_connected)
+		return true;
+
+	spin_lock_irq(&port->outvq_lock);
+	/*
+	 * Check if the Host has consumed any buffers since we last
+	 * sent data (this is only applicable for nonblocking ports).
+	 */
+	reclaim_consumed_buffers(port);
+	ret = port->outvq_full;
+	spin_unlock_irq(&port->outvq_lock);
+
+	return ret;
+}
+
 static ssize_t port_fops_read(struct file *filp, char __user *ubuf,
 			      size_t count, loff_t *offp)
 {
@@ -530,9 +587,22 @@ static ssize_t port_fops_write(struct file *filp, const char __user *ubuf,
 	struct port *port;
 	char *buf;
 	ssize_t ret;
+	bool nonblock;
 
 	port = filp->private_data;
 
+	nonblock = filp->f_flags & O_NONBLOCK;
+
+	if (will_write_block(port)) {
+		if (nonblock)
+			return -EAGAIN;
+
+		ret = wait_event_interruptible(port->waitqueue,
+					       !will_write_block(port));
+		if (ret < 0)
+			return ret;
+	}
+
 	count = min((size_t)(32 * 1024), count);
 
 	buf = kmalloc(count, GFP_KERNEL);
@@ -545,9 +615,14 @@ static ssize_t port_fops_write(struct file *filp, const char __user *ubuf,
 		goto free_buf;
 	}
 
-	ret = send_buf(port, buf, count);
+	ret = send_buf(port, buf, count, nonblock);
+
+	if (nonblock && ret > 0)
+		goto out;
+
 free_buf:
 	kfree(buf);
+out:
 	return ret;
 }
 
@@ -562,7 +637,7 @@ static unsigned int port_fops_poll(struct file *filp, poll_table *wait)
 	ret = 0;
 	if (port->inbuf)
 		ret |= POLLIN | POLLRDNORM;
-	if (port->host_connected)
+	if (!will_write_block(port))
 		ret |= POLLOUT;
 	if (!port->host_connected)
 		ret |= POLLHUP;
@@ -586,6 +661,10 @@ static int port_fops_release(struct inode *inode, struct file *filp)
 
 	spin_unlock_irq(&port->inbuf_lock);
 
+	spin_lock_irq(&port->outvq_lock);
+	reclaim_consumed_buffers(port);
+	spin_unlock_irq(&port->outvq_lock);
+
 	return 0;
 }
 
@@ -614,6 +693,15 @@ static int port_fops_open(struct inode *inode, struct file *filp)
 	port->guest_connected = true;
 	spin_unlock_irq(&port->inbuf_lock);
 
+	spin_lock_irq(&port->outvq_lock);
+	/*
+	 * There might be a chance that we missed reclaiming a few
+	 * buffers in the window of the port getting previously closed
+	 * and opening now.
+	 */
+	reclaim_consumed_buffers(port);
+	spin_unlock_irq(&port->outvq_lock);
+
 	/* Notify host of port being opened */
 	send_control_msg(filp->private_data, VIRTIO_CONSOLE_PORT_OPEN, 1);
 
@@ -654,7 +742,7 @@ static int put_chars(u32 vtermno, const char *buf, int count)
 	if (!port)
 		return -EPIPE;
 
-	return send_buf(port, (void *)buf, count);
+	return send_buf(port, (void *)buf, count, false);
 }
 
 /*
@@ -846,6 +934,8 @@ static ssize_t debugfs_read(struct file *filp, char __user *ubuf,
 	out_offset += snprintf(buf + out_offset, out_count - out_offset,
 			       "host_connected: %d\n", port->host_connected);
 	out_offset += snprintf(buf + out_offset, out_count - out_offset,
+			       "outvq_full: %d\n", port->outvq_full);
+	out_offset += snprintf(buf + out_offset, out_count - out_offset,
 			       "is_console: %s\n",
 			       is_console_port(port) ? "yes" : "no");
 	out_offset += snprintf(buf + out_offset, out_count - out_offset,
@@ -912,6 +1002,8 @@ static int add_port(struct ports_device *portdev, u32 id)
 
 	port->host_connected = port->guest_connected = false;
 
+	port->outvq_full = false;
+
 	port->in_vq = portdev->in_vqs[port->id];
 	port->out_vq = portdev->out_vqs[port->id];
 
@@ -936,6 +1028,7 @@ static int add_port(struct ports_device *portdev, u32 id)
 	}
 
 	spin_lock_init(&port->inbuf_lock);
+	spin_lock_init(&port->outvq_lock);
 	init_waitqueue_head(&port->waitqueue);
 
 	/* Fill the in_vq with buffers so the host can send us data. */
@@ -1029,6 +1122,8 @@ static int remove_port(struct port *port)
 	/* Remove unused data this port might have received. */
 	discard_port_data(port);
 
+	reclaim_consumed_buffers(port);
+
 	/* Remove buffers we queued up for the Host to send us data in. */
 	while ((buf = port->in_vq->vq_ops->detach_unused_buf(port->in_vq)))
 		free_buf(buf);
@@ -1100,6 +1195,14 @@ static void handle_control_message(struct ports_device *portdev,
 	case VIRTIO_CONSOLE_PORT_OPEN:
 		port->host_connected = cpkt->value;
 		wake_up_interruptible(&port->waitqueue);
+		/*
+		 * If the host port got closed and the host had any
+		 * unconsumed buffers, we'll be able to reclaim them
+		 * now.
+		 */
+		spin_lock_irq(&port->outvq_lock);
+		reclaim_consumed_buffers(port);
+		spin_unlock_irq(&port->outvq_lock);
 		break;
 	case VIRTIO_CONSOLE_PORT_NAME:
 		/*
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH 09/11] virtio: console: Don't always create a port 0 if using multiport
  2010-04-08 14:49                 ` [PATCH 09/11] virtio: console: Don't always create a port 0 if using multiport Amit Shah
  2010-04-08 14:49                   ` [PATCH 10/11] virtio: console: Rename wait_is_over() to will_read_block() Amit Shah
@ 2010-04-10  7:19                   ` Amit Shah
  1 sibling, 0 replies; 13+ messages in thread
From: Amit Shah @ 2010-04-10  7:19 UTC (permalink / raw)
  To: Virtualization List; +Cc: Juan Quintela, Michael S. Tsirkin

On (Thu) Apr 08 2010 [20:19:38], Amit Shah wrote:
> If we're using multiport, there's no point in always creating a console
> port. Create the console port only if the host doesn't support
> multiport.

Er, please use the version below. It adds a console port if multiport is
turned off.

> @@ -1409,15 +1410,6 @@ static int __devinit virtcons_probe(struct virtio_device *vdev)
>  		}
>  	}
>  
> -	/*
> -	 * For backward compatibility: if we're running on an older
> -	 * host, we always want to create a console port.
> -	 */
> -	add_port(portdev, 0);
> -
> -	/* Start using the new console output. */
> -	early_put_chars = NULL;
> -

From ac3c3b09e88e8547a01ff71e516ec75e9d34916b Mon Sep 17 00:00:00 2001
From: Amit Shah <amit.shah@redhat.com>
Date: Tue, 23 Mar 2010 10:27:00 +0530
Subject: [PATCH 09/11] virtio: console: Don't always create a port 0 if using multiport

If we're using multiport, there's no point in always creating a console
port. Create the console port only if the host doesn't support
multiport.

Signed-off-by: Amit Shah <amit.shah@redhat.com>
---
 drivers/char/virtio_console.c |   32 +++++++++++++++-----------------
 1 files changed, 15 insertions(+), 17 deletions(-)

diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 4087248..7d45fcc 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -784,6 +784,13 @@ int init_port_console(struct port *port)
 	spin_unlock_irq(&pdrvdata_lock);
 	port->guest_connected = true;
 
+	/*
+	 * Start using the new console output if this is the first
+	 * console to come up.
+	 */
+	if (early_put_chars)
+		early_put_chars = NULL;
+
 	/* Notify host of port being opened */
 	send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 1);
 
@@ -1056,14 +1063,8 @@ static void handle_control_message(struct ports_device *portdev,
 	switch (cpkt->event) {
 	case VIRTIO_CONSOLE_PORT_ADD:
 		if (port) {
-			/*
-			 * This can happen for port 0: we have to
-			 * create a console port during probe() as was
-			 * the behaviour before the MULTIPORT feature.
-			 * On a newer host, when the host tells us
-			 * that a port 0 is available, we should just
-			 * say we have the port all set up.
-			 */
+			dev_dbg(&portdev->vdev->dev,
+				"Port %u already added\n", port->id);
 			send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1);
 			break;
 		}
@@ -1407,17 +1408,14 @@ static int __devinit virtcons_probe(struct virtio_device *vdev)
 			err = -ENOMEM;
 			goto free_vqs;
 		}
+	} else {
+		/*
+		 * For backward compatibility: Create a console port
+		 * if we're running on older host.
+		 */
+		add_port(portdev, 0);
 	}
 
-	/*
-	 * For backward compatibility: if we're running on an older
-	 * host, we always want to create a console port.
-	 */
-	add_port(portdev, 0);
-
-	/* Start using the new console output. */
-	early_put_chars = NULL;
-
 	__send_control_msg(portdev, VIRTIO_CONSOLE_BAD_ID,
 			   VIRTIO_CONSOLE_DEVICE_READY, 1);
 	return 0;
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2010-04-10  7:19 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-04-08 14:49 [PATCH 00/11] (v6) virtio: console: Fixes, new way of discovering ports Amit Shah
2010-04-08 14:49 ` [PATCH 01/11] Revert "virtio: disable multiport console support." Amit Shah
2010-04-08 14:49   ` [PATCH 02/11] virtio: console: Add a __send_control_msg() that can send messages without a valid port Amit Shah
2010-04-08 14:49     ` [PATCH 03/11] virtio: console: Let host know of port or device add failures Amit Shah
2010-04-08 14:49       ` [PATCH 04/11] virtio: console: Return -EPIPE to hvc_console if we lost the connection Amit Shah
2010-04-08 14:49         ` [PATCH 05/11] virtio: console: Don't call hvc_remove() on unplugging console ports Amit Shah
2010-04-08 14:49           ` [PATCH 06/11] virtio: console: Remove config work handler Amit Shah
2010-04-08 14:49             ` [PATCH 07/11] virtio: console: Move code around for future patches Amit Shah
2010-04-08 14:49               ` [PATCH 08/11] virtio: console: Use a control message to add ports Amit Shah
2010-04-08 14:49                 ` [PATCH 09/11] virtio: console: Don't always create a port 0 if using multiport Amit Shah
2010-04-08 14:49                   ` [PATCH 10/11] virtio: console: Rename wait_is_over() to will_read_block() Amit Shah
2010-04-08 14:49                     ` [PATCH 11/11] virtio: console: Add support for nonblocking write()s Amit Shah
2010-04-10  7:19                   ` [PATCH 09/11] virtio: console: Don't always create a port 0 if using multiport Amit Shah

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.