Linux virtualization list
 help / color / mirror / Atom feed
* Re: Remove host throttling
From: Rusty Russell @ 2010-01-25 10:32 UTC (permalink / raw)
  To: Amit Shah; +Cc: virtualization
In-Reply-To: <1263977465-13983-1-git-send-email-amit.shah@redhat.com>

On Wed, 20 Jan 2010 07:21:02 pm Amit Shah wrote:
> 
> Hey Rusty,
> 
> These are the patches to be replaced -- patches 19, 30, 31 from the
> previous series. Patch 26 from the earlier series is to be dropped.

Thanks, applied!
Rusty.

^ permalink raw reply

* CFP: VPACT 2010: Third International Workshop on Virtualization Performance: Analysis, Characterization and Tools
From: Ming Zhao @ 2010-01-23 16:29 UTC (permalink / raw)
  To: tcpp-announce, performance, infodir_sigarch, vsigplan-l,
	publicity, micro_publicity, hpc-announ
In-Reply-To: <4B5B2044.6070709@cis.fiu.edu>

(our apologies if you receive this announcement multiple times)



VPACT 2010  CALL FOR PAPERS

Third International Workshop on
Virtualization Performance: Analysis, Characterization and Tools

March 28, 2010
White Plains, New York
(co-located with IEEE ISPASS 2010)

The International Workshop on Virtualization Performance: Analysis,
Characterization and Tools (VPACT) is a selective venue for reporting
and discussing new initial results in the measurement,
characterization, analysis, and modeling of the performance of
virtualized computer systems, including the tools to support such
work.  VPACT is interested in results at all scales, including
multicore/manycore processors, mobile devices, desktops, servers, data
centers, clusters, parallel supercomputers, and distributed
virtualized computing environments.

VPACT 2010 seeks papers from researchers and practitioners in both
academia and industry.  Topics of interest include, but are not
limited to the following, in the context of virtualized computer
systems:

- Performance measurement, characterization, analysis, and modeling
- Power measurement characterization, analysis, and modeling
- Workload measurement characterization, analysis, and modeling
- Benchmarks and benchmarking
- Evaluation of hardware virtualization features
- Evaluation of virtualization software (VMMs, etc)
- Evaluation of virtualization services (Clouds, etc)
- Evaluation of scalability in virtualized environments
- Evaluation of innovative uses of virtualization
- Interaction of virtualization and multicore/manycore architectures
- Interaction of virtualization and parallel computing
- Interaction of language and OS virtual machines
- Tools and techniques

Papers should be no more than 10 pages in length, should be
formatted according to the ACM SIG Proceedings style
(http://www.acm.org/sigs/publications/proceedings-templates), and must
be in PDF format.  Reviewing is single-blind.  Submission instructions
are available on the workshop web site, http://vpact.org.

DATES

Submission deadline:     February 1, 2010
Notification:            March 1, 2010
Final form:              March 8, 2010
Workshop:                March 28, 2010


ORGANIZATION

General Chair

Mazin Yousif, IBM


Program Chair

Peter Dinda, Northwestern University


Publicity Chair

Ming Zhao, Florida International University


Program Committee

Patrick Bridges, University of New Mexico
Ron Brightwell, Sandia National Labs
Kshitij Doshi, Intel
Renato Figueiredo, University of Florida
Russ Joseph, Northwestern University
John Lange, Northwestern University
Arthur Maccabe, Oak Ridge National Labs
Elmoustapha Ould-ahmed-vall, Intel
Dhabaleswar Panda, Ohio State University
Kevin Pedretti, Sandia National Labs
Stephen Scott, Oak Ridge National Labs
Benjamin Serebrin, AMD
Tim Sherwood, UC Santa Barbara
Seetharami Seelam, IBM Research
Karsten Schwan, Georgia Tech
Richard Uhlig, Intel
Bhuvan Urgaonkar, Penn State
Peter Varman, Rice University
Dongyan Xu, Purdue
Ming Zhao, Florida International University





--
Ming Zhao, Assistant Professor
School of Computing and Information Sciences
Florida International University
Tel: (305) 348-2034, Fax: (305) 348-3549
Web: http://www.cis.fiu.edu/~zhaom

^ permalink raw reply

* CFP: Workshop on Virtualization Technologies in Distributed Computing (VTDC 2010)
From: Ming Zhao @ 2010-01-23 16:13 UTC (permalink / raw)
  To: tcpp-announce, performance, infodir_sigarch, vsigplan-l,
	publicity, micro_publicity, hpc-announ

(our apologies if you receive this announcement multiple times)

                     Call for Papers
                     ---------------

Workshop on Virtualization Technologies in Distributed Computing (VTDC 2010)

in conjunction with the 19-th International Symposium on High 
Performance Distributed Computing (HPDC-19)

Chicago, Illinois, USA, June 22, 2010
  http://www.grid-appliance.org/wiki/index.php/VTDC10

WORKSHOP SCOPE

Virtualization has proven to be a powerful enabler in the field of 
distributed computing and has led to the emergence of the cloud 
computing paradigm and the provisioning of Infrastructure-as-a-Service 
(IaaS). This new paradigm raises challenges ranging from performance 
evaluation of IaaS platforms, through new methods of resource management 
including providing Service Level Agreements (SLAs) and energy- and 
cost-efficient schedules, to the emergence of supporting technologies 
such as virtual appliance management.

For the last three years, the VTDC workshop has served as a forum for 
the exchange of ideas and experiences studying the challenges and 
opportunities created by IaaS/cloud computing and virtualization 
technologies. VTDC brings together researchers in academia and industry 
who are involved in research and development on resource virtualization 
technologies and on techniques applied to the management of virtualized 
environments in distributed systems.

Topics of interest include but are not limited to:

VTDC 2010 topics of interest include, but are not limited to:

    * Infrastructure as a service (IaaS)
    * Virtualization in data centers
    * Virtualization for resource management and QoS assurance
    * Security aspects of using virtualization in a distributed environment
    * Virtual networks
    * Virtual data, storage as a service
    * Fault tolerance in virtualized environments
    * Virtualization in P2P systems
    * Virtualization-based adaptive/autonomic systems
    * The creation and management of environments/appliances
    * Virtualization technologies
    * Performance modeling (applications and systems)
    * Virtualization techniques for energy/thermal management
    * Case studies of applications on IaaS platforms
    * Deployment studies of virtualization technologies
    * Tools relevant to virtualization

SUBMISSION GUIDELINES

Submitted papers should be limited to 8 pages (including tables, images, 
and references) and should be formatted according to the ACM SIGS Style. 
Please use the official HPDC conference submission site to submit your 
paper; only pdf format is accepted. All papers will receive at least 
three reviews.
Submission implies the willingness of at least one of the authors to 
register
or the workshop and present the paper. The authors of the best paper in 
the workshop will receive a best-paper award.

PROCEEDINGS

The proceedings of the workshop will be published by the ACM.

IMPORTANT DATES

  Submission deadline: March 1, 2010 (11:59 PM EST)
  Author notification: March 26, 2010
  Final papers due:    April 14, 2010
  Workshop:           June 22, 2010

SUBMISSION SITE

Official HPDC conference submission site,
https://ssl.linklings.net/conferences/hpdc/

WORKSHOP WEBSITE

http://www.grid-appliance.org/wiki/index.php/VTDC10

WORKSHOP CHAIRS

General Chair: Renato Figueiredo, University of Florida

Program Chair: Frederic Desprez, INRIA

Steering Committee: Jose A. B. Fortes, University of Florida, Kate 
Keahey, University of Chicago, Argonne National Laboratory

PROGRAM COMMITTEE

  -  James Broberg, The University of Melbourne, Australia
  -  Franck Cappello, INRIA and University of Illinois at Urbana 
Champaign, USA
  -  Dilma M Da silva, IBM Research, USA
  -  Peter Dinda, Northwestern University, USA
  -  Ian Foster, Argonne National Laboratory & The University of 
Chicago, USA
  -  Sebastien Goasguen, Clemson University, USA
  -  Kartik Gopalan, Computer Science, State University of New York at 
Binghamton, USA
  -  Sverre Jarp, CERN, Switzerland
  -  Thilo Kielmann, Vrije Universiteit, Amsterdam, Netherland
  -  Jack Lange, Northwestern University, USA
  -  Laurent Lefèvre, INRIA, University of Lyon, France
  -  Ignacio Lorente, DSA-Research, Universidad Complutense de Madrid, Spain
  -  Norbert Meyer, Poznan Supercomputing and Networking Center, Poland
  -  Christine MORIN, INRIA Rennes - Bretagne Atlantique, France
  -  D. K. Panda, The Ohio State University, USA
  -  Matei Ripeanu, University of British Columbia, Canada
  -  Paul Ruth, University of Mississippi, USA
  -  Kyung D Ryu, IBM T.J. Watson Research Center, USA
  -  Chris Samuel, The Victorian Partnership for Advanced Computing, 
Australia
  -  Frank Siebenlist, Argonne National Laboratory, USA
  -  Frederic Suter, CC IN2P3 / CNRS, France
  -  Dongyan Xu, Purdue University, USA
  -  Mike Wray, HP Labs, Bristol, UK
  -  Mazin Yousif, IBM Corporation, USA
  -  Ming Zhao, Florida International University, USA

CONTACT

For further information please contact
  Frederic.Desprez@inria.fr or renato@acis.ufl.edu



-- 
Ming Zhao, Assistant Professor
School of Computing and Information Sciences
Florida International University
Tel: (305) 348-2034, Fax: (305) 348-3549
Web: http://www.cis.fiu.edu/~zhaom

^ permalink raw reply

* [PATCH] virtio: use smp_XX barriers
From: Michael S. Tsirkin @ 2010-01-21 17:10 UTC (permalink / raw)
  To: Rusty Russell, virtualization

Documentation/memory-barriers.txt says:
Mandatory barriers should not be used to control SMP effects, since
mandatory barriers unnecessarily impose overhead on UP systems.

This rule applies to virtio, so let's do it correctly.

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
 drivers/virtio/virtio_ring.c |   12 ++++++------
 1 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index fbd2ecd..2216587 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -36,10 +36,10 @@
 			panic("%s:in_use = %i\n",		\
 			      (_vq)->vq.name, (_vq)->in_use);	\
 		(_vq)->in_use = __LINE__;			\
-		mb();						\
+		smp_mb();						\
 	} while (0)
 #define END_USE(_vq) \
