[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <tkrat.e2b0bc32f455c4b6@s5r6.in-berlin.de>
Date: Wed, 7 Nov 2007 01:11:56 +0100 (CET)
From: Stefan Richter <stefanr@...6.in-berlin.de>
To: linux1394-devel@...ts.sourceforge.net
cc: Kristian Høgsberg <krh@...hat.com>,
linux-kernel@...r.kernel.org
Subject: [PATCH 1/2] 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
disconnected.
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 <stefanr@...6.in-berlin.de>
---
drivers/firewire/fw-sbp2.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
Index: linux/drivers/firewire/fw-sbp2.c
===================================================================
--- linux.orig/drivers/firewire/fw-sbp2.c
+++ linux/drivers/firewire/fw-sbp2.c
@@ -650,13 +650,14 @@ static void sbp2_login(struct work_struc
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);
return;
}
@@ -914,7 +915,9 @@ static void sbp2_reconnect(struct work_s
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);
return;
}
--
Stefan Richter
-=====-=-=== =-== --===
http://arcgraph.de/sr/
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists