 661f7fda21
			
		
	
	
	661f7fda21
	
	
	
		
			
			Use schedule_work() to avoid potentially taking the spinlock in
interrupt context.
Commit cc9fa74e2a ("slip/slcan: added locking in wakeup function") added
necessary locking to the wakeup function and 367525c8c2/ddcde142be ("can:
slcan: Fix spinlock variant") converted it to spin_lock_bh() because the lock
is also taken in timers.
Disabling softirqs is not sufficient, however, as tty drivers may call
write_wakeup from interrupt context. This driver calls tty->ops->write() with
its spinlock held, which may immediately cause an interrupt on the same CPU and
subsequent spin_bug().
Simply converting to spin_lock_irq/irqsave() prevents this deadlock, but
causes lockdep to point out a possible circular locking dependency
between these locks:
(&(&sl->lock)->rlock){-.....}, at: slip_write_wakeup
(&port_lock_key){-.....}, at: serial8250_handle_irq.part.13
The slip transmit is holding the slip spinlock when calling the tty write.
This grabs the port lock. On an interrupt, the handler grabs the port
lock and calls write_wakeup which grabs the slip lock. This could be a
problem if a serial interrupt occurs on another CPU during the slip
transmit.
To deal with these issues, don't grab the lock in the wakeup function by
deferring the writeout to a workqueue. Also hold the lock during close
when de-assigning the tty pointer to safely disarm the worker and
timers.
This bug is easily reproducible on the first transmit when slip is
used with the standard 8250 serial driver.
[<c0410b7c>] (spin_bug+0x0/0x38) from [<c006109c>] (do_raw_spin_lock+0x60/0x1d0)
 r5:eab27000 r4:ec02754c
[<c006103c>] (do_raw_spin_lock+0x0/0x1d0) from [<c04185c0>] (_raw_spin_lock+0x28/0x2c)
 r10:0000001f r9:eabb814c r8:eabb8140 r7:40070193 r6:ec02754c r5:eab27000
 r4:ec02754c r3:00000000
[<c0418598>] (_raw_spin_lock+0x0/0x2c) from [<bf3a0220>] (slip_write_wakeup+0x50/0xe0 [slip])
 r4:ec027540 r3:00000003
[<bf3a01d0>] (slip_write_wakeup+0x0/0xe0 [slip]) from [<c026e420>] (tty_wakeup+0x48/0x68)
 r6:00000000 r5:ea80c480 r4:eab27000 r3:bf3a01d0
[<c026e3d8>] (tty_wakeup+0x0/0x68) from [<c028a8ec>] (uart_write_wakeup+0x2c/0x30)
 r5:ed68ea90 r4:c06790d8
[<c028a8c0>] (uart_write_wakeup+0x0/0x30) from [<c028dc44>] (serial8250_tx_chars+0x114/0x170)
[<c028db30>] (serial8250_tx_chars+0x0/0x170) from [<c028dffc>] (serial8250_handle_irq+0xa0/0xbc)
 r6:000000c2 r5:00000060 r4:c06790d8 r3:00000000
[<c028df5c>] (serial8250_handle_irq+0x0/0xbc) from [<c02933a4>] (dw8250_handle_irq+0x38/0x64)
 r7:00000000 r6:edd2f390 r5:000000c2 r4:c06790d8
[<c029336c>] (dw8250_handle_irq+0x0/0x64) from [<c028d2f4>] (serial8250_interrupt+0x44/0xc4)
 r6:00000000 r5:00000000 r4:c06791c4 r3:c029336c
[<c028d2b0>] (serial8250_interrupt+0x0/0xc4) from [<c0067fe4>] (handle_irq_event_percpu+0xb4/0x2b0)
 r10:c06790d8 r9:eab27000 r8:00000000 r7:00000000 r6:0000001f r5:edd52980
 r4:ec53b6c0 r3:c028d2b0
[<c0067f30>] (handle_irq_event_percpu+0x0/0x2b0) from [<c006822c>] (handle_irq_event+0x4c/0x6c)
 r10:c06790d8 r9:eab27000 r8:c0673ae0 r7:c05c2020 r6:ec53b6c0 r5:edd529d4
 r4:edd52980
[<c00681e0>] (handle_irq_event+0x0/0x6c) from [<c006b140>] (handle_level_irq+0xe8/0x100)
 r6:00000000 r5:edd529d4 r4:edd52980 r3:00022000
[<c006b058>] (handle_level_irq+0x0/0x100) from [<c00676f8>] (generic_handle_irq+0x30/0x40)
 r5:0000001f r4:0000001f
[<c00676c8>] (generic_handle_irq+0x0/0x40) from [<c000f57c>] (handle_IRQ+0xd0/0x13c)
 r4:ea997b18 r3:000000e0
[<c000f4ac>] (handle_IRQ+0x0/0x13c) from [<c00086c4>] (armada_370_xp_handle_irq+0x4c/0x118)
 r8:000003ff r7:ea997b18 r6:ffffffff r5:60070013 r4:c0674dc0
[<c0008678>] (armada_370_xp_handle_irq+0x0/0x118) from [<c0013840>] (__irq_svc+0x40/0x70)
Exception stack(0xea997b18 to 0xea997b60)
7b00:                                                       00000001 20070013
7b20: 00000000 0000000b 20070013 eab27000 20070013 00000000 ed10103e eab27000
7b40: c06790d8 ea997b74 ea997b60 ea997b60 c04186c0 c04186c8 60070013 ffffffff
 r9:eab27000 r8:ed10103e r7:ea997b4c r6:ffffffff r5:60070013 r4:c04186c8
[<c04186a4>] (_raw_spin_unlock_irqrestore+0x0/0x54) from [<c0288fc0>] (uart_start+0x40/0x44)
 r4:c06790d8 r3:c028ddd8
[<c0288f80>] (uart_start+0x0/0x44) from [<c028982c>] (uart_write+0xe4/0xf4)
 r6:0000003e r5:00000000 r4:ed68ea90 r3:0000003e
[<c0289748>] (uart_write+0x0/0xf4) from [<bf3a0d20>] (sl_xmit+0x1c4/0x228 [slip])
 r10:ed388e60 r9:0000003c r8:ffffffdd r7:0000003e r6:ec02754c r5:ea717eb8
 r4:ec027000
[<bf3a0b5c>] (sl_xmit+0x0/0x228 [slip]) from [<c0368d74>] (dev_hard_start_xmit+0x39c/0x6d0)
 r8:eaf163c0 r7:ec027000 r6:ea717eb8 r5:00000000 r4:00000000
Signed-off-by: Tyler Hall <tylerwhall@gmail.com>
Cc: Oliver Hartkopp <socketcan@hartkopp.net>
Cc: Andre Naujoks <nautsch2@gmail.com>
Cc: David S. Miller <davem@davemloft.net>
Cc: linux-kernel@vger.kernel.org
Signed-off-by: David S. Miller <davem@davemloft.net>
		
	
			
		
			
				
	
	
		
			102 lines
		
	
	
	
		
			3.3 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			102 lines
		
	
	
	
		
			3.3 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * slip.h	Define the SLIP device driver interface and constants.
 | |
|  *
 | |
|  * NOTE:	THIS FILE WILL BE MOVED TO THE LINUX INCLUDE DIRECTORY
 | |
|  *		AS SOON AS POSSIBLE!
 | |
|  *
 | |
|  * Version:	@(#)slip.h	1.2.0	03/28/93
 | |
|  *
 | |
|  * Fixes:
 | |
|  *		Alan Cox	: 	Added slip mtu field.
 | |
|  *		Matt Dillon	:	Printable slip (borrowed from net2e)
 | |
|  *		Alan Cox	:	Added SL_SLIP_LOTS
 | |
|  *	Dmitry Gorodchanin	:	A lot of changes in the 'struct slip'
 | |
|  *	Dmitry Gorodchanin	:	Added CSLIP statistics.
 | |
|  *	Stanislav Voronyi	:	Make line checking as created by
 | |
|  *					Igor Chechik, RELCOM Corp.
 | |
|  *	Craig Schlenter		:	Fixed #define bug that caused
 | |
|  *					CSLIP telnets to hang in 1.3.61-6
 | |
|  *
 | |
|  * Author:	Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
 | |
|  */
 | |
| #ifndef _LINUX_SLIP_H
 | |
| #define _LINUX_SLIP_H
 | |
| 
 | |
| 
 | |
| #if defined(CONFIG_INET) && defined(CONFIG_SLIP_COMPRESSED)
 | |
| # define SL_INCLUDE_CSLIP
 | |
| #endif
 | |
| 
 | |
| #ifdef SL_INCLUDE_CSLIP
 | |
| # define SL_MODE_DEFAULT SL_MODE_ADAPTIVE
 | |
| #else
 | |
| # define SL_MODE_DEFAULT SL_MODE_SLIP
 | |
| #endif
 | |
| 
 | |
| /* SLIP configuration. */
 | |
| #define SL_NRUNIT	256		/* MAX number of SLIP channels;
 | |
| 					   This can be overridden with
 | |
| 					   insmod -oslip_maxdev=nnn	*/
 | |
| #define SL_MTU		296		/* 296; I am used to 600- FvK	*/
 | |
| 
 | |
| /* SLIP protocol characters. */
 | |
| #define END             0300		/* indicates end of frame	*/
 | |
| #define ESC             0333		/* indicates byte stuffing	*/
 | |
| #define ESC_END         0334		/* ESC ESC_END means END 'data'	*/
 | |
| #define ESC_ESC         0335		/* ESC ESC_ESC means ESC 'data'	*/
 | |
| 
 | |
| 
 | |
| struct slip {
 | |
|   int			magic;
 | |
| 
 | |
|   /* Various fields. */
 | |
|   struct tty_struct	*tty;		/* ptr to TTY structure		*/
 | |
|   struct net_device	*dev;		/* easy for intr handling	*/
 | |
|   spinlock_t		lock;
 | |
|   struct work_struct	tx_work;	/* Flushes transmit buffer	*/
 | |
| 
 | |
| #ifdef SL_INCLUDE_CSLIP
 | |
|   struct slcompress	*slcomp;	/* for header compression 	*/
 | |
|   unsigned char		*cbuff;		/* compression buffer		*/
 | |
| #endif
 | |
| 
 | |
|   /* These are pointers to the malloc()ed frame buffers. */
 | |
|   unsigned char		*rbuff;		/* receiver buffer		*/
 | |
|   int                   rcount;         /* received chars counter       */
 | |
|   unsigned char		*xbuff;		/* transmitter buffer		*/
 | |
|   unsigned char         *xhead;         /* pointer to next byte to XMIT */
 | |
|   int                   xleft;          /* bytes left in XMIT queue     */
 | |
|   int			mtu;		/* Our mtu (to spot changes!)   */
 | |
|   int                   buffsize;       /* Max buffers sizes            */
 | |
| 
 | |
| #ifdef CONFIG_SLIP_MODE_SLIP6
 | |
|   int			xdata, xbits;	/* 6 bit slip controls 		*/
 | |
| #endif
 | |
| 
 | |
|   unsigned long		flags;		/* Flag values/ mode etc	*/
 | |
| #define SLF_INUSE	0		/* Channel in use               */
 | |
| #define SLF_ESCAPE	1               /* ESC received                 */
 | |
| #define SLF_ERROR	2               /* Parity, etc. error           */
 | |
| #define SLF_KEEPTEST	3		/* Keepalive test flag		*/
 | |
| #define SLF_OUTWAIT	4		/* is outpacket was flag	*/
 | |
| 
 | |
|   unsigned char		mode;		/* SLIP mode			*/
 | |
|   unsigned char		leased;
 | |
|   pid_t			pid;
 | |
| #define SL_MODE_SLIP	0
 | |
| #define SL_MODE_CSLIP	1
 | |
| #define SL_MODE_SLIP6	2		/* Matt Dillon's printable slip */
 | |
| #define SL_MODE_CSLIP6	(SL_MODE_SLIP6|SL_MODE_CSLIP)
 | |
| #define SL_MODE_AX25	4
 | |
| #define SL_MODE_ADAPTIVE 8
 | |
| #ifdef CONFIG_SLIP_SMART
 | |
|   unsigned char		outfill;	/* # of sec between outfill packet */
 | |
|   unsigned char		keepalive;	/* keepalive seconds		*/
 | |
|   struct timer_list	outfill_timer;
 | |
|   struct timer_list	keepalive_timer;
 | |
| #endif
 | |
| };
 | |
| 
 | |
| #define SLIP_MAGIC 0x5302
 | |
| 
 | |
| #endif	/* _LINUX_SLIP.H */
 |