aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty/hvc
diff options
context:
space:
mode:
authorNicholas Piggin <npiggin@gmail.com>2018-05-01 00:55:56 +1000
committerMichael Ellerman <mpe@ellerman.id.au>2018-07-23 20:12:32 +1000
commit550ddadcc7580ec2a6c22d4ed04291bc6e2428fb (patch)
tree107bfb0355a6943e6765293702828fe109310920 /drivers/tty/hvc
parenttty: hvc: hvc_poll() may sleep (diff)
downloadlinux-dev-550ddadcc7580ec2a6c22d4ed04291bc6e2428fb.tar.xz
linux-dev-550ddadcc7580ec2a6c22d4ed04291bc6e2428fb.zip
tty: hvc: hvc_write() may sleep
Rework the hvc_write loop to drop and re-take the spinlock on each iteration, add a cond_resched. Don't bother with an initial hvc_push initially, which makes the logic simpler -- just do a hvc_push on each time around the loop. Signed-off-by: Nicholas Piggin <npiggin@gmail.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Diffstat (limited to 'drivers/tty/hvc')
-rw-r--r--drivers/tty/hvc/hvc_console.c36
1 files changed, 21 insertions, 15 deletions
diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c
index 2abfc0b15fbb..6131d5084c42 100644
--- a/drivers/tty/hvc/hvc_console.c
+++ b/drivers/tty/hvc/hvc_console.c
@@ -493,23 +493,29 @@ static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count
if (hp->port.count <= 0)
return -EIO;
- spin_lock_irqsave(&hp->lock, flags);
+ while (count > 0) {
+ spin_lock_irqsave(&hp->lock, flags);
- /* Push pending writes */
- if (hp->n_outbuf > 0)
- hvc_push(hp);
-
- while (count > 0 && (rsize = hp->outbuf_size - hp->n_outbuf) > 0) {
- if (rsize > count)
- rsize = count;
- memcpy(hp->outbuf + hp->n_outbuf, buf, rsize);
- count -= rsize;
- buf += rsize;
- hp->n_outbuf += rsize;
- written += rsize;
- hvc_push(hp);
+ rsize = hp->outbuf_size - hp->n_outbuf;
+
+ if (rsize) {
+ if (rsize > count)
+ rsize = count;
+ memcpy(hp->outbuf + hp->n_outbuf, buf, rsize);
+ count -= rsize;
+ buf += rsize;
+ hp->n_outbuf += rsize;
+ written += rsize;
+ }
+
+ if (hp->n_outbuf > 0)
+ hvc_push(hp);
+
+ spin_unlock_irqrestore(&hp->lock, flags);
+
+ if (count)
+ cond_resched();
}
- spin_unlock_irqrestore(&hp->lock, flags);
/*
* Racy, but harmless, kick thread if there is still pending data.