-	do { BUG_ON(!(_vq)->in_use); (_vq)->in_use = 0; mb(); } while(0)
+	do { BUG_ON(!(_vq)->in_use); (_vq)->in_use = 0; smp_mb(); } while(0)
 #else
 #define BAD_RING(_vq, fmt, args...)				\
 	do {							\
@@ -221,13 +221,13 @@ static void vring_kick(struct virtqueue *_vq)
 	START_USE(vq);
 	/* Descriptors and available array need to be set before we expose the
 	 * new available array entries. */
-	wmb();
+	smp_wmb();
 
 	vq->vring.avail->idx += vq->num_added;
 	vq->num_added = 0;
 
 	/* Need to update avail index before checking if we should notify */
-	mb();
+	smp_mb();
 
 	if (!(vq->vring.used->flags & VRING_USED_F_NO_NOTIFY))
 		/* Prod other side to tell it about changes. */
@@ -286,7 +286,7 @@ static void *vring_get_buf(struct virtqueue *_vq, unsigned int *len)
 	}
 
 	/* Only get used array entries after they have been exposed by host. */
-	rmb();
+	smp_rmb();
 
 	i = vq->vring.used->ring[vq->last_used_idx%vq->vring.num].id;
 	*len = vq->vring.used->ring[vq->last_used_idx%vq->vring.num].len;
@@ -324,7 +324,7 @@ static bool vring_enable_cb(struct virtqueue *_vq)
 	/* We optimistically turn back on interrupts, then check if there was
 	 * more to do. */
 	vq->vring.avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT;
-	mb();
+	smp_mb();
 	if (unlikely(more_used(vq))) {
 		END_USE(vq);
 		return false;
-- 
1.6.6.144.g5c3af

^ permalink raw reply related

* [PATCH] virtio-spec: Update the spec for recent virtio-console changes
From: Amit Shah @ 2010-01-20 14:01 UTC (permalink / raw)
  To: Rusty Russell; +Cc: virtualization

The virtio-console device has recently been updated to support multiple
devices and multiple ports. These ports can also function as generic
serial ports. Reflect these changes in the spec.

Signed-off-by: Amit Shah <amit.shah@redhat.com>


--- virtio-spec/virtio-spec-0.8.3.lyx.orig	2010-01-20 19:21:02.239131766 +0530
+++ virtio-spec/virtio-spec-0.8.3.lyx	2010-01-20 19:21:02.228131971 +0530
@@ -1,4 +1,4 @@
-#LyX 1.6.4 created this file. For more info see http://www.lyx.org/
+#LyX 1.6.5 created this file. For more info see http://www.lyx.org/
 \lyxformat 345
 \begin_document
 \begin_header
@@ -36,7 +36,7 @@
 \paperpagestyle default
 \tracking_changes true
 \output_changes true
-\author "" 
+\author "Amit Shah" 
 \author "" 
 \end_header
 
@@ -4371,9 +4371,33 @@
 \end_layout
 
 \begin_layout Standard
-The virtio console device is a simple device for text input and output.
- One or more empty buffers are placed in the receive queue for incoming
- keystrokes, and outgoing characters are placed in the transmit queue.
+The virtio console device is a simple device for 
+\change_inserted 0 1262777844
+data
+\change_deleted 0 1262777844
+text
+\change_unchanged
+ input and output.
+ 
+\change_inserted 0 1263990903
+A device may have one or more ports.
+ Each port has a pair of input and output virtqueues.
+ Moreover, a device has a pair of control IO virtqueues.
+ The control virtqueues are used to communicate information between the
+ device and the driver about ports being opened and closed on either side
+ of the connection, indication from the host about whether a particular
+ port is a console port, port hotunplug, etc.
+ For data IO, o
+\change_deleted 0 1263990904
+O
+\change_unchanged
+ne or more empty buffers are placed in the receive queue for incoming 
+\change_inserted 0 1263965568
+data
+\change_deleted 0 1263990911
+keystrokes,
+\change_unchanged
+ and outgoing characters are placed in the transmit queue.
 \end_layout
 
 \begin_layout Section*
@@ -4393,8 +4417,19 @@
 \end_layout
 
 \begin_layout Description
-Virtqueues 0:receiveq.
- 1:transmitq.
+Virtqueues 0:receiveq
+\change_inserted 0 1263965615
+(port0)
+\change_unchanged
+.
+ 1:transmitq
+\change_inserted 0 1263965633
+(port0), 2:control receiveq, 3:control transmitq, 4:receiveq(port1), 5:transmitq
+(port1), ...
+\change_deleted 0 1263965580
+.
+\change_unchanged
+
 \end_layout
 
 \begin_layout Description
@@ -4412,6 +4447,18 @@
 \end_inset
 
 (0) Configuration cols and rows fields are valid.
+\change_inserted 0 1263965646
+
+\end_layout
+
+\begin_layout Description
+
+\change_inserted 0 1263990941
+VIRTIO_CONSOLE_F_MULTIPORT(1) Device has support for multiple ports; configurati
+on fields nr_ports and max_nr_ports are valid and control virtqueues will
+ be used.
+\change_unchanged
+
 \end_layout
 
 \end_deeper
@@ -4425,7 +4472,16 @@
 \end_inset
 
 layout The size of the console is supplied in the configuration space if
- the VIRTIO_CONSOLE_F_SIZE feature is set:
+ the VIRTIO_CONSOLE_F_SIZE feature is set
+\change_inserted 0 1263965899
+.
+ Furthermore, if the VIRTIO_CONSOLE_F_MULTIPORT feature is set, the maximum
+ number of ports supported by the device and the number of ports currently
+ active can be fetched.
+\change_deleted 0 1263965839
+:
+\change_unchanged
+
 \begin_inset listings
 inline false
 status open
@@ -4443,6 +4499,30 @@
 \begin_layout Plain Layout
 
 	u16 rows;
+\change_inserted 0 1263965922
+
+\end_layout
+
+\begin_layout Plain Layout
+
+\change_inserted 0 1263965904
+
+\end_layout
+
+\begin_layout Plain Layout
+
+\change_inserted 0 1263965912
+
+	u32 max_nr_ports;
+\end_layout
+
+\begin_layout Plain Layout
+
+\change_inserted 0 1263965914
+
+	u32 nr_ports;
+\change_unchanged
+
 \end_layout
 
 \begin_layout Plain Layout
@@ -4462,10 +4542,32 @@
 \begin_layout Enumerate
 If the VIRTIO_CONSOLE_F_SIZE feature is negotiated, the driver can read
  the console dimensions from the configuration fields.
+\change_inserted 0 1263965931
+
+\end_layout
+
+\begin_layout Enumerate
+
+\change_inserted 0 1263991285
+If the VIRTIO_CONSOLE_F_MULTIPORT feature is negotiated, the driver can
+ spawn multiple ports, not all of which may be attached to a console.
+ Some could be generic ports.
+ In this case, the control virtqueues are enabled and according to the nr_ports
+ configuration-space value, the appropriate number of ports and corresponding
+ virtqueues are spawned.
+ After creating and initializing each port, a VIRTIO_CONSOLE_PORT_READY
+ control message is sent to the host for that port so the host can let us
+ know of any additional configuration options set for that port.
+\change_unchanged
+
 \end_layout
 
 \begin_layout Enumerate
-The receiveq is populated with one or more receive buffers.
+The receiveq 
+\change_inserted 0 1263966035
+for each port 
+\change_unchanged
+is populated with one or more receive buffers.
 \end_layout
 
 \begin_layout Section*
@@ -4473,8 +4575,15 @@
 \end_layout
 
 \begin_layout Enumerate
-For console output, a buffer containing the characters is placed in the
- transmitq.
+For 
+\change_deleted 0 1263966990
+console 
+\change_unchanged
+output, a buffer containing the characters is placed in the 
+\change_inserted 0 1263966995
+port's 
+\change_unchanged
+transmitq.
 \begin_inset Foot
 status collapsed
 
@@ -4490,14 +4599,141 @@
 \end_layout
 
 \begin_layout Enumerate
-When a buffer is used in the receiveq, the contents is the input to the
- console.
+When a buffer is used in the receiveq
+\change_inserted 0 1263967036
+ (signalled by an interrupt)
+\change_unchanged
+, the contents is the input to the 
+\change_deleted 0 1263967042
+console.
+\change_inserted 0 1263967164
+port associated with the virtqueue for which the notification was received.
+\change_unchanged
+
 \end_layout
 
 \begin_layout Enumerate
 If the driver negotiated the VIRTIO_CONSOLE_F_SIZE feature, a configuration
  change interrupt may occur.
  The updated size can be read from the configuration fields.
+\change_inserted 0 1263966908
+
+\end_layout
+
+\begin_layout Enumerate
+
+\change_inserted 0 1263967171
+If the driver negotiated the VIRTIO_CONSOLE_F_MULTIPORT feature, a configuration
+ change interrupt may occur that bumps up the value of nr_ports.
+ In this case, ports are hot-added.
+\end_layout
+
+\begin_layout Enumerate
+
+\change_inserted 0 1263991858
+Changes to ports' state are effected by control messages.
+ Appropriate action is taken on the port indicated in the control message.
+ The layout of the structure of the control buffer and the events associated
+ are:
+\begin_inset listings
+inline false
+status open
+
+\begin_layout Plain Layout
+
+\change_inserted 0 1263991870
+
+struct virtio_console_control {
+\end_layout
+
+\begin_layout Plain Layout
+
+\change_inserted 0 1263991937
+
+	uint32_t id;    /* Port number */
+\end_layout
+
+\begin_layout Plain Layout
+
+\change_inserted 0 1263991940
+
+	uint16_t event; /* The kind of control event */
+\end_layout
+
+\begin_layout Plain Layout
+
+\change_inserted 0 1263991943
+
+	uint16_t value; /* Extra information for the event */
+\end_layout
+
+\begin_layout Plain Layout
+
+\change_inserted 0 1263991870
+
+};
+\end_layout
+
+\begin_layout Plain Layout
+
+\change_inserted 0 1263991870
+
+\end_layout
+
+\begin_layout Plain Layout
+
+\change_inserted 0 1263991870
+
+/* Some events for the internal messages (control packets) */
+\end_layout
+
+\begin_layout Plain Layout
+
+\change_inserted 0 1263991870
+
+#define VIRTIO_CONSOLE_PORT_READY       0
+\end_layout
+
+\begin_layout Plain Layout
+
+\change_inserted 0 1263991870
+
+#define VIRTIO_CONSOLE_CONSOLE_PORT     1
+\end_layout
+
+\begin_layout Plain Layout
+
+\change_inserted 0 1263991870
+
+#define VIRTIO_CONSOLE_RESIZE           2
+\end_layout
+
+\begin_layout Plain Layout
+
+\change_inserted 0 1263991870
+
+#define VIRTIO_CONSOLE_PORT_OPEN        3
+\end_layout
+
+\begin_layout Plain Layout
+
+\change_inserted 0 1263991870
+
+#define VIRTIO_CONSOLE_PORT_NAME        4
+\end_layout
+
+\begin_layout Plain Layout
+
+\change_inserted 0 1263991870
+
+#define VIRTIO_CONSOLE_PORT_REMOVE      5
+\change_unchanged
+
+\end_layout
+
+\end_inset
+
+
 \end_layout
 
 \begin_layout Chapter*

^ permalink raw reply

* [PATCH 30/31] virtio: console: Add debugfs files for each port to expose debug info
From: Amit Shah @ 2010-01-20  8:51 UTC (permalink / raw)
  To: rusty; +Cc: Amit Shah, virtualization
In-Reply-To: <1263977465-13983-3-git-send-email-amit.shah@redhat.com>

This is helpful in examining ports' state.

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

diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 1b5fa5c..f337f9f 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -17,6 +17,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 #include <linux/cdev.h>
+#include <linux/debugfs.h>
 #include <linux/device.h>
 #include <linux/err.h>
 #include <linux/fs.h>
@@ -43,6 +44,9 @@ struct ports_driver_data {
 	/* Used for registering chardevs */
 	struct class *class;
 
+	/* Used for exporting per-port information to debugfs */
+	struct dentry *debugfs_dir;
+
 	/* Number of devices this driver is handling */
 	unsigned int index;
 
@@ -164,6 +168,9 @@ struct port {
 	/* The IO vqs for this port */
 	struct virtqueue *in_vq, *out_vq;
 
+	/* File in the debugfs directory that exposes this port's information */
+	struct dentry *debugfs_file;
+
 	/*
 	 * The entries in this struct will be valid if this port is
 	 * hooked up to an hvc console
@@ -798,6 +805,49 @@ static struct attribute_group port_attribute_group = {
 	.attrs = port_sysfs_entries,
 };
 
+static int debugfs_open(struct inode *inode, struct file *filp)
+{
+	filp->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t debugfs_read(struct file *filp, char __user *ubuf,
+			    size_t count, loff_t *offp)
+{
+	struct port *port;
+	char *buf;
+	ssize_t ret, out_offset, out_count;
+
+	out_count = 1024;
+	buf = kmalloc(out_count, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	port = filp->private_data;
+	out_offset = 0;
+	out_offset += snprintf(buf + out_offset, out_count,
+			       "name: %s\n", port->name ? port->name : "");
+	out_offset += snprintf(buf + out_offset, out_count - out_offset,
+			       "guest_connected: %d\n", port->guest_connected);
+	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,
+			       "is_console: %s\n",
+			       is_console_port(port) ? "yes" : "no");
+	out_offset += snprintf(buf + out_offset, out_count - out_offset,
+			       "console_vtermno: %u\n", port->cons.vtermno);
+
+	ret = simple_read_from_buffer(ubuf, count, offp, buf, out_offset);
+	kfree(buf);
+	return ret;
+}
+
+static const struct file_operations port_debugfs_ops = {
+	.owner = THIS_MODULE,
+	.open  = debugfs_open,
+	.read  = debugfs_read,
+};
+
 /* Remove all port-specific data. */
 static int remove_port(struct port *port)
 {
@@ -825,6 +875,8 @@ static int remove_port(struct port *port)
 	free_buf(port->outbuf);
 	kfree(port->name);
 
+	debugfs_remove(port->debugfs_file);
+
 	kfree(port);
 	return 0;
 }
@@ -1037,6 +1089,7 @@ static void fill_queue(struct virtqueue *vq, spinlock_t *lock)
 
 static int add_port(struct ports_device *portdev, u32 id)
 {
+	char debugfs_name[16];
 	struct port *port;
 	struct port_buffer *inbuf;
 	dev_t devt;
@@ -1117,6 +1170,18 @@ static int add_port(struct ports_device *portdev, u32 id)
 	 */
 	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_outbuf:
@@ -1439,6 +1504,12 @@ static int __init init(void)
 		pr_err("Error %d creating virtio-ports class\n", err);
 		return err;
 	}
+
+	pdrvdata.debugfs_dir = debugfs_create_dir("virtio-ports", NULL);
+	if (!pdrvdata.debugfs_dir) {
+		pr_warning("Error %ld creating debugfs dir for virtio-ports\n",
+			   PTR_ERR(pdrvdata.debugfs_dir));
+	}
 	INIT_LIST_HEAD(&pdrvdata.consoles);
 
 	return register_virtio_driver(&virtio_console);
-- 
1.6.2.5

^ permalink raw reply related

* [PATCH 29/31] virtio: console: Add ability to hot-unplug ports
From: Amit Shah @ 2010-01-20  8:51 UTC (permalink / raw)
  To: rusty; +Cc: Amit Shah, virtualization
In-Reply-To: <1263977465-13983-2-git-send-email-amit.shah@redhat.com>

Remove port data; deregister from the hvc core if it's a console port.

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

diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 5e86b21..1b5fa5c 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -798,6 +798,37 @@ static struct attribute_group port_attribute_group = {
 	.attrs = port_sysfs_entries,
 };
 
+/* Remove all port-specific data. */
+static int remove_port(struct port *port)
+{
+	spin_lock_irq(&port->portdev->ports_lock);
+	list_del(&port->list);
+	spin_unlock_irq(&port->portdev->ports_lock);
+
+	if (is_console_port(port)) {
+		spin_lock_irq(&pdrvdata_lock);
+		list_del(&port->cons.list);
+		spin_unlock_irq(&pdrvdata_lock);
+		hvc_remove(port->cons.hvc);
+	}
+	if (port->guest_connected)
+		send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 0);
+
+	while (port->in_vq->vq_ops->detach_unused_buf(port->in_vq))
+		;
+
+	sysfs_remove_group(&port->dev->kobj, &port_attribute_group);
+	device_destroy(pdrvdata.class, port->dev->devt);
+	cdev_del(&port->cdev);
+
+	discard_port_data(port);
+	free_buf(port->outbuf);
+	kfree(port->name);
+
+	kfree(port);
+	return 0;
+}
+
 /* Any private messages that the Host and Guest want to share */
 static void handle_control_message(struct ports_device *portdev,
 				   struct port_buffer *buf)
@@ -869,6 +900,32 @@ static void handle_control_message(struct ports_device *portdev,
 				err);
 
 		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;
 	}
 }
 
