Commit ae11b1b36da726a8a93409b896704edc6b4f3402

Authored by Hannes Reinecke
Committed by James Bottomley
1 parent 057ea7c968

[SCSI] scsi_dh: attach to hardware handler from dm-mpath

multipath keeps a separate device table which may be
more current than the built-in one.
So we should make sure to always call ->attach whenever
a multipath map with hardware handler is instantiated.
And we should call ->detach on removal, too.

[sekharan: update as per comments from agk]
Signed-off-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Chandra Seetharaman <sekharan@us.ibm.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>

Showing 3 changed files with 87 additions and 0 deletions Side-by-side Diff

drivers/md/dm-mpath.c
... ... @@ -147,9 +147,12 @@
147 147 static void free_pgpaths(struct list_head *pgpaths, struct dm_target *ti)
148 148 {
149 149 struct pgpath *pgpath, *tmp;
  150 + struct multipath *m = ti->private;
150 151  
151 152 list_for_each_entry_safe(pgpath, tmp, pgpaths, list) {
152 153 list_del(&pgpath->list);
  154 + if (m->hw_handler_name)
  155 + scsi_dh_detach(bdev_get_queue(pgpath->path.dev->bdev));
153 156 dm_put_device(ti, pgpath->path.dev);
154 157 free_pgpath(pgpath);
155 158 }
... ... @@ -548,6 +551,7 @@
548 551 {
549 552 int r;
550 553 struct pgpath *p;
  554 + struct multipath *m = ti->private;
551 555  
552 556 /* we need at least a path arg */
553 557 if (as->argc < 1) {
... ... @@ -564,6 +568,15 @@
564 568 if (r) {
565 569 ti->error = "error getting device";
566 570 goto bad;
  571 + }
  572 +
  573 + if (m->hw_handler_name) {
  574 + r = scsi_dh_attach(bdev_get_queue(p->path.dev->bdev),
  575 + m->hw_handler_name);
  576 + if (r < 0) {
  577 + dm_put_device(ti, p->path.dev);
  578 + goto bad;
  579 + }
567 580 }
568 581  
569 582 r = ps->type->add_path(ps, &p->path, as->argc, as->argv, &ti->error);
drivers/scsi/device_handler/scsi_dh.c
... ... @@ -369,6 +369,70 @@
369 369 }
370 370 EXPORT_SYMBOL_GPL(scsi_dh_handler_exist);
371 371  
  372 +/*
  373 + * scsi_dh_handler_attach - Attach device handler
  374 + * @sdev - sdev the handler should be attached to
  375 + * @name - name of the handler to attach
  376 + */
  377 +int scsi_dh_attach(struct request_queue *q, const char *name)
  378 +{
  379 + unsigned long flags;
  380 + struct scsi_device *sdev;
  381 + struct scsi_device_handler *scsi_dh;
  382 + int err = 0;
  383 +
  384 + scsi_dh = get_device_handler(name);
  385 + if (!scsi_dh)
  386 + return -EINVAL;
  387 +
  388 + spin_lock_irqsave(q->queue_lock, flags);
  389 + sdev = q->queuedata;
  390 + if (!sdev || !get_device(&sdev->sdev_gendev))
  391 + err = -ENODEV;
  392 + spin_unlock_irqrestore(q->queue_lock, flags);
  393 +
  394 + if (!err) {
  395 + err = scsi_dh_handler_attach(sdev, scsi_dh);
  396 +
  397 + put_device(&sdev->sdev_gendev);
  398 + }
  399 + return err;
  400 +}
  401 +EXPORT_SYMBOL_GPL(scsi_dh_attach);
  402 +
  403 +/*
  404 + * scsi_dh_handler_detach - Detach device handler
  405 + * @sdev - sdev the handler should be detached from
  406 + *
  407 + * This function will detach the device handler only
  408 + * if the sdev is not part of the internal list, ie
  409 + * if it has been attached manually.
  410 + */
  411 +void scsi_dh_detach(struct request_queue *q)
  412 +{
  413 + unsigned long flags;
  414 + struct scsi_device *sdev;
  415 + struct scsi_device_handler *scsi_dh = NULL;
  416 +
  417 + spin_lock_irqsave(q->queue_lock, flags);
  418 + sdev = q->queuedata;
  419 + if (!sdev || !get_device(&sdev->sdev_gendev))
  420 + sdev = NULL;
  421 + spin_unlock_irqrestore(q->queue_lock, flags);
  422 +
  423 + if (!sdev)
  424 + return;
  425 +
  426 + if (sdev->scsi_dh_data) {
  427 + /* if sdev is not on internal list, detach */
  428 + scsi_dh = sdev->scsi_dh_data->scsi_dh;
  429 + if (!device_handler_match(scsi_dh, sdev))
  430 + scsi_dh_handler_detach(sdev, scsi_dh);
  431 + }
  432 + put_device(&sdev->sdev_gendev);
  433 +}
  434 +EXPORT_SYMBOL_GPL(scsi_dh_detach);
  435 +
372 436 static struct notifier_block scsi_dh_nb = {
373 437 .notifier_call = scsi_dh_notifier
374 438 };
include/scsi/scsi_dh.h
... ... @@ -58,6 +58,8 @@
58 58 #if defined(CONFIG_SCSI_DH) || defined(CONFIG_SCSI_DH_MODULE)
59 59 extern int scsi_dh_activate(struct request_queue *);
60 60 extern int scsi_dh_handler_exist(const char *);
  61 +extern int scsi_dh_attach(struct request_queue *, const char *);
  62 +extern void scsi_dh_detach(struct request_queue *);
61 63 #else
62 64 static inline int scsi_dh_activate(struct request_queue *req)
63 65 {
... ... @@ -66,6 +68,14 @@
66 68 static inline int scsi_dh_handler_exist(const char *name)
67 69 {
68 70 return 0;
  71 +}
  72 +static inline int scsi_dh_attach(struct request_queue *req, const char *name)
  73 +{
  74 + return SCSI_DH_NOSYS;
  75 +}
  76 +static inline void scsi_dh_detach(struct request_queue *q)
  77 +{
  78 + return;
69 79 }
70 80 #endif