aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorKristian Høgsberg <krh@redhat.com>2007-03-14 17:34:58 -0400
committerStefan Richter <stefanr@s5r6.in-berlin.de>2007-03-15 13:27:40 -0400
commitb3d6e151142c6d22abdf1e3e7bde0f6d828df945 (patch)
treeb3a53c81b0ed144c589d25d92bf2754d51e6b623 /drivers
parent7e35f7f318168f1b735abc87754108c06955f50d (diff)
firewire: Add ref-counting for sbp2_device and hold a ref while we have work scheduled.
Signed-off-by: Kristian Høgsberg <krh@redhat.com> Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/firewire/fw-sbp2.c42
1 files changed, 30 insertions, 12 deletions
diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c
index 0c87724cec3f..d7940db30a5b 100644
--- a/drivers/firewire/fw-sbp2.c
+++ b/drivers/firewire/fw-sbp2.c
@@ -51,6 +51,7 @@ typedef void (*scsi_done_fn_t) (struct scsi_cmnd *);
51static const char sbp2_driver_name[] = "sbp2"; 51static const char sbp2_driver_name[] = "sbp2";
52 52
53struct sbp2_device { 53struct sbp2_device {
54 struct kref kref;
54 struct fw_unit *unit; 55 struct fw_unit *unit;
55 struct fw_address_handler address_handler; 56 struct fw_address_handler address_handler;
56 struct list_head orb_list; 57 struct list_head orb_list;
@@ -513,6 +514,22 @@ static int add_scsi_devices(struct fw_unit *unit);
513static void remove_scsi_devices(struct fw_unit *unit); 514static void remove_scsi_devices(struct fw_unit *unit);
514static void sbp2_reconnect(struct work_struct *work); 515static void sbp2_reconnect(struct work_struct *work);
515 516
517static void
518release_sbp2_device(struct kref *kref)
519{
520 struct sbp2_device *sd = container_of(kref, struct sbp2_device, kref);
521
522 sbp2_send_management_orb(sd->unit, sd->node_id, sd->generation,
523 SBP2_LOGOUT_REQUEST, sd->login_id, NULL);
524
525 remove_scsi_devices(sd->unit);
526
527 fw_core_remove_address_handler(&sd->address_handler);
528 fw_notify("removed sbp2 unit %s\n", sd->unit->device.bus_id);
529 put_device(&sd->unit->device);
530 kfree(sd);
531}
532
516static void sbp2_login(struct work_struct *work) 533static void sbp2_login(struct work_struct *work)
517{ 534{
518 struct sbp2_device *sd = 535 struct sbp2_device *sd =
@@ -537,6 +554,7 @@ static void sbp2_login(struct work_struct *work)
537 fw_error("failed to login to %s\n", 554 fw_error("failed to login to %s\n",
538 unit->device.bus_id); 555 unit->device.bus_id);
539 remove_scsi_devices(unit); 556 remove_scsi_devices(unit);
557 kref_put(&sd->kref, release_sbp2_device);
540 } 558 }
541 return; 559 return;
542 } 560 }
@@ -577,6 +595,7 @@ static void sbp2_login(struct work_struct *work)
577 * retry login on bus reset. */ 595 * retry login on bus reset. */
578 PREPARE_DELAYED_WORK(&sd->work, sbp2_login); 596 PREPARE_DELAYED_WORK(&sd->work, sbp2_login);
579 } 597 }
598 kref_put(&sd->kref, release_sbp2_device);
580} 599}
581 600
582static int sbp2_probe(struct device *dev) 601static int sbp2_probe(struct device *dev)
@@ -595,6 +614,7 @@ static int sbp2_probe(struct device *dev)
595 unit->device.driver_data = sd; 614 unit->device.driver_data = sd;
596 sd->unit = unit; 615 sd->unit = unit;
597 INIT_LIST_HEAD(&sd->orb_list); 616 INIT_LIST_HEAD(&sd->orb_list);
617 kref_init(&sd->kref);
598 618
599 sd->address_handler.length = 0x100; 619 sd->address_handler.length = 0x100;
600 sd->address_handler.address_callback = sbp2_status_write; 620 sd->address_handler.address_callback = sbp2_status_write;
@@ -650,10 +670,14 @@ static int sbp2_probe(struct device *dev)
650 unit->device.bus_id, 670 unit->device.bus_id,
651 sd->workarounds, firmware_revision, model); 671 sd->workarounds, firmware_revision, model);
652 672
673 get_device(&unit->device);
674
653 /* We schedule work to do the login so we can easily 675 /* We schedule work to do the login so we can easily
654 * reschedule retries. */ 676 * reschedule retries. Always get the ref before scheduling
677 * work.*/
655 INIT_DELAYED_WORK(&sd->work, sbp2_login); 678 INIT_DELAYED_WORK(&sd->work, sbp2_login);
656 schedule_delayed_work(&sd->work, 0); 679 if (schedule_delayed_work(&sd->work, 0))
680 kref_get(&sd->kref);
657 681
658 return 0; 682 return 0;
659} 683}
@@ -663,15 +687,7 @@ static int sbp2_remove(struct device *dev)
663 struct fw_unit *unit = fw_unit(dev); 687 struct fw_unit *unit = fw_unit(dev);
664 struct sbp2_device *sd = unit->device.driver_data; 688 struct sbp2_device *sd = unit->device.driver_data;
665 689
666 sbp2_send_management_orb(unit, sd->node_id, sd->generation, 690 kref_put(&sd->kref, release_sbp2_device);
667 SBP2_LOGOUT_REQUEST, sd->login_id, NULL);
668
669 remove_scsi_devices(unit);
670
671 fw_core_remove_address_handler(&sd->address_handler);
672 kfree(sd);
673
674 fw_notify("removed sbp2 unit %s\n", dev->bus_id);
675 691
676 return 0; 692 return 0;
677} 693}
@@ -710,6 +726,7 @@ static void sbp2_reconnect(struct work_struct *work)
710 unit->device.bus_id, sd->retries); 726 unit->device.bus_id, sd->retries);
711 sbp2_agent_reset(unit); 727 sbp2_agent_reset(unit);
712 sbp2_cancel_orbs(unit); 728 sbp2_cancel_orbs(unit);
729 kref_put(&sd->kref, release_sbp2_device);
713} 730}
714 731
715static void sbp2_update(struct fw_unit *unit) 732static void sbp2_update(struct fw_unit *unit)
@@ -719,7 +736,8 @@ static void sbp2_update(struct fw_unit *unit)
719 736
720 sd->retries = 0; 737 sd->retries = 0;
721 fw_device_enable_phys_dma(device); 738 fw_device_enable_phys_dma(device);
722 schedule_delayed_work(&sd->work, 0); 739 if (schedule_delayed_work(&sd->work, 0))
740 kref_get(&sd->kref);
723} 741}
724 742
725#define SBP2_UNIT_SPEC_ID_ENTRY 0x0000609e 743#define SBP2_UNIT_SPEC_ID_ENTRY 0x0000609e