@@ -1100,12 +1157,17 @@ static void config_work_handler(struct work_struct *work)
 		/*
 		 * Port 0 got hot-added.  Since we already did all the
 		 * other initialisation for it, just tell the Host
-		 * that the port is ready.
+		 * 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);
-		send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1);
+		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) {
diff --git a/include/linux/virtio_console.h b/include/linux/virtio_console.h
index 13e56c8..dd08675 100644
--- a/include/linux/virtio_console.h
+++ b/include/linux/virtio_console.h
@@ -41,6 +41,7 @@ struct virtio_console_control {
 #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));
-- 
1.6.2.5

^ permalink raw reply related

* [PATCH 19/31] virtio: console: Introduce a send_buf function for a common path for sending data to host
From: Amit Shah @ 2010-01-20  8:51 UTC (permalink / raw)
  To: rusty; +Cc: Amit Shah, virtualization
In-Reply-To: <1263977465-13983-1-git-send-email-amit.shah@redhat.com>

Adding support for generic ports that will write to userspace will need
some code changes.

Consolidate the write routine into send_buf() and put_chars() now just
calls into the new function.

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

diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 5096d92..9400b96 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -107,6 +107,9 @@ struct port {
 	 */
 	spinlock_t inbuf_lock;
 
+	/* Buffer that's used to pass data from the guest to the host */
+	struct port_buffer *outbuf;
+
 	/* The IO vqs for this port */
 	struct virtqueue *in_vq, *out_vq;
 
@@ -233,6 +236,55 @@ static bool port_has_data(struct port *port)
 	return ret;
 }
 
