Skip to content

Commit 434fd63

Browse files
committed
Merge tag 'tty-4.11-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
Pull tty/serial fixes frpm Greg KH: "Here are two bugfixes for tty stuff for 4.11-rc2. One of them resolves the pretty bad bug in the n_hdlc code that Alexander Popov found and fixed and has been reported everywhere. The other just fixes a samsung serial driver issue when DMA fails on some systems. Both have been in linux-next with no reported issues" * tag 'tty-4.11-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: serial: samsung: Continue to work if DMA request fails tty: n_hdlc: get rid of racy n_hdlc.tbuf
2 parents 8529880 + f98c7bc commit 434fd63

File tree

2 files changed

+73
-65
lines changed

2 files changed

+73
-65
lines changed

drivers/tty/n_hdlc.c

Lines changed: 69 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -114,16 +114,15 @@
114114
#define DEFAULT_TX_BUF_COUNT 3
115115

116116
struct n_hdlc_buf {
117-
struct n_hdlc_buf *link;
117+
struct list_head list_item;
118118
int count;
119119
char buf[1];
120120
};
121121

122122
#define N_HDLC_BUF_SIZE (sizeof(struct n_hdlc_buf) + maxframe)
123123

124124
struct n_hdlc_buf_list {
125-
struct n_hdlc_buf *head;
126-
struct n_hdlc_buf *tail;
125+
struct list_head list;
127126
int count;
128127
spinlock_t spinlock;
129128
};
@@ -136,7 +135,6 @@ struct n_hdlc_buf_list {
136135
* @backup_tty - TTY to use if tty gets closed
137136
* @tbusy - reentrancy flag for tx wakeup code
138137
* @woke_up - FIXME: describe this field
139-
* @tbuf - currently transmitting tx buffer
140138
* @tx_buf_list - list of pending transmit frame buffers
141139
* @rx_buf_list - list of received frame buffers
142140
* @tx_free_buf_list - list unused transmit frame buffers
@@ -149,7 +147,6 @@ struct n_hdlc {
149147
struct tty_struct *backup_tty;
150148
int tbusy;
151149
int woke_up;
152-
struct n_hdlc_buf *tbuf;
153150
struct n_hdlc_buf_list tx_buf_list;
154151
struct n_hdlc_buf_list rx_buf_list;
155152
struct n_hdlc_buf_list tx_free_buf_list;
@@ -159,6 +156,8 @@ struct n_hdlc {
159156
/*
160157
* HDLC buffer list manipulation functions
161158
*/
159+
static void n_hdlc_buf_return(struct n_hdlc_buf_list *buf_list,
160+
struct n_hdlc_buf *buf);
162161
static void n_hdlc_buf_put(struct n_hdlc_buf_list *list,
163162
struct n_hdlc_buf *buf);
164163
static struct n_hdlc_buf *n_hdlc_buf_get(struct n_hdlc_buf_list *list);
@@ -208,16 +207,9 @@ static void flush_tx_queue(struct tty_struct *tty)
208207
{
209208
struct n_hdlc *n_hdlc = tty2n_hdlc(tty);
210209
struct n_hdlc_buf *buf;
211-
unsigned long flags;
212210

213211
while ((buf = n_hdlc_buf_get(&n_hdlc->tx_buf_list)))
214212
n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, buf);
215-
spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags);
216-
if (n_hdlc->tbuf) {
217-
n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, n_hdlc->tbuf);
218-
n_hdlc->tbuf = NULL;
219-
}
220-
spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags);
221213
}
222214

223215
static struct tty_ldisc_ops n_hdlc_ldisc = {
@@ -283,7 +275,6 @@ static void n_hdlc_release(struct n_hdlc *n_hdlc)
283275
} else
284276
break;
285277
}
286-
kfree(n_hdlc->tbuf);
287278
kfree(n_hdlc);
288279

289280
} /* end of n_hdlc_release() */
@@ -402,13 +393,7 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty)
402393
n_hdlc->woke_up = 0;
403394
spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags);
404395

405-
/* get current transmit buffer or get new transmit */
406-
/* buffer from list of pending transmit buffers */
407-
408-
tbuf = n_hdlc->tbuf;
409-
if (!tbuf)
410-
tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list);
411-
396+
tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list);
412397
while (tbuf) {
413398
if (debuglevel >= DEBUG_LEVEL_INFO)
414399
printk("%s(%d)sending frame %p, count=%d\n",
@@ -420,7 +405,7 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty)
420405

421406
/* rollback was possible and has been done */
422407
if (actual == -ERESTARTSYS) {
423-
n_hdlc->tbuf = tbuf;
408+
n_hdlc_buf_return(&n_hdlc->tx_buf_list, tbuf);
424409
break;
425410
}
426411
/* if transmit error, throw frame away by */
@@ -435,10 +420,7 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty)
435420

