]> git.neil.brown.name Git - history.git/commitdiff
[PATCH] bug fix for megaraid memory leak
authorPaul Wagland <paul@wagland.net>
Thu, 6 May 2004 00:50:40 +0000 (17:50 -0700)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Thu, 6 May 2004 00:50:40 +0000 (17:50 -0700)
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.

drivers/scsi/megaraid.c

index 94008551f7ba1ead2df79badd4c4c5324688bd4b..caf78b6be7061d72912544a516f33e59599eb4df 100644 (file)
@@ -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;