Commit 4c76a6b2 authored by Paul Wagland's avatar Paul Wagland Committed by Linus Torvalds

[PATCH] bug fix for megaraid memory leak

I was going through the code looking for bits and pieces to pull across
into the new LSI Logic beta megaraid driver /sys fs code and came across
this one.

LSI Logic have already fixed this issue for the 2.4 driver, and the new
beta driver does not use the /proc filesystem at all, so no problem
there.

The problem is that resources are not freed upon certain error
conditions in the in-kernel megaraid driver, to quote from Lester
Hightower (who originally found the issue):

   "The problem occurs only in the circumstance where one reads one of
    the /proc/megaraid/hba<X>/diskdrives-ch<N> files where the card <X>
    does not have channel <N> on it.  Most people would likely not
    notice this leak in normal operation, but due to the way that we
    monitor our MegaRaid cards in our company (we read these /proc
    entries every 180s) so we found the leak rather quickly, and
    unpleasantly (when your kernel eats all your RAM)."

Anyway, here is the fix, compiled and tested OK for me.
parent f0d61324
......@@ -2572,21 +2572,15 @@ proc_pdrv(adapter_t *adapter, char *page, int channel)
}
if( (inquiry = mega_allocate_inquiry(&dma_handle, pdev)) == NULL ) {
free_local_pdev(pdev);
return len;
goto free_pdev;
}
if( mega_adapinq(adapter, dma_handle) != 0 ) {
len = sprintf(page, "Adapter inquiry failed.\n");
printk(KERN_WARNING "megaraid: inquiry failed.\n");
mega_free_inquiry(inquiry, dma_handle, pdev);
free_local_pdev(pdev);
return len;
goto free_inquiry;
}
......@@ -2595,11 +2589,7 @@ proc_pdrv(adapter_t *adapter, char *page, int channel)
if( scsi_inq == NULL ) {
len = sprintf(page, "memory not available for scsi inq.\n");
mega_free_inquiry(inquiry, dma_handle, pdev);
free_local_pdev(pdev);
return len;
goto free_inquiry;
}
if( adapter->flag & BOARD_40LD ) {
......@@ -2612,7 +2602,9 @@ proc_pdrv(adapter_t *adapter, char *page, int channel)
max_channels = adapter->product_info.nchannels;
if( channel >= max_channels ) return 0;
if( channel >= max_channels ) {
goto free_pci;
}
for( tgt = 0; tgt <= MAX_TARGET; tgt++ ) {
......@@ -2677,10 +2669,11 @@ proc_pdrv(adapter_t *adapter, char *page, int channel)
len += mega_print_inquiry(page+len, scsi_inq);
}
free_pci:
pci_free_consistent(pdev, 256, scsi_inq, scsi_inq_dma_handle);
free_inquiry:
mega_free_inquiry(inquiry, dma_handle, pdev);
free_pdev:
free_local_pdev(pdev);
return len;
......
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