aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Richter <stefanr@s5r6.in-berlin.de>2010-08-16 15:58:03 -0400
committerStefan Richter <stefanr@s5r6.in-berlin.de>2010-08-19 14:28:25 -0400
commit6c74340bce253ea95c9ee801b3c411a333937edf (patch)
tree4be487165cfc295cba5613094430248f6fb968e9
parent840fe6359c1db978d01fceb8a023f5f6efdf7f1c (diff)
firewire: sbp2: fix memory leak in sbp2_cancel_orbs or at send error
When an ORB was canceled (Command ORB i.e. SCSI request timed out, or Management ORB timed out), or there was a send error in the initial transaction, we missed to drop one of the ORB's references and thus leaked memory. Background: In total, we hold 3 references to each Operation Request Block: - 1 during sbp2_scsi_queuecommand() or sbp2_send_management_orb() respectively, - 1 for the duration of the write transaction to the ORB_Pointer or Management_Agent register of the target, - 1 for as long as the ORB stays within the lu->orb_list, until the ORB is unlinked from the list and the orb->callback was executed. The latter one of these 3 references is finished - normally by sbp2_status_write() when the target wrote status for a pending ORB, - or by sbp2_cancel_orbs() in case of an ORB time-out, - or by complete_transaction() in case of a send error. Of them, the latter two lacked the kref_put. Add the missing kref_put()s. Add comments to the gets and puts of references for transaction callbacks and ORB callbacks so that it is easier to see what is supposed to happen. Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
-rw-r--r--drivers/firewire/sbp2.c12
1 files changed, 7 insertions, 5 deletions
diff --git a/drivers/firewire/sbp2.c b/drivers/firewire/sbp2.c
index 9f76171717e5..e6cbe491f7ee 100644
--- a/drivers/firewire/sbp2.c
+++ b/drivers/firewire/sbp2.c
@@ -450,7 +450,7 @@ static void sbp2_status_write(struct fw_card *card, struct fw_request *request,
450 450
451 if (&orb->link != &lu->orb_list) { 451 if (&orb->link != &lu->orb_list) {
452 orb->callback(orb, &status); 452 orb->callback(orb, &status);
453 kref_put(&orb->kref, free_orb); 453 kref_put(&orb->kref, free_orb); /* orb callback reference */
454 } else { 454 } else {
455 fw_error("status write for unknown orb\n"); 455 fw_error("status write for unknown orb\n");
456 } 456 }
@@ -480,12 +480,14 @@ static void complete_transaction(struct fw_card *card, int rcode,
480 if (orb->rcode != RCODE_COMPLETE) { 480 if (orb->rcode != RCODE_COMPLETE) {
481 list_del(&orb->link); 481 list_del(&orb->link);
482 spin_unlock_irqrestore(&card->lock, flags); 482 spin_unlock_irqrestore(&card->lock, flags);
483
483 orb->callback(orb, NULL); 484 orb->callback(orb, NULL);
485 kref_put(&orb->kref, free_orb); /* orb callback reference */
484 } else { 486 } else {
485 spin_unlock_irqrestore(&card->lock, flags); 487 spin_unlock_irqrestore(&card->lock, flags);
486 } 488 }
487 489
488 kref_put(&orb->kref, free_orb); 490 kref_put(&orb->kref, free_orb); /* transaction callback reference */
489} 491}
490 492
491static void sbp2_send_orb(struct sbp2_orb *orb, struct sbp2_logical_unit *lu, 493static void sbp2_send_orb(struct sbp2_orb *orb, struct sbp2_logical_unit *lu,
@@ -501,9 +503,8 @@ static void sbp2_send_orb(struct sbp2_orb *orb, struct sbp2_logical_unit *lu,
501 list_add_tail(&orb->link, &lu->orb_list); 503 list_add_tail(&orb->link, &lu->orb_list);
502 spin_unlock_irqrestore(&device->card->lock, flags); 504 spin_unlock_irqrestore(&device->card->lock, flags);
503 505
504 /* Take a ref for the orb list and for the transaction callback. */ 506 kref_get(&orb->kref); /* transaction callback reference */
505 kref_get(&orb->kref); 507 kref_get(&orb->kref); /* orb callback reference */
506 kref_get(&orb->kref);
507 508
508 fw_send_request(device->card, &orb->t, TCODE_WRITE_BLOCK_REQUEST, 509 fw_send_request(device->card, &orb->t, TCODE_WRITE_BLOCK_REQUEST,
509 node_id, generation, device->max_speed, offset, 510 node_id, generation, device->max_speed, offset,
@@ -530,6 +531,7 @@ static int sbp2_cancel_orbs(struct sbp2_logical_unit *lu)
530 531
531 orb->rcode = RCODE_CANCELLED; 532 orb->rcode = RCODE_CANCELLED;
532 orb->callback(orb, NULL); 533 orb->callback(orb, NULL);
534 kref_put(&orb->kref, free_orb); /* orb callback reference */
533 } 535 }
534 536
535 return retval; 537 return retval;