diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2019-05-15 10:20:16 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2019-05-15 10:20:16 +0200 |
commit | 2c3266e8829eb5a611a08cddca97f79c05ed28db (patch) | |
tree | b7aaa09c1ee1f738acd83b9a46ae2d135f89b22c | |
parent | cf6fd4d72fe78061c68af7a241387ec2d26dc161 (diff) | |
download | patches-2c3266e8829eb5a611a08cddca97f79c05ed28db.tar.gz |
tty patches added
17 files changed, 2483 insertions, 6 deletions
diff --git a/0001-tty-n_r3964-locking-fixups.patch b/0001-tty-n_r3964-locking-fixups.patch new file mode 100644 index 00000000000000..dbcbfeff34d067 --- /dev/null +++ b/0001-tty-n_r3964-locking-fixups.patch @@ -0,0 +1,212 @@ +From 51d25226b066ddeff053d36a74af38e53472520b Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +Date: Wed, 23 Jan 2019 11:00:42 +0100 +Subject: [PATCH 01/15] tty: n_r3964: locking fixups + +The n_r3964 line discipline has an "interesting" concept of locking. The +list of client's are not always properly accessed under a lock, which +can cause problems with some multi-threaded systems. + +To resolve this, do two different things: + - serialize ioctl and read accesses. + Right now ioctls can mess with the structures that a read call wants + to also touch, so serialze them to make it simpler. Note, this + _might_ break some userspace applications, as one thread could be + waiting in a read while another one wanted to make an ioctl call. + In reality, the ioctls mess with things so much that any outstanding + read might be really confused, so this is not a good thing for + userspace to be doing anyway. + - properly protect the client list + The list of clients could be accessed by different threads at the + same time without any locking. Well, there was some attempt at + locking, but the main access, findClient(), was not locked at all. + Also fix this up in a few other places. + +This line discipline needs a major overhaul. It was written at a time +there was not any SMP machines, and it shows. Rewriting some of the +object handling logic will allow the read/ioctl serialization to be +removed again. + +Reported-by: Jann Horn <jannh@google.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + drivers/tty/n_r3964.c | 54 +++++++++++++++++++++++++++++++---------- + include/linux/n_r3964.h | 2 +- + 2 files changed, 42 insertions(+), 14 deletions(-) + +diff --git a/drivers/tty/n_r3964.c b/drivers/tty/n_r3964.c +index f75696f0ee2d..664b201b9abc 100644 +--- a/drivers/tty/n_r3964.c ++++ b/drivers/tty/n_r3964.c +@@ -484,6 +484,7 @@ static void on_receive_block(struct r3964_info *pInfo) + unsigned int length; + struct r3964_client_info *pClient; + struct r3964_block_header *pBlock; ++ unsigned long flags; + + length = pInfo->rx_position; + +@@ -541,12 +542,14 @@ static void on_receive_block(struct r3964_info *pInfo) + add_rx_queue(pInfo, pBlock); + + /* notify attached client processes: */ ++ spin_lock_irqsave(&pInfo->lock, flags); + for (pClient = pInfo->firstClient; pClient; pClient = pClient->next) { + if (pClient->sig_flags & R3964_SIG_DATA) { + add_msg(pClient, R3964_MSG_DATA, length, R3964_OK, + pBlock); + } + } ++ spin_unlock_irqrestore(&pInfo->lock, flags); + wake_up_interruptible(&pInfo->tty->read_wait); + + pInfo->state = R3964_IDLE; +@@ -743,13 +746,17 @@ static struct r3964_client_info *findClient(struct r3964_info *pInfo, + struct pid *pid) + { + struct r3964_client_info *pClient; ++ unsigned long flags; + ++ spin_lock_irqsave(&pInfo->lock, flags); + for (pClient = pInfo->firstClient; pClient; pClient = pClient->next) { + if (pClient->pid == pid) { +- return pClient; ++ goto exit; + } + } +- return NULL; ++exit: ++ spin_unlock_irqrestore(&pInfo->lock, flags); ++ return pClient; + } + + static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg) +@@ -757,8 +764,11 @@ static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg) + struct r3964_client_info *pClient; + struct r3964_client_info **ppClient; + struct r3964_message *pMsg; ++ unsigned long flags; + + if ((arg & R3964_SIG_ALL) == 0) { ++ spin_lock_irqsave(&pInfo->lock, flags); ++ + /* Remove client from client list */ + for (ppClient = &pInfo->firstClient; *ppClient; + ppClient = &(*ppClient)->next) { +@@ -779,9 +789,11 @@ static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg) + put_pid(pClient->pid); + kfree(pClient); + TRACE_M("enable_signals - kfree %p", pClient); ++ spin_unlock_irqrestore(&pInfo->lock, flags); + return 0; + } + } ++ spin_unlock_irqrestore(&pInfo->lock, flags); + return -EINVAL; + } else { + pClient = findClient(pInfo, pid); +@@ -796,6 +808,7 @@ static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg) + if (pClient == NULL) + return -ENOMEM; + ++ spin_lock_irqsave(&pInfo->lock, flags); + TRACE_PS("add client %d to client list", pid_nr(pid)); + spin_lock_init(&pClient->lock); + pClient->sig_flags = arg; +@@ -806,6 +819,7 @@ static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg) + pClient->next_block_to_read = NULL; + pClient->msg_count = 0; + pInfo->firstClient = pClient; ++ spin_unlock_irqrestore(&pInfo->lock, flags); + } + } + +@@ -850,8 +864,7 @@ static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg, + if (pClient->msg_count < R3964_MAX_MSG_COUNT - 1) { + queue_the_message: + +- pMsg = kmalloc(sizeof(struct r3964_message), +- error_code ? GFP_ATOMIC : GFP_KERNEL); ++ pMsg = kmalloc(sizeof(*pMsg), GFP_ATOMIC); + TRACE_M("add_msg - kmalloc %p", pMsg); + if (pMsg == NULL) { + return; +@@ -1069,9 +1082,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file, + + TRACE_L("read()"); + +- /* +- * Internal serialization of reads. +- */ ++ /* Internal serialization of reads and ioctls. */ + if (file->f_flags & O_NONBLOCK) { + if (!mutex_trylock(&pInfo->read_lock)) + return -EAGAIN; +@@ -1193,28 +1204,45 @@ static int r3964_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) + { + struct r3964_info *pInfo = tty->disc_data; ++ int retval = 0; ++ + if (pInfo == NULL) + return -EINVAL; ++ /* Internal serialization of reads and ioctls */ ++ if (file->f_flags & O_NONBLOCK) { ++ if (!mutex_trylock(&pInfo->read_lock)) ++ return -EAGAIN; ++ } else { ++ if (mutex_lock_interruptible(&pInfo->read_lock)) ++ return -ERESTARTSYS; ++ } ++ + switch (cmd) { + case R3964_ENABLE_SIGNALS: +- return enable_signals(pInfo, task_pid(current), arg); ++ retval = enable_signals(pInfo, task_pid(current), arg); ++ break; + case R3964_SETPRIORITY: + if (arg < R3964_MASTER || arg > R3964_SLAVE) + return -EINVAL; + pInfo->priority = arg & 0xff; +- return 0; ++ break; + case R3964_USE_BCC: + if (arg) + pInfo->flags |= R3964_BCC; + else + pInfo->flags &= ~R3964_BCC; +- return 0; ++ break; + case R3964_READ_TELEGRAM: +- return read_telegram(pInfo, task_pid(current), +- (unsigned char __user *)arg); ++ retval = read_telegram(pInfo, task_pid(current), ++ (unsigned char __user *)arg); ++ break; + default: +- return -ENOIOCTLCMD; ++ retval = -ENOIOCTLCMD; ++ break; + } ++ ++ mutex_unlock(&pInfo->read_lock); ++ return retval; + } + + #ifdef CONFIG_COMPAT +diff --git a/include/linux/n_r3964.h b/include/linux/n_r3964.h +index 90a803aa42e8..9cc0020930ad 100644 +--- a/include/linux/n_r3964.h ++++ b/include/linux/n_r3964.h +@@ -162,7 +162,7 @@ struct r3964_info { + unsigned char bcc; + unsigned int blocks_in_rx_queue; + +- struct mutex read_lock; /* serialize r3964_read */ ++ struct mutex read_lock; /* serialize read and ioctl */ + + struct r3964_client_info *firstClient; + unsigned int state; +-- +2.21.0 + diff --git a/0002-tty-n_r3964-fix-poll-return-value.patch b/0002-tty-n_r3964-fix-poll-return-value.patch new file mode 100644 index 00000000000000..e2e91facfa6269 --- /dev/null +++ b/0002-tty-n_r3964-fix-poll-return-value.patch @@ -0,0 +1,30 @@ +From f93faa310cf3da0d54ee2232a76729b2063cc551 Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +Date: Fri, 25 Jan 2019 15:13:58 +0100 +Subject: [PATCH 02/15] tty: n_r3964: fix poll return value + +-EINVAL is not a valid __poll_t return value for when an error happens. +Instead, set return EPOLLNVAL | EPOLLERR to tell userspace that what it +wanted to have happen did not. + +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + drivers/tty/n_r3964.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/tty/n_r3964.c b/drivers/tty/n_r3964.c +index 664b201b9abc..b4a205f9f8ac 100644 +--- a/drivers/tty/n_r3964.c ++++ b/drivers/tty/n_r3964.c +@@ -1286,7 +1286,7 @@ static __poll_t r3964_poll(struct tty_struct *tty, struct file *file, + if (pMsg) + result |= EPOLLIN | EPOLLRDNORM; + } else { +- result = -EINVAL; ++ result = EPOLLNVAL | EPOLLERR; + } + return result; + } +-- +2.21.0 + diff --git a/0003-tty-n_r3964-remove-n_r3964.h.patch b/0003-tty-n_r3964-remove-n_r3964.h.patch new file mode 100644 index 00000000000000..3831fbbcfef200 --- /dev/null +++ b/0003-tty-n_r3964-remove-n_r3964.h.patch @@ -0,0 +1,337 @@ +From 3383e7c9df4908b5f3ac97e5ac0492775d0a4b35 Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +Date: Wed, 23 Jan 2019 20:28:46 +0100 +Subject: [PATCH 03/15] tty: n_r3964: remove n_r3964.h + +No need to have a .h file in include/linux/ for a line discipline where +the only things in it are needed by a single c file. + +So move the contents (and fix the formatting at the same time) into +drivers/tty/n_r3964.c + +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + drivers/tty/n_r3964.c | 114 +++++++++++++++++++++++++- + include/linux/n_r3964.h | 175 ---------------------------------------- + 2 files changed, 113 insertions(+), 176 deletions(-) + delete mode 100644 include/linux/n_r3964.h + +diff --git a/drivers/tty/n_r3964.c b/drivers/tty/n_r3964.c +index b4a205f9f8ac..62a0e869eab5 100644 +--- a/drivers/tty/n_r3964.c ++++ b/drivers/tty/n_r3964.c +@@ -60,10 +60,11 @@ + #include <linux/string.h> /* used in new tty drivers */ + #include <linux/signal.h> /* used in new tty drivers */ + #include <linux/ioctl.h> +-#include <linux/n_r3964.h> ++#include <linux/param.h> + #include <linux/poll.h> + #include <linux/init.h> + #include <linux/uaccess.h> ++#include <uapi/linux/n_r3964.h> + + /*#define DEBUG_QUEUE*/ + +@@ -107,6 +108,117 @@ + #else + #define TRACE_Q(fmt, arg...) do {} while (0) + #endif ++ ++/* Common ascii handshake characters: */ ++#define STX 0x02 ++#define ETX 0x03 ++#define DLE 0x10 ++#define NAK 0x15 ++ ++/* Timeouts (from milliseconds to jiffies) */ ++#define R3964_TO_QVZ ((550)*HZ/1000) ++#define R3964_TO_ZVZ ((220)*HZ/1000) ++#define R3964_TO_NO_BUF ((400)*HZ/1000) ++#define R3964_NO_TX_ROOM ((100)*HZ/1000) ++#define R3964_TO_RX_PANIC ((4000)*HZ/1000) ++#define R3964_MAX_RETRIES 5 ++ ++enum { ++ R3964_IDLE, ++ R3964_TX_REQUEST, ++ R3964_TRANSMITTING, ++ R3964_WAIT_ZVZ_BEFORE_TX_RETRY, ++ R3964_WAIT_FOR_TX_ACK, ++ R3964_WAIT_FOR_RX_BUF, ++ R3964_RECEIVING, ++ R3964_WAIT_FOR_BCC, ++ R3964_WAIT_FOR_RX_REPEAT ++}; ++ ++/* All open file-handles are 'clients' and are stored in a linked list: */ ++ ++struct r3964_message; ++ ++struct r3964_client_info { ++ spinlock_t lock; ++ struct pid *pid; ++ unsigned int sig_flags; ++ ++ struct r3964_client_info *next; ++ ++ struct r3964_message *first_msg; ++ struct r3964_message *last_msg; ++ struct r3964_block_header *next_block_to_read; ++ int msg_count; ++}; ++ ++struct r3964_block_header; ++ ++/* internal version of client_message: */ ++struct r3964_message { ++ int msg_id; ++ int arg; ++ int error_code; ++ struct r3964_block_header *block; ++ struct r3964_message *next; ++}; ++ ++/* Header of received block in rx_buf/tx_buf: */ ++struct r3964_block_header { ++ unsigned int length; /* length in chars without header */ ++ unsigned char *data; /* usually data is located immediately ++ * behind this struct */ ++ unsigned int locks; /* only used in rx_buffer */ ++ ++ struct r3964_block_header *next; ++ struct r3964_client_info *owner; /* =NULL in rx_buffer */ ++}; ++ ++/* ++ * If rx_buf hasn't enough space to store R3964_MTU chars, ++ * we will reject all incoming STX-requests by sending NAK. ++ */ ++#define RX_BUF_SIZE 4000 ++#define TX_BUF_SIZE 4000 ++#define R3964_MAX_BLOCKS_IN_RX_QUEUE 100 ++ ++#define R3964_PARITY 0x0001 ++#define R3964_FRAME 0x0002 ++#define R3964_OVERRUN 0x0004 ++#define R3964_UNKNOWN 0x0008 ++#define R3964_BREAK 0x0010 ++#define R3964_CHECKSUM 0x0020 ++#define R3964_ERROR 0x003f ++#define R3964_BCC 0x4000 ++#define R3964_DEBUG 0x8000 ++ ++struct r3964_info { ++ spinlock_t lock; ++ struct tty_struct *tty; ++ unsigned char priority; ++ unsigned char *rx_buf; /* ring buffer */ ++ unsigned char *tx_buf; ++ ++ struct r3964_block_header *rx_first; ++ struct r3964_block_header *rx_last; ++ struct r3964_block_header *tx_first; ++ struct r3964_block_header *tx_last; ++ unsigned int tx_position; ++ unsigned int rx_position; ++ unsigned char last_rx; ++ unsigned char bcc; ++ unsigned int blocks_in_rx_queue; ++ ++ struct mutex read_lock; /* serialize read and ioctl */ ++ ++ struct r3964_client_info *firstClient; ++ unsigned int state; ++ unsigned int flags; ++ ++ struct timer_list tmr; ++ int nRetry; ++}; ++ + static void add_tx_queue(struct r3964_info *, struct r3964_block_header *); + static void remove_from_tx_queue(struct r3964_info *pInfo, int error_code); + static void put_char(struct r3964_info *pInfo, unsigned char ch); +diff --git a/include/linux/n_r3964.h b/include/linux/n_r3964.h +deleted file mode 100644 +index 9cc0020930ad..000000000000 +--- a/include/linux/n_r3964.h ++++ /dev/null +@@ -1,175 +0,0 @@ +-/* r3964 linediscipline for linux +- * +- * ----------------------------------------------------------- +- * Copyright by +- * Philips Automation Projects +- * Kassel (Germany) +- * ----------------------------------------------------------- +- * This software may be used and distributed according to the terms of +- * the GNU General Public License, incorporated herein by reference. +- * +- * Author: +- * L. Haag +- * +- * $Log: r3964.h,v $ +- * Revision 1.4 2005/12/21 19:54:24 Kurt Huwig <kurt huwig de> +- * Fixed HZ usage on 2.6 kernels +- * Removed unnecessary include +- * +- * Revision 1.3 2001/03/18 13:02:24 dwmw2 +- * Fix timer usage, use spinlocks properly. +- * +- * Revision 1.2 2001/03/18 12:53:15 dwmw2 +- * Merge changes in 2.4.2 +- * +- * Revision 1.1.1.1 1998/10/13 16:43:14 dwmw2 +- * This'll screw the version control +- * +- * Revision 1.6 1998/09/30 00:40:38 dwmw2 +- * Updated to use kernel's N_R3964 if available +- * +- * Revision 1.4 1998/04/02 20:29:44 lhaag +- * select, blocking, ... +- * +- * Revision 1.3 1998/02/12 18:58:43 root +- * fixed some memory leaks +- * calculation of checksum characters +- * +- * Revision 1.2 1998/02/07 13:03:17 root +- * ioctl read_telegram +- * +- * Revision 1.1 1998/02/06 19:19:43 root +- * Initial revision +- * +- * +- */ +-#ifndef __LINUX_N_R3964_H__ +-#define __LINUX_N_R3964_H__ +- +- +-#include <linux/param.h> +-#include <uapi/linux/n_r3964.h> +- +-/* +- * Common ascii handshake characters: +- */ +- +-#define STX 0x02 +-#define ETX 0x03 +-#define DLE 0x10 +-#define NAK 0x15 +- +-/* +- * Timeouts (from milliseconds to jiffies) +- */ +- +-#define R3964_TO_QVZ ((550)*HZ/1000) +-#define R3964_TO_ZVZ ((220)*HZ/1000) +-#define R3964_TO_NO_BUF ((400)*HZ/1000) +-#define R3964_NO_TX_ROOM ((100)*HZ/1000) +-#define R3964_TO_RX_PANIC ((4000)*HZ/1000) +-#define R3964_MAX_RETRIES 5 +- +- +-enum { R3964_IDLE, +- R3964_TX_REQUEST, R3964_TRANSMITTING, +- R3964_WAIT_ZVZ_BEFORE_TX_RETRY, R3964_WAIT_FOR_TX_ACK, +- R3964_WAIT_FOR_RX_BUF, +- R3964_RECEIVING, R3964_WAIT_FOR_BCC, R3964_WAIT_FOR_RX_REPEAT +- }; +- +-/* +- * All open file-handles are 'clients' and are stored in a linked list: +- */ +- +-struct r3964_message; +- +-struct r3964_client_info { +- spinlock_t lock; +- struct pid *pid; +- unsigned int sig_flags; +- +- struct r3964_client_info *next; +- +- struct r3964_message *first_msg; +- struct r3964_message *last_msg; +- struct r3964_block_header *next_block_to_read; +- int msg_count; +-}; +- +- +- +-struct r3964_block_header; +- +-/* internal version of client_message: */ +-struct r3964_message { +- int msg_id; +- int arg; +- int error_code; +- struct r3964_block_header *block; +- struct r3964_message *next; +-}; +- +-/* +- * Header of received block in rx_buf/tx_buf: +- */ +- +-struct r3964_block_header +-{ +- unsigned int length; /* length in chars without header */ +- unsigned char *data; /* usually data is located +- immediately behind this struct */ +- unsigned int locks; /* only used in rx_buffer */ +- +- struct r3964_block_header *next; +- struct r3964_client_info *owner; /* =NULL in rx_buffer */ +-}; +- +-/* +- * If rx_buf hasn't enough space to store R3964_MTU chars, +- * we will reject all incoming STX-requests by sending NAK. +- */ +- +-#define RX_BUF_SIZE 4000 +-#define TX_BUF_SIZE 4000 +-#define R3964_MAX_BLOCKS_IN_RX_QUEUE 100 +- +-#define R3964_PARITY 0x0001 +-#define R3964_FRAME 0x0002 +-#define R3964_OVERRUN 0x0004 +-#define R3964_UNKNOWN 0x0008 +-#define R3964_BREAK 0x0010 +-#define R3964_CHECKSUM 0x0020 +-#define R3964_ERROR 0x003f +-#define R3964_BCC 0x4000 +-#define R3964_DEBUG 0x8000 +- +- +-struct r3964_info { +- spinlock_t lock; +- struct tty_struct *tty; +- unsigned char priority; +- unsigned char *rx_buf; /* ring buffer */ +- unsigned char *tx_buf; +- +- struct r3964_block_header *rx_first; +- struct r3964_block_header *rx_last; +- struct r3964_block_header *tx_first; +- struct r3964_block_header *tx_last; +- unsigned int tx_position; +- unsigned int rx_position; +- unsigned char last_rx; +- unsigned char bcc; +- unsigned int blocks_in_rx_queue; +- +- struct mutex read_lock; /* serialize read and ioctl */ +- +- struct r3964_client_info *firstClient; +- unsigned int state; +- unsigned int flags; +- +- struct timer_list tmr; +- int nRetry; +-}; +- +-#endif +-- +2.21.0 + diff --git a/0004-tty-n_r3964-drop-ancient-header-changelog-text.patch b/0004-tty-n_r3964-drop-ancient-header-changelog-text.patch new file mode 100644 index 00000000000000..46c61661f16528 --- /dev/null +++ b/0004-tty-n_r3964-drop-ancient-header-changelog-text.patch @@ -0,0 +1,74 @@ +From d01e4fbee328ad33555c740d7881129fe6d15175 Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +Date: Wed, 23 Jan 2019 20:31:02 +0100 +Subject: [PATCH 04/15] tty: n_r3964: drop ancient header changelog text + +No need to keep changelog text from 2001 and earlier in the file itself, +drop it all. This keeps the original copyright and author information +in the file. + +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + drivers/tty/n_r3964.c | 45 ++++--------------------------------------- + 1 file changed, 4 insertions(+), 41 deletions(-) + +diff --git a/drivers/tty/n_r3964.c b/drivers/tty/n_r3964.c +index 62a0e869eab5..6c0abb04c4f0 100644 +--- a/drivers/tty/n_r3964.c ++++ b/drivers/tty/n_r3964.c +@@ -1,48 +1,11 @@ + // SPDX-License-Identifier: GPL-1.0+ +-/* r3964 linediscipline for linux ++/* ++ * r3964 line discipline + * +- * ----------------------------------------------------------- +- * Copyright by +- * Philips Automation Projects ++ * Copyright by Philips Automation Projects + * Kassel (Germany) +- * ----------------------------------------------------------- +- * Author: +- * L. Haag +- * +- * $Log: n_r3964.c,v $ +- * Revision 1.10 2001/03/18 13:02:24 dwmw2 +- * Fix timer usage, use spinlocks properly. +- * +- * Revision 1.9 2001/03/18 12:52:14 dwmw2 +- * Merge changes in 2.4.2 +- * +- * Revision 1.8 2000/03/23 14:14:54 dwmw2 +- * Fix race in sleeping in r3964_read() +- * +- * Revision 1.7 1999/28/08 11:41:50 dwmw2 +- * Port to 2.3 kernel +- * +- * Revision 1.6 1998/09/30 00:40:40 dwmw2 +- * Fixed compilation on 2.0.x kernels +- * Updated to newly registered tty-ldisc number 9 +- * +- * Revision 1.5 1998/09/04 21:57:36 dwmw2 +- * Signal handling bug fixes, port to 2.1.x. +- * +- * Revision 1.4 1998/04/02 20:26:59 lhaag +- * select, blocking, ... +- * +- * Revision 1.3 1998/02/12 18:58:43 root +- * fixed some memory leaks +- * calculation of checksum characters +- * +- * Revision 1.2 1998/02/07 13:03:34 root +- * ioctl read_telegram +- * +- * Revision 1.1 1998/02/06 19:21:03 root +- * Initial revision +- * + * ++ * Author: L. Haag + */ + + #include <linux/module.h> +-- +2.21.0 + diff --git a/0005-tty-n_r3964-split-rx-and-tx-header-structures.patch b/0005-tty-n_r3964-split-rx-and-tx-header-structures.patch new file mode 100644 index 00000000000000..0f633183531e36 --- /dev/null +++ b/0005-tty-n_r3964-split-rx-and-tx-header-structures.patch @@ -0,0 +1,265 @@ +From b717816885270bfe80ed184cb894b14c10c3f48f Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +Date: Thu, 24 Jan 2019 12:32:05 +0100 +Subject: [PATCH 05/15] tty: n_r3964: split rx and tx header structures + +It's really confusing to try to figure out what structure is what type +of header when both the tx and rx queues are using the same header +structure, but not all of the fields in it. + +So split this into two different structures. That makes it much more +obvious what variable and queue and type of message is being kept track +of where. + +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + drivers/tty/n_r3964.c | 78 +++++++++++++++++++++---------------------- + 1 file changed, 39 insertions(+), 39 deletions(-) + +diff --git a/drivers/tty/n_r3964.c b/drivers/tty/n_r3964.c +index 6c0abb04c4f0..487aa6a38f7d 100644 +--- a/drivers/tty/n_r3964.c ++++ b/drivers/tty/n_r3964.c +@@ -101,6 +101,8 @@ enum { + /* All open file-handles are 'clients' and are stored in a linked list: */ + + struct r3964_message; ++struct rx_block_header; ++struct tx_block_header; + + struct r3964_client_info { + spinlock_t lock; +@@ -111,30 +113,35 @@ struct r3964_client_info { + + struct r3964_message *first_msg; + struct r3964_message *last_msg; +- struct r3964_block_header *next_block_to_read; ++ struct rx_block_header *next_block_to_read; + int msg_count; + }; + +-struct r3964_block_header; +- + /* internal version of client_message: */ + struct r3964_message { + int msg_id; + int arg; + int error_code; +- struct r3964_block_header *block; ++ struct rx_block_header *block; + struct r3964_message *next; + }; + +-/* Header of received block in rx_buf/tx_buf: */ +-struct r3964_block_header { ++/* Header of received block in rx_buf: */ ++struct rx_block_header { + unsigned int length; /* length in chars without header */ + unsigned char *data; /* usually data is located immediately + * behind this struct */ + unsigned int locks; /* only used in rx_buffer */ + +- struct r3964_block_header *next; +- struct r3964_client_info *owner; /* =NULL in rx_buffer */ ++ struct rx_block_header *next; ++}; ++ ++/* Header of received block in tx_buf: */ ++struct tx_block_header { ++ unsigned int length; /* length in chars without header */ ++ unsigned char *data; ++ struct tx_block_header *next; ++ struct r3964_client_info *owner; + }; + + /* +@@ -162,10 +169,10 @@ struct r3964_info { + unsigned char *rx_buf; /* ring buffer */ + unsigned char *tx_buf; + +- struct r3964_block_header *rx_first; +- struct r3964_block_header *rx_last; +- struct r3964_block_header *tx_first; +- struct r3964_block_header *tx_last; ++ struct rx_block_header *rx_first; ++ struct rx_block_header *rx_last; ++ struct tx_block_header *tx_first; ++ struct tx_block_header *tx_last; + unsigned int tx_position; + unsigned int rx_position; + unsigned char last_rx; +@@ -182,8 +189,6 @@ struct r3964_info { + int nRetry; + }; + +-static void add_tx_queue(struct r3964_info *, struct r3964_block_header *); +-static void remove_from_tx_queue(struct r3964_info *pInfo, int error_code); + static void put_char(struct r3964_info *pInfo, unsigned char ch); + static void trigger_transmit(struct r3964_info *pInfo); + static void retry_transmit(struct r3964_info *pInfo); +@@ -195,7 +200,7 @@ static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg); + static int read_telegram(struct r3964_info *pInfo, struct pid *pid, + unsigned char __user * buf); + static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg, +- int error_code, struct r3964_block_header *pBlock); ++ int error_code, struct rx_block_header *pBlock); + static struct r3964_message *remove_msg(struct r3964_info *pInfo, + struct r3964_client_info *pClient); + static void remove_client_block(struct r3964_info *pInfo, +@@ -306,7 +311,7 @@ module_exit(r3964_exit); + *************************************************************/ + + static void add_tx_queue(struct r3964_info *pInfo, +- struct r3964_block_header *pHeader) ++ struct tx_block_header *pHeader) + { + unsigned long flags; + +@@ -329,10 +334,10 @@ static void add_tx_queue(struct r3964_info *pInfo, + + static void remove_from_tx_queue(struct r3964_info *pInfo, int error_code) + { +- struct r3964_block_header *pHeader; ++ struct tx_block_header *pHeader; + unsigned long flags; + #ifdef DEBUG_QUEUE +- struct r3964_block_header *pDump; ++ struct tx_block_header *pDump; + #endif + + pHeader = pInfo->tx_first; +@@ -376,7 +381,7 @@ static void remove_from_tx_queue(struct r3964_info *pInfo, int error_code) + } + + static void add_rx_queue(struct r3964_info *pInfo, +- struct r3964_block_header *pHeader) ++ struct rx_block_header *pHeader) + { + unsigned long flags; + +@@ -400,10 +405,10 @@ static void add_rx_queue(struct r3964_info *pInfo, + } + + static void remove_from_rx_queue(struct r3964_info *pInfo, +- struct r3964_block_header *pHeader) ++ struct rx_block_header *pHeader) + { + unsigned long flags; +- struct r3964_block_header *pFind; ++ struct rx_block_header *pFind; + + if (pHeader == NULL) + return; +@@ -517,7 +522,7 @@ static void retry_transmit(struct r3964_info *pInfo) + static void transmit_block(struct r3964_info *pInfo) + { + struct tty_struct *tty = pInfo->tty; +- struct r3964_block_header *pBlock = pInfo->tx_first; ++ struct tx_block_header *pBlock = pInfo->tx_first; + int room = 0; + + if (tty == NULL || pBlock == NULL) { +@@ -558,7 +563,7 @@ static void on_receive_block(struct r3964_info *pInfo) + { + unsigned int length; + struct r3964_client_info *pClient; +- struct r3964_block_header *pBlock; ++ struct rx_block_header *pBlock; + unsigned long flags; + + length = pInfo->rx_position; +@@ -596,20 +601,17 @@ static void on_receive_block(struct r3964_info *pInfo) + del_timer_sync(&pInfo->tmr); + TRACE_PS(" rx success: got %d chars", length); + +- /* prepare struct r3964_block_header: */ +- pBlock = kmalloc(length + sizeof(struct r3964_block_header), +- GFP_KERNEL); ++ /* prepare struct rx_block_header: */ ++ pBlock = kmalloc(length + sizeof(*pBlock), GFP_KERNEL); + TRACE_M("on_receive_block - kmalloc %p", pBlock); + + if (pBlock == NULL) + return; + + pBlock->length = length; +- pBlock->data = ((unsigned char *)pBlock) + +- sizeof(struct r3964_block_header); ++ pBlock->data = ((unsigned char *)pBlock) + sizeof(*pBlock); + pBlock->locks = 0; + pBlock->next = NULL; +- pBlock->owner = NULL; + + memcpy(pBlock->data, pInfo->rx_buf, length); + +@@ -905,7 +907,7 @@ static int read_telegram(struct r3964_info *pInfo, struct pid *pid, + unsigned char __user * buf) + { + struct r3964_client_info *pClient; +- struct r3964_block_header *block; ++ struct rx_block_header *block; + + if (!buf) { + return -EINVAL; +@@ -931,7 +933,7 @@ static int read_telegram(struct r3964_info *pInfo, struct pid *pid, + } + + static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg, +- int error_code, struct r3964_block_header *pBlock) ++ int error_code, struct rx_block_header *pBlock) + { + struct r3964_message *pMsg; + unsigned long flags; +@@ -1014,7 +1016,7 @@ static struct r3964_message *remove_msg(struct r3964_info *pInfo, + static void remove_client_block(struct r3964_info *pInfo, + struct r3964_client_info *pClient) + { +- struct r3964_block_header *block; ++ struct rx_block_header *block; + + TRACE_PS("remove_client_block PID %d", pid_nr(pClient->pid)); + +@@ -1098,7 +1100,7 @@ static void r3964_close(struct tty_struct *tty) + struct r3964_info *pInfo = tty->disc_data; + struct r3964_client_info *pClient, *pNext; + struct r3964_message *pMsg; +- struct r3964_block_header *pHeader, *pNextHeader; ++ struct tx_block_header *pHeader, *pNextHeader; + unsigned long flags; + + TRACE_L("close"); +@@ -1214,7 +1216,7 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file, + const unsigned char *data, size_t count) + { + struct r3964_info *pInfo = tty->disc_data; +- struct r3964_block_header *pHeader; ++ struct tx_block_header *pHeader; + struct r3964_client_info *pClient; + unsigned char *new_data; + +@@ -1239,8 +1241,7 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file, + /* + * Allocate a buffer for the data and copy it from the buffer with header prepended + */ +- new_data = kmalloc(count + sizeof(struct r3964_block_header), +- GFP_KERNEL); ++ new_data = kmalloc(count + sizeof(*pHeader), GFP_KERNEL); + TRACE_M("r3964_write - kmalloc %p", new_data); + if (new_data == NULL) { + if (pInfo->flags & R3964_DEBUG) { +@@ -1249,10 +1250,9 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file, + return -ENOSPC; + } + +- pHeader = (struct r3964_block_header *)new_data; +- pHeader->data = new_data + sizeof(struct r3964_block_header); ++ pHeader = (struct tx_block_header *)new_data; ++ pHeader->data = new_data + sizeof(*pHeader); + pHeader->length = count; +- pHeader->locks = 0; + pHeader->owner = NULL; + + pClient = findClient(pInfo, task_pid(current)); +-- +2.21.0 + diff --git a/0006-tty-n_r3964-for-tx_blocks-use-a-real-kernel-list.patch b/0006-tty-n_r3964-for-tx_blocks-use-a-real-kernel-list.patch new file mode 100644 index 00000000000000..5dacea8486862b --- /dev/null +++ b/0006-tty-n_r3964-for-tx_blocks-use-a-real-kernel-list.patch @@ -0,0 +1,187 @@ +From 55124901b0e4b05999669830cf6e0b240f8cb2fd Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +Date: Thu, 24 Jan 2019 13:35:36 +0100 +Subject: [PATCH 06/15] tty: n_r3964: for tx_blocks, use a real kernel list + +The tx blocks have a hand-rolled linked list structure, use a "normal" +kernel list structure instead, making the code smaller and easier to +understand and verify that it really does what we think it should be +doing. + +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + drivers/tty/n_r3964.c | 85 +++++++++++++------------------------------ + 1 file changed, 26 insertions(+), 59 deletions(-) + +diff --git a/drivers/tty/n_r3964.c b/drivers/tty/n_r3964.c +index 487aa6a38f7d..4a9750adcc56 100644 +--- a/drivers/tty/n_r3964.c ++++ b/drivers/tty/n_r3964.c +@@ -140,7 +140,7 @@ struct rx_block_header { + struct tx_block_header { + unsigned int length; /* length in chars without header */ + unsigned char *data; +- struct tx_block_header *next; ++ struct list_head node; + struct r3964_client_info *owner; + }; + +@@ -171,8 +171,7 @@ struct r3964_info { + + struct rx_block_header *rx_first; + struct rx_block_header *rx_last; +- struct tx_block_header *tx_first; +- struct tx_block_header *tx_last; ++ struct list_head tx_blocks; + unsigned int tx_position; + unsigned int rx_position; + unsigned char last_rx; +@@ -316,42 +315,25 @@ static void add_tx_queue(struct r3964_info *pInfo, + unsigned long flags; + + spin_lock_irqsave(&pInfo->lock, flags); +- +- pHeader->next = NULL; +- +- if (pInfo->tx_last == NULL) { +- pInfo->tx_first = pInfo->tx_last = pHeader; +- } else { +- pInfo->tx_last->next = pHeader; +- pInfo->tx_last = pHeader; +- } +- ++ list_add_tail(&pHeader->node, &pInfo->tx_blocks); + spin_unlock_irqrestore(&pInfo->lock, flags); +- +- TRACE_Q("add_tx_queue %p, length %d, tx_first = %p", +- pHeader, pHeader->length, pInfo->tx_first); + } + + static void remove_from_tx_queue(struct r3964_info *pInfo, int error_code) + { + struct tx_block_header *pHeader; + unsigned long flags; +-#ifdef DEBUG_QUEUE +- struct tx_block_header *pDump; +-#endif + +- pHeader = pInfo->tx_first; +- +- if (pHeader == NULL) ++ spin_lock_irqsave(&pInfo->lock, flags); ++ if (list_empty(&pInfo->tx_blocks)) { ++ spin_unlock_irqrestore(&pInfo->lock, flags); + return; ++ } + +-#ifdef DEBUG_QUEUE +- printk("r3964: remove_from_tx_queue: %p, length %u - ", +- pHeader, pHeader->length); +- for (pDump = pHeader; pDump; pDump = pDump->next) +- printk("%p ", pDump); +- printk("\n"); +-#endif ++ pHeader = list_first_entry(&pInfo->tx_blocks, struct tx_block_header, ++ node); ++ list_del(&pHeader->node); ++ spin_unlock_irqrestore(&pInfo->lock, flags); + + if (pHeader->owner) { + if (error_code) { +@@ -364,20 +346,7 @@ static void remove_from_tx_queue(struct r3964_info *pInfo, int error_code) + wake_up_interruptible(&pInfo->tty->read_wait); + } + +- spin_lock_irqsave(&pInfo->lock, flags); +- +- pInfo->tx_first = pHeader->next; +- if (pInfo->tx_first == NULL) { +- pInfo->tx_last = NULL; +- } +- +- spin_unlock_irqrestore(&pInfo->lock, flags); +- + kfree(pHeader); +- TRACE_M("remove_from_tx_queue - kfree %p", pHeader); +- +- TRACE_Q("remove_from_tx_queue: tx_first = %p, tx_last = %p", +- pInfo->tx_first, pInfo->tx_last); + } + + static void add_rx_queue(struct r3964_info *pInfo, +@@ -476,7 +445,7 @@ static void trigger_transmit(struct r3964_info *pInfo) + + spin_lock_irqsave(&pInfo->lock, flags); + +- if ((pInfo->state == R3964_IDLE) && (pInfo->tx_first != NULL)) { ++ if ((pInfo->state == R3964_IDLE) && (!list_empty(&pInfo->tx_blocks))) { + pInfo->state = R3964_TX_REQUEST; + pInfo->nRetry = 0; + pInfo->flags &= ~R3964_ERROR; +@@ -522,17 +491,19 @@ static void retry_transmit(struct r3964_info *pInfo) + static void transmit_block(struct r3964_info *pInfo) + { + struct tty_struct *tty = pInfo->tty; +- struct tx_block_header *pBlock = pInfo->tx_first; +- int room = 0; ++ struct tx_block_header *pBlock; ++ int room; + +- if (tty == NULL || pBlock == NULL) { ++ if (!tty) + return; +- } + +- room = tty_write_room(tty); ++ if (list_empty(&pInfo->tx_blocks)) ++ return; ++ ++ pBlock = list_first_entry(&pInfo->tx_blocks, struct tx_block_header, ++ node); + +- TRACE_PS("transmit_block %p, room %d, length %d", +- pBlock, room, pBlock->length); ++ room = tty_write_room(tty); + + while (pInfo->tx_position < pBlock->length) { + if (room < 2) +@@ -1077,7 +1048,7 @@ static int r3964_open(struct tty_struct *tty) + pInfo->tty = tty; + pInfo->priority = R3964_MASTER; + pInfo->rx_first = pInfo->rx_last = NULL; +- pInfo->tx_first = pInfo->tx_last = NULL; ++ INIT_LIST_HEAD(&pInfo->tx_blocks); + pInfo->rx_position = 0; + pInfo->tx_position = 0; + pInfo->last_rx = 0; +@@ -1100,7 +1071,7 @@ static void r3964_close(struct tty_struct *tty) + struct r3964_info *pInfo = tty->disc_data; + struct r3964_client_info *pClient, *pNext; + struct r3964_message *pMsg; +- struct tx_block_header *pHeader, *pNextHeader; ++ struct tx_block_header *pHeader, *tmp; + unsigned long flags; + + TRACE_L("close"); +@@ -1129,15 +1100,11 @@ static void r3964_close(struct tty_struct *tty) + } + /* Remove jobs from tx_queue: */ + spin_lock_irqsave(&pInfo->lock, flags); +- pHeader = pInfo->tx_first; +- pInfo->tx_first = pInfo->tx_last = NULL; +- spin_unlock_irqrestore(&pInfo->lock, flags); +- +- while (pHeader) { +- pNextHeader = pHeader->next; ++ list_for_each_entry_safe(pHeader, tmp, &pInfo->tx_blocks, node) { ++ list_del(&pHeader->node); + kfree(pHeader); +- pHeader = pNextHeader; + } ++ spin_unlock_irqrestore(&pInfo->lock, flags); + + /* Free buffers: */ + kfree(pInfo->rx_buf); +-- +2.21.0 + diff --git a/0007-tty-n_r3964-for-rx_blocks-use-a-real-kernel-list.patch b/0007-tty-n_r3964-for-rx_blocks-use-a-real-kernel-list.patch new file mode 100644 index 00000000000000..749651594132ab --- /dev/null +++ b/0007-tty-n_r3964-for-rx_blocks-use-a-real-kernel-list.patch @@ -0,0 +1,141 @@ +From c711e9d95e2fbc99dc88c0797f58194ade169258 Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +Date: Thu, 24 Jan 2019 16:04:54 +0100 +Subject: [PATCH 07/15] tty: n_r3964: for rx_blocks, use a real kernel list + +The rx blocks have a hand-rolled linked list structure, use a "normal" +kernel list structure instead, making the code smaller and easier to +understand and verify that it really does what we think it should be +doing. + +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + drivers/tty/n_r3964.c | 67 +++++++++---------------------------------- + 1 file changed, 13 insertions(+), 54 deletions(-) + +diff --git a/drivers/tty/n_r3964.c b/drivers/tty/n_r3964.c +index 4a9750adcc56..8275fb905aeb 100644 +--- a/drivers/tty/n_r3964.c ++++ b/drivers/tty/n_r3964.c +@@ -132,8 +132,7 @@ struct rx_block_header { + unsigned char *data; /* usually data is located immediately + * behind this struct */ + unsigned int locks; /* only used in rx_buffer */ +- +- struct rx_block_header *next; ++ struct list_head node; + }; + + /* Header of received block in tx_buf: */ +@@ -169,8 +168,7 @@ struct r3964_info { + unsigned char *rx_buf; /* ring buffer */ + unsigned char *tx_buf; + +- struct rx_block_header *rx_first; +- struct rx_block_header *rx_last; ++ struct list_head rx_blocks; + struct list_head tx_blocks; + unsigned int tx_position; + unsigned int rx_position; +@@ -355,71 +353,32 @@ static void add_rx_queue(struct r3964_info *pInfo, + unsigned long flags; + + spin_lock_irqsave(&pInfo->lock, flags); +- +- pHeader->next = NULL; +- +- if (pInfo->rx_last == NULL) { +- pInfo->rx_first = pInfo->rx_last = pHeader; +- } else { +- pInfo->rx_last->next = pHeader; +- pInfo->rx_last = pHeader; +- } +- pInfo->blocks_in_rx_queue++; +- ++ list_add_tail(&pHeader->node, &pInfo->rx_blocks); + spin_unlock_irqrestore(&pInfo->lock, flags); +- +- TRACE_Q("add_rx_queue: %p, length = %d, rx_first = %p, count = %d", +- pHeader, pHeader->length, +- pInfo->rx_first, pInfo->blocks_in_rx_queue); + } + + static void remove_from_rx_queue(struct r3964_info *pInfo, + struct rx_block_header *pHeader) + { ++ struct rx_block_header *pFind, *tmp; + unsigned long flags; +- struct rx_block_header *pFind; + + if (pHeader == NULL) + return; + +- TRACE_Q("remove_from_rx_queue: rx_first = %p, rx_last = %p, count = %d", +- pInfo->rx_first, pInfo->rx_last, pInfo->blocks_in_rx_queue); +- TRACE_Q("remove_from_rx_queue: %p, length %u", +- pHeader, pHeader->length); +- + spin_lock_irqsave(&pInfo->lock, flags); +- +- if (pInfo->rx_first == pHeader) { +- /* Remove the first block in the linked list: */ +- pInfo->rx_first = pHeader->next; +- +- if (pInfo->rx_first == NULL) { +- pInfo->rx_last = NULL; +- } +- pInfo->blocks_in_rx_queue--; +- } else { +- /* Find block to remove: */ +- for (pFind = pInfo->rx_first; pFind; pFind = pFind->next) { +- if (pFind->next == pHeader) { +- /* Got it. */ +- pFind->next = pHeader->next; +- pInfo->blocks_in_rx_queue--; +- if (pFind->next == NULL) { +- /* Oh, removed the last one! */ +- pInfo->rx_last = pFind; +- } +- break; +- } ++ list_for_each_entry_safe(pFind, tmp, &pInfo->rx_blocks, node) { ++ if (pFind == pHeader) { ++ /* Got it. */ ++ list_del(&pFind->node); ++ pInfo->blocks_in_rx_queue--; ++ goto exit; + } + } +- ++exit: + spin_unlock_irqrestore(&pInfo->lock, flags); + + kfree(pHeader); +- TRACE_M("remove_from_rx_queue - kfree %p", pHeader); +- +- TRACE_Q("remove_from_rx_queue: rx_first = %p, rx_last = %p, count = %d", +- pInfo->rx_first, pInfo->rx_last, pInfo->blocks_in_rx_queue); + } + + static void put_char(struct r3964_info *pInfo, unsigned char ch) +@@ -582,7 +541,7 @@ static void on_receive_block(struct r3964_info *pInfo) + pBlock->length = length; + pBlock->data = ((unsigned char *)pBlock) + sizeof(*pBlock); + pBlock->locks = 0; +- pBlock->next = NULL; ++ INIT_LIST_HEAD(&pBlock->node); + + memcpy(pBlock->data, pInfo->rx_buf, length); + +@@ -1047,7 +1006,7 @@ static int r3964_open(struct tty_struct *tty) + mutex_init(&pInfo->read_lock); + pInfo->tty = tty; + pInfo->priority = R3964_MASTER; +- pInfo->rx_first = pInfo->rx_last = NULL; ++ INIT_LIST_HEAD(&pInfo->rx_blocks); + INIT_LIST_HEAD(&pInfo->tx_blocks); + pInfo->rx_position = 0; + pInfo->tx_position = 0; +-- +2.21.0 + diff --git a/0008-tty-n_r3964-don-t-hand-roll-a-reference-count.patch b/0008-tty-n_r3964-don-t-hand-roll-a-reference-count.patch new file mode 100644 index 00000000000000..0fd59803294b63 --- /dev/null +++ b/0008-tty-n_r3964-don-t-hand-roll-a-reference-count.patch @@ -0,0 +1,160 @@ +From 6e885d94ba582aec3e689d94b3b2deb3570a5e06 Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +Date: Thu, 24 Jan 2019 16:44:28 +0100 +Subject: [PATCH 08/15] tty: n_r3964: don't hand-roll a reference count + +rx_block_header had a "locks" variable that was trying to be a reference +count on the header. When it would drop to zero, the memory would be +freed. Convert this to be a kref instead to handle the housekeeping for +doing reference counting properly. + +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + drivers/tty/n_r3964.c | 61 ++++++++++++++++++++----------------------- + 1 file changed, 28 insertions(+), 33 deletions(-) + +diff --git a/drivers/tty/n_r3964.c b/drivers/tty/n_r3964.c +index 8275fb905aeb..a79c8d485030 100644 +--- a/drivers/tty/n_r3964.c ++++ b/drivers/tty/n_r3964.c +@@ -26,6 +26,7 @@ + #include <linux/param.h> + #include <linux/poll.h> + #include <linux/init.h> ++#include <linux/kref.h> + #include <linux/uaccess.h> + #include <uapi/linux/n_r3964.h> + +@@ -131,8 +132,9 @@ struct rx_block_header { + unsigned int length; /* length in chars without header */ + unsigned char *data; /* usually data is located immediately + * behind this struct */ +- unsigned int locks; /* only used in rx_buffer */ + struct list_head node; ++ struct kref kref; ++ struct r3964_info *info; + }; + + /* Header of received block in tx_buf: */ +@@ -200,8 +202,7 @@ static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg, + int error_code, struct rx_block_header *pBlock); + static struct r3964_message *remove_msg(struct r3964_info *pInfo, + struct r3964_client_info *pClient); +-static void remove_client_block(struct r3964_info *pInfo, +- struct r3964_client_info *pClient); ++static void remove_client_block(struct r3964_client_info *pClient); + + static int r3964_open(struct tty_struct *tty); + static void r3964_close(struct tty_struct *tty); +@@ -357,28 +358,28 @@ static void add_rx_queue(struct r3964_info *pInfo, + spin_unlock_irqrestore(&pInfo->lock, flags); + } + +-static void remove_from_rx_queue(struct r3964_info *pInfo, +- struct rx_block_header *pHeader) ++static void remove_from_rx_queue(struct kref *kref) + { +- struct rx_block_header *pFind, *tmp; ++ struct rx_block_header *header, *find; ++ struct r3964_info *info; + unsigned long flags; + +- if (pHeader == NULL) +- return; ++ header = container_of(kref, struct rx_block_header, kref); ++ info = header->info; + +- spin_lock_irqsave(&pInfo->lock, flags); +- list_for_each_entry_safe(pFind, tmp, &pInfo->rx_blocks, node) { +- if (pFind == pHeader) { ++ spin_lock_irqsave(&info->lock, flags); ++ list_for_each_entry(find, &info->rx_blocks, node) { ++ if (find == header) { + /* Got it. */ +- list_del(&pFind->node); +- pInfo->blocks_in_rx_queue--; ++ list_del(&find->node); ++ info->blocks_in_rx_queue--; + goto exit; + } + } + exit: +- spin_unlock_irqrestore(&pInfo->lock, flags); ++ spin_unlock_irqrestore(&info->lock, flags); + +- kfree(pHeader); ++ kfree(header); + } + + static void put_char(struct r3964_info *pInfo, unsigned char ch) +@@ -540,7 +541,8 @@ static void on_receive_block(struct r3964_info *pInfo) + + pBlock->length = length; + pBlock->data = ((unsigned char *)pBlock) + sizeof(*pBlock); +- pBlock->locks = 0; ++ pBlock->info = pInfo; ++ kref_init(&pBlock->kref); + INIT_LIST_HEAD(&pBlock->node); + + memcpy(pBlock->data, pInfo->rx_buf, length); +@@ -855,7 +857,7 @@ static int read_telegram(struct r3964_info *pInfo, struct pid *pid, + if (copy_to_user(buf, block->data, block->length)) + return -EFAULT; + +- remove_client_block(pInfo, pClient); ++ remove_client_block(pClient); + return block->length; + } + +@@ -894,9 +896,9 @@ static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg, + + pClient->msg_count++; + +- if (pBlock != NULL) { +- pBlock->locks++; +- } ++ if (pBlock != NULL) ++ kref_get(&pBlock->kref); ++ + spin_unlock_irqrestore(&pClient->lock, flags); + } else { + if ((pClient->last_msg->msg_id == R3964_MSG_ACK) +@@ -935,7 +937,7 @@ static struct r3964_message *remove_msg(struct r3964_info *pInfo, + + pClient->msg_count--; + if (pMsg->block) { +- remove_client_block(pInfo, pClient); ++ remove_client_block(pClient); + pClient->next_block_to_read = pMsg->block; + } + spin_unlock_irqrestore(&pClient->lock, flags); +@@ -943,21 +945,14 @@ static struct r3964_message *remove_msg(struct r3964_info *pInfo, + return pMsg; + } + +-static void remove_client_block(struct r3964_info *pInfo, +- struct r3964_client_info *pClient) ++static void remove_client_block(struct r3964_client_info *client) + { + struct rx_block_header *block; + +- TRACE_PS("remove_client_block PID %d", pid_nr(pClient->pid)); +- +- block = pClient->next_block_to_read; +- if (block) { +- block->locks--; +- if (block->locks == 0) { +- remove_from_rx_queue(pInfo, block); +- } +- } +- pClient->next_block_to_read = NULL; ++ block = client->next_block_to_read; ++ if (block) ++ kref_put(&block->kref, remove_from_rx_queue); ++ client->next_block_to_read = NULL; + } + + /************************************************************* +-- +2.21.0 + diff --git a/0009-tty-n_r3964-for-messages-use-a-real-kernel-list.patch b/0009-tty-n_r3964-for-messages-use-a-real-kernel-list.patch new file mode 100644 index 00000000000000..bafeacf154ba65 --- /dev/null +++ b/0009-tty-n_r3964-for-messages-use-a-real-kernel-list.patch @@ -0,0 +1,268 @@ +From df04ddde6d9577c3cf230e725f36ae2480908040 Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +Date: Thu, 24 Jan 2019 17:43:52 +0100 +Subject: [PATCH 09/15] tty: n_r3964: for messages, use a real kernel list + +The message list associated with a client was a hand-rolled linked list +structure, so use a "normal" kernel list structure instead. This makes +the code smaller and simpler to understand. + +In doing so, fix up a number of locking mistakes where the proper lock +was not being held for every time the client message list was being +accessed. + +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + drivers/tty/n_r3964.c | 132 ++++++++++++++++++++---------------------- + 1 file changed, 62 insertions(+), 70 deletions(-) + +diff --git a/drivers/tty/n_r3964.c b/drivers/tty/n_r3964.c +index a79c8d485030..cf2a3dc3a870 100644 +--- a/drivers/tty/n_r3964.c ++++ b/drivers/tty/n_r3964.c +@@ -101,7 +101,6 @@ enum { + + /* All open file-handles are 'clients' and are stored in a linked list: */ + +-struct r3964_message; + struct rx_block_header; + struct tx_block_header; + +@@ -112,8 +111,7 @@ struct r3964_client_info { + + struct r3964_client_info *next; + +- struct r3964_message *first_msg; +- struct r3964_message *last_msg; ++ struct list_head msgs; + struct rx_block_header *next_block_to_read; + int msg_count; + }; +@@ -124,7 +122,7 @@ struct r3964_message { + int arg; + int error_code; + struct rx_block_header *block; +- struct r3964_message *next; ++ struct list_head node; + }; + + /* Header of received block in rx_buf: */ +@@ -200,8 +198,7 @@ static int read_telegram(struct r3964_info *pInfo, struct pid *pid, + unsigned char __user * buf); + static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg, + int error_code, struct rx_block_header *pBlock); +-static struct r3964_message *remove_msg(struct r3964_info *pInfo, +- struct r3964_client_info *pClient); ++static struct r3964_message *remove_msg(struct r3964_client_info *client); + static void remove_client_block(struct r3964_client_info *pClient); + + static int r3964_open(struct tty_struct *tty); +@@ -788,7 +785,7 @@ static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg) + pid_nr(pid)); + *ppClient = pClient->next; + while (pClient->msg_count) { +- pMsg = remove_msg(pInfo, pClient); ++ pMsg = remove_msg(pClient); + if (pMsg) { + kfree(pMsg); + TRACE_M("enable_signals - msg " +@@ -823,8 +820,7 @@ static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg) + pClient->sig_flags = arg; + pClient->pid = get_pid(pid); + pClient->next = pInfo->firstClient; +- pClient->first_msg = NULL; +- pClient->last_msg = NULL; ++ INIT_LIST_HEAD(&pClient->msgs); + pClient->next_block_to_read = NULL; + pClient->msg_count = 0; + pInfo->firstClient = pClient; +@@ -864,85 +860,83 @@ static int read_telegram(struct r3964_info *pInfo, struct pid *pid, + return -EINVAL; + } + +-static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg, +- int error_code, struct rx_block_header *pBlock) ++static void __add_msg(struct r3964_client_info *pClient, int msg_id, int arg, ++ int error_code, struct rx_block_header *pBlock) ++ __must_hold(&pClient->lock) + { + struct r3964_message *pMsg; +- unsigned long flags; + +- if (pClient->msg_count < R3964_MAX_MSG_COUNT - 1) { +-queue_the_message: ++ pMsg = kmalloc(sizeof(*pMsg), GFP_ATOMIC); ++ if (pMsg == NULL) ++ return; + +- pMsg = kmalloc(sizeof(*pMsg), GFP_ATOMIC); +- TRACE_M("add_msg - kmalloc %p", pMsg); +- if (pMsg == NULL) { +- return; +- } ++ pMsg->msg_id = msg_id; ++ pMsg->arg = arg; ++ pMsg->error_code = error_code; ++ pMsg->block = pBlock; ++ INIT_LIST_HEAD(&pMsg->node); + +- spin_lock_irqsave(&pClient->lock, flags); ++ list_add_tail(&pMsg->node, &pClient->msgs); ++ pClient->msg_count++; + +- pMsg->msg_id = msg_id; +- pMsg->arg = arg; +- pMsg->error_code = error_code; +- pMsg->block = pBlock; +- pMsg->next = NULL; +- +- if (pClient->last_msg == NULL) { +- pClient->first_msg = pClient->last_msg = pMsg; +- } else { +- pClient->last_msg->next = pMsg; +- pClient->last_msg = pMsg; +- } ++ if (pBlock != NULL) ++ kref_get(&pBlock->kref); ++} + +- pClient->msg_count++; ++static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg, ++ int error_code, struct rx_block_header *pBlock) ++{ ++ struct r3964_message *pMsg; ++ unsigned long flags; + +- if (pBlock != NULL) +- kref_get(&pBlock->kref); ++ spin_lock_irqsave(&pClient->lock, flags); + +- spin_unlock_irqrestore(&pClient->lock, flags); ++ if (pClient->msg_count < R3964_MAX_MSG_COUNT - 1) { ++ __add_msg(pClient, msg_id, arg, error_code, pBlock); + } else { +- if ((pClient->last_msg->msg_id == R3964_MSG_ACK) +- && (pClient->last_msg->error_code == R3964_OVERFLOW)) { +- pClient->last_msg->arg++; +- TRACE_PE("add_msg - inc prev OVERFLOW-msg"); ++ if (!list_empty(&pClient->msgs)) { ++ pMsg = list_last_entry(&pClient->msgs, ++ struct r3964_message, node); ++ if ((pMsg->msg_id == R3964_MSG_ACK) && ++ (pMsg->error_code == R3964_OVERFLOW)) { ++ pMsg->arg++; ++ TRACE_PE("add_msg - inc prev OVERFLOW-msg"); ++ } + } else { +- msg_id = R3964_MSG_ACK; +- arg = 0; +- error_code = R3964_OVERFLOW; +- pBlock = NULL; ++ __add_msg(pClient, R3964_MSG_ACK, 0, R3964_OVERFLOW, ++ pBlock); + TRACE_PE("add_msg - queue OVERFLOW-msg"); +- goto queue_the_message; + } + } ++ spin_unlock_irqrestore(&pClient->lock, flags); ++ + /* Send SIGIO signal to client process: */ + if (pClient->sig_flags & R3964_USE_SIGIO) { + kill_pid(pClient->pid, SIGIO, 1); + } + } + +-static struct r3964_message *remove_msg(struct r3964_info *pInfo, +- struct r3964_client_info *pClient) ++static struct r3964_message *remove_msg(struct r3964_client_info *client) + { +- struct r3964_message *pMsg = NULL; ++ struct r3964_message *msg = NULL; + unsigned long flags; + +- if (pClient->first_msg) { +- spin_lock_irqsave(&pClient->lock, flags); ++ spin_lock_irqsave(&client->lock, flags); ++ if (list_empty(&client->msgs)) { ++ spin_unlock_irqrestore(&client->lock, flags); ++ return NULL; ++ } + +- pMsg = pClient->first_msg; +- pClient->first_msg = pMsg->next; +- if (pClient->first_msg == NULL) { +- pClient->last_msg = NULL; +- } ++ msg = list_first_entry(&client->msgs, struct r3964_message, node); ++ list_del(&msg->node); + +- pClient->msg_count--; +- if (pMsg->block) { +- remove_client_block(pClient); +- pClient->next_block_to_read = pMsg->block; +- } +- spin_unlock_irqrestore(&pClient->lock, flags); ++ client->msg_count--; ++ if (msg->block) { ++ remove_client_block(client); ++ client->next_block_to_read = msg->block; + } +- return pMsg; ++ spin_unlock_irqrestore(&client->lock, flags); ++ return msg; + } + + static void remove_client_block(struct r3964_client_info *client) +@@ -1041,7 +1035,7 @@ static void r3964_close(struct tty_struct *tty) + while (pClient) { + pNext = pClient->next; + while (pClient->msg_count) { +- pMsg = remove_msg(pInfo, pClient); ++ pMsg = remove_msg(pClient); + if (pMsg) { + kfree(pMsg); + TRACE_M("r3964_close - msg kfree %p", pMsg); +@@ -1091,7 +1085,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file, + + pClient = findClient(pInfo, task_pid(current)); + if (pClient) { +- pMsg = remove_msg(pInfo, pClient); ++ pMsg = remove_msg(pClient); + if (pMsg == NULL) { + /* no messages available. */ + if (tty_io_nonblock(tty, file)) { +@@ -1100,7 +1094,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file, + } + /* block until there is a message: */ + wait_event_interruptible(tty->read_wait, +- (pMsg = remove_msg(pInfo, pClient))); ++ (pMsg = remove_msg(pClient))); + } + + /* If we still haven't got a message, we must have been signalled */ +@@ -1267,7 +1261,6 @@ static __poll_t r3964_poll(struct tty_struct *tty, struct file *file, + { + struct r3964_info *pInfo = tty->disc_data; + struct r3964_client_info *pClient; +- struct r3964_message *pMsg = NULL; + unsigned long flags; + __poll_t result = EPOLLOUT; + +@@ -1276,11 +1269,10 @@ static __poll_t r3964_poll(struct tty_struct *tty, struct file *file, + pClient = findClient(pInfo, task_pid(current)); + if (pClient) { + poll_wait(file, &tty->read_wait, wait); +- spin_lock_irqsave(&pInfo->lock, flags); +- pMsg = pClient->first_msg; +- spin_unlock_irqrestore(&pInfo->lock, flags); +- if (pMsg) ++ spin_lock_irqsave(&pClient->lock, flags); ++ if (!list_empty(&pClient->msgs)) + result |= EPOLLIN | EPOLLRDNORM; ++ spin_unlock_irqrestore(&pClient->lock, flags); + } else { + result = EPOLLNVAL | EPOLLERR; + } +-- +2.21.0 + diff --git a/0010-tty-n_r3964-for-clients-use-a-real-kernel-list.patch b/0010-tty-n_r3964-for-clients-use-a-real-kernel-list.patch new file mode 100644 index 00000000000000..de4cc61f1ed61a --- /dev/null +++ b/0010-tty-n_r3964-for-clients-use-a-real-kernel-list.patch @@ -0,0 +1,148 @@ +From 336b06e9db65482b6146e112670cff7e4e52c7ef Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +Date: Fri, 25 Jan 2019 09:35:45 +0100 +Subject: [PATCH 10/15] tty: n_r3964: for clients, use a real kernel list + +The "info" structure had a hand-rolled linked list of all of the clients +associated with it. Convert that over to a kernel list structure, +making the logic a lot simpler and easier to understand. + +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + drivers/tty/n_r3964.c | 31 ++++++++++++------------------- + 1 file changed, 12 insertions(+), 19 deletions(-) + +diff --git a/drivers/tty/n_r3964.c b/drivers/tty/n_r3964.c +index cf2a3dc3a870..f752eec92448 100644 +--- a/drivers/tty/n_r3964.c ++++ b/drivers/tty/n_r3964.c +@@ -109,8 +109,7 @@ struct r3964_client_info { + struct pid *pid; + unsigned int sig_flags; + +- struct r3964_client_info *next; +- ++ struct list_head node; + struct list_head msgs; + struct rx_block_header *next_block_to_read; + int msg_count; +@@ -178,7 +177,7 @@ struct r3964_info { + + struct mutex read_lock; /* serialize read and ioctl */ + +- struct r3964_client_info *firstClient; ++ struct list_head clients; + unsigned int state; + unsigned int flags; + +@@ -549,7 +548,7 @@ static void on_receive_block(struct r3964_info *pInfo) + + /* notify attached client processes: */ + spin_lock_irqsave(&pInfo->lock, flags); +- for (pClient = pInfo->firstClient; pClient; pClient = pClient->next) { ++ list_for_each_entry(pClient, &pInfo->clients, node) { + if (pClient->sig_flags & R3964_SIG_DATA) { + add_msg(pClient, R3964_MSG_DATA, length, R3964_OK, + pBlock); +@@ -755,11 +754,12 @@ static struct r3964_client_info *findClient(struct r3964_info *pInfo, + unsigned long flags; + + spin_lock_irqsave(&pInfo->lock, flags); +- for (pClient = pInfo->firstClient; pClient; pClient = pClient->next) { ++ list_for_each_entry(pClient, &pInfo->clients, node) { + if (pClient->pid == pid) { + goto exit; + } + } ++ pClient = NULL; + exit: + spin_unlock_irqrestore(&pInfo->lock, flags); + return pClient; +@@ -768,7 +768,6 @@ static struct r3964_client_info *findClient(struct r3964_info *pInfo, + static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg) + { + struct r3964_client_info *pClient; +- struct r3964_client_info **ppClient; + struct r3964_message *pMsg; + unsigned long flags; + +@@ -776,14 +775,10 @@ static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg) + spin_lock_irqsave(&pInfo->lock, flags); + + /* Remove client from client list */ +- for (ppClient = &pInfo->firstClient; *ppClient; +- ppClient = &(*ppClient)->next) { +- pClient = *ppClient; +- ++ list_for_each_entry(pClient, &pInfo->clients, node) { + if (pClient->pid == pid) { + TRACE_PS("removing client %d from client list", + pid_nr(pid)); +- *ppClient = pClient->next; + while (pClient->msg_count) { + pMsg = remove_msg(pClient); + if (pMsg) { +@@ -793,6 +788,7 @@ static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg) + } + } + put_pid(pClient->pid); ++ list_del(&pClient->node); + kfree(pClient); + TRACE_M("enable_signals - kfree %p", pClient); + spin_unlock_irqrestore(&pInfo->lock, flags); +@@ -819,11 +815,10 @@ static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg) + spin_lock_init(&pClient->lock); + pClient->sig_flags = arg; + pClient->pid = get_pid(pid); +- pClient->next = pInfo->firstClient; + INIT_LIST_HEAD(&pClient->msgs); + pClient->next_block_to_read = NULL; + pClient->msg_count = 0; +- pInfo->firstClient = pClient; ++ list_add(&pClient->node, &pInfo->clients); + spin_unlock_irqrestore(&pInfo->lock, flags); + } + } +@@ -1001,7 +996,7 @@ static int r3964_open(struct tty_struct *tty) + pInfo->tx_position = 0; + pInfo->last_rx = 0; + pInfo->blocks_in_rx_queue = 0; +- pInfo->firstClient = NULL; ++ INIT_LIST_HEAD(&pInfo->clients); + pInfo->state = R3964_IDLE; + pInfo->flags = R3964_DEBUG; + pInfo->nRetry = 0; +@@ -1017,7 +1012,7 @@ static int r3964_open(struct tty_struct *tty) + static void r3964_close(struct tty_struct *tty) + { + struct r3964_info *pInfo = tty->disc_data; +- struct r3964_client_info *pClient, *pNext; ++ struct r3964_client_info *pClient, *tmp_client; + struct r3964_message *pMsg; + struct tx_block_header *pHeader, *tmp; + unsigned long flags; +@@ -1031,9 +1026,7 @@ static void r3964_close(struct tty_struct *tty) + del_timer_sync(&pInfo->tmr); + + /* Remove client-structs and message queues: */ +- pClient = pInfo->firstClient; +- while (pClient) { +- pNext = pClient->next; ++ list_for_each_entry_safe(pClient, tmp_client, &pInfo->clients, node) { + while (pClient->msg_count) { + pMsg = remove_msg(pClient); + if (pMsg) { +@@ -1042,9 +1035,9 @@ static void r3964_close(struct tty_struct *tty) + } + } + put_pid(pClient->pid); ++ list_del(&pClient->node); + kfree(pClient); + TRACE_M("r3964_close - client kfree %p", pClient); +- pClient = pNext; + } + /* Remove jobs from tx_queue: */ + spin_lock_irqsave(&pInfo->lock, flags); +-- +2.21.0 + diff --git a/0011-tty-n_r3964-fix-race-with-add_msg-and-read_telegram.patch b/0011-tty-n_r3964-fix-race-with-add_msg-and-read_telegram.patch new file mode 100644 index 00000000000000..8823e994d83ef4 --- /dev/null +++ b/0011-tty-n_r3964-fix-race-with-add_msg-and-read_telegram.patch @@ -0,0 +1,113 @@ +From b54481aa9fb9cab7a0ca3257c4a6ba6082ef9652 Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +Date: Fri, 25 Jan 2019 15:03:15 +0100 +Subject: [PATCH 11/15] tty: n_r3964: fix race with add_msg() and read_telegram + +read_telegram() could race with the client block access code that can be +called through add_msg() as it did not hold any locks. + +Fix that up by properly holding the client->lock when touching the next +message to be read structures. Gyrations ensue due to the data having +to be copied to userspace, but the potential corruption problem is now +gone, to be replaced with a possible race where we free a block that no +one sent to userspace yet. Given that no one has reported this problem +in the 20+ years of this code, I'll take the potential race condition +over a known corruption problems. + +Reported-by: Jann Horn <jannh@google.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + drivers/tty/n_r3964.c | 52 ++++++++++++++++++++++++++++++++++--------- + 1 file changed, 42 insertions(+), 10 deletions(-) + +diff --git a/drivers/tty/n_r3964.c b/drivers/tty/n_r3964.c +index f752eec92448..1514b17f5615 100644 +--- a/drivers/tty/n_r3964.c ++++ b/drivers/tty/n_r3964.c +@@ -193,8 +193,6 @@ static void receive_char(struct r3964_info *pInfo, const unsigned char c); + static void receive_error(struct r3964_info *pInfo, const char flag); + static void on_timeout(struct timer_list *t); + static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg); +-static int read_telegram(struct r3964_info *pInfo, struct pid *pid, +- unsigned char __user * buf); + static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg, + int error_code, struct rx_block_header *pBlock); + static struct r3964_message *remove_msg(struct r3964_client_info *client); +@@ -831,6 +829,10 @@ static int read_telegram(struct r3964_info *pInfo, struct pid *pid, + { + struct r3964_client_info *pClient; + struct rx_block_header *block; ++ unsigned long flags; ++ unsigned int length; ++ int retval = 0; ++ u8 *data; + + if (!buf) { + return -EINVAL; +@@ -841,18 +843,47 @@ static int read_telegram(struct r3964_info *pInfo, struct pid *pid, + return -EINVAL; + } + ++ spin_lock_irqsave(&pClient->lock, flags); ++ + block = pClient->next_block_to_read; +- if (!block) { +- return 0; +- } else { +- if (copy_to_user(buf, block->data, block->length)) +- return -EFAULT; ++ if (!block) ++ goto exit; ++ ++ /* ++ * Duplicate the data so we can release the lock while we copy to ++ * userspace ++ */ ++ length = block->length; ++ data = kmemdup(block->data, length, GFP_ATOMIC); ++ if (!data) { ++ retval = -ENOMEM; ++ goto exit; ++ } ++ ++ spin_unlock_irqrestore(&pClient->lock, flags); + +- remove_client_block(pClient); +- return block->length; ++ if (copy_to_user(buf, data, length)) { ++ kfree(data); ++ return -EFAULT; + } ++ kfree(data); ++ ++ /* ++ * Copy succeeded, so grab the lock again, and then drop the buffer, as ++ * remove_client_block() has to have the lock held. ++ * ++ * Note, the client's next_block_to_read could have changed here, so ++ * worst case, we just dropped a buffer that wasn't read. But, nothing ++ * was corrupted or accidentally freed, so we are doing better than we ++ * used to. Ideally the whole issue of "read_telegram" would be handled ++ * some other way as this races with the add_msg() path in a bad manner ++ */ ++ spin_lock_irqsave(&pClient->lock, flags); ++ remove_client_block(pClient); + +- return -EINVAL; ++exit: ++ spin_unlock_irqrestore(&pClient->lock, flags); ++ return retval; + } + + static void __add_msg(struct r3964_client_info *pClient, int msg_id, int arg, +@@ -935,6 +966,7 @@ static struct r3964_message *remove_msg(struct r3964_client_info *client) + } + + static void remove_client_block(struct r3964_client_info *client) ++ __must_hold(&client->lock) + { + struct rx_block_header *block; + +-- +2.21.0 + diff --git a/0012-tty-n_r3964-remove-read_lock-from-some-ioctls.patch b/0012-tty-n_r3964-remove-read_lock-from-some-ioctls.patch new file mode 100644 index 00000000000000..cd450701c65fb6 --- /dev/null +++ b/0012-tty-n_r3964-remove-read_lock-from-some-ioctls.patch @@ -0,0 +1,92 @@ +From 3e1d022e31e12398690f4f8638453b3929fa73d4 Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +Date: Fri, 25 Jan 2019 15:20:31 +0100 +Subject: [PATCH 12/15] tty: n_r3964: remove read_lock from some ioctls + +Now that read_telegram() properly grabs the needed locks for its +operation, we can move the "heavy" read lock away from all ioctls except +one, the R3964_ENABLE_SIGNALS lock. + +When we move this lock away, properly grab the info->lock for the other +ioctls that need it so that they will not have any problems. + +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + drivers/tty/n_r3964.c | 28 ++++++++++++++++++---------- + 1 file changed, 18 insertions(+), 10 deletions(-) + +diff --git a/drivers/tty/n_r3964.c b/drivers/tty/n_r3964.c +index 1514b17f5615..d3f53fa201b7 100644 +--- a/drivers/tty/n_r3964.c ++++ b/drivers/tty/n_r3964.c +@@ -175,7 +175,8 @@ struct r3964_info { + unsigned char bcc; + unsigned int blocks_in_rx_queue; + +- struct mutex read_lock; /* serialize read and ioctl */ ++ /* serialize read and R3964_ENABLE_SIGNALS ioctl */ ++ struct mutex read_lock; + + struct list_head clients; + unsigned int state; +@@ -1219,33 +1220,41 @@ static int r3964_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) + { + struct r3964_info *pInfo = tty->disc_data; ++ unsigned long flags; + int retval = 0; + + if (pInfo == NULL) + return -EINVAL; +- /* Internal serialization of reads and ioctls */ +- if (file->f_flags & O_NONBLOCK) { +- if (!mutex_trylock(&pInfo->read_lock)) +- return -EAGAIN; +- } else { +- if (mutex_lock_interruptible(&pInfo->read_lock)) +- return -ERESTARTSYS; +- } + + switch (cmd) { + case R3964_ENABLE_SIGNALS: ++ /* Internal serialization of reads and this ioctl */ ++ if (file->f_flags & O_NONBLOCK) { ++ if (!mutex_trylock(&pInfo->read_lock)) ++ return -EAGAIN; ++ } else { ++ if (mutex_lock_interruptible(&pInfo->read_lock)) ++ return -ERESTARTSYS; ++ } ++ + retval = enable_signals(pInfo, task_pid(current), arg); ++ ++ mutex_unlock(&pInfo->read_lock); + break; + case R3964_SETPRIORITY: + if (arg < R3964_MASTER || arg > R3964_SLAVE) + return -EINVAL; ++ spin_lock_irqsave(&pInfo->lock, flags); + pInfo->priority = arg & 0xff; ++ spin_unlock_irqrestore(&pInfo->lock, flags); + break; + case R3964_USE_BCC: ++ spin_lock_irqsave(&pInfo->lock, flags); + if (arg) + pInfo->flags |= R3964_BCC; + else + pInfo->flags &= ~R3964_BCC; ++ spin_unlock_irqrestore(&pInfo->lock, flags); + break; + case R3964_READ_TELEGRAM: + retval = read_telegram(pInfo, task_pid(current), +@@ -1256,7 +1265,6 @@ static int r3964_ioctl(struct tty_struct *tty, struct file *file, + break; + } + +- mutex_unlock(&pInfo->read_lock); + return retval; + } + +-- +2.21.0 + diff --git a/0013-tty-n_r3964-properly-protect-sig_flags-of-client-str.patch b/0013-tty-n_r3964-properly-protect-sig_flags-of-client-str.patch new file mode 100644 index 00000000000000..cb1010fbeb2d2c --- /dev/null +++ b/0013-tty-n_r3964-properly-protect-sig_flags-of-client-str.patch @@ -0,0 +1,82 @@ +From 7105eeab4aa73032fe40f5e72f51601da0cd7c4f Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +Date: Fri, 25 Jan 2019 16:35:57 +0100 +Subject: [PATCH 13/15] tty: n_r3964: properly protect sig_flags of client + structure + +This cleans up the remaining users of the sig_flags field in the client +structure to allways access it under the client structure's lock. + +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + drivers/tty/n_r3964.c | 20 ++++++++++++++++---- + 1 file changed, 16 insertions(+), 4 deletions(-) + +diff --git a/drivers/tty/n_r3964.c b/drivers/tty/n_r3964.c +index d3f53fa201b7..a00c34ea9c27 100644 +--- a/drivers/tty/n_r3964.c ++++ b/drivers/tty/n_r3964.c +@@ -193,7 +193,6 @@ static void transmit_block(struct r3964_info *pInfo); + static void receive_char(struct r3964_info *pInfo, const unsigned char c); + static void receive_error(struct r3964_info *pInfo, const char flag); + static void on_timeout(struct timer_list *t); +-static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg); + static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg, + int error_code, struct rx_block_header *pBlock); + static struct r3964_message *remove_msg(struct r3964_client_info *client); +@@ -548,7 +547,14 @@ static void on_receive_block(struct r3964_info *pInfo) + /* notify attached client processes: */ + spin_lock_irqsave(&pInfo->lock, flags); + list_for_each_entry(pClient, &pInfo->clients, node) { +- if (pClient->sig_flags & R3964_SIG_DATA) { ++ unsigned long client_flags; ++ unsigned int sig_flags; ++ ++ spin_lock_irqsave(&pClient->lock, client_flags); ++ sig_flags = pClient->sig_flags; ++ spin_unlock_irqrestore(&pClient->lock, client_flags); ++ ++ if (sig_flags & R3964_SIG_DATA) { + add_msg(pClient, R3964_MSG_DATA, length, R3964_OK, + pBlock); + } +@@ -799,8 +805,12 @@ static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg) + } else { + pClient = findClient(pInfo, pid); + if (pClient) { ++ unsigned long client_flags; ++ + /* update signal options */ ++ spin_lock_irqsave(&pClient->lock, client_flags); + pClient->sig_flags = arg; ++ spin_unlock_irqrestore(&pClient->lock, client_flags); + } else { + /* add client to client list */ + pClient = kmalloc(sizeof(struct r3964_client_info), +@@ -915,6 +925,7 @@ static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg, + { + struct r3964_message *pMsg; + unsigned long flags; ++ unsigned int sig_flags; + + spin_lock_irqsave(&pClient->lock, flags); + +@@ -935,12 +946,13 @@ static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg, + TRACE_PE("add_msg - queue OVERFLOW-msg"); + } + } ++ ++ sig_flags = pClient->sig_flags; + spin_unlock_irqrestore(&pClient->lock, flags); + + /* Send SIGIO signal to client process: */ +- if (pClient->sig_flags & R3964_USE_SIGIO) { ++ if (sig_flags & R3964_USE_SIGIO) + kill_pid(pClient->pid, SIGIO, 1); +- } + } + + static struct r3964_message *remove_msg(struct r3964_client_info *client) +-- +2.21.0 + diff --git a/0014-tty-n_r3964-properly-reference-count-pids.patch b/0014-tty-n_r3964-properly-reference-count-pids.patch new file mode 100644 index 00000000000000..68aec18727fa26 --- /dev/null +++ b/0014-tty-n_r3964-properly-reference-count-pids.patch @@ -0,0 +1,103 @@ +From 4607af3f8237114c8c679e5d976ef00fe7053123 Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +Date: Fri, 25 Jan 2019 16:47:16 +0100 +Subject: [PATCH 14/15] tty: n_r3964: properly reference count pids + +The driver likes to look up things based on the current pid, yet the +structure is never properly reference counted when passing around the +pointer. Luckily when it is saved off it is correct, but for all other +usages, we need to handle the reference properly. + +The function find_client_current() is created to handle some of the +common housekeeping when trying to lookup a structure on the current +pid. + +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + drivers/tty/n_r3964.c | 28 ++++++++++++++++++++++------ + 1 file changed, 22 insertions(+), 6 deletions(-) + +diff --git a/drivers/tty/n_r3964.c b/drivers/tty/n_r3964.c +index a00c34ea9c27..aef0befd068d 100644 +--- a/drivers/tty/n_r3964.c ++++ b/drivers/tty/n_r3964.c +@@ -770,6 +770,18 @@ static struct r3964_client_info *findClient(struct r3964_info *pInfo, + return pClient; + } + ++/* Find a client that refers to the pid of the current task */ ++static struct r3964_client_info *find_client_current(struct r3964_info *info) ++{ ++ struct r3964_client_info *client; ++ struct pid *pid; ++ ++ pid = get_pid(task_pid(current)); ++ client = findClient(info, pid); ++ put_pid(pid); ++ return client; ++} ++ + static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg) + { + struct r3964_client_info *pClient; +@@ -1121,7 +1133,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file, + return -ERESTARTSYS; + } + +- pClient = findClient(pInfo, task_pid(current)); ++ pClient = find_client_current(pInfo); + if (pClient) { + pMsg = remove_msg(pClient); + if (pMsg == NULL) { +@@ -1208,7 +1220,7 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file, + pHeader->length = count; + pHeader->owner = NULL; + +- pClient = findClient(pInfo, task_pid(current)); ++ pClient = find_client_current(pInfo); + if (pClient) { + pHeader->owner = pClient; + } +@@ -1232,6 +1244,7 @@ static int r3964_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) + { + struct r3964_info *pInfo = tty->disc_data; ++ struct pid *pid; + unsigned long flags; + int retval = 0; + +@@ -1249,7 +1262,9 @@ static int r3964_ioctl(struct tty_struct *tty, struct file *file, + return -ERESTARTSYS; + } + +- retval = enable_signals(pInfo, task_pid(current), arg); ++ pid = get_pid(task_pid(current)); ++ retval = enable_signals(pInfo, pid, arg); ++ put_pid(pid); + + mutex_unlock(&pInfo->read_lock); + break; +@@ -1269,8 +1284,9 @@ static int r3964_ioctl(struct tty_struct *tty, struct file *file, + spin_unlock_irqrestore(&pInfo->lock, flags); + break; + case R3964_READ_TELEGRAM: +- retval = read_telegram(pInfo, task_pid(current), +- (unsigned char __user *)arg); ++ pid = get_pid(task_pid(current)); ++ retval = read_telegram(pInfo, pid, (unsigned char __user *)arg); ++ put_pid(pid); + break; + default: + retval = -ENOIOCTLCMD; +@@ -1311,7 +1327,7 @@ static __poll_t r3964_poll(struct tty_struct *tty, struct file *file, + + TRACE_L("POLL"); + +- pClient = findClient(pInfo, task_pid(current)); ++ pClient = find_client_current(pInfo); + if (pClient) { + poll_wait(file, &tty->read_wait, wait); + spin_lock_irqsave(&pClient->lock, flags); +-- +2.21.0 + diff --git a/0015-tty-n_r3964-add-reference-counting-to-the-client-str.patch b/0015-tty-n_r3964-add-reference-counting-to-the-client-str.patch new file mode 100644 index 00000000000000..d7fbe7d31aa68e --- /dev/null +++ b/0015-tty-n_r3964-add-reference-counting-to-the-client-str.patch @@ -0,0 +1,250 @@ +From da04c3926a73304489a320796045814ac48f2e37 Mon Sep 17 00:00:00 2001 +From: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +Date: Fri, 1 Feb 2019 10:44:55 +0100 +Subject: [PATCH 15/15] tty: n_r3964: add reference counting to the client + structure + +The client structure pointer is thrown around a lot, and trying to keep +track of who has, and does not have, a valid pointer is almost +impossible to audit properly, especially when looking up client +structures from the lists. So add a kref to the structure so that it +will be automatically reference counted and no one can access a stale +pointer and memory will be freed when everything is finished. + +This should resolve the problem with the client structure pointer beging +able to be accessed when it was removed by someone else at the same +time. + +Reported-by: Jann Horn <jannh@google.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + drivers/tty/n_r3964.c | 82 +++++++++++++++++++++++++++++++++---------- + 1 file changed, 64 insertions(+), 18 deletions(-) + +diff --git a/drivers/tty/n_r3964.c b/drivers/tty/n_r3964.c +index aef0befd068d..37d03ef8e75d 100644 +--- a/drivers/tty/n_r3964.c ++++ b/drivers/tty/n_r3964.c +@@ -106,6 +106,7 @@ struct tx_block_header; + + struct r3964_client_info { + spinlock_t lock; ++ struct kref kref; + struct pid *pid; + unsigned int sig_flags; + +@@ -298,6 +299,30 @@ static int __init r3964_init(void) + module_init(r3964_init); + module_exit(r3964_exit); + ++static struct r3964_client_info *client_get(struct r3964_client_info *client) ++{ ++ if (client) ++ kref_get(&client->kref); ++ return client; ++} ++ ++static void client_free(struct kref *kref) ++{ ++ struct r3964_client_info *client; ++ ++ client = container_of(kref, struct r3964_client_info, kref); ++ ++ put_pid(client->pid); ++ list_del(&client->node); ++ kfree(client); ++} ++ ++static void client_put(struct r3964_client_info *client) ++{ ++ if (client) ++ kref_put(&client->kref, client_free); ++} ++ + /************************************************************* + * Protocol implementation routines + *************************************************************/ +@@ -339,6 +364,7 @@ static void remove_from_tx_queue(struct r3964_info *pInfo, int error_code) + wake_up_interruptible(&pInfo->tty->read_wait); + } + ++ client_put(pHeader->owner); + kfree(pHeader); + } + +@@ -550,6 +576,7 @@ static void on_receive_block(struct r3964_info *pInfo) + unsigned long client_flags; + unsigned int sig_flags; + ++ client_get(pClient); + spin_lock_irqsave(&pClient->lock, client_flags); + sig_flags = pClient->sig_flags; + spin_unlock_irqrestore(&pClient->lock, client_flags); +@@ -558,6 +585,7 @@ static void on_receive_block(struct r3964_info *pInfo) + add_msg(pClient, R3964_MSG_DATA, length, R3964_OK, + pBlock); + } ++ client_put(pClient); + } + spin_unlock_irqrestore(&pInfo->lock, flags); + wake_up_interruptible(&pInfo->tty->read_wait); +@@ -752,25 +780,40 @@ static void on_timeout(struct timer_list *t) + } + } + ++/* ++ * The reference count of the pointer returned will be incremented ++ * (if it is not NULL) so client_put() must be called on it when the ++ * caller is finished with it. ++ */ + static struct r3964_client_info *findClient(struct r3964_info *pInfo, + struct pid *pid) + { + struct r3964_client_info *pClient; +- unsigned long flags; ++ unsigned long client_flags; ++ unsigned long info_flags; + +- spin_lock_irqsave(&pInfo->lock, flags); ++ spin_lock_irqsave(&pInfo->lock, info_flags); + list_for_each_entry(pClient, &pInfo->clients, node) { ++ client_get(pClient); ++ spin_lock_irqsave(&pClient->lock, client_flags); + if (pClient->pid == pid) { ++ spin_unlock_irqrestore(&pClient->lock, client_flags); + goto exit; + } ++ spin_unlock_irqrestore(&pClient->lock, client_flags); ++ client_put(pClient); + } + pClient = NULL; + exit: +- spin_unlock_irqrestore(&pInfo->lock, flags); ++ spin_unlock_irqrestore(&pInfo->lock, info_flags); + return pClient; + } + +-/* Find a client that refers to the pid of the current task */ ++/* ++ * Find a client that refers to the pid of the current task ++ * The reference count of the pointer will be incremented so ++ * client_put() must be called when the caller is finished with it ++ */ + static struct r3964_client_info *find_client_current(struct r3964_info *info) + { + struct r3964_client_info *client; +@@ -793,6 +836,7 @@ static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg) + + /* Remove client from client list */ + list_for_each_entry(pClient, &pInfo->clients, node) { ++ client_get(pClient); + if (pClient->pid == pid) { + TRACE_PS("removing client %d from client list", + pid_nr(pid)); +@@ -804,13 +848,13 @@ static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg) + "kfree %p", pMsg); + } + } +- put_pid(pClient->pid); +- list_del(&pClient->node); +- kfree(pClient); +- TRACE_M("enable_signals - kfree %p", pClient); ++ /* Second put will free the structure */ ++ client_put(pClient); ++ client_put(pClient); + spin_unlock_irqrestore(&pInfo->lock, flags); + return 0; + } ++ client_put(pClient); + } + spin_unlock_irqrestore(&pInfo->lock, flags); + return -EINVAL; +@@ -823,6 +867,7 @@ static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg) + spin_lock_irqsave(&pClient->lock, client_flags); + pClient->sig_flags = arg; + spin_unlock_irqrestore(&pClient->lock, client_flags); ++ client_put(pClient); + } else { + /* add client to client list */ + pClient = kmalloc(sizeof(struct r3964_client_info), +@@ -834,6 +879,7 @@ static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg) + spin_lock_irqsave(&pInfo->lock, flags); + TRACE_PS("add client %d to client list", pid_nr(pid)); + spin_lock_init(&pClient->lock); ++ kref_init(&pClient->kref); + pClient->sig_flags = arg; + pClient->pid = get_pid(pid); + INIT_LIST_HEAD(&pClient->msgs); +@@ -887,6 +933,7 @@ static int read_telegram(struct r3964_info *pInfo, struct pid *pid, + + if (copy_to_user(buf, data, length)) { + kfree(data); ++ client_put(pClient); + return -EFAULT; + } + kfree(data); +@@ -906,6 +953,7 @@ static int read_telegram(struct r3964_info *pInfo, struct pid *pid, + + exit: + spin_unlock_irqrestore(&pClient->lock, flags); ++ client_put(pClient); + return retval; + } + +@@ -1091,10 +1139,7 @@ static void r3964_close(struct tty_struct *tty) + TRACE_M("r3964_close - msg kfree %p", pMsg); + } + } +- put_pid(pClient->pid); +- list_del(&pClient->node); +- kfree(pClient); +- TRACE_M("r3964_close - client kfree %p", pClient); ++ client_put(pClient); + } + /* Remove jobs from tx_queue: */ + spin_lock_irqsave(&pInfo->lock, flags); +@@ -1174,6 +1219,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file, + ret = -EPERM; + unlock: + mutex_unlock(&pInfo->read_lock); ++ client_put(pClient); + return ret; + } + +@@ -1182,7 +1228,6 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file, + { + struct r3964_info *pInfo = tty->disc_data; + struct tx_block_header *pHeader; +- struct r3964_client_info *pClient; + unsigned char *new_data; + + TRACE_L("write request, %d characters", count); +@@ -1218,12 +1263,12 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file, + pHeader = (struct tx_block_header *)new_data; + pHeader->data = new_data + sizeof(*pHeader); + pHeader->length = count; +- pHeader->owner = NULL; + +- pClient = find_client_current(pInfo); +- if (pClient) { +- pHeader->owner = pClient; +- } ++ /* ++ * The reference count is left incremented as the last user of ++ * this pointer will drop it when needed ++ */ ++ pHeader->owner = find_client_current(pInfo); + + memcpy(pHeader->data, data, count); /* We already verified this */ + +@@ -1334,6 +1379,7 @@ static __poll_t r3964_poll(struct tty_struct *tty, struct file *file, + if (!list_empty(&pClient->msgs)) + result |= EPOLLIN | EPOLLRDNORM; + spin_unlock_irqrestore(&pClient->lock, flags); ++ client_put(pClient); + } else { + result = EPOLLNVAL | EPOLLERR; + } +-- +2.21.0 + @@ -49,7 +49,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> --- a/arch/powerpc/kernel/fadump.c +++ b/arch/powerpc/kernel/fadump.c -@@ -1649,7 +1649,6 @@ DEFINE_SHOW_ATTRIBUTE(fadump_region); +@@ -1650,7 +1650,6 @@ DEFINE_SHOW_ATTRIBUTE(fadump_region); static void fadump_init_files(void) { @@ -57,7 +57,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> int rc = 0; rc = sysfs_create_file(kernel_kobj, &fadump_attr.attr); -@@ -1662,12 +1661,8 @@ static void fadump_init_files(void) +@@ -1663,12 +1662,8 @@ static void fadump_init_files(void) printk(KERN_ERR "fadump: unable to create sysfs file" " fadump_registered (%d)\n", rc); @@ -74,7 +74,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> rc = sysfs_create_file(kernel_kobj, &fadump_release_attr.attr); --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c -@@ -779,8 +779,7 @@ EXPORT_SYMBOL(powerpc_debugfs_root); +@@ -771,8 +771,7 @@ EXPORT_SYMBOL(powerpc_debugfs_root); static int powerpc_debugfs_init(void) { powerpc_debugfs_root = debugfs_create_dir("powerpc", NULL); @@ -86,7 +86,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> #endif --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c -@@ -2257,35 +2257,20 @@ void ppc_warn_emulated_print(const char +@@ -2265,35 +2265,20 @@ void ppc_warn_emulated_print(const char static int __init ppc_warn_emulated_init(void) { @@ -158,7 +158,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> int kvmppc_radix_init(void) --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c -@@ -2160,14 +2160,9 @@ static void debugfs_vcpu_init(struct kvm +@@ -2161,14 +2161,9 @@ static void debugfs_vcpu_init(struct kvm struct kvm *kvm = vcpu->kvm; snprintf(buf, sizeof(buf), "vcpu%u", id); @@ -322,7 +322,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> /* --- a/arch/powerpc/platforms/powernv/pci-ioda.c +++ b/arch/powerpc/platforms/powernv/pci-ioda.c -@@ -3107,11 +3107,6 @@ static void pnv_pci_ioda_create_dbgfs(vo +@@ -3108,11 +3108,6 @@ static void pnv_pci_ioda_create_dbgfs(vo sprintf(name, "PCI%04x", hose->global_number); phb->dbgfs = debugfs_create_dir(name, powerpc_debugfs_root); @@ -1,5 +1,20 @@ # +0001-tty-n_r3964-locking-fixups.patch +0002-tty-n_r3964-fix-poll-return-value.patch +0003-tty-n_r3964-remove-n_r3964.h.patch +0004-tty-n_r3964-drop-ancient-header-changelog-text.patch +0005-tty-n_r3964-split-rx-and-tx-header-structures.patch +0006-tty-n_r3964-for-tx_blocks-use-a-real-kernel-list.patch +0007-tty-n_r3964-for-rx_blocks-use-a-real-kernel-list.patch +0008-tty-n_r3964-don-t-hand-roll-a-reference-count.patch +0009-tty-n_r3964-for-messages-use-a-real-kernel-list.patch +0010-tty-n_r3964-for-clients-use-a-real-kernel-list.patch +0011-tty-n_r3964-fix-race-with-add_msg-and-read_telegram.patch +0012-tty-n_r3964-remove-read_lock-from-some-ioctls.patch +0013-tty-n_r3964-properly-protect-sig_flags-of-client-str.patch +0014-tty-n_r3964-properly-reference-count-pids.patch +0015-tty-n_r3964-add-reference-counting-to-the-client-str.patch l.patch spdxcheck-print-out-files-without-any-spdx-lines.patch p02 |