Commit 28c0447d authored by Jiri Slaby's avatar Jiri Slaby Committed by Greg Kroah-Hartman

TTY: hvsi, sanitize uses of tty

- use tty, not hp->tty wherever possible
- pass tty down to some functions and go to step one
- do not defer tty_hangup calls -- it is as simple as schedule_work,
  so might be called with hp->lock held
- do not defer tty buffer flips -- since the driver does not use
  low_latency (it cannot actually), the flip is a simple tail move
  plus schedule_work. It will make our life easier in the next patch.
Signed-off-by: default avatarJiri Slaby <jslaby@suse.cz>
Cc: linuxppc-dev@lists.ozlabs.org
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent d73a4e79
...@@ -237,7 +237,7 @@ static int hvsi_read(struct hvsi_struct *hp, char *buf, int count) ...@@ -237,7 +237,7 @@ static int hvsi_read(struct hvsi_struct *hp, char *buf, int count)
} }
static void hvsi_recv_control(struct hvsi_struct *hp, uint8_t *packet, static void hvsi_recv_control(struct hvsi_struct *hp, uint8_t *packet,
struct tty_struct **to_hangup, struct hvsi_struct **to_handshake) struct tty_struct *tty, struct hvsi_struct **to_handshake)
{ {
struct hvsi_control *header = (struct hvsi_control *)packet; struct hvsi_control *header = (struct hvsi_control *)packet;
...@@ -247,9 +247,8 @@ static void hvsi_recv_control(struct hvsi_struct *hp, uint8_t *packet, ...@@ -247,9 +247,8 @@ static void hvsi_recv_control(struct hvsi_struct *hp, uint8_t *packet,
/* CD went away; no more connection */ /* CD went away; no more connection */
pr_debug("hvsi%i: CD dropped\n", hp->index); pr_debug("hvsi%i: CD dropped\n", hp->index);
hp->mctrl &= TIOCM_CD; hp->mctrl &= TIOCM_CD;
/* If userland hasn't done an open(2) yet, hp->tty is NULL. */ if (tty && !C_CLOCAL(tty))
if (hp->tty && !C_CLOCAL(hp->tty)) tty_hangup(tty);
*to_hangup = hp->tty;
} }
break; break;
case VSV_CLOSE_PROTOCOL: case VSV_CLOSE_PROTOCOL:
...@@ -331,7 +330,8 @@ static void hvsi_recv_query(struct hvsi_struct *hp, uint8_t *packet) ...@@ -331,7 +330,8 @@ static void hvsi_recv_query(struct hvsi_struct *hp, uint8_t *packet)
} }
} }
static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len) static void hvsi_insert_chars(struct hvsi_struct *hp, struct tty_struct *tty,
const char *buf, int len)
{ {
int i; int i;
...@@ -347,7 +347,7 @@ static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len) ...@@ -347,7 +347,7 @@ static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len)
continue; continue;
} }
#endif /* CONFIG_MAGIC_SYSRQ */ #endif /* CONFIG_MAGIC_SYSRQ */
tty_insert_flip_char(hp->tty, c, 0); tty_insert_flip_char(tty, c, 0);
} }
} }
...@@ -360,7 +360,7 @@ static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len) ...@@ -360,7 +360,7 @@ static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len)
* revisited. * revisited.
*/ */
#define TTY_THRESHOLD_THROTTLE 128 #define TTY_THRESHOLD_THROTTLE 128
static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp, static bool hvsi_recv_data(struct hvsi_struct *hp, struct tty_struct *tty,
const uint8_t *packet) const uint8_t *packet)
{ {
const struct hvsi_header *header = (const struct hvsi_header *)packet; const struct hvsi_header *header = (const struct hvsi_header *)packet;
...@@ -371,14 +371,14 @@ static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp, ...@@ -371,14 +371,14 @@ static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp,
pr_debug("queueing %i chars '%.*s'\n", datalen, datalen, data); pr_debug("queueing %i chars '%.*s'\n", datalen, datalen, data);
if (datalen == 0) if (datalen == 0)
return NULL; return false;
if (overflow > 0) { if (overflow > 0) {
pr_debug("%s: got >TTY_THRESHOLD_THROTTLE bytes\n", __func__); pr_debug("%s: got >TTY_THRESHOLD_THROTTLE bytes\n", __func__);
datalen = TTY_THRESHOLD_THROTTLE; datalen = TTY_THRESHOLD_THROTTLE;
} }
hvsi_insert_chars(hp, data, datalen); hvsi_insert_chars(hp, tty, data, datalen);
if (overflow > 0) { if (overflow > 0) {
/* /*
...@@ -390,7 +390,7 @@ static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp, ...@@ -390,7 +390,7 @@ static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp,
hp->n_throttle = overflow; hp->n_throttle = overflow;
} }
return hp->tty; return true;
} }
/* /*
...@@ -399,14 +399,13 @@ static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp, ...@@ -399,14 +399,13 @@ static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp,
* machine during console handshaking (in which case tty = NULL and we ignore * machine during console handshaking (in which case tty = NULL and we ignore
* incoming data). * incoming data).
*/ */
static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip, static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct *tty,
struct tty_struct **hangup, struct hvsi_struct **handshake) struct hvsi_struct **handshake)
{ {
uint8_t *packet = hp->inbuf; uint8_t *packet = hp->inbuf;
int chunklen; int chunklen;
bool flip = false;
*flip = NULL;
*hangup = NULL;
*handshake = NULL; *handshake = NULL;
chunklen = hvsi_read(hp, hp->inbuf_end, HVSI_MAX_READ); chunklen = hvsi_read(hp, hp->inbuf_end, HVSI_MAX_READ);
...@@ -440,12 +439,12 @@ static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip, ...@@ -440,12 +439,12 @@ static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip,
case VS_DATA_PACKET_HEADER: case VS_DATA_PACKET_HEADER:
if (!is_open(hp)) if (!is_open(hp))
break; break;
if (hp->tty == NULL) if (tty == NULL)
break; /* no tty buffer to put data in */ break; /* no tty buffer to put data in */
*flip = hvsi_recv_data(hp, packet); flip = hvsi_recv_data(hp, tty, packet);
break; break;
case VS_CONTROL_PACKET_HEADER: case VS_CONTROL_PACKET_HEADER:
hvsi_recv_control(hp, packet, hangup, handshake); hvsi_recv_control(hp, packet, tty, handshake);
break; break;
case VS_QUERY_RESPONSE_PACKET_HEADER: case VS_QUERY_RESPONSE_PACKET_HEADER:
hvsi_recv_response(hp, packet); hvsi_recv_response(hp, packet);
...@@ -462,28 +461,26 @@ static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip, ...@@ -462,28 +461,26 @@ static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip,
packet += len_packet(packet); packet += len_packet(packet);
if (*hangup || *handshake) { if (*handshake) {
pr_debug("%s: hangup or handshake\n", __func__); pr_debug("%s: handshake\n", __func__);
/*
* we need to send the hangup now before receiving any more data.
* If we get "data, hangup, data", we can't deliver the second
* data before the hangup.
*/
break; break;
} }
} }
compact_inbuf(hp, packet); compact_inbuf(hp, packet);
if (flip)
tty_flip_buffer_push(tty);
return 1; return 1;
} }
static void hvsi_send_overflow(struct hvsi_struct *hp) static void hvsi_send_overflow(struct hvsi_struct *hp, struct tty_struct *tty)
{ {
pr_debug("%s: delivering %i bytes overflow\n", __func__, pr_debug("%s: delivering %i bytes overflow\n", __func__,
hp->n_throttle); hp->n_throttle);
hvsi_insert_chars(hp, hp->throttle_buf, hp->n_throttle); hvsi_insert_chars(hp, tty, hp->throttle_buf, hp->n_throttle);
hp->n_throttle = 0; hp->n_throttle = 0;
} }
...@@ -494,8 +491,6 @@ static void hvsi_send_overflow(struct hvsi_struct *hp) ...@@ -494,8 +491,6 @@ static void hvsi_send_overflow(struct hvsi_struct *hp)
static irqreturn_t hvsi_interrupt(int irq, void *arg) static irqreturn_t hvsi_interrupt(int irq, void *arg)
{ {
struct hvsi_struct *hp = (struct hvsi_struct *)arg; struct hvsi_struct *hp = (struct hvsi_struct *)arg;
struct tty_struct *flip;
struct tty_struct *hangup;
struct hvsi_struct *handshake; struct hvsi_struct *handshake;
unsigned long flags; unsigned long flags;
int again = 1; int again = 1;
...@@ -504,25 +499,9 @@ static irqreturn_t hvsi_interrupt(int irq, void *arg) ...@@ -504,25 +499,9 @@ static irqreturn_t hvsi_interrupt(int irq, void *arg)
while (again) { while (again) {
spin_lock_irqsave(&hp->lock, flags); spin_lock_irqsave(&hp->lock, flags);
again = hvsi_load_chunk(hp, &flip, &hangup, &handshake); again = hvsi_load_chunk(hp, hp->tty, &handshake);
spin_unlock_irqrestore(&hp->lock, flags); spin_unlock_irqrestore(&hp->lock, flags);
/*
* we have to call tty_flip_buffer_push() and tty_hangup() outside our
* spinlock. But we also have to keep going until we've read all the
* available data.
*/
if (flip) {
/* there was data put in the tty flip buffer */
tty_flip_buffer_push(flip);
flip = NULL;
}
if (hangup) {
tty_hangup(hangup);
}
if (handshake) { if (handshake) {
pr_debug("hvsi%i: attempting re-handshake\n", handshake->index); pr_debug("hvsi%i: attempting re-handshake\n", handshake->index);
schedule_work(&handshake->handshaker); schedule_work(&handshake->handshaker);
...@@ -534,15 +513,11 @@ static irqreturn_t hvsi_interrupt(int irq, void *arg) ...@@ -534,15 +513,11 @@ static irqreturn_t hvsi_interrupt(int irq, void *arg)
&& (!test_bit(TTY_THROTTLED, &hp->tty->flags))) { && (!test_bit(TTY_THROTTLED, &hp->tty->flags))) {
/* we weren't hung up and we weren't throttled, so we can deliver the /* we weren't hung up and we weren't throttled, so we can deliver the
* rest now */ * rest now */
flip = hp->tty; hvsi_send_overflow(hp, hp->tty);
hvsi_send_overflow(hp); tty_flip_buffer_push(hp->tty);
} }
spin_unlock_irqrestore(&hp->lock, flags); spin_unlock_irqrestore(&hp->lock, flags);
if (flip) {
tty_flip_buffer_push(flip);
}
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -966,8 +941,8 @@ static int hvsi_write(struct tty_struct *tty, ...@@ -966,8 +941,8 @@ static int hvsi_write(struct tty_struct *tty,
* and hvsi_write_worker will be scheduled. subsequent hvsi_write() calls * and hvsi_write_worker will be scheduled. subsequent hvsi_write() calls
* will see there is no room in outbuf and return. * will see there is no room in outbuf and return.
*/ */
while ((count > 0) && (hvsi_write_room(hp->tty) > 0)) { while ((count > 0) && (hvsi_write_room(tty) > 0)) {
int chunksize = min(count, hvsi_write_room(hp->tty)); int chunksize = min(count, hvsi_write_room(tty));
BUG_ON(hp->n_outbuf < 0); BUG_ON(hp->n_outbuf < 0);
memcpy(hp->outbuf + hp->n_outbuf, source, chunksize); memcpy(hp->outbuf + hp->n_outbuf, source, chunksize);
...@@ -1014,19 +989,16 @@ static void hvsi_unthrottle(struct tty_struct *tty) ...@@ -1014,19 +989,16 @@ static void hvsi_unthrottle(struct tty_struct *tty)
{ {
struct hvsi_struct *hp = tty->driver_data; struct hvsi_struct *hp = tty->driver_data;
unsigned long flags; unsigned long flags;
int shouldflip = 0;
pr_debug("%s\n", __func__); pr_debug("%s\n", __func__);
spin_lock_irqsave(&hp->lock, flags); spin_lock_irqsave(&hp->lock, flags);
if (hp->n_throttle) { if (hp->n_throttle) {
hvsi_send_overflow(hp); hvsi_send_overflow(hp, tty);
shouldflip = 1; tty_flip_buffer_push(tty);
} }
spin_unlock_irqrestore(&hp->lock, flags); spin_unlock_irqrestore(&hp->lock, flags);
if (shouldflip)
tty_flip_buffer_push(hp->tty);
h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE); h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment