diff options
author | Paul Fulghum <paulkf@microgate.com> | 2006-06-25 08:49:12 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-06-25 13:01:22 -0400 |
commit | cc44a817f65f9b4651643d334f6351b6d1f5e6c2 (patch) | |
tree | 818ea9a738b72cfd11f97637312e743aa344e195 /drivers/char/rocket.c | |
parent | 45c9b11a1d07770cabb48cb0f7960a77650ffc64 (diff) |
[PATCH] fix memory leak in rocketport rp_do_receive
Fix memory leak caused by incorrect use of tty buffer facility. tty
buffers are allocated but never processed by call to tty_flip_buffer_push
so they accumulate on the full buffer list. Current code uses the buffers
as a temporary storage for data before passing it directly to the line
discipline.
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/rocket.c')
-rw-r--r-- | drivers/char/rocket.c | 62 |
1 files changed, 23 insertions, 39 deletions
diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c index 7edc6a4dbdc4..0708c5164c83 100644 --- a/drivers/char/rocket.c +++ b/drivers/char/rocket.c | |||
@@ -324,35 +324,15 @@ static void rp_do_receive(struct r_port *info, | |||
324 | CHANNEL_t * cp, unsigned int ChanStatus) | 324 | CHANNEL_t * cp, unsigned int ChanStatus) |
325 | { | 325 | { |
326 | unsigned int CharNStat; | 326 | unsigned int CharNStat; |
327 | int ToRecv, wRecv, space = 0, count; | 327 | int ToRecv, wRecv, space; |
328 | unsigned char *cbuf, *chead; | 328 | unsigned char *cbuf; |
329 | char *fbuf, *fhead; | ||
330 | struct tty_ldisc *ld; | ||
331 | |||
332 | ld = tty_ldisc_ref(tty); | ||
333 | 329 | ||
334 | ToRecv = sGetRxCnt(cp); | 330 | ToRecv = sGetRxCnt(cp); |
335 | space = tty->receive_room; | ||
336 | if (space > 2 * TTY_FLIPBUF_SIZE) | ||
337 | space = 2 * TTY_FLIPBUF_SIZE; | ||
338 | count = 0; | ||
339 | #ifdef ROCKET_DEBUG_INTR | 331 | #ifdef ROCKET_DEBUG_INTR |
340 | printk(KERN_INFO "rp_do_receive(%d, %d)...", ToRecv, space); | 332 | printk(KERN_INFO "rp_do_receive(%d)...", ToRecv); |
341 | #endif | 333 | #endif |
342 | 334 | if (ToRecv == 0) | |
343 | /* | 335 | return; |
344 | * determine how many we can actually read in. If we can't | ||
345 | * read any in then we have a software overrun condition. | ||
346 | */ | ||
347 | if (ToRecv > space) | ||
348 | ToRecv = space; | ||
349 | |||
350 | ToRecv = tty_prepare_flip_string_flags(tty, &chead, &fhead, ToRecv); | ||
351 | if (ToRecv <= 0) | ||
352 | goto done; | ||
353 | |||
354 | cbuf = chead; | ||
355 | fbuf = fhead; | ||
356 | 336 | ||
357 | /* | 337 | /* |
358 | * if status indicates there are errored characters in the | 338 | * if status indicates there are errored characters in the |
@@ -380,6 +360,8 @@ static void rp_do_receive(struct r_port *info, | |||
380 | info->read_status_mask); | 360 | info->read_status_mask); |
381 | #endif | 361 | #endif |
382 | while (ToRecv) { | 362 | while (ToRecv) { |
363 | char flag; | ||
364 | |||
383 | CharNStat = sInW(sGetTxRxDataIO(cp)); | 365 | CharNStat = sInW(sGetTxRxDataIO(cp)); |
384 | #ifdef ROCKET_DEBUG_RECEIVE | 366 | #ifdef ROCKET_DEBUG_RECEIVE |
385 | printk(KERN_INFO "%x...", CharNStat); | 367 | printk(KERN_INFO "%x...", CharNStat); |
@@ -392,17 +374,16 @@ static void rp_do_receive(struct r_port *info, | |||
392 | } | 374 | } |
393 | CharNStat &= info->read_status_mask; | 375 | CharNStat &= info->read_status_mask; |
394 | if (CharNStat & STMBREAKH) | 376 | if (CharNStat & STMBREAKH) |
395 | *fbuf++ = TTY_BREAK; | 377 | flag = TTY_BREAK; |
396 | else if (CharNStat & STMPARITYH) | 378 | else if (CharNStat & STMPARITYH) |
397 | *fbuf++ = TTY_PARITY; | 379 | flag = TTY_PARITY; |
398 | else if (CharNStat & STMFRAMEH) | 380 | else if (CharNStat & STMFRAMEH) |
399 | *fbuf++ = TTY_FRAME; | 381 | flag = TTY_FRAME; |
400 | else if (CharNStat & STMRCVROVRH) | 382 | else if (CharNStat & STMRCVROVRH) |
401 | *fbuf++ = TTY_OVERRUN; | 383 | flag = TTY_OVERRUN; |
402 | else | 384 | else |
403 | *fbuf++ = TTY_NORMAL; | 385 | flag = TTY_NORMAL; |
404 | *cbuf++ = CharNStat & 0xff; | 386 | tty_insert_flip_char(tty, CharNStat & 0xff, flag); |
405 | count++; | ||
406 | ToRecv--; | 387 | ToRecv--; |
407 | } | 388 | } |
408 | 389 | ||
@@ -422,20 +403,23 @@ static void rp_do_receive(struct r_port *info, | |||
422 | * characters at time by doing repeated word IO | 403 | * characters at time by doing repeated word IO |
423 | * transfer. | 404 | * transfer. |
424 | */ | 405 | */ |
406 | space = tty_prepare_flip_string(tty, &cbuf, ToRecv); | ||
407 | if (space < ToRecv) { | ||
408 | #ifdef ROCKET_DEBUG_RECEIVE | ||
409 | printk(KERN_INFO "rp_do_receive:insufficient space ToRecv=%d space=%d\n", ToRecv, space); | ||
410 | #endif | ||
411 | if (space <= 0) | ||
412 | return; | ||
413 | ToRecv = space; | ||
414 | } | ||
425 | wRecv = ToRecv >> 1; | 415 | wRecv = ToRecv >> 1; |
426 | if (wRecv) | 416 | if (wRecv) |
427 | sInStrW(sGetTxRxDataIO(cp), (unsigned short *) cbuf, wRecv); | 417 | sInStrW(sGetTxRxDataIO(cp), (unsigned short *) cbuf, wRecv); |
428 | if (ToRecv & 1) | 418 | if (ToRecv & 1) |
429 | cbuf[ToRecv - 1] = sInB(sGetTxRxDataIO(cp)); | 419 | cbuf[ToRecv - 1] = sInB(sGetTxRxDataIO(cp)); |
430 | memset(fbuf, TTY_NORMAL, ToRecv); | ||
431 | cbuf += ToRecv; | ||
432 | fbuf += ToRecv; | ||
433 | count += ToRecv; | ||
434 | } | 420 | } |
435 | /* Push the data up to the tty layer */ | 421 | /* Push the data up to the tty layer */ |
436 | ld->receive_buf(tty, chead, fhead, count); | 422 | tty_flip_buffer_push(tty); |
437 | done: | ||
438 | tty_ldisc_deref(ld); | ||
439 | } | 423 | } |
440 | 424 | ||
441 | /* | 425 | /* |