436421
/* free current transmit buffer */
437422
n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, tbuf);
438-
439-
/* this tx buffer is done */
440-
n_hdlc->tbuf = NULL;
441-
423+
442424
/* wait up sleeping writers */
443425
wake_up_interruptible(&tty->write_wait);
444426

@@ -448,10 +430,12 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty)
448430
if (debuglevel >= DEBUG_LEVEL_INFO)
449431
printk("%s(%d)frame %p pending\n",
450432
__FILE__,__LINE__,tbuf);
451-
452-
/* buffer not accepted by driver */
453-
/* set this buffer as pending buffer */
454-
n_hdlc->tbuf = tbuf;
433+
434+
/*
435+
* the buffer was not accepted by driver,
436+
* return it back into tx queue
437+
*/
438+
n_hdlc_buf_return(&n_hdlc->tx_buf_list, tbuf);
455439
break;
456440
}
457441
}
@@ -749,7 +733,8 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file,
749733
int error = 0;
750734
int count;
751735
unsigned long flags;
752-
736+
struct n_hdlc_buf *buf = NULL;
737+
753738
if (debuglevel >= DEBUG_LEVEL_INFO)
754739
printk("%s(%d)n_hdlc_tty_ioctl() called %d\n",
755740
__FILE__,__LINE__,cmd);
@@ -763,8 +748,10 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file,
763748
/* report count of read data available */
764749
/* in next available frame (if any) */
765750
spin_lock_irqsave(&n_hdlc->rx_buf_list.spinlock,flags);
766-
if (n_hdlc->rx_buf_list.head)
767-
count = n_hdlc->rx_buf_list.head->count;
751+
buf = list_first_entry_or_null(&n_hdlc->rx_buf_list.list,
752+
struct n_hdlc_buf, list_item);
753+
if (buf)
754+
count = buf->count;
768755
else
769756
count = 0;
770757
spin_unlock_irqrestore(&n_hdlc->rx_buf_list.spinlock,flags);
@@ -776,8 +763,10 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file,
776763
count = tty_chars_in_buffer(tty);
777764
/* add size of next output frame in queue */
778765
spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock,flags);
779-
if (n_hdlc->tx_buf_list.head)
780-
count += n_hdlc->tx_buf_list.head->count;
766+
buf = list_first_entry_or_null(&n_hdlc->tx_buf_list.list,
767+
struct n_hdlc_buf, list_item);
768+
if (buf)
769+
count += buf->count;
781770
spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock,flags);
782771
error = put_user(count, (int __user *)arg);
783772
break;
@@ -825,14 +814,14 @@ static unsigned int n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp,
825814
poll_wait(filp, &tty->write_wait, wait);
826815

827816
/* set bits for operations that won't block */
828-
if (n_hdlc->rx_buf_list.head)
817+
if (!list_empty(&n_hdlc->rx_buf_list.list))
829818
mask |= POLLIN | POLLRDNORM; /* readable */
830819
if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
831820
mask |= POLLHUP;
832821
if (tty_hung_up_p(filp))
833822
mask |= POLLHUP;
834823
if (!tty_is_writelocked(tty) &&
835-
n_hdlc->tx_free_buf_list.head)
824+
!list_empty(&n_hdlc->tx_free_buf_list.list))
836825
mask |= POLLOUT | POLLWRNORM; /* writable */
837826
}
838827
return mask;
@@ -856,7 +845,12 @@ static struct n_hdlc *n_hdlc_alloc(void)
856845
spin_lock_init(&n_hdlc->tx_free_buf_list.spinlock);
857846
spin_lock_init(&n_hdlc->rx_buf_list.spinlock);
858847
spin_lock_init(&n_hdlc->tx_buf_list.spinlock);
859-
848+
849+
INIT_LIST_HEAD(&n_hdlc->rx_free_buf_list.list);
850+
INIT_LIST_HEAD(&n_hdlc->tx_free_buf_list.list);
851+
INIT_LIST_HEAD(&n_hdlc->rx_buf_list.list);
852+
INIT_LIST_HEAD(&n_hdlc->tx_buf_list.list);
853+
860854
/* allocate free rx buffer list */
861855
for(i=0;i<DEFAULT_RX_BUF_COUNT;i++) {
862856
buf = kmalloc(N_HDLC_BUF_SIZE, GFP_KERNEL);
@@ -883,54 +877,66 @@ static struct n_hdlc *n_hdlc_alloc(void)
883877

884878
} /* end of n_hdlc_alloc() */
885879

