Skip to contentSkip to conversation

fc transport: bug fix: correct references

PATCH New James Smart 1 participant 1 message Jun 15, 2006 SCSI

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 fc transport: bug fix: correct references

Updating the FC transport for the following:
- Take a self-reference on the rport. Prior, when the starget was removed, the ref count would hit zero and fc_rport_dev_release was called, which would free the rport. This left corrupt lists, etc... Symptoms of error is oops w/ either:
"Badness in kref_get in lib/kref.c:32"
"Unable to handle kernel paging request for data at address 0x00000010"
from kref_get
- Fix fc_rport_create failure path - too many put's on parent
- Add commenting to easily track ref taking.

-- james s

drivers/scsi/scsi_transport_fc.c +10 -7
diff -upNr a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
@@ -1077,7 +1077,7 @@ static int fc_target_match(struct attrib
 static void fc_rport_dev_release(struct device *dev)
 {
 	struct fc_rport *rport = dev_to_rport(dev);
-	put_device(dev->parent);
+	put_device(dev->parent);		/* for parent reference */
 	kfree(rport);
 }
 
@@ -1476,7 +1476,8 @@ fc_rport_final_delete(void *data)
 	transport_remove_device(dev);
 	device_del(dev);
 	transport_destroy_device(dev);
-	put_device(&shost->shost_gendev);
+	put_device(&shost->shost_gendev);	/* for fc_host->rport list */
+	put_device(dev);			/* for self-reference */
 }
 
 
@@ -1537,13 +1538,13 @@ fc_rport_create(struct Scsi_Host *shost,
 	else
 		rport->scsi_target_id = -1;
 	list_add_tail(&rport->peers, &fc_host->rports);
-	get_device(&shost->shost_gendev);
+	get_device(&shost->shost_gendev);	/* for fc_host->rport list */
 
 	spin_unlock_irqrestore(shost->host_lock, flags);
 
 	dev = &rport->dev;
 	device_initialize(dev);
-	dev->parent = get_device(&shost->shost_gendev);
+	dev->parent = get_device(&shost->shost_gendev); /* parent reference */
 	dev->release = fc_rport_dev_release;
 	sprintf(dev->bus_id, "rport-%d:%d-%d",
 		shost->host_no, channel, rport->number);
@@ -1554,6 +1555,9 @@ fc_rport_create(struct Scsi_Host *shost,
 		printk(KERN_ERR "FC Remote Port device_add failed\n");
 		goto delete_rport;
 	}
+	
+	get_device(dev);			/* for self-reference */
+
 	transport_add_device(dev);
 	transport_configure_device(dev);
 
@@ -1567,12 +1571,11 @@ fc_rport_create(struct Scsi_Host *shost,
 
 delete_rport:
 	transport_destroy_device(dev);
-	put_device(dev->parent);
+	put_device(dev->parent);		/* for parent reference */
 	spin_lock_irqsave(shost->host_lock, flags);
 	list_del(&rport->peers);
-	put_device(&shost->shost_gendev);
+	put_device(&shost->shost_gendev);	/* for fc_host->rport list */
 	spin_unlock_irqrestore(shost->host_lock, flags);
-	put_device(dev->parent);
 	kfree(rport);
 	return NULL;
 }