+static ssize_t send_buf(struct port *port, const char *in_buf, size_t in_count)
+{
+	struct scatterlist sg[1];
+	struct virtqueue *out_vq;
+	struct port_buffer *buf;
+	ssize_t ret;
+	unsigned int tmplen;
+
+	out_vq = port->out_vq;
+	buf = port->outbuf;
+
+	if (in_count > buf->size)
+		in_count = buf->size;
+
+	/*
+	 * Since we're not sure when the host will actually
+	 * consume the data and tell us about it, we have to
+	 * copy the data here in case the caller frees the
+	 * in_buf.
+	 */
+	memcpy(buf->buf, in_buf, in_count);
+
+	buf->len = in_count;
+
+	sg_init_one(sg, buf->buf, buf->len);
+	ret = out_vq->vq_ops->add_buf(out_vq, sg, 1, 0, buf);
+
+	/* Tell Host to go! */
+	out_vq->vq_ops->kick(out_vq);
+
+	if (ret < 0) {
+		buf->len = 0;
+		goto fail;
+	}
+
+	/*
+	 * Wait till the host acknowledges it pushed out the data we
+	 * sent. Also ensure we return to userspace the number of
+	 * bytes that were successfully consumed by the host.
+	 */
+	while (!out_vq->vq_ops->get_buf(out_vq, &tmplen))
+		cpu_relax();
+
+	buf->len = tmplen;
+fail:
+	/* We're expected to return the amount of data we wrote */
+	return buf->len;
+}
+
 /*
  * Give out the data that's requested from the buffer that we have
  * queued up.
@@ -280,10 +332,7 @@ static ssize_t fill_readbuf(struct port *port, char *out_buf, size_t out_count)
  */
 static int put_chars(u32 vtermno, const char *buf, int count)
 {
-	struct scatterlist sg[1];
 	struct port *port;
-	struct virtqueue *out_vq;
-	unsigned int len;
 
 	port = find_port_by_vtermno(vtermno);
 	if (!port)
@@ -292,20 +341,7 @@ static int put_chars(u32 vtermno, const char *buf, int count)
 	if (unlikely(early_put_chars))
 		return early_put_chars(vtermno, buf, count);
 
-	out_vq = port->out_vq;
-	/* This is a convenient routine to initialize a single-elem sg list */
-	sg_init_one(sg, buf, count);
-
-	/* This shouldn't fail: if it does, we lose chars. */
-	if (out_vq->vq_ops->add_buf(out_vq, sg, 1, 0, port) >= 0) {
-		/* Tell Host to go! */
-		out_vq->vq_ops->kick(out_vq);
-		while (!out_vq->vq_ops->get_buf(out_vq, &len))
-			cpu_relax();
-	}
-
-	/* We're expected to return the amount of data we wrote: all of it. */
-	return count;
+	return send_buf(port, buf, count);
 }
 
 /*
@@ -475,16 +511,23 @@ static int __devinit add_port(struct ports_device *portdev)
 		err = -ENOMEM;
 		goto free_port;
 	}
+	port->outbuf = alloc_buf(PAGE_SIZE);
+	if (!port->outbuf) {
+		err = -ENOMEM;
+		goto free_inbuf;
+	}
 
 	/* Register the input buffer the first time. */
 	add_inbuf(port->in_vq, inbuf);
 
 	err = init_port_console(port);
 	if (err)
-		goto free_inbuf;
+		goto free_outbuf;
 
 	return 0;
 
+free_outbuf:
+	free_buf(port->outbuf);
 free_inbuf:
 	free_buf(inbuf);
 free_port:
-- 
1.6.2.5

^ permalink raw reply related

* Remove host throttling
From: Amit Shah @ 2010-01-20  8:51 UTC (permalink / raw)
  To: rusty; +Cc: virtualization
In-Reply-To: <201001201850.56114.rusty@rustcorp.com.au>


Hey Rusty,

These are the patches to be replaced -- patches 19, 30, 31 from the
previous series. Patch 26 from the earlier series is to be dropped.

The diff to the previous version is:


diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index e936026..4218cb9 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -195,9 +195,6 @@ struct port {
 
 	/* We should allow only one process to open a port */
 	bool guest_connected;
-
-	/* Does the Host not want to accept more data currently?  */
-	bool host_throttled;
 };
 
 /* This is the very early arch-specified put chars function. */
@@ -414,17 +411,6 @@ static ssize_t send_buf(struct port *port, const char *in_buf, size_t in_count,
 	out_vq = port->out_vq;
 	buf = port->outbuf;
 
-	if (buf->len) {
-		/*
-		 * Nonzero buf->len means we had queued a buffer
-		 * earlier to the Host to be consumed.  Get the buffer
-		 * back for this write request; wait while the Host
-		 * consumes it.
-		 */
-		while (!out_vq->vq_ops->get_buf(out_vq, &tmplen))
-			cpu_relax();
-	}
-
 	if (in_count > buf->size)
 		in_count = buf->size;
 
@@ -448,9 +434,21 @@ static ssize_t send_buf(struct port *port, const char *in_buf, size_t in_count,
 	/* Tell Host to go! */
 	out_vq->vq_ops->kick(out_vq);
 
-	if (ret < 0)
+	if (ret < 0) {
 		buf->len = 0;
+		goto fail;
+	}
 
+	/*
+	 * Wait till the host acknowledges it pushed out the data we
+	 * sent. Also ensure we return to userspace the number of
+	 * bytes that were successfully consumed by the host.
+	 */
+	while (!out_vq->vq_ops->get_buf(out_vq, &tmplen))
+		cpu_relax();
+
+	buf->len = tmplen;
+fail:
 	/* We're expected to return the amount of data we wrote */
 	return buf->len;
 }
@@ -553,9 +551,6 @@ static ssize_t port_fops_write(struct file *filp, const char __user *ubuf,
 
 	port = filp->private_data;
 
-	if (port->host_throttled)
-		return -ENOSPC;
-
 	return send_buf(port, ubuf, count, true);
 }
 
@@ -570,7 +565,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 && !port->host_throttled)
+	if (port->host_connected)
 		ret |= POLLOUT;
 	if (!port->host_connected)
 		ret |= POLLHUP;
@@ -839,8 +834,6 @@ 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,
-			       "host_throttled: %d\n", port->host_throttled);
-	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,
@@ -961,18 +954,6 @@ static void handle_control_message(struct ports_device *portdev,
 				err);
 
 		break;
-	case VIRTIO_CONSOLE_THROTTLE_PORT:
-		/*
-		 * Hosts can govern some policy to disallow rogue
-		 * guest processes writing indefinitely to ports
-		 * leading to OOM situations.  If we receive this
-		 * message here, it means the Host side of the port
-		 * either reached its max. limit to cache data or
-		 * signal to us that the host is ready to accept more
-		 * data.
-		 */
-		port->host_throttled = cpkt->value;
-		break;
 	case VIRTIO_CONSOLE_PORT_REMOVE:
 		/*
 		 * Hot unplug the port.  We don't decrement nr_ports
@@ -1130,7 +1111,6 @@ static int add_port(struct ports_device *portdev, u32 id)
 	port->cons.hvc = NULL;
 
 	port->host_connected = port->guest_connected = false;
-	port->host_throttled = false;
 
 	port->in_vq = portdev->in_vqs[port->id];
 	port->out_vq = portdev->out_vqs[port->id];
diff --git a/include/linux/virtio_console.h b/include/linux/virtio_console.h
index 96c5832..dd08675 100644
--- a/include/linux/virtio_console.h
+++ b/include/linux/virtio_console.h
@@ -41,8 +41,7 @@ struct virtio_console_control {
 #define VIRTIO_CONSOLE_RESIZE		2
 #define VIRTIO_CONSOLE_PORT_OPEN	3
 #define VIRTIO_CONSOLE_PORT_NAME	4
-#define VIRTIO_CONSOLE_THROTTLE_PORT	5
-#define VIRTIO_CONSOLE_PORT_REMOVE	6
+#define VIRTIO_CONSOLE_PORT_REMOVE	5
 
 #ifdef __KERNEL__
 int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int));

^ permalink raw reply related

* Re: [PATCH 32/32] virtio: console: show error message if hvc_alloc fails for console ports
From: Rusty Russell @ 2010-01-20  8:20 UTC (permalink / raw)
  To: Amit Shah; +Cc: virtualization
In-Reply-To: <20100119170627.GE27165@amit-x200.redhat.com>

On Wed, 20 Jan 2010 03:36:27 am Amit Shah wrote:
> On (Tue) Jan 19 2010 [11:52:50], Rusty Russell wrote:
> > On Tue, 19 Jan 2010 12:15:26 am Amit Shah wrote:
> > > Signed-off-by: Amit Shah <amit.shah@redhat.com>
> > 
> > These all look great!  I'm not entirely convinced about the host throttling,
> > but it's harmless to have.
> 
> I'll rip out the throttling feature -- and ensure write(2) returns only
> when the host acks the data.
> 
> The changes will touch 3 patches in the series -- do you want me to
> resend those 3 patches, or new patches on top of my series, or send a new
> series altogether?

Replacements for those will be fine.

Thanks!
Rusty.

^ permalink raw reply

* Re: [PATCH 32/32] virtio: console: show error message if hvc_alloc fails for console ports
From: Rusty Russell @ 2010-01-20  8:09 UTC (permalink / raw)
  To: Amit Shah; +Cc: virtualization
In-Reply-To: <20100119045730.GD25684@amit-x200.redhat.com>

On Tue, 19 Jan 2010 03:27:30 pm Amit Shah wrote:
> On (Tue) Jan 19 2010 [11:52:50], Rusty Russell wrote:
> > On Tue, 19 Jan 2010 12:15:26 am Amit Shah wrote:
> > > Signed-off-by: Amit Shah <amit.shah@redhat.com>
> > 
> > These all look great!  I'm not entirely convinced about the host throttling,
> > but it's harmless to have.
> > 
> > Applied, thanks!
> > Rusty.
> 
> Thanks, Rusty!
> 
> Can you point me to the repo that has the patches?

They will be in linux-next tomorrow from my tree:

	http://ozlabs.org/~rusty/kernel/rr-latest/

Cheers,
Rusty.

^ permalink raw reply

* Re: [PATCH 32/32] virtio: console: show error message if hvc_alloc fails for console ports
From: Amit Shah @ 2010-01-19 17:06 UTC (permalink / raw)
  To: Rusty Russell; +Cc: virtualization
In-Reply-To: <201001191152.52445.rusty@rustcorp.com.au>

On (Tue) Jan 19 2010 [11:52:50], Rusty Russell wrote:
> On Tue, 19 Jan 2010 12:15:26 am Amit Shah wrote:
> > Signed-off-by: Amit Shah <amit.shah@redhat.com>
> 
> These all look great!  I'm not entirely convinced about the host throttling,
> but it's harmless to have.

I'll rip out the throttling feature -- and ensure write(2) returns only
when the host acks the data.

The changes will touch 3 patches in the series -- do you want me to
resend those 3 patches, or new patches on top of my series, or send a new
series altogether?

		Amit

^ permalink raw reply

* Re: [PATCH 32/32] virtio: console: show error message if hvc_alloc fails for console ports
From: Amit Shah @ 2010-01-19  4:57 UTC (permalink / raw)
  To: Rusty Russell; +Cc: virtualization
In-Reply-To: <201001191152.52445.rusty@rustcorp.com.au>

On (Tue) Jan 19 2010 [11:52:50], Rusty Russell wrote:
> On Tue, 19 Jan 2010 12:15:26 am Amit Shah wrote:
> > Signed-off-by: Amit Shah <amit.shah@redhat.com>
> 
> These all look great!  I'm not entirely convinced about the host throttling,
> but it's harmless to have.
> 
> Applied, thanks!
> Rusty.

Thanks, Rusty!

Can you point me to the repo that has the patches?

		Amit

^ permalink raw reply

* Re: [PATCH 32/32] virtio: console: show error message if hvc_alloc fails for console ports
From: Rusty Russell @ 2010-01-19  1:22 UTC (permalink / raw)
  To: Amit Shah; +Cc: virtualization
In-Reply-To: <1263822326-24208-33-git-send-email-amit.shah@redhat.com>

On Tue, 19 Jan 2010 12:15:26 am Amit Shah wrote:
> Signed-off-by: Amit Shah <amit.shah@redhat.com>

These all look great!  I'm not entirely convinced about the host throttling,
but it's harmless to have.

Applied, thanks!
Rusty.

^ permalink raw reply

* [PATCH 32/32] virtio: console: show error message if hvc_alloc fails for console ports
From: Amit Shah @ 2010-01-18 13:45 UTC (permalink / raw)
  To: rusty; +Cc: Amit Shah, virtualization
In-Reply-To: <1263822326-24208-32-git-send-email-amit.shah@redhat.com>

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

diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 6580d3b..166c5b2 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -773,6 +773,8 @@ int init_port_console(struct port *port)
 	port->cons.hvc = hvc_alloc(port->cons.vtermno, 0, &hv_ops, PAGE_SIZE);
 	if (IS_ERR(port->cons.hvc)) {
 		ret = PTR_ERR(port->cons.hvc);
+		dev_err(port->dev,
+			"error %d allocating hvc for port\n", ret);
 		port->cons.hvc = NULL;
 		return ret;
 	}
-- 
1.6.2.5

^ permalink raw reply related

* [PATCH 31/32] virtio: console: Add debugfs files for each port to expose debug info
From: Amit Shah @ 2010-01-18 13:45 UTC (permalink / raw)
  To: rusty; +Cc: Amit Shah, virtualization
In-Reply-To: <1263822326-24208-31-git-send-email-amit.shah@redhat.com>

This is helpful in examining ports' state.

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

diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 4a4eaba..6580d3b 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -17,6 +17,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 #include <linux/cdev.h>
+#include <linux/debugfs.h>
 #include <linux/device.h>
 #include <linux/err.h>
 #include <linux/fs.h>
@@ -43,6 +44,9 @@ struct ports_driver_data {
 	/* Used for registering chardevs */
 	struct class *class;
 
