Commit 59c4d783 authored by Jiri Slaby's avatar Jiri Slaby Committed by Greg Kroah-Hartman

TTY: n_hdlc, fix lockdep false positive

commit e9b736d8 upstream.

The class of 4 n_hdls buf locks is the same because a single function
n_hdlc_buf_list_init is used to init all the locks. But since
flush_tx_queue takes n_hdlc->tx_buf_list.spinlock and then calls
n_hdlc_buf_put which takes n_hdlc->tx_free_buf_list.spinlock, lockdep
emits a warning:
=============================================
[ INFO: possible recursive locking detected ]
4.3.0-25.g91e30a7-default #1 Not tainted
---------------------------------------------
a.out/1248 is trying to acquire lock:
 (&(&list->spinlock)->rlock){......}, at: [<ffffffffa01fd020>] n_hdlc_buf_put+0x20/0x60 [n_hdlc]

but task is already holding lock:
 (&(&list->spinlock)->rlock){......}, at: [<ffffffffa01fdc07>] n_hdlc_tty_ioctl+0x127/0x1d0 [n_hdlc]

other info that might help us debug this:
 Possible unsafe locking scenario:

       CPU0
       ----
  lock(&(&list->spinlock)->rlock);
  lock(&(&list->spinlock)->rlock);

 *** DEADLOCK ***

 May be due to missing lock nesting notation

2 locks held by a.out/1248:
 #0:  (&tty->ldisc_sem){++++++}, at: [<ffffffff814c9eb0>] tty_ldisc_ref_wait+0x20/0x50
 #1:  (&(&list->spinlock)->rlock){......}, at: [<ffffffffa01fdc07>] n_hdlc_tty_ioctl+0x127/0x1d0 [n_hdlc]
...
Call Trace:
...
 [<ffffffff81738fd0>] _raw_spin_lock_irqsave+0x50/0x70
 [<ffffffffa01fd020>] n_hdlc_buf_put+0x20/0x60 [n_hdlc]
 [<ffffffffa01fdc24>] n_hdlc_tty_ioctl+0x144/0x1d0 [n_hdlc]
 [<ffffffff814c25c1>] tty_ioctl+0x3f1/0xe40
...

Fix it by initializing the spin_locks separately. This removes also
reduntand memset of a freshly kzallocated space.
Signed-off-by: default avatarJiri Slaby <jslaby@suse.cz>
Reported-by: default avatarDmitry Vyukov <dvyukov@google.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 49616e71
...@@ -159,7 +159,6 @@ struct n_hdlc { ...@@ -159,7 +159,6 @@ struct n_hdlc {
/* /*
* HDLC buffer list manipulation functions * HDLC buffer list manipulation functions
*/ */
static void n_hdlc_buf_list_init(struct n_hdlc_buf_list *list);
static void n_hdlc_buf_put(struct n_hdlc_buf_list *list, static void n_hdlc_buf_put(struct n_hdlc_buf_list *list,
struct n_hdlc_buf *buf); struct n_hdlc_buf *buf);
static struct n_hdlc_buf *n_hdlc_buf_get(struct n_hdlc_buf_list *list); static struct n_hdlc_buf *n_hdlc_buf_get(struct n_hdlc_buf_list *list);
...@@ -853,10 +852,10 @@ static struct n_hdlc *n_hdlc_alloc(void) ...@@ -853,10 +852,10 @@ static struct n_hdlc *n_hdlc_alloc(void)
if (!n_hdlc) if (!n_hdlc)
return NULL; return NULL;
n_hdlc_buf_list_init(&n_hdlc->rx_free_buf_list); spin_lock_init(&n_hdlc->rx_free_buf_list.spinlock);
n_hdlc_buf_list_init(&n_hdlc->tx_free_buf_list); spin_lock_init(&n_hdlc->tx_free_buf_list.spinlock);
n_hdlc_buf_list_init(&n_hdlc->rx_buf_list); spin_lock_init(&n_hdlc->rx_buf_list.spinlock);
n_hdlc_buf_list_init(&n_hdlc->tx_buf_list); spin_lock_init(&n_hdlc->tx_buf_list.spinlock);
/* allocate free rx buffer list */ /* allocate free rx buffer list */
for(i=0;i<DEFAULT_RX_BUF_COUNT;i++) { for(i=0;i<DEFAULT_RX_BUF_COUNT;i++) {
...@@ -884,16 +883,6 @@ static struct n_hdlc *n_hdlc_alloc(void) ...@@ -884,16 +883,6 @@ static struct n_hdlc *n_hdlc_alloc(void)
} /* end of n_hdlc_alloc() */ } /* end of n_hdlc_alloc() */
/**
* n_hdlc_buf_list_init - initialize specified HDLC buffer list
* @list - pointer to buffer list
*/
static void n_hdlc_buf_list_init(struct n_hdlc_buf_list *list)
{
memset(list, 0, sizeof(*list));
spin_lock_init(&list->spinlock);
} /* end of n_hdlc_buf_list_init() */
/** /**
* n_hdlc_buf_put - add specified HDLC buffer to tail of specified list * n_hdlc_buf_put - add specified HDLC buffer to tail of specified list
* @list - pointer to buffer list * @list - pointer to buffer list
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment