Commit 643eb2d932c97a0583381629d632d486934cf7ee
1 parent
f7120a4f75
Exists in
master
and in
4 other branches
[SCSI] rework scsi_target allocation
The current target allocation code registeres each possible target with sysfs; it will be deleted again if no useable LUN on this target was found. This results in a string of 'target add/target remove' uevents. Based on a patch by Hannes Reinecke <hare@suse.de> this patch reworks the target allocation code so that only uevents for existing targets are sent. The sysfs registration is split off from the existing scsi_target_alloc() into a in a new scsi_add_target() function, which should be called whenever an existing target is found. Only then a uevent is sent, so we'll be generating events for existing targets only. Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Showing 3 changed files with 63 additions and 39 deletions Side-by-side Diff
drivers/scsi/scsi_scan.c
... | ... | @@ -322,6 +322,21 @@ |
322 | 322 | return NULL; |
323 | 323 | } |
324 | 324 | |
325 | +static void scsi_target_destroy(struct scsi_target *starget) | |
326 | +{ | |
327 | + struct device *dev = &starget->dev; | |
328 | + struct Scsi_Host *shost = dev_to_shost(dev->parent); | |
329 | + unsigned long flags; | |
330 | + | |
331 | + transport_destroy_device(dev); | |
332 | + spin_lock_irqsave(shost->host_lock, flags); | |
333 | + if (shost->hostt->target_destroy) | |
334 | + shost->hostt->target_destroy(starget); | |
335 | + list_del_init(&starget->siblings); | |
336 | + spin_unlock_irqrestore(shost->host_lock, flags); | |
337 | + put_device(dev); | |
338 | +} | |
339 | + | |
325 | 340 | static void scsi_target_dev_release(struct device *dev) |
326 | 341 | { |
327 | 342 | struct device *parent = dev->parent; |
... | ... | @@ -406,7 +421,7 @@ |
406 | 421 | starget->channel = channel; |
407 | 422 | INIT_LIST_HEAD(&starget->siblings); |
408 | 423 | INIT_LIST_HEAD(&starget->devices); |
409 | - starget->state = STARGET_RUNNING; | |
424 | + starget->state = STARGET_CREATED; | |
410 | 425 | starget->scsi_level = SCSI_2; |
411 | 426 | retry: |
412 | 427 | spin_lock_irqsave(shost->host_lock, flags); |
... | ... | @@ -419,18 +434,6 @@ |
419 | 434 | spin_unlock_irqrestore(shost->host_lock, flags); |
420 | 435 | /* allocate and add */ |
421 | 436 | transport_setup_device(dev); |
422 | - error = device_add(dev); | |
423 | - if (error) { | |
424 | - dev_err(dev, "target device_add failed, error %d\n", error); | |
425 | - spin_lock_irqsave(shost->host_lock, flags); | |
426 | - list_del_init(&starget->siblings); | |
427 | - spin_unlock_irqrestore(shost->host_lock, flags); | |
428 | - transport_destroy_device(dev); | |
429 | - put_device(parent); | |
430 | - kfree(starget); | |
431 | - return NULL; | |
432 | - } | |
433 | - transport_add_device(dev); | |
434 | 437 | if (shost->hostt->target_alloc) { |
435 | 438 | error = shost->hostt->target_alloc(starget); |
436 | 439 | |
... | ... | @@ -438,9 +441,7 @@ |
438 | 441 | dev_printk(KERN_ERR, dev, "target allocation failed, error %d\n", error); |
439 | 442 | /* don't want scsi_target_reap to do the final |
440 | 443 | * put because it will be under the host lock */ |
441 | - get_device(dev); | |
442 | - scsi_target_reap(starget); | |
443 | - put_device(dev); | |
444 | + scsi_target_destroy(starget); | |
444 | 445 | return NULL; |
445 | 446 | } |
446 | 447 | } |
447 | 448 | |
... | ... | @@ -467,18 +468,10 @@ |
467 | 468 | { |
468 | 469 | struct scsi_target *starget = |
469 | 470 | container_of(work, struct scsi_target, ew.work); |
470 | - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); | |
471 | - unsigned long flags; | |
472 | 471 | |
473 | 472 | transport_remove_device(&starget->dev); |
474 | 473 | device_del(&starget->dev); |
475 | - transport_destroy_device(&starget->dev); | |
476 | - spin_lock_irqsave(shost->host_lock, flags); | |
477 | - if (shost->hostt->target_destroy) | |
478 | - shost->hostt->target_destroy(starget); | |
479 | - list_del_init(&starget->siblings); | |
480 | - spin_unlock_irqrestore(shost->host_lock, flags); | |
481 | - put_device(&starget->dev); | |
474 | + scsi_target_destroy(starget); | |
482 | 475 | } |
483 | 476 | |
484 | 477 | /** |
485 | 478 | |
486 | 479 | |
487 | 480 | |
... | ... | @@ -493,21 +486,25 @@ |
493 | 486 | { |
494 | 487 | struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); |
495 | 488 | unsigned long flags; |
489 | + enum scsi_target_state state; | |
490 | + int empty; | |
496 | 491 | |
497 | 492 | spin_lock_irqsave(shost->host_lock, flags); |
493 | + state = starget->state; | |
494 | + empty = --starget->reap_ref == 0 && | |
495 | + list_empty(&starget->devices) ? 1 : 0; | |
496 | + spin_unlock_irqrestore(shost->host_lock, flags); | |
498 | 497 | |
499 | - if (--starget->reap_ref == 0 && list_empty(&starget->devices)) { | |
500 | - BUG_ON(starget->state == STARGET_DEL); | |
501 | - starget->state = STARGET_DEL; | |
502 | - spin_unlock_irqrestore(shost->host_lock, flags); | |
503 | - execute_in_process_context(scsi_target_reap_usercontext, | |
504 | - &starget->ew); | |
498 | + if (!empty) | |
505 | 499 | return; |
506 | 500 | |
507 | - } | |
508 | - spin_unlock_irqrestore(shost->host_lock, flags); | |
509 | - | |
510 | - return; | |
501 | + BUG_ON(state == STARGET_DEL); | |
502 | + starget->state = STARGET_DEL; | |
503 | + if (state == STARGET_CREATED) | |
504 | + scsi_target_destroy(starget); | |
505 | + else | |
506 | + execute_in_process_context(scsi_target_reap_usercontext, | |
507 | + &starget->ew); | |
511 | 508 | } |
512 | 509 | |
513 | 510 | /** |
514 | 511 | |
... | ... | @@ -1056,8 +1053,9 @@ |
1056 | 1053 | scsi_inq_str(vend, result, 8, 16), |
1057 | 1054 | scsi_inq_str(mod, result, 16, 32)); |
1058 | 1055 | }); |
1056 | + | |
1059 | 1057 | } |
1060 | - | |
1058 | + | |
1061 | 1059 | res = SCSI_SCAN_TARGET_PRESENT; |
1062 | 1060 | goto out_free_result; |
1063 | 1061 | } |
... | ... | @@ -1497,7 +1495,6 @@ |
1497 | 1495 | if (scsi_host_scan_allowed(shost)) |
1498 | 1496 | scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata); |
1499 | 1497 | mutex_unlock(&shost->scan_mutex); |
1500 | - transport_configure_device(&starget->dev); | |
1501 | 1498 | scsi_target_reap(starget); |
1502 | 1499 | put_device(&starget->dev); |
1503 | 1500 | |
... | ... | @@ -1578,7 +1575,6 @@ |
1578 | 1575 | out_reap: |
1579 | 1576 | /* now determine if the target has any children at all |
1580 | 1577 | * and if not, nuke it */ |
1581 | - transport_configure_device(&starget->dev); | |
1582 | 1578 | scsi_target_reap(starget); |
1583 | 1579 | |
1584 | 1580 | put_device(&starget->dev); |
drivers/scsi/scsi_sysfs.c
... | ... | @@ -809,6 +809,27 @@ |
809 | 809 | return count; |
810 | 810 | } |
811 | 811 | |
812 | +static int scsi_target_add(struct scsi_target *starget) | |
813 | +{ | |
814 | + int error; | |
815 | + | |
816 | + if (starget->state != STARGET_CREATED) | |
817 | + return 0; | |
818 | + | |
819 | + error = device_add(&starget->dev); | |
820 | + if (error) { | |
821 | + dev_err(&starget->dev, "target device_add failed, error %d\n", error); | |
822 | + get_device(&starget->dev); | |
823 | + scsi_target_reap(starget); | |
824 | + put_device(&starget->dev); | |
825 | + return error; | |
826 | + } | |
827 | + transport_add_device(&starget->dev); | |
828 | + starget->state = STARGET_RUNNING; | |
829 | + | |
830 | + return 0; | |
831 | +} | |
832 | + | |
812 | 833 | static struct device_attribute sdev_attr_queue_type_rw = |
813 | 834 | __ATTR(queue_type, S_IRUGO | S_IWUSR, show_queue_type_field, |
814 | 835 | sdev_store_queue_type_rw); |
815 | 836 | |
... | ... | @@ -824,10 +845,16 @@ |
824 | 845 | { |
825 | 846 | int error, i; |
826 | 847 | struct request_queue *rq = sdev->request_queue; |
848 | + struct scsi_target *starget = sdev->sdev_target; | |
827 | 849 | |
828 | 850 | if ((error = scsi_device_set_state(sdev, SDEV_RUNNING)) != 0) |
829 | 851 | return error; |
830 | 852 | |
853 | + error = scsi_target_add(starget); | |
854 | + if (error) | |
855 | + return error; | |
856 | + | |
857 | + transport_configure_device(&starget->dev); | |
831 | 858 | error = device_add(&sdev->sdev_gendev); |
832 | 859 | if (error) { |
833 | 860 | put_device(sdev->sdev_gendev.parent); |
include/scsi/scsi_device.h