880+
/**
881+
* n_hdlc_buf_return - put the HDLC buffer after the head of the specified list
882+
* @buf_list - pointer to the buffer list
883+
* @buf - pointer to the buffer
884+
*/
885+
static void n_hdlc_buf_return(struct n_hdlc_buf_list *buf_list,
886+
struct n_hdlc_buf *buf)
887+
{
888+
unsigned long flags;
889+
890+
spin_lock_irqsave(&buf_list->spinlock, flags);
891+
892+
list_add(&buf->list_item, &buf_list->list);
893+
buf_list->count++;
894+
895+
spin_unlock_irqrestore(&buf_list->spinlock, flags);
896+
}
897+
886898
/**
887899
* n_hdlc_buf_put - add specified HDLC buffer to tail of specified list
888-
* @list - pointer to buffer list
900+
* @buf_list - pointer to buffer list
889901
* @buf - pointer to buffer
890902
*/
891-
static void n_hdlc_buf_put(struct n_hdlc_buf_list *list,
903+
static void n_hdlc_buf_put(struct n_hdlc_buf_list *buf_list,
892904
struct n_hdlc_buf *buf)
893905
{
894906
unsigned long flags;
895-
spin_lock_irqsave(&list->spinlock,flags);
896-
897-
buf->link=NULL;
898-
if (list->tail)
899-
list->tail->link = buf;
900-
else
901-
list->head = buf;
902-
list->tail = buf;
903-
(list->count)++;
904-
905-
spin_unlock_irqrestore(&list->spinlock,flags);
906-
907+
908+
spin_lock_irqsave(&buf_list->spinlock, flags);
909+
910+
list_add_tail(&buf->list_item, &buf_list->list);
911+
buf_list->count++;
912+
913+
spin_unlock_irqrestore(&buf_list->spinlock, flags);
907914
} /* end of n_hdlc_buf_put() */
908915

909916
/**
910917
* n_hdlc_buf_get - remove and return an HDLC buffer from list
911-
* @list - pointer to HDLC buffer list
918+
* @buf_list - pointer to HDLC buffer list
912919
*
913920
* Remove and return an HDLC buffer from the head of the specified HDLC buffer
914921
* list.
915922
* Returns a pointer to HDLC buffer if available, otherwise %NULL.
916923
*/
917-
static struct n_hdlc_buf* n_hdlc_buf_get(struct n_hdlc_buf_list *list)
924+
static struct n_hdlc_buf *n_hdlc_buf_get(struct n_hdlc_buf_list *buf_list)
918925
{
919926
unsigned long flags;
920927
struct n_hdlc_buf *buf;
921-
spin_lock_irqsave(&list->spinlock,flags);
922-
923-
buf = list->head;
928+
929+
spin_lock_irqsave(&buf_list->spinlock, flags);
930+
931+
buf = list_first_entry_or_null(&buf_list->list,
932+
struct n_hdlc_buf, list_item);
924933
if (buf) {
925-
list->head = buf->link;
926-
(list->count)--;
934+
list_del(&buf->list_item);
935+
buf_list->count--;
927936
}
928-
if (!list->head)
929-
list->tail = NULL;
930-
931-
spin_unlock_irqrestore(&list->spinlock,flags);
937+
938+
spin_unlock_irqrestore(&buf_list->spinlock, flags);
932939
return buf;
933-
934940
} /* end of n_hdlc_buf_get() */
935941

936942
static char hdlc_banner[] __initdata =

drivers/tty/serial/samsung.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1031,8 +1031,10 @@ static int s3c64xx_serial_startup(struct uart_port *port)
10311031
if (ourport->dma) {
10321032
ret = s3c24xx_serial_request_dma(ourport);
10331033
if (ret < 0) {
1034-
dev_warn(port->dev, "DMA request failed\n");
1035-
return ret;
1034+
dev_warn(port->dev,
1035+
"DMA request failed, DMA will not be used\n");
1036+
devm_kfree(port->dev, ourport->dma);
1037+
ourport->dma = NULL;
10361038
}
10371039
}
10381040

0 commit comments

Comments
 (0)