diff options
author | Paul Fulghum <paulkf@microgate.com> | 2006-02-03 06:04:41 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-02-03 11:32:09 -0500 |
commit | 808249ceba49cdb3054c0aa5b75a61862d6cab94 (patch) | |
tree | 246d11a687db3e8a775e746ed8f0da1aeedae70c /drivers/char/tty_io.c | |
parent | 546cfdf47f2ea2438b01f8626a60b87f9d8d1e53 (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.c | 77 |
1 files changed, 50 insertions, 27 deletions
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index eb8b5be4e24..076e07c1da3 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 | ||
254 | static void tty_buffer_init(struct tty_struct *tty) | 254 | static 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 | ||
313 | int tty_buffer_request_room(struct tty_struct *tty, size_t size) | 315 | int 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); | |||
396 | int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars, size_t size) | 409 | int 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); | |||
416 | int tty_prepare_flip_string_flags(struct tty_struct *tty, unsigned char **chars, char **flags, size_t size) | 431 | int 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); |
2764 | out: | 2781 | out: |
2765 | tty_ldisc_deref(disc); | 2782 | tty_ldisc_deref(disc); |
2766 | } | 2783 | } |
@@ -2852,6 +2869,12 @@ EXPORT_SYMBOL(tty_get_baud_rate); | |||
2852 | 2869 | ||
2853 | void tty_flip_buffer_push(struct tty_struct *tty) | 2870 | void 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 |