+	/* Used for exporting per-port information to debugfs */
+	struct dentry *debugfs_dir;
+
 	/* Number of devices this driver is handling */
 	unsigned int index;
 
@@ -164,6 +168,9 @@ struct port {
 	/* The IO vqs for this port */
 	struct virtqueue *in_vq, *out_vq;
 
+	/* File in the debugfs directory that exposes this port's information */
+	struct dentry *debugfs_file;
+
 	/*
 	 * The entries in this struct will be valid if this port is
 	 * hooked up to an hvc console
@@ -803,6 +810,51 @@ static struct attribute_group port_attribute_group = {
 	.attrs = port_sysfs_entries,
 };
 
+static int debugfs_open(struct inode *inode, struct file *filp)
+{
+	filp->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t debugfs_read(struct file *filp, char __user *ubuf,
+			    size_t count, loff_t *offp)
+{
+	struct port *port;
+	char *buf;
+	ssize_t ret, out_offset, out_count;
+
+	out_count = 1024;
+	buf = kmalloc(out_count, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	port = filp->private_data;
+	out_offset = 0;
+	out_offset += snprintf(buf + out_offset, out_count,
+			       "name: %s\n", port->name ? port->name : "");
+	out_offset += snprintf(buf + out_offset, out_count - out_offset,
+			       "guest_connected: %d\n", port->guest_connected);
+	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,
+			       "host_throttled: %d\n", port->host_throttled);
+	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,
+			       "console_vtermno: %u\n", port->cons.vtermno);
+
+	ret = simple_read_from_buffer(ubuf, count, offp, buf, out_offset);
+	kfree(buf);
+	return ret;
+}
+
+static const struct file_operations port_debugfs_ops = {
+	.owner = THIS_MODULE,
+	.open  = debugfs_open,
+	.read  = debugfs_read,
+};
+
 /* Remove all port-specific data. */
 static int remove_port(struct port *port)
 {
@@ -830,6 +882,8 @@ static int remove_port(struct port *port)
 	free_buf(port->outbuf);
 	kfree(port->name);
 
+	debugfs_remove(port->debugfs_file);
+
 	kfree(port);
 	return 0;
 }
@@ -1054,6 +1108,7 @@ static void fill_queue(struct virtqueue *vq, spinlock_t *lock)
 
 static int add_port(struct ports_device *portdev, u32 id)
 {
+	char debugfs_name[16];
 	struct port *port;
 	struct port_buffer *inbuf;
 	dev_t devt;
@@ -1135,6 +1190,18 @@ static int add_port(struct ports_device *portdev, u32 id)
 	 */
 	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_outbuf:
@@ -1457,6 +1524,12 @@ static int __init init(void)
 		pr_err("Error %d creating virtio-ports class\n", err);
 		return err;
 	}
+
+	pdrvdata.debugfs_dir = debugfs_create_dir("virtio-ports", NULL);
+	if (!pdrvdata.debugfs_dir) {
+		pr_warning("Error %ld creating debugfs dir for virtio-ports\n",
+			   PTR_ERR(pdrvdata.debugfs_dir));
+	}
 	INIT_LIST_HEAD(&pdrvdata.consoles);
 
 	return register_virtio_driver(&virtio_console);
-- 
1.6.2.5

^ permalink raw reply related

* [PATCH 30/32] virtio: console: Add ability to hot-unplug ports
From: Amit Shah @ 2010-01-18 13:45 UTC (permalink / raw)
  To: rusty; +Cc: Amit Shah, virtualization
In-Reply-To: <1263822326-24208-30-git-send-email-amit.shah@redhat.com>

Remove port data; deregister from the hvc core if it's a console port.

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

diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 36cd7d4..4a4eaba 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -803,6 +803,37 @@ static struct attribute_group port_attribute_group = {
 	.attrs = port_sysfs_entries,
 };
 
+/* Remove all port-specific data. */
+static int remove_port(struct port *port)
+{
+	spin_lock_irq(&port->portdev->ports_lock);
+	list_del(&port->list);
+	spin_unlock_irq(&port->portdev->ports_lock);
+
+	if (is_console_port(port)) {
+		spin_lock_irq(&pdrvdata_lock);
+		list_del(&port->cons.list);
+		spin_unlock_irq(&pdrvdata_lock);
+		hvc_remove(port->cons.hvc);
+	}
+	if (port->guest_connected)
+		send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 0);
+
+	while (port->in_vq->vq_ops->detach_unused_buf(port->in_vq))
+		;
+
+	sysfs_remove_group(&port->dev->kobj, &port_attribute_group);
+	device_destroy(pdrvdata.class, port->dev->devt);
+	cdev_del(&port->cdev);
+
+	discard_port_data(port);
+	free_buf(port->outbuf);
+	kfree(port->name);
+
+	kfree(port);
+	return 0;
+}
+
 /* Any private messages that the Host and Guest want to share */
 static void handle_control_message(struct ports_device *portdev,
 				   struct port_buffer *buf)
@@ -886,6 +917,32 @@ static void handle_control_message(struct ports_device *portdev,
 		 */
 		port->host_throttled = cpkt->value;
 		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;
 	}
 }
 
