aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/firewire/fw-sbp2.c56
1 files changed, 30 insertions, 26 deletions
diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c
index c2169d215bf7..2108cd92451b 100644
--- a/drivers/firewire/fw-sbp2.c
+++ b/drivers/firewire/fw-sbp2.c
@@ -628,6 +628,21 @@ static void sbp2_release_target(struct kref *kref)
628 628
629static struct workqueue_struct *sbp2_wq; 629static struct workqueue_struct *sbp2_wq;
630 630
631/*
632 * Always get the target's kref when scheduling work on one its units.
633 * Each workqueue job is responsible to call sbp2_target_put() upon return.
634 */
635static void sbp2_queue_work(struct sbp2_logical_unit *lu, unsigned long delay)
636{
637 if (queue_delayed_work(sbp2_wq, &lu->work, delay))
638 kref_get(&lu->tgt->kref);
639}
640
641static void sbp2_target_put(struct sbp2_target *tgt)
642{
643 kref_put(&tgt->kref, sbp2_release_target);
644}
645
631static void sbp2_reconnect(struct work_struct *work); 646static void sbp2_reconnect(struct work_struct *work);
632 647
633static void sbp2_login(struct work_struct *work) 648static void sbp2_login(struct work_struct *work)
@@ -649,16 +664,12 @@ static void sbp2_login(struct work_struct *work)
649 664
650 if (sbp2_send_management_orb(lu, node_id, generation, 665 if (sbp2_send_management_orb(lu, node_id, generation,
651 SBP2_LOGIN_REQUEST, lu->lun, &response) < 0) { 666 SBP2_LOGIN_REQUEST, lu->lun, &response) < 0) {
652 if (lu->retries++ < 5) { 667 if (lu->retries++ < 5)
653 if (queue_delayed_work(sbp2_wq, &lu->work, 668 sbp2_queue_work(lu, DIV_ROUND_UP(HZ, 5));
654 DIV_ROUND_UP(HZ, 5))) 669 else
655 kref_get(&lu->tgt->kref);
656 } else {
657 fw_error("failed to login to %s LUN %04x\n", 670 fw_error("failed to login to %s LUN %04x\n",
658 unit->device.bus_id, lu->lun); 671 unit->device.bus_id, lu->lun);
659 } 672 goto out;
660 kref_put(&lu->tgt->kref, sbp2_release_target);
661 return;
662 } 673 }
663 674
664 lu->generation = generation; 675 lu->generation = generation;
@@ -700,7 +711,8 @@ static void sbp2_login(struct work_struct *work)
700 lu->sdev = sdev; 711 lu->sdev = sdev;
701 scsi_device_put(sdev); 712 scsi_device_put(sdev);
702 } 713 }
703 kref_put(&lu->tgt->kref, sbp2_release_target); 714 out:
715 sbp2_target_put(lu->tgt);
704} 716}
705 717
706static int sbp2_add_logical_unit(struct sbp2_target *tgt, int lun_entry) 718static int sbp2_add_logical_unit(struct sbp2_target *tgt, int lun_entry)
@@ -865,18 +877,13 @@ static int sbp2_probe(struct device *dev)
865 877
866 get_device(&unit->device); 878 get_device(&unit->device);
867 879
868 /* 880 /* Do the login in a workqueue so we can easily reschedule retries. */
869 * We schedule work to do the login so we can easily
870 * reschedule retries. Always get the ref before scheduling
871 * work.
872 */
873 list_for_each_entry(lu, &tgt->lu_list, link) 881 list_for_each_entry(lu, &tgt->lu_list, link)
874 if (queue_delayed_work(sbp2_wq, &lu->work, 0)) 882 sbp2_queue_work(lu, 0);
875 kref_get(&tgt->kref);
876 return 0; 883 return 0;
877 884
878 fail_tgt_put: 885 fail_tgt_put:
879 kref_put(&tgt->kref, sbp2_release_target); 886 sbp2_target_put(tgt);
880 return -ENOMEM; 887 return -ENOMEM;
881 888
882 fail_shost_put: 889 fail_shost_put:
@@ -889,7 +896,7 @@ static int sbp2_remove(struct device *dev)
889 struct fw_unit *unit = fw_unit(dev); 896 struct fw_unit *unit = fw_unit(dev);
890 struct sbp2_target *tgt = unit->device.driver_data; 897 struct sbp2_target *tgt = unit->device.driver_data;
891 898
892 kref_put(&tgt->kref, sbp2_release_target); 899 sbp2_target_put(tgt);
893 return 0; 900 return 0;
894} 901}
895 902
@@ -915,10 +922,8 @@ static void sbp2_reconnect(struct work_struct *work)
915 lu->retries = 0; 922 lu->retries = 0;
916 PREPARE_DELAYED_WORK(&lu->work, sbp2_login); 923 PREPARE_DELAYED_WORK(&lu->work, sbp2_login);
917 } 924 }
918 if (queue_delayed_work(sbp2_wq, &lu->work, DIV_ROUND_UP(HZ, 5))) 925 sbp2_queue_work(lu, DIV_ROUND_UP(HZ, 5));
919 kref_get(&lu->tgt->kref); 926 goto out;
920 kref_put(&lu->tgt->kref, sbp2_release_target);
921 return;
922 } 927 }
923 928
924 lu->generation = generation; 929 lu->generation = generation;
@@ -930,8 +935,8 @@ static void sbp2_reconnect(struct work_struct *work)
930 935
931 sbp2_agent_reset(lu); 936 sbp2_agent_reset(lu);
932 sbp2_cancel_orbs(lu); 937 sbp2_cancel_orbs(lu);
933 938 out:
934 kref_put(&lu->tgt->kref, sbp2_release_target); 939 sbp2_target_put(lu->tgt);
935} 940}
936 941
937static void sbp2_update(struct fw_unit *unit) 942static void sbp2_update(struct fw_unit *unit)
@@ -947,8 +952,7 @@ static void sbp2_update(struct fw_unit *unit)
947 */ 952 */
948 list_for_each_entry(lu, &tgt->lu_list, link) { 953 list_for_each_entry(lu, &tgt->lu_list, link) {
949 lu->retries = 0; 954 lu->retries = 0;
950 if (queue_delayed_work(sbp2_wq, &lu->work, 0)) 955 sbp2_queue_work(lu, 0);
951 kref_get(&tgt->kref);
952 } 956 }
953} 957}
954 958