Skip to content

Commit

Permalink
[SCSI] scsi_dh: Reference count scsi_dh_attach
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Chandra Seetharaman authored and James Bottomley committed Aug 22, 2009
1 parent b4567ca commit 6c10db7
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 7 deletions.
23 changes: 16 additions & 7 deletions drivers/scsi/device_handler/scsi_dh.c
Original file line number Diff line number Diff line change
Expand Up @@ -153,12 +153,24 @@ static int scsi_dh_handler_attach(struct scsi_device *sdev,
if (sdev->scsi_dh_data) {
if (sdev->scsi_dh_data->scsi_dh != scsi_dh)
err = -EBUSY;
} else if (scsi_dh->attach)
else
kref_get(&sdev->scsi_dh_data->kref);
} else if (scsi_dh->attach) {
err = scsi_dh->attach(sdev);

if (!err) {
kref_init(&sdev->scsi_dh_data->kref);
sdev->scsi_dh_data->sdev = sdev;
}
}
return err;
}

static void __detach_handler (struct kref *kref)
{
struct scsi_dh_data *scsi_dh_data = container_of(kref, struct scsi_dh_data, kref);
scsi_dh_data->scsi_dh->detach(scsi_dh_data->sdev);
}

/*
* scsi_dh_handler_detach - Detach a device handler from a device
* @sdev - SCSI device the device handler should be detached from
Expand All @@ -180,7 +192,7 @@ static void scsi_dh_handler_detach(struct scsi_device *sdev,
scsi_dh = sdev->scsi_dh_data->scsi_dh;

if (scsi_dh && scsi_dh->detach)
scsi_dh->detach(sdev);
kref_put(&sdev->scsi_dh_data->kref, __detach_handler);
}

/*
Expand Down Expand Up @@ -474,7 +486,6 @@ int scsi_dh_attach(struct request_queue *q, const char *name)

if (!err) {
err = scsi_dh_handler_attach(sdev, scsi_dh);

put_device(&sdev->sdev_gendev);
}
return err;
Expand Down Expand Up @@ -505,10 +516,8 @@ void scsi_dh_detach(struct request_queue *q)
return;

if (sdev->scsi_dh_data) {
/* if sdev is not on internal list, detach */
scsi_dh = sdev->scsi_dh_data->scsi_dh;
if (!device_handler_match(scsi_dh, sdev))
scsi_dh_handler_detach(sdev, scsi_dh);
scsi_dh_handler_detach(sdev, scsi_dh);
}
put_device(&sdev->sdev_gendev);
}
Expand Down
2 changes: 2 additions & 0 deletions include/scsi/scsi_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,8 @@ struct scsi_device_handler {

struct scsi_dh_data {
struct scsi_device_handler *scsi_dh;
struct scsi_device *sdev;
struct kref kref;
char buf[0];
};

Expand Down

0 comments on commit 6c10db7

Please sign in to comment.