@@ -1118,12 +1175,17 @@ static void config_work_handler(struct work_struct *work)
 		/*
 		 * Port 0 got hot-added.  Since we already did all the
 		 * other initialisation for it, just tell the Host
-		 * that the port is ready.
+		 * 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);
-		send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1);
+		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) {
diff --git a/include/linux/virtio_console.h b/include/linux/virtio_console.h
index c096eb2..96c5832 100644
--- a/include/linux/virtio_console.h
+++ b/include/linux/virtio_console.h
@@ -42,6 +42,7 @@ struct virtio_console_control {
 #define VIRTIO_CONSOLE_PORT_OPEN	3
 #define VIRTIO_CONSOLE_PORT_NAME	4
 #define VIRTIO_CONSOLE_THROTTLE_PORT	5
+#define VIRTIO_CONSOLE_PORT_REMOVE	6
 
 #ifdef __KERNEL__
 int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int));
-- 
1.6.2.5

^ permalink raw reply related

* [PATCH 29/32] virtio: Add ability to detach unused buffers from vrings
From: Amit Shah @ 2010-01-18 13:45 UTC (permalink / raw)
  To: rusty; +Cc: Amit Shah, Shirley Ma, Shirley Ma, virtualization
In-Reply-To: <1263822326-24208-29-git-send-email-amit.shah@redhat.com>

From: Shirley Ma <mashirle@us.ibm.com>

There's currently no way for a virtio driver to ask for unused
buffers, so it has to keep a list itself to reclaim them at shutdown.
This is redundant, since virtio_ring stores that information.  So
add a new hook to do this.

Signed-off-by: Shirley Ma <xma@us.ibm.com>
Signed-off-by: Amit Shah <amit.shah@redhat.com>
---
 drivers/virtio/virtio_ring.c |   25 +++++++++++++++++++++++++
 include/linux/virtio.h       |    4 ++++
 2 files changed, 29 insertions(+), 0 deletions(-)

diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index fbd2ecd..71929ee 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -334,6 +334,30 @@ static bool vring_enable_cb(struct virtqueue *_vq)
 	return true;
 }
 
+static void *vring_detach_unused_buf(struct virtqueue *_vq)
+{
+	struct vring_virtqueue *vq = to_vvq(_vq);
+	unsigned int i;
+	void *buf;
+
+	START_USE(vq);
+
+	for (i = 0; i < vq->vring.num; i++) {
+		if (!vq->data[i])
+			continue;
+		/* detach_buf clears data, so grab it now. */
+		buf = vq->data[i];
+		detach_buf(vq, i);
+		END_USE(vq);
+		return buf;
+	}
+	/* That should have freed everything. */
+	BUG_ON(vq->num_free != vq->vring.num);
+
+	END_USE(vq);
+	return NULL;
+}
+
 irqreturn_t vring_interrupt(int irq, void *_vq)
 {
 	struct vring_virtqueue *vq = to_vvq(_vq);
@@ -360,6 +384,7 @@ static struct virtqueue_ops vring_vq_ops = {
 	.kick = vring_kick,
 	.disable_cb = vring_disable_cb,
 	.enable_cb = vring_enable_cb,
+	.detach_unused_buf = vring_detach_unused_buf,
 };
 
 struct virtqueue *vring_new_virtqueue(unsigned int num,
diff --git a/include/linux/virtio.h b/include/linux/virtio.h
index 057a2e0..f508c65 100644
--- a/include/linux/virtio.h
+++ b/include/linux/virtio.h
@@ -51,6 +51,9 @@ struct virtqueue {
  *	This re-enables callbacks; it returns "false" if there are pending
  *	buffers in the queue, to detect a possible race between the driver
  *	checking for more work, and enabling callbacks.
+ * @detach_unused_buf: detach first unused buffer
+ * 	vq: the struct virtqueue we're talking about.
+ * 	Returns NULL or the "data" token handed to add_buf
  *
  * Locking rules are straightforward: the driver is responsible for
  * locking.  No two operations may be invoked simultaneously, with the exception
@@ -71,6 +74,7 @@ struct virtqueue_ops {
 
 	void (*disable_cb)(struct virtqueue *vq);
 	bool (*enable_cb)(struct virtqueue *vq);
+	void *(*detach_unused_buf)(struct virtqueue *vq);
 };
 
 /**
-- 
1.6.2.5

^ permalink raw reply related

* [PATCH 28/32] virtio: console: Handle port hot-plug
From: Amit Shah @ 2010-01-18 13:45 UTC (permalink / raw)
  To: rusty; +Cc: Amit Shah, virtualization
In-Reply-To: <1263822326-24208-28-git-send-email-amit.shah@redhat.com>

If the 'nr_ports' variable in the config space is updated to a higher
value, that means new ports have been hotplugged.

Introduce a new workqueue to handle such updates and create new ports.

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

diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 0be5562..36cd7d4 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -105,6 +105,7 @@ struct ports_device {
 	 * notification
 	 */
 	struct work_struct control_work;
+	struct work_struct config_work;
 
 	struct list_head ports;
 
@@ -695,11 +696,6 @@ static void resize_console(struct port *port)
 	}
 }
 
-static void virtcons_apply_config(struct virtio_device *vdev)
-{
-	resize_console(find_port_by_vtermno(0));
-}
-
 /* We set the configuration at this point, since we now have a tty */
 static int notifier_add_vio(struct hvc_struct *hp, int data)
 {
@@ -960,6 +956,24 @@ static void control_intr(struct virtqueue *vq)
 	schedule_work(&portdev->control_work);
 }
 
+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
+	 * control messages to indicate console size changes so that
+	 * it can be done per-port
+	 */
+	resize_console(find_port_by_id(portdev, 0));
+}
+
 static void fill_queue(struct virtqueue *vq, spinlock_t *lock)
 {
 	struct port_buffer *buf;
@@ -1080,6 +1094,57 @@ 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.
+		 */
+		struct port *port;
+
+		port = find_port_by_id(portdev, 0);
+		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;
@@ -1270,6 +1335,7 @@ static int __devinit virtcons_probe(struct virtio_device *vdev)
 	if (multiport) {
 		spin_lock_init(&portdev->cvq_lock);
 		INIT_WORK(&portdev->control_work, &control_work_handler);
+		INIT_WORK(&portdev->config_work, &config_work_handler);
 
 		portdev->outbuf = alloc_buf(PAGE_SIZE);
 		if (!portdev->outbuf) {
@@ -1316,7 +1382,7 @@ static struct virtio_driver virtio_console = {
 	.driver.owner =	THIS_MODULE,
 	.id_table =	id_table,
 	.probe =	virtcons_probe,
-	.config_changed = virtcons_apply_config,
+	.config_changed = config_intr,
 };
 
 static int __init init(void)
-- 
1.6.2.5

^ permalink raw reply related

* [PATCH 27/32] virtio: console: Remove cached data on port close
From: Amit Shah @ 2010-01-18 13:45 UTC (permalink / raw)
  To: rusty; +Cc: Amit Shah, virtualization
In-Reply-To: <1263822326-24208-27-git-send-email-amit.shah@redhat.com>

Remove any data that we might have in a port's inbuf when closing a port
or when any data is received when a port is closed.

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

diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 7154224..0be5562 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -325,6 +325,31 @@ static int add_inbuf(struct virtqueue *vq, struct port_buffer *buf)
 	return ret;
 }
 
+/* Discard any unread data this port has. Callers lockers. */
+static void discard_port_data(struct port *port)
+{
+	struct port_buffer *buf;
+	struct virtqueue *vq;
+	unsigned int len;
+
+	vq = port->in_vq;
+	if (port->inbuf)
+		buf = port->inbuf;
+	else
+		buf = vq->vq_ops->get_buf(vq, &len);
+
+	if (!buf)
+		return;
+
+	if (add_inbuf(vq, buf) < 0) {
+		buf->len = buf->offset = 0;
+		dev_warn(port->dev, "Error adding buffer back to vq\n");
+		return;
+	}
+
+	port->inbuf = NULL;
+}
+
 static bool port_has_data(struct port *port)
 {
 	unsigned long flags;
@@ -554,8 +579,13 @@ static int port_fops_release(struct inode *inode, struct file *filp)
 	/* Notify host of port being closed */
 	send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 0);
 
+	spin_lock_irq(&port->inbuf_lock);
 	port->guest_connected = false;
 
+	discard_port_data(port);
+
+	spin_unlock_irq(&port->inbuf_lock);
+
 	return 0;
 }
 
@@ -904,6 +934,16 @@ static void in_intr(struct virtqueue *vq)
 	spin_lock_irqsave(&port->inbuf_lock, flags);
 	port->inbuf = get_inbuf(port);
 
+	/*
+	 * Don't queue up data when port is closed.  This condition
+	 * can be reached when a console port is not yet connected (no
+	 * tty is spawned) and the host sends out data to console
+	 * ports.  For generic serial ports, the host won't
+	 * (shouldn't) send data till the guest is connected.
+	 */
+	if (!port->guest_connected)
+		discard_port_data(port);
+
 	spin_unlock_irqrestore(&port->inbuf_lock, flags);
 
 	wake_up_interruptible(&port->waitqueue);
-- 
1.6.2.5

^ permalink raw reply related

* [PATCH 26/32] virtio: console: Add throttling support to prevent flooding ports
From: Amit Shah @ 2010-01-18 13:45 UTC (permalink / raw)
  To: rusty; +Cc: Amit Shah, virtualization
In-Reply-To: <1263822326-24208-26-git-send-email-amit.shah@redhat.com>

Rogue processes on guests could pump in data to hosts and cause an OOM
condition on the host. The host can indicate when to stop and start
sending data via control messages.

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

diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index e76eacf..7154224 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -187,6 +187,9 @@ struct port {
 
 	/* We should allow only one process to open a port */
 	bool guest_connected;
+
+	/* Does the Host not want to accept more data currently?  */
+	bool host_throttled;
 };
 
 /* This is the very early arch-specified put chars function. */
@@ -517,6 +520,9 @@ static ssize_t port_fops_write(struct file *filp, const char __user *ubuf,
 
 	port = filp->private_data;
 
+	if (port->host_throttled)
+		return -ENOSPC;
+
 	return send_buf(port, ubuf, count, true);
 }
 
@@ -531,7 +537,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 (port->host_connected && !port->host_throttled)
 		ret |= POLLOUT;
 	if (!port->host_connected)
 		ret |= POLLHUP;
@@ -842,6 +848,18 @@ static void handle_control_message(struct ports_device *portdev,
 				err);
 
 		break;
+	case VIRTIO_CONSOLE_THROTTLE_PORT:
+		/*
+		 * Hosts can govern some policy to disallow rogue
+		 * guest processes writing indefinitely to ports
+		 * leading to OOM situations.  If we receive this
+		 * message here, it means the Host side of the port
+		 * either reached its max. limit to cache data or
+		 * signal to us that the host is ready to accept more
+		 * data.
+		 */
+		port->host_throttled = cpkt->value;
+		break;
 	}
 }
 
@@ -944,6 +962,7 @@ static int add_port(struct ports_device *portdev, u32 id)
 	port->cons.hvc = NULL;
 
 	port->host_connected = port->guest_connected = false;
+	port->host_throttled = false;
 
 	port->in_vq = portdev->in_vqs[port->id];
 	port->out_vq = portdev->out_vqs[port->id];
diff --git a/include/linux/virtio_console.h b/include/linux/virtio_console.h
index 13e56c8..c096eb2 100644
--- a/include/linux/virtio_console.h
+++ b/include/linux/virtio_console.h
@@ -41,6 +41,7 @@ struct virtio_console_control {
 #define VIRTIO_CONSOLE_RESIZE		2
 #define VIRTIO_CONSOLE_PORT_OPEN	3
 #define VIRTIO_CONSOLE_PORT_NAME	4
+#define VIRTIO_CONSOLE_THROTTLE_PORT	5
 
 #ifdef __KERNEL__
 int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int));
-- 
1.6.2.5

^ permalink raw reply related

* [PATCH 25/32] virtio: console: Register with sysfs and create a 'name' attribute for ports
From: Amit Shah @ 2010-01-18 13:45 UTC (permalink / raw)
  To: rusty; +Cc: Amit Shah, virtualization
In-Reply-To: <1263822326-24208-25-git-send-email-amit.shah@redhat.com>

