Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 55db4c64 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Revert "tty: make receive_buf() return the amout of bytes received"



This reverts commit b1c43f82.

It was broken in so many ways, and results in random odd pty issues.

It re-introduced the buggy schedule_work() in flush_to_ldisc() that can
cause endless work-loops (see commit a5660b41: "tty: fix endless
work loop when the buffer fills up").

It also used an "unsigned int" return value fo the ->receive_buf()
function, but then made multiple functions return a negative error code,
and didn't actually check for the error in the caller.

And it didn't actually work at all.  BenH bisected down odd tty behavior
to it:
  "It looks like the patch is causing some major malfunctions of the X
   server for me, possibly related to PTYs.  For example, cat'ing a
   large file in a gnome terminal hangs the kernel for -minutes- in a
   loop of what looks like flush_to_ldisc/workqueue code, (some ftrace
   data in the quoted bits further down).

   ...

   Some more data: It -looks- like what happens is that the
   flush_to_ldisc work queue entry constantly re-queues itself (because
   the PTY is full ?) and the workqueue thread will basically loop
   forver calling it without ever scheduling, thus starving the consumer
   process that could have emptied the PTY."

which is pretty much exactly the problem we fixed in a5660b41.

Milton Miller pointed out the 'unsigned int' issue.

Reported-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
Reported-by: default avatarMilton Miller <miltonm@bga.com>
Cc: Stefan Bigler <stefan.bigler@keymile.com>
Cc: Toby Gray <toby.gray@realvnc.com>
Cc: Felipe Balbi <balbi@ti.com>
Cc: Greg Kroah-Hartman <gregkh@suse.de>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 1fa7b6a2
Loading
Loading
Loading
Loading
+6 −11
Original line number Diff line number Diff line
@@ -355,29 +355,24 @@ static void hci_uart_tty_wakeup(struct tty_struct *tty)
 *             flags        pointer to flags for data
 *             count        count of received data in bytes
 *     
 * Return Value:    Number of bytes received
 * Return Value:    None
 */
static unsigned int hci_uart_tty_receive(struct tty_struct *tty,
		const u8 *data, char *flags, int count)
static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *flags, int count)
{
	struct hci_uart *hu = (void *)tty->disc_data;
	int received;

	if (!hu || tty != hu->tty)
		return -ENODEV;
		return;

	if (!test_bit(HCI_UART_PROTO_SET, &hu->flags))
		return -EINVAL;
		return;

	spin_lock(&hu->rx_lock);
	received = hu->proto->recv(hu, (void *) data, count);
	if (received > 0)
		hu->hdev->stat.byte_rx += received;
	hu->proto->recv(hu, (void *) data, count);
	hu->hdev->stat.byte_rx += count;
	spin_unlock(&hu->rx_lock);

	tty_unthrottle(tty);

	return received;
}

static int hci_uart_register_dev(struct hci_uart *hu)
+2 −8
Original line number Diff line number Diff line
@@ -120,21 +120,17 @@ static void serport_ldisc_close(struct tty_struct *tty)
 * 'interrupt' routine.
 */

static unsigned int serport_ldisc_receive(struct tty_struct *tty,
		const unsigned char *cp, char *fp, int count)
static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
{
	struct serport *serport = (struct serport*) tty->disc_data;
	unsigned long flags;
	unsigned int ch_flags;
	int ret = 0;
	int i;

	spin_lock_irqsave(&serport->lock, flags);

	if (!test_bit(SERPORT_ACTIVE, &serport->flags)) {
		ret = -EINVAL;
	if (!test_bit(SERPORT_ACTIVE, &serport->flags))
		goto out;
	}

	for (i = 0; i < count; i++) {
		switch (fp[i]) {
@@ -156,8 +152,6 @@ static unsigned int serport_ldisc_receive(struct tty_struct *tty,

out:
	spin_unlock_irqrestore(&serport->lock, flags);

	return ret == 0 ? count : ret;
}

/*
+3 −5
Original line number Diff line number Diff line
@@ -674,7 +674,7 @@ gigaset_tty_ioctl(struct tty_struct *tty, struct file *file,
 *	cflags	buffer containing error flags for received characters (ignored)
 *	count	number of received characters
 */
static unsigned int
static void
gigaset_tty_receive(struct tty_struct *tty, const unsigned char *buf,
		    char *cflags, int count)
{
@@ -683,12 +683,12 @@ gigaset_tty_receive(struct tty_struct *tty, const unsigned char *buf,
	struct inbuf_t *inbuf;

	if (!cs)
		return -ENODEV;
		return;
	inbuf = cs->inbuf;
	if (!inbuf) {
		dev_err(cs->dev, "%s: no inbuf\n", __func__);
		cs_put(cs);
		return -EINVAL;
		return;
	}

	tail = inbuf->tail;
@@ -725,8 +725,6 @@ gigaset_tty_receive(struct tty_struct *tty, const unsigned char *buf,
	gig_dbg(DEBUG_INTR, "%s-->BH", __func__);
	gigaset_schedule_event(cs);
	cs_put(cs);

	return count;
}

/*
+2 −4
Original line number Diff line number Diff line
@@ -747,8 +747,8 @@ static void st_tty_close(struct tty_struct *tty)
	pr_debug("%s: done ", __func__);
}

static unsigned int st_tty_receive(struct tty_struct *tty,
		const unsigned char *data, char *tty_flags, int count)
static void st_tty_receive(struct tty_struct *tty, const unsigned char *data,
			   char *tty_flags, int count)
{
#ifdef VERBOSE
	print_hex_dump(KERN_DEBUG, ">in>", DUMP_PREFIX_NONE,
@@ -761,8 +761,6 @@ static unsigned int st_tty_receive(struct tty_struct *tty,
	 */
	st_recv(tty->disc_data, data, count);
	pr_debug("done %s", __func__);

	return count;
}

/* wake-up function called in from the TTY layer
+2 −4
Original line number Diff line number Diff line
@@ -167,8 +167,8 @@ static inline void debugfs_tx(struct ser_device *ser, const u8 *data, int size)

#endif

static unsigned int ldisc_receive(struct tty_struct *tty,
		const u8 *data, char *flags, int count)
static void ldisc_receive(struct tty_struct *tty, const u8 *data,
			char *flags, int count)
{
	struct sk_buff *skb = NULL;
	struct ser_device *ser;
@@ -215,8 +215,6 @@ static unsigned int ldisc_receive(struct tty_struct *tty,
	} else
		++ser->dev->stats.rx_dropped;
	update_tty_status(ser);

	return count;
}

static int handle_tx(struct ser_device *ser)
Loading