Fix reference counting for failed SCSI devices
PATCH 1/1 Fix reference counting for failed SCSI devices
Hi James,
whenever the scsi-ml tries to scan non-existent devices the reference count in scsi_alloc_sdev() and scsi_probe_and_add_lun() is not adjusted properly. Every call to XXX_initialize in the driver core sets the reference count to 1, so for a proper deallocation an explicit XXX_put() has to be done.
Please apply.
Cheers,
Hannes
Signature · 4 lines
Dr. Hannes Reinecke [email protected] SuSE Linux AG S390 & zSeries Maxfeldstraße 5 +49 911 74053 688 90409 Nürnberg http://www.suse.de
From: Hannes Reinecke <[email protected]>
Subject: Fix refcount for failed devices
When a non-present device is scanned it is not properly deregistered from the driver core. Calling XXX_initialize() functions from the driver core sets the reference count to 1, so for proper deallocation a XXX_put() has to be issued.
drivers/scsi/scsi_scan.c renamed from drivers/scsi/scsi_scan.c.orig +4 -0
@@ -273,6 +273,7 @@ static struct scsi_device *scsi_alloc_sd*/ if (ret == -ENXIO ) display_failure_msg =0 ; +put_device (&starget->dev); goto out_device_destroy; } }
@@ -282,6 +283,7 @@ static struct scsi_device *scsi_alloc_sd out_device_destroy:transport_destroy_device (&sdev->sdev_gendev);scsi_free_queue (sdev->request_queue); +class_device_put (&sdev->sdev_classdev);put_device (&sdev->sdev_gendev); out:if (display_failure_msg)
@@ -855,6 +857,8 @@ static int scsi_probe_and_add_lun(structif (sdev->host->hostt->slave_destroy) sdev->host->hostt->slave_destroy (sdev);transport_destroy_device (&sdev->sdev_gendev); +class_device_put (&sdev->sdev_classdev); +put_device (sdev->sdev_gendev.parent);put_device (&sdev->sdev_gendev); } out:
Quoted 5 lines · Hannes Reinecke
whenever the scsi-ml tries to scan non-existent devices the reference count in
scsi_alloc_sdev()andscsi_probe_and_add_lun()is not adjusted properly. Every call toXXX_initializein the driver core sets the reference count to 1, so for a proper deallocation an explicitXXX_put()has to be done.
That's true, but I don't see what the problem is if the device has never been made visible.
drivers/scsi/scsi_scan.c static struct scsi_device *scsi_alloc_sd · line 276
Quoted 1 line
drivers/scsi/scsi_scan.c renamed from drivers/scsi/scsi_scan.c.orig +1
-0+put_device (&starget->dev);
this would amount to a double put, since the parent put method is called in the device release.
Review
Quoted 1 line
(quoted diff) +1
-0+ class_device_put(&sdev->sdev_classdev);
This is unnecessary since the class device is simply occupying a private area in the scsi_device. As long as its never made visible to the system, its refcount is irrelevant
drivers/scsi/scsi_scan.c static int scsi_probe_and_add_lun(struct · line 861
Quoted 9 lines
drivers/scsi/scsi_scan.c renamed from drivers/scsi/scsi_scan.c.orig +2
-0put_device (&sdev->sdev_gendev); out:if (display_failure_msg)@@ -855,6 +857,8 @@ static int scsi_probe_and_add_lun(structif (sdev->host->hostt->slave_destroy) sdev->host->hostt->slave_destroy (sdev);transport_destroy_device (&sdev->sdev_gendev); +class_device_put (&sdev->sdev_classdev); +put_device (sdev->sdev_gendev.parent);
same should apply here. As long as this cascade occurs before scsi_add_lun() (which calls scsi_sysfs_add_sdev()), which is what makes the whole set of devices and classes visible.
James
Quoted 10 lines · James Bottomley
Quoted 5 lines · Hannes Reinecke
whenever the scsi-ml tries to scan non-existent devices the reference count in
scsi_alloc_sdev()andscsi_probe_and_add_lun()is not adjusted properly. Every call toXXX_initializein the driver core sets the reference count to 1, so for a proper deallocation an explicitXXX_put()has to be done.That's true, but I don't see what the problem is if the device has never been made visible.
It's not visible but it's still allocated and referenced. So on doing a rmmod these class_devices are being deallocated which crashes as the class device is not connected properly.
Quoted 5 lines
Review
Quoted 1 line
(quoted diff) +1
-0+ put_device(&starget->dev);this would amount to a double put, since the parent put method is called in the device release.
Oops. Correct.
Quoted 6 lines
Review
Quoted 1 line
(quoted diff) +1
-0+ class_device_put(&sdev->sdev_classdev);This is unnecessary since the class device is simply occupying a private area in the
scsi_device. As long as its never made visible to the system, its refcount is irrelevant
It's not. Whenever you try to rmmod the adapter it becomes highly relevant. If it doesn't crash you've at least generated a memleak as the class device is never freed.
(And these are quite a few for Wide-SCSI Double-channel adapters ...)
Quoted 5 lines
Quoted 5 lines
put_device(&sdev->sdev_gendev);out:
if (display_failure_msg)(quoted diff) +0
-0@@ -855,6 +857,8 @@ static int scsi_probe_and_add_lun(struct if (sdev->host->hostt->slave_destroy)
Quoted 9 lines
Review static int scsi_probe_and_add_lun(struct · line 861
Quoted 4 lines
(quoted diff) +2
-0sdev->host->hostt->slave_destroy(sdev); transport_destroy_device(&sdev->sdev_gendev); + class_device_put(&sdev->sdev_classdev); + put_device(sdev->sdev_gendev.parent);same should apply here. As long as this cascade occurs before
scsi_add_lun()(which callsscsi_sysfs_add_sdev()), which is what makes the whole set of devices and classes visible.
Correct for the parent device. The class device has to be deallocated properly if a rmmod should work properly.
New patch attached. Please apply.
Cheers,
Hannes
Signature · 4 lines
Dr. Hannes Reinecke [email protected] SuSE Linux AG S390 & zSeries Maxfeldstraße 5 +49 911 74053 688 90409 Nürnberg http://www.suse.de
From: Hannes Reinecke <[email protected]>
Subject: Fix refcount for failed devices
When a non-present device is scanned it is not properly deregistered from the driver core. Calling XXX_initialize() functions from the driver core sets the reference count to 1, so for proper deallocation a XXX_put() has to be issued.
drivers/scsi/scsi_scan.c renamed from drivers/scsi/scsi_scan.c.orig +2 -0
@@ -282,6 +282,7 @@ static struct scsi_device *scsi_alloc_sd out_device_destroy:transport_destroy_device (&sdev->sdev_gendev);scsi_free_queue (sdev->request_queue); +class_device_put (&sdev->sdev_classdev);put_device (&sdev->sdev_gendev); out:if (display_failure_msg)
@@ -855,6 +856,7 @@ static int scsi_probe_and_add_lun(structif (sdev->host->hostt->slave_destroy) sdev->host->hostt->slave_destroy (sdev);transport_destroy_device (&sdev->sdev_gendev); +class_device_put (&sdev->sdev_classdev);put_device (&sdev->sdev_gendev); } out:
Quoted 10 lines · Hannes Reinecke
Quoted 6 lines
Review
Quoted 1 line
(quoted diff) +1
-0+ class_device_put(&sdev->sdev_classdev);This is unnecessary since the class device is simply occupying a private area in the
scsi_device. As long as its never made visible to the system, its refcount is irrelevantIt's not. Whenever you try to rmmod the adapter it becomes highly relevant. If it doesn't crash you've at least generated a memleak as the class device is never freed.
(And these are quite a few for Wide-SCSI Double-channel adapters ...)
? Look at the code; you're not doing a put on a pointer to the sdev_classdev, you're doing a put on a reference to it.
It's defined in scsi_device.h:
struct scsi_device {
...
struct class_device sdev_classdev;
...
};so it's contained within the scsi_device. Freeing the scsi_device frees the classdev (and the gendev).
James
Quoted 16 lines · James Bottomley
Quoted 9 lines · Hannes Reinecke
Quoted 5 lines
Review
Quoted 1 line
(quoted diff) +1
-0+ class_device_put(&sdev->sdev_classdev);This is unnecessary since the class device is simply occupying a private area in the
scsi_device. As long as its never made visible to the system, its refcount is irrelevantIt's not. Whenever you try to rmmod the adapter it becomes highly relevant. If it doesn't crash you've at least generated a memleak as the class device is never freed.
(And these are quite a few for Wide-SCSI Double-channel adapters ...)? Look at the code; you're not doing a put on a pointer to the
sdev_classdev, you're doing a put on a reference to it.It's defined in
scsi_device.h:
Quoted 9 lines
struct scsi_device { ... struct class_device sdev_classdev; ... };so it's contained within the
scsi_device. Freeing thescsi_devicefrees the classdev (and the gendev).
But does not call the ->release function.
Put it the other way round: does 'rmmod aic7xxx' work for you? It certainly did _not_ work for aic79xx, hence the fix.
Cheers,
Hannes
Signature · 8 lines
Dr. Hannes Reinecke [email protected] SuSE Linux AG S390 & zSeries Maxfeldstraße 5 +49 911 74053 688 90409 Nürnberg http://www.suse.de - To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 4 lines · Hannes Reinecke
Quoted 3 lines
so it's contained within the
scsi_device. Freeing thescsi_devicefrees the classdev (and the gendev).But does not call the ->release function.
Please just read the code like I asked. If you do, you'll find that the sdev_classdev release method is NULL until scsi_sysfs_add_sdev() precisely for the reason that the class references don't matter until that point. We're free to kill the whole thing without bothering about the class devices until scsi_add_lun detects something and calls scsi_sysfs_add_sdev() to make the whole thing visible. Then all classdevs get a ref on the parent gendev which their release method relinquishes.
Quoted 2 lines
Put it the other way round: does 'rmmod aic7xxx' work for you? It certainly did _not_ work for aic79xx, hence the fix.
Well, I know aic7xxx works perfectly on a dual channel card, because I actually test the failure paths and insmod/rmmod is one of my tests. I can't comment on aic79xx because I don't have the hardware.
James
Quoted 6 lines · James Bottomley
Quoted 4 lines · Hannes Reinecke
Quoted 3 lines
so it's contained within the
scsi_device. Freeing thescsi_devicefrees the classdev (and the gendev).But does not call the ->release function.
Quoted 9 lines
Please just read the code like I asked. If you do, you'll find that the
sdev_classdevrelease method is NULL untilscsi_sysfs_add_sdev()precisely for the reason that the class references don't matter until that point. We're free to kill the whole thing without bothering about the class devices untilscsi_add_lundetects something and callsscsi_sysfs_add_sdev()to make the whole thing visible. Then all classdevs get a ref on the parent gendev which their release method relinquishes.
Oh, right. Indeed, you are totally correct. Sorry for the noise.
Quoted 7 lines
Quoted 2 lines
Put it the other way round: does 'rmmod aic7xxx' work for you? It certainly did _not_ work for aic79xx, hence the fix.
Well, I know aic7xxx works perfectly on a dual channel card, because I actually test the failure paths and insmod/rmmod is one of my tests. I can't comment on aic79xx because I don't have the hardware.
I guess it's time to convert aic79xx to the spi_transport class. Unfortunately my attempt segfaults when removing a device in attribute_container_device_trigger(); someone is overwriting the ->match function. Oh well, further debugging needed.
Cheers,
Hannes
Signature · 8 lines
Dr. Hannes Reinecke [email protected] SuSE Linux AG S390 & zSeries Maxfeldstraße 5 +49 911 74053 688 90409 Nürnberg http://www.suse.de - To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 4 lines · Hannes Reinecke
I guess it's time to convert aic79xx to the
spi_transportclass. Unfortunately my attempt segfaults when removing a device inattribute_container_device_trigger(); someone is overwriting the ->match function. Oh well, further debugging needed.
Well ... best of luck. Given the problems incurred doing this for aic7xxx (mainly in initial inquiry and domain validation, one of which is outstanding still) it's not going to be easy.
Large segments of the aic79xx driver are identical to the aic7xxx driver except that all the functions being ahd_ instead of ahc_, so you should just be able to mirror quite a lot of the aic7xxx updates. However, you need to include a large number of rather nasty u320 parameters in the SPI transport Class (and make sure they're coupled correctly) to get domain validation to work ... the transport class has also only been tested on speeds up to u160, so going to u320 will be a first for it too...
James
Quoted 8 lines · James Bottomley
Large segments of the aic79xx driver are identical to the aic7xxx driver except that all the functions being
ahd_instead ofahc_, so you should just be able to mirror quite a lot of the aic7xxx updates. However, you need to include a large number of rather nasty u320 parameters in the SPI transport Class (and make sure they're coupled correctly) to get domain validation to work ... the transport class has also only been tested on speeds up to u160, so going to u320 will be a first for it too...
I wonder if LSI have any preliminary work in that area for the Fusion driver. Eric?
Signature · 6 lines
"Next the statesmen will invent cheap lies, putting the blame upon the nation that is attacked, and every man will be glad of those conscience-soothing falsities, and will diligently study them, and refuse to examine any refutations of them; and thus he will by and by convince himself that the war is just, and will thank God for the better sleep he enjoys after this process of grotesque self-deception." -- Mark Twain