From: Amit Shah <amit.shah@redhat.com>
To: qemu-devel@nongnu.org, kvm@vger.kernel.org,
virtualization@lists.linux-foundation.org
Cc: borntraeger@de.ibm.com, linux-kernel@vger.kernel.org,
miltonm@bga.com, linuxppc-dev@ozlabs.org,
brueckner@linux.vnet.ibm.com, alan@linux.intel.com
Subject: [Qemu-devel] Re: Extending virtio_console to support multiple ports
Date: Wed, 26 Aug 2009 21:15:52 +0530 [thread overview]
Message-ID: <20090826154552.GA31910@amit-x200.redhat.com> (raw)
In-Reply-To: <20090826112718.GA11117@amit-x200.redhat.com>
[cc'ing some people who have made some commits in hvc_console.c]
On (Wed) Aug 26 2009 [16:57:18], Amit Shah wrote:
> On (Tue) Aug 25 2009 [11:47:20], Amit Shah wrote:
> >
> > Hello all,
> >
> > Here is a new iteration of the patch series that implements a
> > transport for guest and host communications.
> >
> > The code has been updated to reuse the virtio-console device instead
> > of creating a new virtio-serial device.
>
> And the problem now is that hvc calls the put_chars function with
> spinlocks held and we now allocate pages in send_buf(), called from
> put_chars.
>
> A few solutions:
[snip]
> - Convert hvc's usage of spinlocks to mutexes. I've no idea how this
> will play out; I'm no expert here. But I did try doing this and so far
> it all looks OK. No lockups, lockdep warnings, nothing. I have full
> debugging enabled. But this doesn't mean it's right.
So just to test this further I added the capability to have more than
one hvc console spawn from virtio_console, created two consoles and did
a 'cat' of a file in each of the virtio-consoles. It's been running for
half an hour now without any badness. No spew in debug logs too.
I also checked the code in hvc_console.c that takes the spin_locks.
Nothing there that runs from (or needs to run from) interrupt context.
So the change to mutexes does seem reasonable. Also, the spinlock code
was added really long back -- git blame shows Linus' first git commit
introduced them in the git history, so it's pure legacy baggage.
Also found a bug: hvc_resize() wants to be called with a lock held
(hp->lock) but virtio_console just calls it directly.
Anyway I'm wondering whether all those locks are needed.
Amit
diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c
index d97779e..51078a3 100644
--- a/drivers/char/hvc_console.c
+++ b/drivers/char/hvc_console.c
@@ -35,7 +35,7 @@
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/sched.h>
-#include <linux/spinlock.h>
+#include <linux/mutex.h>
#include <linux/delay.h>
#include <linux/freezer.h>
@@ -81,7 +81,7 @@ static LIST_HEAD(hvc_structs);
* Protect the list of hvc_struct instances from inserts and removals during
* list traversal.
*/
-static DEFINE_SPINLOCK(hvc_structs_lock);
+static DEFINE_MUTEX(hvc_structs_lock);
/*
* This value is used to assign a tty->index value to a hvc_struct based
@@ -98,23 +98,22 @@ static int last_hvc = -1;
static struct hvc_struct *hvc_get_by_index(int index)
{
struct hvc_struct *hp;
- unsigned long flags;
- spin_lock(&hvc_structs_lock);
+ mutex_lock(&hvc_structs_lock);
list_for_each_entry(hp, &hvc_structs, next) {
- spin_lock_irqsave(&hp->lock, flags);
+ mutex_lock(&hp->lock);
if (hp->index == index) {
kref_get(&hp->kref);
- spin_unlock_irqrestore(&hp->lock, flags);
- spin_unlock(&hvc_structs_lock);
+ mutex_unlock(&hp->lock);
+ mutex_unlock(&hvc_structs_lock);
return hp;
}
- spin_unlock_irqrestore(&hp->lock, flags);
+ mutex_unlock(&hp->lock);
}
hp = NULL;
- spin_unlock(&hvc_structs_lock);
+ mutex_unlock(&hvc_structs_lock);
return hp;
}
@@ -228,15 +227,14 @@ console_initcall(hvc_console_init);
static void destroy_hvc_struct(struct kref *kref)
{
struct hvc_struct *hp = container_of(kref, struct hvc_struct, kref);
- unsigned long flags;
- spin_lock(&hvc_structs_lock);
+ mutex_lock(&hvc_structs_lock);
- spin_lock_irqsave(&hp->lock, flags);
+ mutex_lock(&hp->lock);
list_del(&(hp->next));
- spin_unlock_irqrestore(&hp->lock, flags);
+ mutex_unlock(&hp->lock);
- spin_unlock(&hvc_structs_lock);
+ mutex_unlock(&hvc_structs_lock);
kfree(hp);
}
@@ -302,17 +300,16 @@ static void hvc_unthrottle(struct tty_struct *tty)
static int hvc_open(struct tty_struct *tty, struct file * filp)
{
struct hvc_struct *hp;
- unsigned long flags;
int rc = 0;
/* Auto increments kref reference if found. */
if (!(hp = hvc_get_by_index(tty->index)))
return -ENODEV;
- spin_lock_irqsave(&hp->lock, flags);
+ mutex_lock(&hp->lock);
/* Check and then increment for fast path open. */
if (hp->count++ > 0) {
- spin_unlock_irqrestore(&hp->lock, flags);
+ mutex_unlock(&hp->lock);
hvc_kick();
return 0;
} /* else count == 0 */
@@ -321,7 +318,7 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
hp->tty = tty;
- spin_unlock_irqrestore(&hp->lock, flags);
+ mutex_unlock(&hp->lock);
if (hp->ops->notifier_add)
rc = hp->ops->notifier_add(hp, hp->data);
@@ -333,9 +330,9 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
* tty fields and return the kref reference.
*/
if (rc) {
- spin_lock_irqsave(&hp->lock, flags);
+ mutex_lock(&hp->lock);
hp->tty = NULL;
- spin_unlock_irqrestore(&hp->lock, flags);
+ mutex_unlock(&hp->lock);
tty->driver_data = NULL;
kref_put(&hp->kref, destroy_hvc_struct);
printk(KERN_ERR "hvc_open: request_irq failed with rc %d.\n", rc);
@@ -349,7 +346,6 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
static void hvc_close(struct tty_struct *tty, struct file * filp)
{
struct hvc_struct *hp;
- unsigned long flags;
if (tty_hung_up_p(filp))
return;
@@ -363,12 +359,12 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
return;
hp = tty->driver_data;
- spin_lock_irqsave(&hp->lock, flags);
+ mutex_lock(&hp->lock);
if (--hp->count == 0) {
/* We are done with the tty pointer now. */
hp->tty = NULL;
- spin_unlock_irqrestore(&hp->lock, flags);
+ mutex_unlock(&hp->lock);
if (hp->ops->notifier_del)
hp->ops->notifier_del(hp, hp->data);
@@ -386,7 +382,7 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
if (hp->count < 0)
printk(KERN_ERR "hvc_close %X: oops, count is %d\n",
hp->vtermno, hp->count);
- spin_unlock_irqrestore(&hp->lock, flags);
+ mutex_unlock(&hp->lock);
}
kref_put(&hp->kref, destroy_hvc_struct);
@@ -395,7 +391,6 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
static void hvc_hangup(struct tty_struct *tty)
{
struct hvc_struct *hp = tty->driver_data;
- unsigned long flags;
int temp_open_count;
if (!hp)
@@ -404,7 +399,7 @@ static void hvc_hangup(struct tty_struct *tty)
/* cancel pending tty resize work */
cancel_work_sync(&hp->tty_resize);
- spin_lock_irqsave(&hp->lock, flags);
+ mutex_lock(&hp->lock);
/*
* The N_TTY line discipline has problems such that in a close vs
@@ -412,7 +407,7 @@ static void hvc_hangup(struct tty_struct *tty)
* that from happening for now.
*/
if (hp->count <= 0) {
- spin_unlock_irqrestore(&hp->lock, flags);
+ mutex_unlock(&hp->lock);
return;
}
@@ -421,7 +416,7 @@ static void hvc_hangup(struct tty_struct *tty)
hp->n_outbuf = 0;
hp->tty = NULL;
- spin_unlock_irqrestore(&hp->lock, flags);
+ mutex_unlock(&hp->lock);
if (hp->ops->notifier_hangup)
hp->ops->notifier_hangup(hp, hp->data);
@@ -462,7 +457,6 @@ static int hvc_push(struct hvc_struct *hp)
static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count)
{
struct hvc_struct *hp = tty->driver_data;
- unsigned long flags;
int rsize, written = 0;
/* This write was probably executed during a tty close. */
@@ -472,7 +466,7 @@ static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count
if (hp->count <= 0)
return -EIO;
- spin_lock_irqsave(&hp->lock, flags);
+ mutex_lock(&hp->lock);
/* Push pending writes */
if (hp->n_outbuf > 0)
@@ -488,7 +482,7 @@ static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count
written += rsize;
hvc_push(hp);
}
- spin_unlock_irqrestore(&hp->lock, flags);
+ mutex_unlock(&hp->lock);
/*
* Racy, but harmless, kick thread if there is still pending data.
@@ -511,7 +505,6 @@ static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count
static void hvc_set_winsz(struct work_struct *work)
{
struct hvc_struct *hp;
- unsigned long hvc_flags;
struct tty_struct *tty;
struct winsize ws;
@@ -519,14 +512,14 @@ static void hvc_set_winsz(struct work_struct *work)
if (!hp)
return;
- spin_lock_irqsave(&hp->lock, hvc_flags);
+ mutex_lock(&hp->lock);
if (!hp->tty) {
- spin_unlock_irqrestore(&hp->lock, hvc_flags);
+ mutex_unlock(&hp->lock);
return;
}
ws = hp->ws;
tty = tty_kref_get(hp->tty);
- spin_unlock_irqrestore(&hp->lock, hvc_flags);
+ mutex_unlock(&hp->lock);
tty_do_resize(tty, &ws);
tty_kref_put(tty);
@@ -576,11 +569,10 @@ int hvc_poll(struct hvc_struct *hp)
struct tty_struct *tty;
int i, n, poll_mask = 0;
char buf[N_INBUF] __ALIGNED__;
- unsigned long flags;
int read_total = 0;
int written_total = 0;
- spin_lock_irqsave(&hp->lock, flags);
+ mutex_lock(&hp->lock);
/* Push pending writes */
if (hp->n_outbuf > 0)
@@ -622,9 +614,9 @@ int hvc_poll(struct hvc_struct *hp)
if (n <= 0) {
/* Hangup the tty when disconnected from host */
if (n == -EPIPE) {
- spin_unlock_irqrestore(&hp->lock, flags);
+ mutex_unlock(&hp->lock);
tty_hangup(tty);
- spin_lock_irqsave(&hp->lock, flags);
+ mutex_lock(&hp->lock);
} else if ( n == -EAGAIN ) {
/*
* Some back-ends can only ensure a certain min
@@ -665,7 +657,7 @@ int hvc_poll(struct hvc_struct *hp)
tty_wakeup(tty);
}
bail:
- spin_unlock_irqrestore(&hp->lock, flags);
+ mutex_unlock(&hp->lock);
if (read_total) {
/* Activity is occurring, so reset the polling backoff value to
@@ -714,11 +706,11 @@ static int khvcd(void *unused)
try_to_freeze();
wmb();
if (!cpus_are_in_xmon()) {
- spin_lock(&hvc_structs_lock);
+ mutex_lock(&hvc_structs_lock);
list_for_each_entry(hp, &hvc_structs, next) {
poll_mask |= hvc_poll(hp);
}
- spin_unlock(&hvc_structs_lock);
+ mutex_unlock(&hvc_structs_lock);
} else
poll_mask |= HVC_POLL_READ;
if (hvc_kicked)
@@ -777,8 +769,8 @@ struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int data,
kref_init(&hp->kref);
INIT_WORK(&hp->tty_resize, hvc_set_winsz);
- spin_lock_init(&hp->lock);
- spin_lock(&hvc_structs_lock);
+ mutex_init(&hp->lock);
+ mutex_lock(&hvc_structs_lock);
/*
* find index to use:
@@ -796,7 +788,7 @@ struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int data,
hp->index = i;
list_add_tail(&(hp->next), &hvc_structs);
- spin_unlock(&hvc_structs_lock);
+ mutex_unlock(&hvc_structs_lock);
return hp;
}
@@ -804,10 +796,9 @@ EXPORT_SYMBOL_GPL(hvc_alloc);
int hvc_remove(struct hvc_struct *hp)
{
- unsigned long flags;
struct tty_struct *tty;
- spin_lock_irqsave(&hp->lock, flags);
+ mutex_lock(&hp->lock);
tty = hp->tty;
if (hp->index < MAX_NR_HVC_CONSOLES)
@@ -815,7 +806,7 @@ int hvc_remove(struct hvc_struct *hp)
/* Don't whack hp->irq because tty_hangup() will need to free the irq. */
- spin_unlock_irqrestore(&hp->lock, flags);
+ mutex_unlock(&hp->lock);
/*
* We 'put' the instance that was grabbed when the kref instance
diff --git a/drivers/char/hvc_console.h b/drivers/char/hvc_console.h
index 3c85d78..3c086f8 100644
--- a/drivers/char/hvc_console.h
+++ b/drivers/char/hvc_console.h
@@ -45,7 +45,7 @@
#define HVC_ALLOC_TTY_ADAPTERS 8
struct hvc_struct {
- spinlock_t lock;
+ struct mutex lock;
int index;
struct tty_struct *tty;
int count;
next prev parent reply other threads:[~2009-08-26 15:46 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-08-25 6:17 [Qemu-devel] Extending virtio_console to support multiple ports Amit Shah
2009-08-25 6:17 ` [Qemu-devel] [PATCH] virtio_console: Add interface for guest and host communication Amit Shah
2009-08-25 6:17 ` [Qemu-devel] [PATCH 1/3] char: Emit 'CLOSED' events on char device close Amit Shah
2009-08-25 6:17 ` [Qemu-devel] [PATCH 2/3] virtio-console: rename dvq to ovq Amit Shah
2009-08-25 8:16 ` [Qemu-devel] [PATCH 3/3] virtio-console: Add interface for generic guest-host communication Amit Shah
2009-08-26 11:27 ` [Qemu-devel] Re: Extending virtio_console to support multiple ports Amit Shah
2009-08-26 15:45 ` Amit Shah [this message]
2009-08-27 4:07 ` Benjamin Herrenschmidt
2009-08-27 6:51 ` Amit Shah
2009-08-27 9:08 ` Alan Cox
2009-08-27 9:27 ` Benjamin Herrenschmidt
2009-08-27 11:45 ` [Qemu-devel] [PATCH] hvc_console: provide (un)locked version for hvc_resize() Hendrik Brueckner
2009-08-29 1:15 ` [Qemu-devel] Re: Extending virtio_console to support multiple ports Jamie Lokier
2009-08-27 5:04 ` Michael Ellerman
2009-08-27 6:52 ` Amit Shah
2009-08-27 14:13 ` Ryan Arnold
2009-08-28 17:00 ` Anthony Liguori
2009-08-30 10:10 ` Amit Shah
2009-08-30 12:48 ` Anthony Liguori
2009-08-30 13:17 ` Amit Shah
2009-08-31 13:17 ` Anthony Liguori
2009-08-31 13:51 ` Amit Shah
2009-08-31 14:21 ` Anthony Liguori
2009-08-31 14:31 ` Amit Shah
2009-08-31 15:56 ` Anthony Liguori
2009-08-31 16:19 ` Amit Shah
2009-08-31 16:37 ` Anthony Liguori
2009-09-21 5:20 ` Rusty Russell
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20090826154552.GA31910@amit-x200.redhat.com \
--to=amit.shah@redhat.com \
--cc=alan@linux.intel.com \
--cc=borntraeger@de.ibm.com \
--cc=brueckner@linux.vnet.ibm.com \
--cc=kvm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linuxppc-dev@ozlabs.org \
--cc=miltonm@bga.com \
--cc=qemu-devel@nongnu.org \
--cc=virtualization@lists.linux-foundation.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).