The host can set a name for ports so that they're easily discoverable
instead of going by the /dev/vportNpn naming. This attribute will be
placed in /sys/class/virtio-ports/vportNpn/name. udev scripts can then
create symlinks to the port using the name.

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

diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 49cd185..e76eacf 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -176,6 +176,9 @@ struct port {
 	/* A waitqueue for poll() or blocking read operations */
 	wait_queue_head_t waitqueue;
 
+	/* The 'name' of the port that we expose via sysfs properties */
+	char *name;
+
 	/* The 'id' to identify the port with the Host */
 	u32 id;
 
@@ -746,12 +749,36 @@ int init_port_console(struct port *port)
 	return 0;
 }
 
+static ssize_t show_port_name(struct device *dev,
+			      struct device_attribute *attr, char *buffer)
+{
+	struct port *port;
+
+	port = dev_get_drvdata(dev);
+
+	return sprintf(buffer, "%s\n", port->name);
+}
+
+static DEVICE_ATTR(name, S_IRUGO, show_port_name, NULL);
+
+static struct attribute *port_sysfs_entries[] = {
+	&dev_attr_name.attr,
+	NULL
+};
+
+static struct attribute_group port_attribute_group = {
+	.name = NULL,		/* put in device directory */
+	.attrs = port_sysfs_entries,
+};
+
 /* Any private messages that the Host and Guest want to share */
 static void handle_control_message(struct ports_device *portdev,
 				   struct port_buffer *buf)
 {
 	struct virtio_console_control *cpkt;
 	struct port *port;
+	size_t name_size;
+	int err;
 
 	cpkt = (struct virtio_console_control *)(buf->buf + buf->offset);
 
@@ -786,6 +813,35 @@ static void handle_control_message(struct ports_device *portdev,
 		port->host_connected = cpkt->value;
 		wake_up_interruptible(&port->waitqueue);
 		break;
+	case VIRTIO_CONSOLE_PORT_NAME:
+		/*
+		 * Skip the size of the header and the cpkt to get the size
+		 * of the name that was sent
+		 */
+		name_size = buf->len - buf->offset - sizeof(*cpkt) + 1;
+
+		port->name = kmalloc(name_size, GFP_KERNEL);
+		if (!port->name) {
+			dev_err(port->dev,
+				"Not enough space to store port name\n");
+			break;
+		}
+		strncpy(port->name, buf->buf + buf->offset + sizeof(*cpkt),
+			name_size - 1);
+		port->name[name_size - 1] = 0;
+
+		/*
+		 * Since we only have one sysfs attribute, 'name',
+		 * create it only if we have a name for the port.
+		 */
+		err = sysfs_create_group(&port->dev->kobj,
+					 &port_attribute_group);
+		if (err)
+			dev_err(port->dev,
+				"Error %d creating sysfs device attributes\n",
+				err);
+
+		break;
 	}
 }
 
@@ -883,6 +939,7 @@ static int add_port(struct ports_device *portdev, u32 id)
 	port->portdev = portdev;
 	port->id = id;
 
+	port->name = NULL;
 	port->inbuf = NULL;
 	port->cons.hvc = NULL;
 
diff --git a/include/linux/virtio_console.h b/include/linux/virtio_console.h
index 6a76a44..13e56c8 100644
--- a/include/linux/virtio_console.h
+++ b/include/linux/virtio_console.h
@@ -40,6 +40,7 @@ struct virtio_console_control {
 #define VIRTIO_CONSOLE_CONSOLE_PORT	1
 #define VIRTIO_CONSOLE_RESIZE		2
 #define VIRTIO_CONSOLE_PORT_OPEN	3
+#define VIRTIO_CONSOLE_PORT_NAME	4
 
 #ifdef __KERNEL__
 int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int));
-- 
1.6.2.5

^ permalink raw reply related

* [PATCH 24/32] virtio: console: Ensure only one process can have a port open at a time
From: Amit Shah @ 2010-01-18 13:45 UTC (permalink / raw)
  To: rusty; +Cc: Amit Shah, virtualization
In-Reply-To: <1263822326-24208-24-git-send-email-amit.shah@redhat.com>

Add a guest_connected field that ensures only one process
can have a port open at a time.

This also ensures we don't have a race when we later add support for
dropping buffers when closing the char dev and buffer caching is turned
off for the particular port.

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

diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 30cdaf3..49cd185 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -181,6 +181,9 @@ struct port {
 
 	/* Is the host device open */
 	bool host_connected;
+
+	/* We should allow only one process to open a port */
+	bool guest_connected;
 };
 
 /* This is the very early arch-specified put chars function. */
@@ -542,6 +545,8 @@ static int port_fops_release(struct inode *inode, struct file *filp)
 	/* Notify host of port being closed */
 	send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 0);
 
+	port->guest_connected = false;
+
 	return 0;
 }
 
@@ -560,6 +565,16 @@ static int port_fops_open(struct inode *inode, struct file *filp)
 	if (is_console_port(port))
 		return -ENXIO;
 
+	/* Allow only one process to open a particular port at a time */
+	spin_lock_irq(&port->inbuf_lock);
+	if (port->guest_connected) {
+		spin_unlock_irq(&port->inbuf_lock);
+		return -EMFILE;
+	}
+
+	port->guest_connected = true;
+	spin_unlock_irq(&port->inbuf_lock);
+
 	/* Notify host of port being opened */
 	send_control_msg(filp->private_data, VIRTIO_CONSOLE_PORT_OPEN, 1);
 
@@ -723,6 +738,7 @@ int init_port_console(struct port *port)
 	pdrvdata.next_vtermno++;
 	list_add_tail(&port->cons.list, &pdrvdata.consoles);
 	spin_unlock_irq(&pdrvdata_lock);
+	port->guest_connected = true;
 
 	/* Notify host of port being opened */
 	send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 1);
@@ -870,7 +886,7 @@ static int add_port(struct ports_device *portdev, u32 id)
 	port->inbuf = NULL;
 	port->cons.hvc = NULL;
 
-	port->host_connected = false;
+	port->host_connected = port->guest_connected = false;
 
 	port->in_vq = portdev->in_vqs[port->id];
 	port->out_vq = portdev->out_vqs[port->id];
-- 
1.6.2.5

^ permalink raw reply related

* [PATCH 23/32] virtio: console: Add file operations to ports for open/read/write/poll
From: Amit Shah @ 2010-01-18 13:45 UTC (permalink / raw)
  To: rusty; +Cc: Amit Shah, virtualization
In-Reply-To: <1263822326-24208-23-git-send-email-amit.shah@redhat.com>

Allow guest userspace applications to open, read from, write to, poll
the ports via the char dev interface.

When a port gets opened, a notification is sent to the host via a
control message indicating a connection has been established. Similarly,
on closing of the port, a notification is sent indicating disconnection.

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

diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 49bf5af..30cdaf3 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -19,11 +19,15 @@
 #include <linux/cdev.h>
 #include <linux/device.h>
 #include <linux/err.h>
+#include <linux/fs.h>
 #include <linux/init.h>
 #include <linux/list.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
 #include <linux/spinlock.h>
 #include <linux/virtio.h>
 #include <linux/virtio_console.h>
+#include <linux/wait.h>
 #include <linux/workqueue.h>
 #include "hvc_console.h"
 
@@ -169,8 +173,14 @@ struct port {
 	struct cdev cdev;
 	struct device *dev;
 
+	/* A waitqueue for poll() or blocking read operations */
+	wait_queue_head_t waitqueue;
+
 	/* The 'id' to identify the port with the Host */
 	u32 id;
+
+	/* Is the host device open */
+	bool host_connected;
 };
 
 /* This is the very early arch-specified put chars function. */
@@ -448,6 +458,129 @@ static ssize_t fill_readbuf(struct port *port, char *out_buf, size_t out_count,
 	return ret;
 }
 
+/* The condition that must be true for polling to end */
+static bool wait_is_over(struct port *port)
+{
+	return port_has_data(port) || !port->host_connected;
+}
+
+static ssize_t port_fops_read(struct file *filp, char __user *ubuf,
+			      size_t count, loff_t *offp)
+{
+	struct port *port;
+	ssize_t ret;
+
+	port = filp->private_data;
+
+	if (!port_has_data(port)) {
+		/*
+		 * If nothing's connected on the host just return 0 in
+		 * case of list_empty; this tells the userspace app
+		 * that there's no connection
+		 */
+		if (!port->host_connected)
+			return 0;
+		if (filp->f_flags & O_NONBLOCK)
+			return -EAGAIN;
+
+		ret = wait_event_interruptible(port->waitqueue,
+					       wait_is_over(port));
+		if (ret < 0)
+			return ret;
+	}
+	/*
+	 * We could've received a disconnection message while we were
+	 * waiting for more data.
+	 *
+	 * This check is not clubbed in the if() statement above as we
+	 * might receive some data as well as the host could get
+	 * disconnected after we got woken up from our wait.  So we
+	 * really want to give off whatever data we have and only then
+	 * check for host_connected.
+	 */
+	if (!port_has_data(port) && !port->host_connected)
+		return 0;
+
+	return fill_readbuf(port, ubuf, count, true);
+}
+
+static ssize_t port_fops_write(struct file *filp, const char __user *ubuf,
+			       size_t count, loff_t *offp)
+{
+	struct port *port;
+
+	port = filp->private_data;
+
+	return send_buf(port, ubuf, count, true);
+}
+
+static unsigned int port_fops_poll(struct file *filp, poll_table *wait)
+{
+	struct port *port;
+	unsigned int ret;
+
+	port = filp->private_data;
+	poll_wait(filp, &port->waitqueue, wait);
+
+	ret = 0;
+	if (port->inbuf)
+		ret |= POLLIN | POLLRDNORM;
+	if (port->host_connected)
+		ret |= POLLOUT;
+	if (!port->host_connected)
+		ret |= POLLHUP;
+
+	return ret;
+}
+
+static int port_fops_release(struct inode *inode, struct file *filp)
+{
+	struct port *port;
+
+	port = filp->private_data;
+
+	/* Notify host of port being closed */
+	send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 0);
+
+	return 0;
+}
+
+static int port_fops_open(struct inode *inode, struct file *filp)
+{
+	struct cdev *cdev = inode->i_cdev;
+	struct port *port;
+
+	port = container_of(cdev, struct port, cdev);
+	filp->private_data = port;
+
+	/*
+	 * Don't allow opening of console port devices -- that's done
+	 * via /dev/hvc
+	 */
+	if (is_console_port(port))
+		return -ENXIO;
+
+	/* Notify host of port being opened */
+	send_control_msg(filp->private_data, VIRTIO_CONSOLE_PORT_OPEN, 1);
+
+	return 0;
+}
+
+/*
+ * The file operations that we support: programs in the guest can open
+ * a console device, read from it, write to it, poll for data and
+ * close it.  The devices are at
+ *   /dev/vport<device number>p<port number>
+ */
+static const struct file_operations port_fops = {
+	.owner = THIS_MODULE,
+	.open  = port_fops_open,
+	.read  = port_fops_read,
+	.write = port_fops_write,
+	.poll  = port_fops_poll,
+	.release = port_fops_release,
+};
+
 /*
  * The put_chars() callback is pretty straightforward.
  *
@@ -591,6 +724,9 @@ int init_port_console(struct port *port)
 	list_add_tail(&port->cons.list, &pdrvdata.consoles);
 	spin_unlock_irq(&pdrvdata_lock);
 
+	/* Notify host of port being opened */
+	send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 1);
+
 	return 0;
 }
 
