@@ -571,6 +571,8 @@ static struct pgpath *parse_path(struct arg_set *as, struct path_selector *ps,
struct dm_target *ti)
{
int r;
+ char *hw_handler_name;
+ struct request_queue *q;
struct pgpath *p;
struct multipath *m = ti->private;
@@ -591,9 +593,23 @@ static struct pgpath *parse_path(struct arg_set *as, struct path_selector *ps,
goto bad;
}
- if (m->hw_handler_name) {
- r = scsi_dh_attach(bdev_get_queue(p->path.dev->bdev),
- m->hw_handler_name);
+
+ q = bdev_get_queue(p->path.dev->bdev);
+ hw_handler_name = scsi_dh_get_attached_name(q);
+ if (hw_handler_name) {
+ if (!m->hw_handler_name)
+ m->hw_handler_name = hw_handler_name;
+ else if (strcmp(hw_handler_name, m->hw_handler_name)) {
+ /*
+ * if there is a mismatch, then assume
+ * the scsi layer knew best.
+ */
+ kfree(m->hw_handler_name);
+ m->hw_handler_name = hw_handler_name;
+ } else
+ kfree(hw_handler_name);
+ } else if (m->hw_handler_name) {
+ r = scsi_dh_attach(q, m->hw_handler_name);
if (r < 0) {
dm_put_device(ti, p->path.dev);
goto bad;
@@ -481,6 +481,28 @@ int scsi_dh_attach(struct request_queue *q, const char *name)
}
EXPORT_SYMBOL_GPL(scsi_dh_attach);
+/**
+ * scsi_dh_get_attached_name
+ * @q: request queue to test
+ *
+ * Return name of scsi_dh module if attached. Caller must
+ * free returned string.
+ */
+char *scsi_dh_get_attached_name(struct request_queue *q)
+{
+ struct scsi_device *sdev;
+ unsigned long flags;
+ char *attached = NULL;
+
+ spin_lock_irqsave(q->queue_lock, flags);
+ sdev = q->queuedata;
+ if (sdev && sdev->scsi_dh_data)
+ attached = kstrdup(sdev->scsi_dh_data->scsi_dh->name,
+ GFP_ATOMIC);
+ spin_unlock_irqrestore(q->queue_lock, flags);
+ return attached;
+}
+
/*
* scsi_dh_handler_detach - Detach device handler
* @sdev - sdev the handler should be detached from
@@ -60,6 +60,7 @@ extern int scsi_dh_activate(struct request_queue *);
extern int scsi_dh_handler_exist(const char *);
extern int scsi_dh_attach(struct request_queue *, const char *);
extern void scsi_dh_detach(struct request_queue *);
+extern char *scsi_dh_get_attached_name(struct request_queue *);
#else
static inline int scsi_dh_activate(struct request_queue *req)
{
@@ -77,4 +78,9 @@ static inline void scsi_dh_detach(struct request_queue *q)
{
return;
}
+
+extern char *scsi_dh_get_attached_name(struct request_queue *q)
+{
+ return NULL;
+}
#endif