Commit:     7c45d1913f0a1d597eb4bc3b2c962bc2967da9ea
Parent:     dbeeb816e805091e7cfc03baf36dc40b4adb2bbd
Author:     Stefan Richter <[EMAIL PROTECTED]>
AuthorDate: Wed Nov 7 01:11:56 2007 +0100
Committer:  Stefan Richter <[EMAIL PROTECTED]>
CommitDate: Wed Nov 7 01:59:28 2007 +0100

    firewire: fw-sbp2: fix refcounting
    Since patch "fw-sbp2: use an own workqueue (fix system responsiveness)"
    increased parallelism between fw-sbp2 and fw-core, it was possible that
    fw-sbp2 didn't release the SCSI device when the FireWire device was
    This happened if sbp2_update() ran during sbp2_login(), because a bus
    reset occurred during sbp2_login().  The sbp2_login() work would [try
    to] reschedule itself because it failed due to the bus reset, and it
    would _not_ drop its reference on the target.  However, sbp2_update()
    would schedule sbp2_login() too before sbp2_login() rescheduled itself
    and hence sbp2_update() would take an additional reference.  And then
    we would have one reference too many.
    The fix is to _always_ drop the reference when leaving the sbp2_login()
    work.  If the sbp2_login() work reschedules itself, it takes a
    reference, but only if it wasn't already rescheduled by sbp2_update().
    Ditto in the sbp2_reconnect() work.
    The resulting code is actually simpler than before:  We _always_ take
    a reference when successfully scheduling work.  And we _always_ drop
    a reference when leaving a workqueue job.  No exceptions.
    Signed-off-by: Stefan Richter <[EMAIL PROTECTED]>
 drivers/firewire/fw-sbp2.c |   11 +++++++----
 1 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c
index 5596df6..624ff3e 100644
--- a/drivers/firewire/fw-sbp2.c
+++ b/drivers/firewire/fw-sbp2.c
@@ -650,13 +650,14 @@ static void sbp2_login(struct work_struct *work)
        if (sbp2_send_management_orb(lu, node_id, generation,
                                SBP2_LOGIN_REQUEST, lu->lun, &response) < 0) {
                if (lu->retries++ < 5) {
-                       queue_delayed_work(sbp2_wq, &lu->work,
-                                          DIV_ROUND_UP(HZ, 5));
+                       if (queue_delayed_work(sbp2_wq, &lu->work,
+                                              DIV_ROUND_UP(HZ, 5)))
+                               kref_get(&lu->tgt->kref);
                } else {
                        fw_error("failed to login to %s LUN %04x\n",
                                 unit->device.bus_id, lu->lun);
-                       kref_put(&lu->tgt->kref, sbp2_release_target);
+               kref_put(&lu->tgt->kref, sbp2_release_target);
@@ -914,7 +915,9 @@ static void sbp2_reconnect(struct work_struct *work)
                        lu->retries = 0;
                        PREPARE_DELAYED_WORK(&lu->work, sbp2_login);
-               queue_delayed_work(sbp2_wq, &lu->work, DIV_ROUND_UP(HZ, 5));
+               if (queue_delayed_work(sbp2_wq, &lu->work, DIV_ROUND_UP(HZ, 5)))
+                       kref_get(&lu->tgt->kref);
+               kref_put(&lu->tgt->kref, sbp2_release_target);
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at

Reply via email to