aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorStefan Richter <stefanr@s5r6.in-berlin.de>2008-02-26 17:30:02 -0500
committerStefan Richter <stefanr@s5r6.in-berlin.de>2008-03-02 06:35:46 -0500
commitf8436158b1d76e6842856048f287799468b56eb2 (patch)
tree45f1b707668819b83fee5a8d82a7c5333b989f0f /drivers
parentd395991c117d43bfca97101a931a41d062a93852 (diff)
firewire: fw-sbp2: better fix for NULL pointer dereference in scsi_remove_device
Patch "firewire: fw-sbp2: fix NULL pointer deref. in scsi_remove_device" had the unintended effect that firewire-sbp2 could not be unloaded anymore until all SBP-2 devices were unplugged. We now fix the NULL pointer bug by reacquiring a reference to the sdev instead of holding a reference to the sdev (and to the module) all the time. Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de> Tested-by: Jarod Wilson <jwilson@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/firewire/fw-sbp2.c46
1 files changed, 27 insertions, 19 deletions
diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c
index 5259491580fc..a093ac329db7 100644
--- a/drivers/firewire/fw-sbp2.c
+++ b/drivers/firewire/fw-sbp2.c
@@ -122,7 +122,6 @@ static const char sbp2_driver_name[] = "sbp2";
122struct sbp2_logical_unit { 122struct sbp2_logical_unit {
123 struct sbp2_target *tgt; 123 struct sbp2_target *tgt;
124 struct list_head link; 124 struct list_head link;
125 struct scsi_device *sdev;
126 struct fw_address_handler address_handler; 125 struct fw_address_handler address_handler;
127 struct list_head orb_list; 126 struct list_head orb_list;
128 127
@@ -139,6 +138,7 @@ struct sbp2_logical_unit {
139 int generation; 138 int generation;
140 int retries; 139 int retries;
141 struct delayed_work work; 140 struct delayed_work work;
141 bool has_sdev;
142 bool blocked; 142 bool blocked;
143}; 143};
144 144
@@ -751,20 +751,33 @@ static void sbp2_unblock(struct sbp2_target *tgt)
751 scsi_unblock_requests(shost); 751 scsi_unblock_requests(shost);
752} 752}
753 753
754static int sbp2_lun2int(u16 lun)
755{
756 struct scsi_lun eight_bytes_lun;
757
758 memset(&eight_bytes_lun, 0, sizeof(eight_bytes_lun));
759 eight_bytes_lun.scsi_lun[0] = (lun >> 8) & 0xff;
760 eight_bytes_lun.scsi_lun[1] = lun & 0xff;
761
762 return scsilun_to_int(&eight_bytes_lun);
763}
764
754static void sbp2_release_target(struct kref *kref) 765static void sbp2_release_target(struct kref *kref)
755{ 766{
756 struct sbp2_target *tgt = container_of(kref, struct sbp2_target, kref); 767 struct sbp2_target *tgt = container_of(kref, struct sbp2_target, kref);
757 struct sbp2_logical_unit *lu, *next; 768 struct sbp2_logical_unit *lu, *next;
758 struct Scsi_Host *shost = 769 struct Scsi_Host *shost =
759 container_of((void *)tgt, struct Scsi_Host, hostdata[0]); 770 container_of((void *)tgt, struct Scsi_Host, hostdata[0]);
771 struct scsi_device *sdev;
760 772
761 /* prevent deadlocks */ 773 /* prevent deadlocks */
762 sbp2_unblock(tgt); 774 sbp2_unblock(tgt);
763 775
764 list_for_each_entry_safe(lu, next, &tgt->lu_list, link) { 776 list_for_each_entry_safe(lu, next, &tgt->lu_list, link) {
765 if (lu->sdev) { 777 sdev = scsi_device_lookup(shost, 0, 0, sbp2_lun2int(lu->lun));
766 scsi_remove_device(lu->sdev); 778 if (sdev) {
767 scsi_device_put(lu->sdev); 779 scsi_remove_device(sdev);
780 scsi_device_put(sdev);
768 } 781 }
769 sbp2_send_management_orb(lu, tgt->node_id, lu->generation, 782 sbp2_send_management_orb(lu, tgt->node_id, lu->generation,
770 SBP2_LOGOUT_REQUEST, lu->login_id, NULL); 783 SBP2_LOGOUT_REQUEST, lu->login_id, NULL);
@@ -807,7 +820,6 @@ static void sbp2_login(struct work_struct *work)
807 struct fw_device *device = fw_device(tgt->unit->device.parent); 820 struct fw_device *device = fw_device(tgt->unit->device.parent);
808 struct Scsi_Host *shost; 821 struct Scsi_Host *shost;
809 struct scsi_device *sdev; 822 struct scsi_device *sdev;
810 struct scsi_lun eight_bytes_lun;
811 struct sbp2_login_response response; 823 struct sbp2_login_response response;
812 int generation, node_id, local_node_id; 824 int generation, node_id, local_node_id;
813 825
@@ -820,7 +832,7 @@ static void sbp2_login(struct work_struct *work)
820 local_node_id = device->card->node_id; 832 local_node_id = device->card->node_id;
821 833
822 /* If this is a re-login attempt, log out, or we might be rejected. */ 834 /* If this is a re-login attempt, log out, or we might be rejected. */
823 if (lu->sdev) 835 if (lu->has_sdev)
824 sbp2_send_management_orb(lu, device->node_id, generation, 836 sbp2_send_management_orb(lu, device->node_id, generation,
825 SBP2_LOGOUT_REQUEST, lu->login_id, NULL); 837 SBP2_LOGOUT_REQUEST, lu->login_id, NULL);
826 838
@@ -859,7 +871,7 @@ static void sbp2_login(struct work_struct *work)
859 sbp2_agent_reset(lu); 871 sbp2_agent_reset(lu);
860 872
861 /* This was a re-login. */ 873 /* This was a re-login. */
862 if (lu->sdev) { 874 if (lu->has_sdev) {
863 sbp2_cancel_orbs(lu); 875 sbp2_cancel_orbs(lu);
864 sbp2_conditionally_unblock(lu); 876 sbp2_conditionally_unblock(lu);
865 goto out; 877 goto out;
@@ -868,13 +880,8 @@ static void sbp2_login(struct work_struct *work)
868 if (lu->tgt->workarounds & SBP2_WORKAROUND_DELAY_INQUIRY) 880 if (lu->tgt->workarounds & SBP2_WORKAROUND_DELAY_INQUIRY)
869 ssleep(SBP2_INQUIRY_DELAY); 881 ssleep(SBP2_INQUIRY_DELAY);
870 882
871 memset(&eight_bytes_lun, 0, sizeof(eight_bytes_lun));
872 eight_bytes_lun.scsi_lun[0] = (lu->lun >> 8) & 0xff;
873 eight_bytes_lun.scsi_lun[1] = lu->lun & 0xff;
874 shost = container_of((void *)tgt, struct Scsi_Host, hostdata[0]); 883 shost = container_of((void *)tgt, struct Scsi_Host, hostdata[0]);
875 884 sdev = __scsi_add_device(shost, 0, 0, sbp2_lun2int(lu->lun), lu);
876 sdev = __scsi_add_device(shost, 0, 0,
877 scsilun_to_int(&eight_bytes_lun), lu);
878 /* 885 /*
879 * FIXME: We are unable to perform reconnects while in sbp2_login(). 886 * FIXME: We are unable to perform reconnects while in sbp2_login().
880 * Therefore __scsi_add_device() will get into trouble if a bus reset 887 * Therefore __scsi_add_device() will get into trouble if a bus reset
@@ -896,7 +903,8 @@ static void sbp2_login(struct work_struct *work)
896 } 903 }
897 904
898 /* No error during __scsi_add_device() */ 905 /* No error during __scsi_add_device() */
899 lu->sdev = sdev; 906 lu->has_sdev = true;
907 scsi_device_put(sdev);
900 sbp2_allow_block(lu); 908 sbp2_allow_block(lu);
901 goto out; 909 goto out;
902 910
@@ -934,11 +942,11 @@ static int sbp2_add_logical_unit(struct sbp2_target *tgt, int lun_entry)
934 return -ENOMEM; 942 return -ENOMEM;
935 } 943 }
936 944
937 lu->tgt = tgt; 945 lu->tgt = tgt;
938 lu->sdev = NULL; 946 lu->lun = lun_entry & 0xffff;
939 lu->lun = lun_entry & 0xffff; 947 lu->retries = 0;
940 lu->retries = 0; 948 lu->has_sdev = false;
941 lu->blocked = false; 949 lu->blocked = false;
942 ++tgt->dont_block; 950 ++tgt->dont_block;
943 INIT_LIST_HEAD(&lu->orb_list); 951 INIT_LIST_HEAD(&lu->orb_list);
944 INIT_DELAYED_WORK(&lu->work, sbp2_login); 952 INIT_DELAYED_WORK(&lu->work, sbp2_login);