aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/tty_io.c
diff options
context:
space:
mode:
authorPaul Fulghum <paulkf@microgate.com>2006-02-03 06:04:41 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-02-03 11:32:09 -0500
commit808249ceba49cdb3054c0aa5b75a61862d6cab94 (patch)
tree246d11a687db3e8a775e746ed8f0da1aeedae70c /drivers/char/tty_io.c
parent546cfdf47f2ea2438b01f8626a60b87f9d8d1e53 (diff)
[PATCH] new tty buffering locking fix
Change locking in the new tty buffering facility from using tty->read_lock, which is currently ignored by drivers and thus ineffective. New locking uses a new tty buffering specific lock enforced centrally in the tty buffering code. Two drivers (esp and cyclades) are updated to use the tty buffering functions instead of accessing tty buffering internals directly. This is required for the new locking to work. Minor checks for NULL buffers added to tty_prepare_flip_string/tty_prepare_flip_string_flags Signed-off-by: Paul Fulghum <paulkf@microgate.com> Cc: Alan Cox <alan@lxorguk.ukuu.org.uk> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/char/tty_io.c')
-rw-r--r--drivers/char/tty_io.c77
1 files changed, 50 insertions, 27 deletions
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index eb8b5be4e249..076e07c1da38 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -253,6 +253,7 @@ static void tty_buffer_free_all(struct tty_struct *tty)
253 253
254static void tty_buffer_init(struct tty_struct *tty) 254static void tty_buffer_init(struct tty_struct *tty)
255{ 255{
256 spin_lock_init(&tty->buf.lock);
256 tty->buf.head = NULL; 257 tty->buf.head = NULL;
257 tty->buf.tail = NULL; 258 tty->buf.tail = NULL;
258 tty->buf.free = NULL; 259 tty->buf.free = NULL;
@@ -266,6 +267,7 @@ static struct tty_buffer *tty_buffer_alloc(size_t size)
266 p->used = 0; 267 p->used = 0;
267 p->size = size; 268 p->size = size;
268 p->next = NULL; 269 p->next = NULL;
270 p->active = 0;
269 p->char_buf_ptr = (char *)(p->data); 271 p->char_buf_ptr = (char *)(p->data);
270 p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size; 272 p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size;
271/* printk("Flip create %p\n", p); */ 273/* printk("Flip create %p\n", p); */
@@ -312,25 +314,36 @@ static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size)
312 314
313int tty_buffer_request_room(struct tty_struct *tty, size_t size) 315int tty_buffer_request_room(struct tty_struct *tty, size_t size)
314{ 316{
315 struct tty_buffer *b = tty->buf.tail, *n; 317 struct tty_buffer *b, *n;
316 int left = 0; 318 int left;
319 unsigned long flags;
320
321 spin_lock_irqsave(&tty->buf.lock, flags);
317 322
318 /* OPTIMISATION: We could keep a per tty "zero" sized buffer to 323 /* OPTIMISATION: We could keep a per tty "zero" sized buffer to
319 remove this conditional if its worth it. This would be invisible 324 remove this conditional if its worth it. This would be invisible
320 to the callers */ 325 to the callers */
321 if(b != NULL) 326 if ((b = tty->buf.tail) != NULL) {
322 left = b->size - b->used; 327 left = b->size - b->used;
323 if(left >= size) 328 b->active = 1;
324 return size; 329 } else
325 /* This is the slow path - looking for new buffers to use */ 330 left = 0;
326 n = tty_buffer_find(tty, size); 331
327 if(n == NULL) 332 if (left < size) {
328 return left; 333 /* This is the slow path - looking for new buffers to use */
329 if(b != NULL) 334 if ((n = tty_buffer_find(tty, size)) != NULL) {
330 b->next = n; 335 if (b != NULL) {
331 else 336 b->next = n;
332 tty->buf.head = n; 337 b->active = 0;
333 tty->buf.tail = n; 338 } else
339 tty->buf.head = n;
340 tty->buf.tail = n;
341 n->active = 1;
342 } else
343 size = left;
344 }
345
346 spin_unlock_irqrestore(&tty->buf.lock, flags);
334 return size; 347 return size;
335} 348}
336 349
@@ -396,10 +409,12 @@ EXPORT_SYMBOL_GPL(tty_insert_flip_string_flags);
396int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars, size_t size) 409int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars, size_t size)
397{ 410{
398 int space = tty_buffer_request_room(tty, size); 411 int space = tty_buffer_request_room(tty, size);
399 struct tty_buffer *tb = tty->buf.tail; 412 if (likely(space)) {
400 *chars = tb->char_buf_ptr + tb->used; 413 struct tty_buffer *tb = tty->buf.tail;
401 memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space); 414 *chars = tb->char_buf_ptr + tb->used;
402 tb->used += space; 415 memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
416 tb->used += space;
417 }
403 return space; 418 return space;
404} 419}
405 420
@@ -416,10 +431,12 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
416int tty_prepare_flip_string_flags(struct tty_struct *tty, unsigned char **chars, char **flags, size_t size) 431int tty_prepare_flip_string_flags(struct tty_struct *tty, unsigned char **chars, char **flags, size_t size)
417{ 432{
418 int space = tty_buffer_request_room(tty, size); 433 int space = tty_buffer_request_room(tty, size);
419 struct tty_buffer *tb = tty->buf.tail; 434 if (likely(space)) {
420 *chars = tb->char_buf_ptr + tb->used; 435 struct tty_buffer *tb = tty->buf.tail;
421 *flags = tb->flag_buf_ptr + tb->used; 436 *chars = tb->char_buf_ptr + tb->used;
422 tb->used += space; 437 *flags = tb->flag_buf_ptr + tb->used;
438 tb->used += space;
439 }
423 return space; 440 return space;
424} 441}
425 442
@@ -2747,20 +2764,20 @@ static void flush_to_ldisc(void *private_)
2747 schedule_delayed_work(&tty->buf.work, 1); 2764 schedule_delayed_work(&tty->buf.work, 1);
2748 goto out; 2765 goto out;
2749 } 2766 }
2750 spin_lock_irqsave(&tty->read_lock, flags); 2767 spin_lock_irqsave(&tty->buf.lock, flags);
2751 while((tbuf = tty->buf.head) != NULL) { 2768 while((tbuf = tty->buf.head) != NULL && !tbuf->active) {
2752 tty->buf.head = tbuf->next; 2769 tty->buf.head = tbuf->next;
2753 if (tty->buf.head == NULL) 2770 if (tty->buf.head == NULL)
2754 tty->buf.tail = NULL; 2771 tty->buf.tail = NULL;
2755 spin_unlock_irqrestore(&tty->read_lock, flags); 2772 spin_unlock_irqrestore(&tty->buf.lock, flags);
2756 /* printk("Process buffer %p for %d\n", tbuf, tbuf->used); */ 2773 /* printk("Process buffer %p for %d\n", tbuf, tbuf->used); */
2757 disc->receive_buf(tty, tbuf->char_buf_ptr, 2774 disc->receive_buf(tty, tbuf->char_buf_ptr,
2758 tbuf->flag_buf_ptr, 2775 tbuf->flag_buf_ptr,
2759 tbuf->used); 2776 tbuf->used);
2760 spin_lock_irqsave(&tty->read_lock, flags); 2777 spin_lock_irqsave(&tty->buf.lock, flags);
2761 tty_buffer_free(tty, tbuf); 2778 tty_buffer_free(tty, tbuf);
2762 } 2779 }
2763 spin_unlock_irqrestore(&tty->read_lock, flags); 2780 spin_unlock_irqrestore(&tty->buf.lock, flags);
2764out: 2781out:
2765 tty_ldisc_deref(disc); 2782 tty_ldisc_deref(disc);
2766} 2783}
@@ -2852,6 +2869,12 @@ EXPORT_SYMBOL(tty_get_baud_rate);
2852 2869
2853void tty_flip_buffer_push(struct tty_struct *tty) 2870void tty_flip_buffer_push(struct tty_struct *tty)
2854{ 2871{
2872 unsigned long flags;
2873 spin_lock_irqsave(&tty->buf.lock, flags);
2874 if (tty->buf.tail != NULL)
2875 tty->buf.tail->active = 0;
2876 spin_unlock_irqrestore(&tty->buf.lock, flags);
2877
2855 if (tty->low_latency) 2878 if (tty->low_latency)
2856 flush_to_ldisc((void *) tty); 2879 flush_to_ldisc((void *) tty);
2857 else 2880 else