Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

+64 -40
+35 -39
drivers/scsi/scsi_scan.c
··· 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; ··· 421 406 starget->channel = channel; 422 407 INIT_LIST_HEAD(&starget->siblings); 423 408 INIT_LIST_HEAD(&starget->devices); 424 - starget->state = STARGET_RUNNING; 409 + starget->state = STARGET_CREATED; 425 410 starget->scsi_level = SCSI_2; 426 411 retry: 427 412 spin_lock_irqsave(shost->host_lock, flags); ··· 434 419 spin_unlock_irqrestore(shost->host_lock, flags); 435 420 /* allocate and add */ 436 421 transport_setup_device(dev); 437 - error = device_add(dev); 438 - if (error) { 439 - dev_err(dev, "target device_add failed, error %d\n", error); 440 - spin_lock_irqsave(shost->host_lock, flags); 441 - list_del_init(&starget->siblings); 442 - spin_unlock_irqrestore(shost->host_lock, flags); 443 - transport_destroy_device(dev); 444 - put_device(parent); 445 - kfree(starget); 446 - return NULL; 447 - } 448 - transport_add_device(dev); 449 422 if (shost->hostt->target_alloc) { 450 423 error = shost->hostt->target_alloc(starget); 451 424 ··· 441 438 dev_printk(KERN_ERR, dev, "target allocation failed, error %d\n", error); 442 439 /* don't want scsi_target_reap to do the final 443 440 * put because it will be under the host lock */ 444 - get_device(dev); 445 - scsi_target_reap(starget); 446 - put_device(dev); 441 + scsi_target_destroy(starget); 447 442 return NULL; 448 443 } 449 444 } ··· 468 467 { 469 468 struct scsi_target *starget = 470 469 container_of(work, struct scsi_target, ew.work); 471 - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); 472 - unsigned long flags; 473 470 474 471 transport_remove_device(&starget->dev); 475 472 device_del(&starget->dev); 476 - transport_destroy_device(&starget->dev); 477 - spin_lock_irqsave(shost->host_lock, flags); 478 - if (shost->hostt->target_destroy) 479 - shost->hostt->target_destroy(starget); 480 - list_del_init(&starget->siblings); 481 - spin_unlock_irqrestore(shost->host_lock, flags); 482 - put_device(&starget->dev); 473 + scsi_target_destroy(starget); 483 474 } 484 475 485 476 /** ··· 486 493 { 487 494 struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); 488 495 unsigned long flags; 496 + enum scsi_target_state state; 497 + int empty; 489 498 490 499 spin_lock_irqsave(shost->host_lock, flags); 491 - 492 - if (--starget->reap_ref == 0 && list_empty(&starget->devices)) { 493 - BUG_ON(starget->state == STARGET_DEL); 494 - starget->state = STARGET_DEL; 495 - spin_unlock_irqrestore(shost->host_lock, flags); 496 - execute_in_process_context(scsi_target_reap_usercontext, 497 - &starget->ew); 498 - return; 499 - 500 - } 500 + state = starget->state; 501 + empty = --starget->reap_ref == 0 && 502 + list_empty(&starget->devices) ? 1 : 0; 501 503 spin_unlock_irqrestore(shost->host_lock, flags); 502 504 503 - return; 505 + if (!empty) 506 + return; 507 + 508 + BUG_ON(state == STARGET_DEL); 509 + starget->state = STARGET_DEL; 510 + if (state == STARGET_CREATED) 511 + scsi_target_destroy(starget); 512 + else 513 + execute_in_process_context(scsi_target_reap_usercontext, 514 + &starget->ew); 504 515 } 505 516 506 517 /** ··· 1053 1056 scsi_inq_str(vend, result, 8, 16), 1054 1057 scsi_inq_str(mod, result, 16, 32)); 1055 1058 }); 1059 + 1056 1060 } 1057 - 1061 + 1058 1062 res = SCSI_SCAN_TARGET_PRESENT; 1059 1063 goto out_free_result; 1060 1064 } ··· 1495 1497 if (scsi_host_scan_allowed(shost)) 1496 1498 scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata); 1497 1499 mutex_unlock(&shost->scan_mutex); 1498 - transport_configure_device(&starget->dev); 1499 1500 scsi_target_reap(starget); 1500 1501 put_device(&starget->dev); 1501 1502 ··· 1575 1578 out_reap: 1576 1579 /* now determine if the target has any children at all 1577 1580 * and if not, nuke it */ 1578 - transport_configure_device(&starget->dev); 1579 1581 scsi_target_reap(starget); 1580 1582 1581 1583 put_device(&starget->dev);
+27
drivers/scsi/scsi_sysfs.c
··· 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); ··· 845 824 { 846 825 int error, i; 847 826 struct request_queue *rq = sdev->request_queue; 827 + struct scsi_target *starget = sdev->sdev_target; 848 828 849 829 if ((error = scsi_device_set_state(sdev, SDEV_RUNNING)) != 0) 850 830 return error; 851 831 832 + error = scsi_target_add(starget); 833 + if (error) 834 + return error; 835 + 836 + transport_configure_device(&starget->dev); 852 837 error = device_add(&sdev->sdev_gendev); 853 838 if (error) { 854 839 put_device(sdev->sdev_gendev.parent);
+2 -1
include/scsi/scsi_device.h
··· 181 181 sdev_printk(prefix, (scmd)->device, fmt, ##a) 182 182 183 183 enum scsi_target_state { 184 - STARGET_RUNNING = 1, 184 + STARGET_CREATED = 1, 185 + STARGET_RUNNING, 185 186 STARGET_DEL, 186 187 }; 187 188