aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firewire/sbp2.c
diff options
context:
space:
mode:
authorStefan Richter <stefanr@s5r6.in-berlin.de>2011-08-27 09:33:34 -0400
committerStefan Richter <stefanr@s5r6.in-berlin.de>2011-09-16 16:23:56 -0400
commit6ff8147d075da2e1eb69fab2ee75104c59f573e0 (patch)
tree8153760829514f80842f5b36159513002b07e577 /drivers/firewire/sbp2.c
parentf39aa30d7741f40ad964341e9243dbbd7f8ff057 (diff)
firewire: sbp2: remove obsolete reference counting
Since commit 0278ccd9d53e07c4e699432b2fed9de6c56f506c "firewire: sbp2: fix panic after rmmod with slow targets", the lifetime of an sbp2_target instance does no longer extent past the return of sbp2_remove(). Therefore it is no longer necessary to call fw_unit_get/put() and fw_device_get/put() in sbp2_probe/remove(). Furthermore, said commit also ensures that lu->work is not going to be executed or requeued at a time when the sbp2_target is no longer in use. Hence there is no need for sbp2_target reference counting for lu->work. Other concurrent contexts: - Processes which access the sysfs of the SCSI host device or of one of its subdevices are safe because these interfaces are all removed by scsi_remove_device/host() in sbp2_release_target(). - SBP-2 command block ORB transactions are finished when scsi_remove_device() in sbp2_release_target() returns. - SBP-2 management ORB transactions are finished when cancel_delayed_work_sync(&lu->work) before sbp2_release_target() returns. Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Diffstat (limited to 'drivers/firewire/sbp2.c')
-rw-r--r--drivers/firewire/sbp2.c57
1 files changed, 17 insertions, 40 deletions
diff --git a/drivers/firewire/sbp2.c b/drivers/firewire/sbp2.c
index 17cef864506..a2715b20ede 100644
--- a/drivers/firewire/sbp2.c
+++ b/drivers/firewire/sbp2.c
@@ -159,7 +159,6 @@ struct sbp2_logical_unit {
159 * and one struct Scsi_Host per sbp2_target. 159 * and one struct Scsi_Host per sbp2_target.
160 */ 160 */
161struct sbp2_target { 161struct sbp2_target {
162 struct kref kref;
163 struct fw_unit *unit; 162 struct fw_unit *unit;
164 const char *bus_id; 163 const char *bus_id;
165 struct list_head lu_list; 164 struct list_head lu_list;
@@ -772,9 +771,8 @@ static int sbp2_lun2int(u16 lun)
772 return scsilun_to_int(&eight_bytes_lun); 771 return scsilun_to_int(&eight_bytes_lun);
773} 772}
774 773
775static void sbp2_release_target(struct kref *kref) 774static void sbp2_release_target(struct sbp2_target *tgt)
776{ 775{
777 struct sbp2_target *tgt = container_of(kref, struct sbp2_target, kref);
778 struct sbp2_logical_unit *lu, *next; 776 struct sbp2_logical_unit *lu, *next;
779 struct Scsi_Host *shost = 777 struct Scsi_Host *shost =
780 container_of((void *)tgt, struct Scsi_Host, hostdata[0]); 778 container_of((void *)tgt, struct Scsi_Host, hostdata[0]);
@@ -811,30 +809,12 @@ static void sbp2_release_target(struct kref *kref)
811 scsi_remove_host(shost); 809 scsi_remove_host(shost);
812 fw_notify("released %s, target %d:0:0\n", tgt->bus_id, shost->host_no); 810 fw_notify("released %s, target %d:0:0\n", tgt->bus_id, shost->host_no);
813 811
814 fw_unit_put(tgt->unit);
815 scsi_host_put(shost); 812 scsi_host_put(shost);
816 fw_device_put(device);
817}
818
819static void sbp2_target_get(struct sbp2_target *tgt)
820{
821 kref_get(&tgt->kref);
822}
823
824static void sbp2_target_put(struct sbp2_target *tgt)
825{
826 kref_put(&tgt->kref, sbp2_release_target);
827} 813}
828 814
829/*
830 * Always get the target's kref when scheduling work on one its units.
831 * Each workqueue job is responsible to call sbp2_target_put() upon return.
832 */
833static void sbp2_queue_work(struct sbp2_logical_unit *lu, unsigned long delay) 815static void sbp2_queue_work(struct sbp2_logical_unit *lu, unsigned long delay)
834{ 816{
835 sbp2_target_get(lu->tgt); 817 queue_delayed_work(fw_workqueue, &lu->work, delay);
836 if (!queue_delayed_work(fw_workqueue, &lu->work, delay))
837 sbp2_target_put(lu->tgt);
838} 818}
839 819
840/* 820/*
@@ -877,7 +857,7 @@ static void sbp2_login(struct work_struct *work)
877 int generation, node_id, local_node_id; 857 int generation, node_id, local_node_id;
878 858
879 if (fw_device_is_shutdown(device)) 859 if (fw_device_is_shutdown(device))
880 goto out; 860 return;
881 861
882 generation = device->generation; 862 generation = device->generation;
883 smp_rmb(); /* node IDs must not be older than generation */ 863 smp_rmb(); /* node IDs must not be older than generation */
@@ -899,7 +879,7 @@ static void sbp2_login(struct work_struct *work)
899 /* Let any waiting I/O fail from now on. */ 879 /* Let any waiting I/O fail from now on. */
900 sbp2_unblock(lu->tgt); 880 sbp2_unblock(lu->tgt);
901 } 881 }
902 goto out; 882 return;
903 } 883 }
904 884
905 tgt->node_id = node_id; 885 tgt->node_id = node_id;
@@ -925,7 +905,8 @@ static void sbp2_login(struct work_struct *work)
925 if (lu->has_sdev) { 905 if (lu->has_sdev) {
926 sbp2_cancel_orbs(lu); 906 sbp2_cancel_orbs(lu);
927 sbp2_conditionally_unblock(lu); 907 sbp2_conditionally_unblock(lu);
928 goto out; 908
909 return;
929 } 910 }
930 911
931 if (lu->tgt->workarounds & SBP2_WORKAROUND_DELAY_INQUIRY) 912 if (lu->tgt->workarounds & SBP2_WORKAROUND_DELAY_INQUIRY)
@@ -957,7 +938,8 @@ static void sbp2_login(struct work_struct *work)
957 lu->has_sdev = true; 938 lu->has_sdev = true;
958 scsi_device_put(sdev); 939 scsi_device_put(sdev);
959 sbp2_allow_block(lu); 940 sbp2_allow_block(lu);
960 goto out; 941
942 return;
961 943
962 out_logout_login: 944 out_logout_login:
963 smp_rmb(); /* generation may have changed */ 945 smp_rmb(); /* generation may have changed */
@@ -971,8 +953,6 @@ static void sbp2_login(struct work_struct *work)
971 * lu->work already. Reset the work from reconnect to login. 953 * lu->work already. Reset the work from reconnect to login.
972 */ 954 */
973 PREPARE_DELAYED_WORK(&lu->work, sbp2_login); 955 PREPARE_DELAYED_WORK(&lu->work, sbp2_login);
974 out:
975 sbp2_target_put(tgt);
976} 956}
977 957
978static int sbp2_add_logical_unit(struct sbp2_target *tgt, int lun_entry) 958static int sbp2_add_logical_unit(struct sbp2_target *tgt, int lun_entry)
@@ -1141,7 +1121,6 @@ static int sbp2_probe(struct device *dev)
1141 tgt = (struct sbp2_target *)shost->hostdata; 1121 tgt = (struct sbp2_target *)shost->hostdata;
1142 dev_set_drvdata(&unit->device, tgt); 1122 dev_set_drvdata(&unit->device, tgt);
1143 tgt->unit = unit; 1123 tgt->unit = unit;
1144 kref_init(&tgt->kref);
1145 INIT_LIST_HEAD(&tgt->lu_list); 1124 INIT_LIST_HEAD(&tgt->lu_list);
1146 tgt->bus_id = dev_name(&unit->device); 1125 tgt->bus_id = dev_name(&unit->device);
1147 tgt->guid = (u64)device->config_rom[3] << 32 | device->config_rom[4]; 1126 tgt->guid = (u64)device->config_rom[3] << 32 | device->config_rom[4];
@@ -1154,9 +1133,6 @@ static int sbp2_probe(struct device *dev)
1154 if (scsi_add_host(shost, &unit->device) < 0) 1133 if (scsi_add_host(shost, &unit->device) < 0)
1155 goto fail_shost_put; 1134 goto fail_shost_put;
1156 1135
1157 fw_device_get(device);
1158 fw_unit_get(unit);
1159
1160 /* implicit directory ID */ 1136 /* implicit directory ID */
1161 tgt->directory_id = ((unit->directory - device->config_rom) * 4 1137 tgt->directory_id = ((unit->directory - device->config_rom) * 4
1162 + CSR_CONFIG_ROM) & 0xffffff; 1138 + CSR_CONFIG_ROM) & 0xffffff;
@@ -1166,7 +1142,7 @@ static int sbp2_probe(struct device *dev)
1166 1142
1167 if (sbp2_scan_unit_dir(tgt, unit->directory, &model, 1143 if (sbp2_scan_unit_dir(tgt, unit->directory, &model,
1168 &firmware_revision) < 0) 1144 &firmware_revision) < 0)
1169 goto fail_tgt_put; 1145 goto fail_release_target;
1170 1146
1171 sbp2_clamp_management_orb_timeout(tgt); 1147 sbp2_clamp_management_orb_timeout(tgt);
1172 sbp2_init_workarounds(tgt, model, firmware_revision); 1148 sbp2_init_workarounds(tgt, model, firmware_revision);
@@ -1183,10 +1159,11 @@ static int sbp2_probe(struct device *dev)
1183 /* Do the login in a workqueue so we can easily reschedule retries. */ 1159 /* Do the login in a workqueue so we can easily reschedule retries. */
1184 list_for_each_entry(lu, &tgt->lu_list, link) 1160 list_for_each_entry(lu, &tgt->lu_list, link)
1185 sbp2_queue_work(lu, DIV_ROUND_UP(HZ, 5)); 1161 sbp2_queue_work(lu, DIV_ROUND_UP(HZ, 5));
1162
1186 return 0; 1163 return 0;
1187 1164
1188 fail_tgt_put: 1165 fail_release_target:
1189 sbp2_target_put(tgt); 1166 sbp2_release_target(tgt);
1190 return -ENOMEM; 1167 return -ENOMEM;
1191 1168
1192 fail_shost_put: 1169 fail_shost_put:
@@ -1203,7 +1180,8 @@ static int sbp2_remove(struct device *dev)
1203 list_for_each_entry(lu, &tgt->lu_list, link) 1180 list_for_each_entry(lu, &tgt->lu_list, link)
1204 cancel_delayed_work_sync(&lu->work); 1181 cancel_delayed_work_sync(&lu->work);
1205 1182
1206 sbp2_target_put(tgt); 1183 sbp2_release_target(tgt);
1184
1207 return 0; 1185 return 0;
1208} 1186}
1209 1187
@@ -1216,7 +1194,7 @@ static void sbp2_reconnect(struct work_struct *work)
1216 int generation, node_id, local_node_id; 1194 int generation, node_id, local_node_id;
1217 1195
1218 if (fw_device_is_shutdown(device)) 1196 if (fw_device_is_shutdown(device))
1219 goto out; 1197 return;
1220 1198
1221 generation = device->generation; 1199 generation = device->generation;
1222 smp_rmb(); /* node IDs must not be older than generation */ 1200 smp_rmb(); /* node IDs must not be older than generation */
@@ -1241,7 +1219,8 @@ static void sbp2_reconnect(struct work_struct *work)
1241 PREPARE_DELAYED_WORK(&lu->work, sbp2_login); 1219 PREPARE_DELAYED_WORK(&lu->work, sbp2_login);
1242 } 1220 }
1243 sbp2_queue_work(lu, DIV_ROUND_UP(HZ, 5)); 1221 sbp2_queue_work(lu, DIV_ROUND_UP(HZ, 5));
1244 goto out; 1222
1223 return;
1245 } 1224 }
1246 1225
1247 tgt->node_id = node_id; 1226 tgt->node_id = node_id;
@@ -1255,8 +1234,6 @@ static void sbp2_reconnect(struct work_struct *work)
1255 sbp2_agent_reset(lu); 1234 sbp2_agent_reset(lu);
1256 sbp2_cancel_orbs(lu); 1235 sbp2_cancel_orbs(lu);
1257 sbp2_conditionally_unblock(lu); 1236 sbp2_conditionally_unblock(lu);
1258 out:
1259 sbp2_target_put(tgt);
1260} 1237}
1261 1238
1262static void sbp2_update(struct fw_unit *unit) 1239static void sbp2_update(struct fw_unit *unit)