diff options
Diffstat (limited to 'drivers/firewire')
-rw-r--r-- | drivers/firewire/fw-sbp2.c | 56 |
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 | ||
629 | static struct workqueue_struct *sbp2_wq; | 629 | static 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 | */ | ||
635 | static 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 | |||
641 | static void sbp2_target_put(struct sbp2_target *tgt) | ||
642 | { | ||
643 | kref_put(&tgt->kref, sbp2_release_target); | ||
644 | } | ||
645 | |||
631 | static void sbp2_reconnect(struct work_struct *work); | 646 | static void sbp2_reconnect(struct work_struct *work); |
632 | 647 | ||
633 | static void sbp2_login(struct work_struct *work) | 648 | static 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 | ||
706 | static int sbp2_add_logical_unit(struct sbp2_target *tgt, int lun_entry) | 718 | static 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 | ||
937 | static void sbp2_update(struct fw_unit *unit) | 942 | static 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 | ||