aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/device_handler
diff options
context:
space:
mode:
authorChandra Seetharaman <sekharan@us.ibm.com>2009-06-26 22:30:06 -0400
committerJames Bottomley <James.Bottomley@suse.de>2009-08-22 18:51:51 -0400
commit6c10db72c94818573552fd71c89540da325efdfb (patch)
tree6afa9b0431d22638a1a11dfe3c5924b8e1a8e2f3 /drivers/scsi/device_handler
parentb4567ca6304a9b31cb2eae62f812e9eb9badcb60 (diff)
[SCSI] scsi_dh: Reference count scsi_dh_attach
Problem reported: http://marc.info/?l=dm-devel&m=124585978305866&w=2 scsi_dh does not do a refernce count for attach/detach, and this affects the way it is supposed to work with multipath when a device is not in the dev_list of the hardware handler. This patch adds a reference count that counts each attach. Signed-off-by: Chandra Seetharaman <sekharan@us.ibm.com> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/device_handler')
-rw-r--r--drivers/scsi/device_handler/scsi_dh.c23
1 files changed, 16 insertions, 7 deletions
diff --git a/drivers/scsi/device_handler/scsi_dh.c b/drivers/scsi/device_handler/scsi_dh.c
index a518f2eff19a..53a7385e1b4d 100644
--- a/drivers/scsi/device_handler/scsi_dh.c
+++ b/drivers/scsi/device_handler/scsi_dh.c
@@ -153,12 +153,24 @@ static int scsi_dh_handler_attach(struct scsi_device *sdev,
153 if (sdev->scsi_dh_data) { 153 if (sdev->scsi_dh_data) {
154 if (sdev->scsi_dh_data->scsi_dh != scsi_dh) 154 if (sdev->scsi_dh_data->scsi_dh != scsi_dh)
155 err = -EBUSY; 155 err = -EBUSY;
156 } else if (scsi_dh->attach) 156 else
157 kref_get(&sdev->scsi_dh_data->kref);
158 } else if (scsi_dh->attach) {
157 err = scsi_dh->attach(sdev); 159 err = scsi_dh->attach(sdev);
158 160 if (!err) {
161 kref_init(&sdev->scsi_dh_data->kref);
162 sdev->scsi_dh_data->sdev = sdev;
163 }
164 }
159 return err; 165 return err;
160} 166}
161 167
168static void __detach_handler (struct kref *kref)
169{
170 struct scsi_dh_data *scsi_dh_data = container_of(kref, struct scsi_dh_data, kref);
171 scsi_dh_data->scsi_dh->detach(scsi_dh_data->sdev);
172}
173
162/* 174/*
163 * scsi_dh_handler_detach - Detach a device handler from a device 175 * scsi_dh_handler_detach - Detach a device handler from a device
164 * @sdev - SCSI device the device handler should be detached from 176 * @sdev - SCSI device the device handler should be detached from
@@ -180,7 +192,7 @@ static void scsi_dh_handler_detach(struct scsi_device *sdev,
180 scsi_dh = sdev->scsi_dh_data->scsi_dh; 192 scsi_dh = sdev->scsi_dh_data->scsi_dh;
181 193
182 if (scsi_dh && scsi_dh->detach) 194 if (scsi_dh && scsi_dh->detach)
183 scsi_dh->detach(sdev); 195 kref_put(&sdev->scsi_dh_data->kref, __detach_handler);
184} 196}
185 197
186/* 198/*
@@ -474,7 +486,6 @@ int scsi_dh_attach(struct request_queue *q, const char *name)
474 486
475 if (!err) { 487 if (!err) {
476 err = scsi_dh_handler_attach(sdev, scsi_dh); 488 err = scsi_dh_handler_attach(sdev, scsi_dh);
477
478 put_device(&sdev->sdev_gendev); 489 put_device(&sdev->sdev_gendev);
479 } 490 }
480 return err; 491 return err;
@@ -505,10 +516,8 @@ void scsi_dh_detach(struct request_queue *q)
505 return; 516 return;
506 517
507 if (sdev->scsi_dh_data) { 518 if (sdev->scsi_dh_data) {
508 /* if sdev is not on internal list, detach */
509 scsi_dh = sdev->scsi_dh_data->scsi_dh; 519 scsi_dh = sdev->scsi_dh_data->scsi_dh;
510 if (!device_handler_match(scsi_dh, sdev)) 520 scsi_dh_handler_detach(sdev, scsi_dh);
511 scsi_dh_handler_detach(sdev, scsi_dh);
512 } 521 }
513 put_device(&sdev->sdev_gendev); 522 put_device(&sdev->sdev_gendev);
514} 523}