@@ -630,6 +766,10 @@ static void handle_control_message(struct ports_device *portdev,
 		port->cons.hvc->irq_requested = 1;
 		resize_console(port);
 		break;
+	case VIRTIO_CONSOLE_PORT_OPEN:
+		port->host_connected = cpkt->value;
+		wake_up_interruptible(&port->waitqueue);
+		break;
 	}
 }
 
@@ -676,6 +816,8 @@ static void in_intr(struct virtqueue *vq)
 
 	spin_unlock_irqrestore(&port->inbuf_lock, flags);
 
+	wake_up_interruptible(&port->waitqueue);
+
 	if (is_console_port(port) && hvc_poll(port->cons.hvc))
 		hvc_kick();
 }
@@ -728,10 +870,12 @@ static int add_port(struct ports_device *portdev, u32 id)
 	port->inbuf = NULL;
 	port->cons.hvc = NULL;
 
+	port->host_connected = false;
+
 	port->in_vq = portdev->in_vqs[port->id];
 	port->out_vq = portdev->out_vqs[port->id];
 
-	cdev_init(&port->cdev, NULL);
+	cdev_init(&port->cdev, &port_fops);
 
 	devt = MKDEV(portdev->chr_major, id);
 	err = cdev_add(&port->cdev, devt, 1);
@@ -752,6 +896,7 @@ static int add_port(struct ports_device *portdev, u32 id)
 	}
 
 	spin_lock_init(&port->inbuf_lock);
+	init_waitqueue_head(&port->waitqueue);
 
 	inbuf = alloc_buf(PAGE_SIZE);
 	if (!inbuf) {
diff --git a/include/linux/virtio_console.h b/include/linux/virtio_console.h
index cada769..6a76a44 100644
--- a/include/linux/virtio_console.h
+++ b/include/linux/virtio_console.h
@@ -39,6 +39,7 @@ struct virtio_console_control {
 #define VIRTIO_CONSOLE_PORT_READY	0
 #define VIRTIO_CONSOLE_CONSOLE_PORT	1
 #define VIRTIO_CONSOLE_RESIZE		2
+#define VIRTIO_CONSOLE_PORT_OPEN	3
 
 #ifdef __KERNEL__
 int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int));
-- 
1.6.2.5

^ permalink raw reply related

* [PATCH 22/32] virtio: console: Associate each port with a char device
From: Amit Shah @ 2010-01-18 13:45 UTC (permalink / raw)
  To: rusty; +Cc: Amit Shah, virtualization
In-Reply-To: <1263822326-24208-22-git-send-email-amit.shah@redhat.com>

The char device will be used as an interface by applications on the
guest to communicate with apps on the host.

The devices created are placed in /dev/vportNpn where N is the
virtio-console device number and n is the port number for that device.

One dynamic major device number is allocated for each device and minor
numbers are allocated for the ports contained within that device.

The file operation for the char devs will be added in the following
commits.

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

diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 31be3ac..bcedee1 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -666,6 +666,14 @@ config VIRTIO_CONSOLE
 	help
 	  Virtio console for use with lguest and other hypervisors.
 
+	  Also serves as a general-purpose serial device for data
+	  transfer between the guest and host.  Character devices at
+	  /dev/vportNpn will be created when corresponding ports are
+	  found, where N is the device number and n is the port number
+	  within that device.  If specified by the host, a sysfs
+	  attribute called 'name' will be populated with a name for
+	  the port which can be used by udev scripts to create a
+	  symlink to the device.
 
 config HVCS
 	tristate "IBM Hypervisor Virtual Console Server support"
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 35bdd41..49bf5af 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -16,6 +16,8 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
+#include <linux/cdev.h>
+#include <linux/device.h>
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/list.h>
@@ -34,6 +36,12 @@
  * across multiple devices and multiple ports per device.
  */
 struct ports_driver_data {
+	/* Used for registering chardevs */
+	struct class *class;
+
+	/* Number of devices this driver is handling */
+	unsigned int index;
+
 	/*
 	 * This is used to keep track of the number of hvc consoles
 	 * spawned by this driver.  This number is given as the first
@@ -119,6 +127,12 @@ struct ports_device {
 
 	/* The control messages to the Host are sent via this buffer */
 	struct port_buffer *outbuf;
+
+	/* Used for numbering devices for sysfs and debugfs */
+	unsigned int drv_index;
+
+	/* Major number for this device.  Ports will be created as minors. */
+	int chr_major;
 };
 
 /* This struct holds the per-port data */
@@ -151,6 +165,10 @@ struct port {
 	 */
 	struct console cons;
 
+	/* Each port associates with a separate char device */
+	struct cdev cdev;
+	struct device *dev;
+
 	/* The 'id' to identify the port with the Host */
 	u32 id;
 };
@@ -423,7 +441,7 @@ static ssize_t fill_readbuf(struct port *port, char *out_buf, size_t out_count,
 		port->inbuf = NULL;
 
 		if (add_inbuf(port->in_vq, buf) < 0)
-			dev_warn(&port->portdev->vdev->dev, "failed add_buf\n");
+			dev_warn(port->dev, "failed add_buf\n");
 
 		spin_unlock_irqrestore(&port->inbuf_lock, flags);
 	}
@@ -695,6 +713,7 @@ static int add_port(struct ports_device *portdev, u32 id)
 {
 	struct port *port;
 	struct port_buffer *inbuf;
+	dev_t devt;
 	int err;
 
 	port = kmalloc(sizeof(*port), GFP_KERNEL);
@@ -712,12 +731,32 @@ static int add_port(struct ports_device *portdev, u32 id)
 	port->in_vq = portdev->in_vqs[port->id];
 	port->out_vq = portdev->out_vqs[port->id];
 
+	cdev_init(&port->cdev, NULL);
+
+	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);
 
 	inbuf = alloc_buf(PAGE_SIZE);
 	if (!inbuf) {
 		err = -ENOMEM;
-		goto free_port;
+		goto free_device;
 	}
 	port->outbuf = alloc_buf(PAGE_SIZE);
 	if (!port->outbuf) {
@@ -754,6 +793,10 @@ free_outbuf:
 	free_buf(port->outbuf);
 free_inbuf:
 	free_buf(inbuf);
+free_device:
+	device_destroy(pdrvdata.class, port->dev->devt);
+free_cdev:
+	cdev_del(&port->cdev);
 free_port:
 	kfree(port);
 fail:
@@ -866,6 +909,10 @@ fail:
 	return err;
 }
 
+static const struct file_operations portdev_fops = {
+	.owner = THIS_MODULE,
+};
+
 /*
  * Once we're further in boot, we get probed like any other virtio
  * device.
@@ -891,6 +938,20 @@ static int __devinit virtcons_probe(struct virtio_device *vdev)
 	portdev->vdev = vdev;
 	vdev->priv = portdev;
 
+	spin_lock_irq(&pdrvdata_lock);
+	portdev->drv_index = pdrvdata.index++;
+	spin_unlock_irq(&pdrvdata_lock);
+
+	portdev->chr_major = register_chrdev(0, "virtio-portsdev",
+					     &portdev_fops);
+	if (portdev->chr_major < 0) {
+		dev_err(&vdev->dev,
+			"Error %d registering chrdev for device %u\n",
+			portdev->chr_major, portdev->drv_index);
+		err = portdev->chr_major;
+		goto free;
+	}
+
 	multiport = false;
 	portdev->config.nr_ports = 1;
 	portdev->config.max_nr_ports = 1;
@@ -923,7 +984,7 @@ static int __devinit virtcons_probe(struct virtio_device *vdev)
 	err = init_vqs(portdev);
 	if (err < 0) {
 		dev_err(&vdev->dev, "Error %d initializing vqs\n", err);
-		goto free;
+		goto free_chrdev;
 	}
 
 	spin_lock_init(&portdev->ports_lock);
@@ -953,6 +1014,8 @@ free_vqs:
 	vdev->config->del_vqs(vdev);
 	kfree(portdev->in_vqs);
 	kfree(portdev->out_vqs);
+free_chrdev:
+	unregister_chrdev(portdev->chr_major, "virtio-portsdev");
 free:
 	kfree(portdev);
 fail:
@@ -981,6 +1044,14 @@ static struct virtio_driver virtio_console = {
 
 static int __init init(void)
 {
+	int err;
+
+	pdrvdata.class = class_create(THIS_MODULE, "virtio-ports");
+	if (IS_ERR(pdrvdata.class)) {
+		err = PTR_ERR(pdrvdata.class);
+		pr_err("Error %d creating virtio-ports class\n", err);
+		return err;
+	}
 	INIT_LIST_HEAD(&pdrvdata.consoles);
 
 	return register_virtio_driver(&virtio_console);
-- 
1.6.2.5

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox