diff options
author | Nicholas Bellinger <nab@linux-iscsi.org> | 2015-03-25 04:02:57 -0400 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2015-06-01 03:24:00 -0400 |
commit | 80bfdfa92481d431b199eff72788588d13a3988f (patch) | |
tree | d3549786f0be21fb1f1f6abbdf1190e9cc4aaece /drivers/target | |
parent | 29a05deebf6c2e3010934fb78ee65cab3d329470 (diff) |
target/pr: Use atomic bitop for se_dev_entry->deve_flags reservation check
This patch converts the core_scsi3_pr_seq_non_holder() check for non
reservation holding registrations to use an atomic bitop in ->deve_flags
to determine if a registration is currently active.
It also includes associated a set_bit() in __core_scsi3_add_registration()
and clear_bit() in __core_scsi3_free_registration(), if se_dev_entry still
exists, and has not already been released via se_dev_entry shutdown path
in core_disable_device_list_for_node().
Also, clear_bit in core_disable_device_list_for_node as well to ensure
the read-critical path in core_scsi3_pr_seq_non_holder() picks up the
new state, preceeding the final kfree_rcu() call.
Reported-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Cc: Sagi Grimberg <sagig@mellanox.com>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
Diffstat (limited to 'drivers/target')
-rw-r--r-- | drivers/target/target_core_device.c | 1 | ||||
-rw-r--r-- | drivers/target/target_core_pr.c | 58 |
2 files changed, 40 insertions, 19 deletions
diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index e44e6bd66659..97792cc81fe4 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c | |||
@@ -413,6 +413,7 @@ void core_disable_device_list_for_node( | |||
413 | core_scsi3_ua_release_all(orig); | 413 | core_scsi3_ua_release_all(orig); |
414 | 414 | ||
415 | hlist_del_rcu(&orig->link); | 415 | hlist_del_rcu(&orig->link); |
416 | clear_bit(DEF_PR_REG_ACTIVE, &orig->deve_flags); | ||
416 | rcu_assign_pointer(orig->se_lun, NULL); | 417 | rcu_assign_pointer(orig->se_lun, NULL); |
417 | rcu_assign_pointer(orig->se_lun_acl, NULL); | 418 | rcu_assign_pointer(orig->se_lun_acl, NULL); |
418 | orig->lun_flags = 0; | 419 | orig->lun_flags = 0; |
diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 909573a682d5..66e686bdf894 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c | |||
@@ -327,9 +327,13 @@ static int core_scsi3_pr_seq_non_holder( | |||
327 | int we = 0; /* Write Exclusive */ | 327 | int we = 0; /* Write Exclusive */ |
328 | int legacy = 0; /* Act like a legacy device and return | 328 | int legacy = 0; /* Act like a legacy device and return |
329 | * RESERVATION CONFLICT on some CDBs */ | 329 | * RESERVATION CONFLICT on some CDBs */ |
330 | bool registered = false; | ||
330 | 331 | ||
331 | rcu_read_lock(); | 332 | rcu_read_lock(); |
332 | se_deve = target_nacl_find_deve(nacl, cmd->orig_fe_lun); | 333 | se_deve = target_nacl_find_deve(nacl, cmd->orig_fe_lun); |
334 | if (se_deve) | ||
335 | registered = test_bit(DEF_PR_REG_ACTIVE, &se_deve->deve_flags); | ||
336 | rcu_read_unlock(); | ||
333 | /* | 337 | /* |
334 | * Determine if the registration should be ignored due to | 338 | * Determine if the registration should be ignored due to |
335 | * non-matching ISIDs in target_scsi3_pr_reservation_check(). | 339 | * non-matching ISIDs in target_scsi3_pr_reservation_check(). |
@@ -346,7 +350,7 @@ static int core_scsi3_pr_seq_non_holder( | |||
346 | * Some commands are only allowed for the persistent reservation | 350 | * Some commands are only allowed for the persistent reservation |
347 | * holder. | 351 | * holder. |
348 | */ | 352 | */ |
349 | if ((se_deve->def_pr_registered) && !(ignore_reg)) | 353 | if ((registered) && !(ignore_reg)) |
350 | registered_nexus = 1; | 354 | registered_nexus = 1; |
351 | break; | 355 | break; |
352 | case PR_TYPE_WRITE_EXCLUSIVE_REGONLY: | 356 | case PR_TYPE_WRITE_EXCLUSIVE_REGONLY: |
@@ -356,7 +360,7 @@ static int core_scsi3_pr_seq_non_holder( | |||
356 | * Some commands are only allowed for registered I_T Nexuses. | 360 | * Some commands are only allowed for registered I_T Nexuses. |
357 | */ | 361 | */ |
358 | reg_only = 1; | 362 | reg_only = 1; |
359 | if ((se_deve->def_pr_registered) && !(ignore_reg)) | 363 | if ((registered) && !(ignore_reg)) |
360 | registered_nexus = 1; | 364 | registered_nexus = 1; |
361 | break; | 365 | break; |
362 | case PR_TYPE_WRITE_EXCLUSIVE_ALLREG: | 366 | case PR_TYPE_WRITE_EXCLUSIVE_ALLREG: |
@@ -366,14 +370,12 @@ static int core_scsi3_pr_seq_non_holder( | |||
366 | * Each registered I_T Nexus is a reservation holder. | 370 | * Each registered I_T Nexus is a reservation holder. |
367 | */ | 371 | */ |
368 | all_reg = 1; | 372 | all_reg = 1; |
369 | if ((se_deve->def_pr_registered) && !(ignore_reg)) | 373 | if ((registered) && !(ignore_reg)) |
370 | registered_nexus = 1; | 374 | registered_nexus = 1; |
371 | break; | 375 | break; |
372 | default: | 376 | default: |
373 | rcu_read_unlock(); | ||
374 | return -EINVAL; | 377 | return -EINVAL; |
375 | } | 378 | } |
376 | rcu_read_unlock(); | ||
377 | /* | 379 | /* |
378 | * Referenced from spc4r17 table 45 for *NON* PR holder access | 380 | * Referenced from spc4r17 table 45 for *NON* PR holder access |
379 | */ | 381 | */ |
@@ -1009,10 +1011,6 @@ static void __core_scsi3_dump_registration( | |||
1009 | pr_reg->pr_reg_aptpl); | 1011 | pr_reg->pr_reg_aptpl); |
1010 | } | 1012 | } |
1011 | 1013 | ||
1012 | /* | ||
1013 | * this function can be called with struct se_device->dev_reservation_lock | ||
1014 | * when register_move = 1 | ||
1015 | */ | ||
1016 | static void __core_scsi3_add_registration( | 1014 | static void __core_scsi3_add_registration( |
1017 | struct se_device *dev, | 1015 | struct se_device *dev, |
1018 | struct se_node_acl *nacl, | 1016 | struct se_node_acl *nacl, |
@@ -1023,6 +1021,7 @@ static void __core_scsi3_add_registration( | |||
1023 | const struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo; | 1021 | const struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo; |
1024 | struct t10_pr_registration *pr_reg_tmp, *pr_reg_tmp_safe; | 1022 | struct t10_pr_registration *pr_reg_tmp, *pr_reg_tmp_safe; |
1025 | struct t10_reservation *pr_tmpl = &dev->t10_pr; | 1023 | struct t10_reservation *pr_tmpl = &dev->t10_pr; |
1024 | struct se_dev_entry *deve; | ||
1026 | 1025 | ||
1027 | /* | 1026 | /* |
1028 | * Increment PRgeneration counter for struct se_device upon a successful | 1027 | * Increment PRgeneration counter for struct se_device upon a successful |
@@ -1039,10 +1038,16 @@ static void __core_scsi3_add_registration( | |||
1039 | 1038 | ||
1040 | spin_lock(&pr_tmpl->registration_lock); | 1039 | spin_lock(&pr_tmpl->registration_lock); |
1041 | list_add_tail(&pr_reg->pr_reg_list, &pr_tmpl->registration_list); | 1040 | list_add_tail(&pr_reg->pr_reg_list, &pr_tmpl->registration_list); |
1042 | pr_reg->pr_reg_deve->def_pr_registered = 1; | ||
1043 | 1041 | ||
1044 | __core_scsi3_dump_registration(tfo, dev, nacl, pr_reg, register_type); | 1042 | __core_scsi3_dump_registration(tfo, dev, nacl, pr_reg, register_type); |
1045 | spin_unlock(&pr_tmpl->registration_lock); | 1043 | spin_unlock(&pr_tmpl->registration_lock); |
1044 | |||
1045 | rcu_read_lock(); | ||
1046 | deve = pr_reg->pr_reg_deve; | ||
1047 | if (deve) | ||
1048 | set_bit(DEF_PR_REG_ACTIVE, &deve->deve_flags); | ||
1049 | rcu_read_unlock(); | ||
1050 | |||
1046 | /* | 1051 | /* |
1047 | * Skip extra processing for ALL_TG_PT=0 or REGISTER_AND_MOVE. | 1052 | * Skip extra processing for ALL_TG_PT=0 or REGISTER_AND_MOVE. |
1048 | */ | 1053 | */ |
@@ -1054,6 +1059,8 @@ static void __core_scsi3_add_registration( | |||
1054 | */ | 1059 | */ |
1055 | list_for_each_entry_safe(pr_reg_tmp, pr_reg_tmp_safe, | 1060 | list_for_each_entry_safe(pr_reg_tmp, pr_reg_tmp_safe, |
1056 | &pr_reg->pr_reg_atp_list, pr_reg_atp_mem_list) { | 1061 | &pr_reg->pr_reg_atp_list, pr_reg_atp_mem_list) { |
1062 | struct se_node_acl *nacl_tmp = pr_reg_tmp->pr_reg_nacl; | ||
1063 | |||
1057 | list_del(&pr_reg_tmp->pr_reg_atp_mem_list); | 1064 | list_del(&pr_reg_tmp->pr_reg_atp_mem_list); |
1058 | 1065 | ||
1059 | pr_reg_tmp->pr_res_generation = core_scsi3_pr_generation(dev); | 1066 | pr_reg_tmp->pr_res_generation = core_scsi3_pr_generation(dev); |
@@ -1061,12 +1068,17 @@ static void __core_scsi3_add_registration( | |||
1061 | spin_lock(&pr_tmpl->registration_lock); | 1068 | spin_lock(&pr_tmpl->registration_lock); |
1062 | list_add_tail(&pr_reg_tmp->pr_reg_list, | 1069 | list_add_tail(&pr_reg_tmp->pr_reg_list, |
1063 | &pr_tmpl->registration_list); | 1070 | &pr_tmpl->registration_list); |
1064 | pr_reg_tmp->pr_reg_deve->def_pr_registered = 1; | ||
1065 | 1071 | ||
1066 | __core_scsi3_dump_registration(tfo, dev, | 1072 | __core_scsi3_dump_registration(tfo, dev, nacl_tmp, pr_reg_tmp, |
1067 | pr_reg_tmp->pr_reg_nacl, pr_reg_tmp, | 1073 | register_type); |
1068 | register_type); | ||
1069 | spin_unlock(&pr_tmpl->registration_lock); | 1074 | spin_unlock(&pr_tmpl->registration_lock); |
1075 | |||
1076 | rcu_read_lock(); | ||
1077 | deve = pr_reg_tmp->pr_reg_deve; | ||
1078 | if (deve) | ||
1079 | set_bit(DEF_PR_REG_ACTIVE, &deve->deve_flags); | ||
1080 | rcu_read_unlock(); | ||
1081 | |||
1070 | /* | 1082 | /* |
1071 | * Drop configfs group dependency reference from | 1083 | * Drop configfs group dependency reference from |
1072 | * __core_scsi3_alloc_registration() | 1084 | * __core_scsi3_alloc_registration() |
@@ -1242,13 +1254,13 @@ static void __core_scsi3_free_registration( | |||
1242 | const struct target_core_fabric_ops *tfo = | 1254 | const struct target_core_fabric_ops *tfo = |
1243 | pr_reg->pr_reg_nacl->se_tpg->se_tpg_tfo; | 1255 | pr_reg->pr_reg_nacl->se_tpg->se_tpg_tfo; |
1244 | struct t10_reservation *pr_tmpl = &dev->t10_pr; | 1256 | struct t10_reservation *pr_tmpl = &dev->t10_pr; |
1257 | struct se_node_acl *nacl = pr_reg->pr_reg_nacl; | ||
1258 | struct se_dev_entry *deve; | ||
1245 | char i_buf[PR_REG_ISID_ID_LEN]; | 1259 | char i_buf[PR_REG_ISID_ID_LEN]; |
1246 | 1260 | ||
1247 | memset(i_buf, 0, PR_REG_ISID_ID_LEN); | 1261 | memset(i_buf, 0, PR_REG_ISID_ID_LEN); |
1248 | core_pr_dump_initiator_port(pr_reg, i_buf, PR_REG_ISID_ID_LEN); | 1262 | core_pr_dump_initiator_port(pr_reg, i_buf, PR_REG_ISID_ID_LEN); |
1249 | 1263 | ||
1250 | pr_reg->pr_reg_deve->def_pr_registered = 0; | ||
1251 | pr_reg->pr_reg_deve->pr_res_key = 0; | ||
1252 | if (!list_empty(&pr_reg->pr_reg_list)) | 1264 | if (!list_empty(&pr_reg->pr_reg_list)) |
1253 | list_del(&pr_reg->pr_reg_list); | 1265 | list_del(&pr_reg->pr_reg_list); |
1254 | /* | 1266 | /* |
@@ -1257,6 +1269,8 @@ static void __core_scsi3_free_registration( | |||
1257 | */ | 1269 | */ |
1258 | if (dec_holders) | 1270 | if (dec_holders) |
1259 | core_scsi3_put_pr_reg(pr_reg); | 1271 | core_scsi3_put_pr_reg(pr_reg); |
1272 | |||
1273 | spin_unlock(&pr_tmpl->registration_lock); | ||
1260 | /* | 1274 | /* |
1261 | * Wait until all reference from any other I_T nexuses for this | 1275 | * Wait until all reference from any other I_T nexuses for this |
1262 | * *pr_reg have been released. Because list_del() is called above, | 1276 | * *pr_reg have been released. Because list_del() is called above, |
@@ -1264,13 +1278,18 @@ static void __core_scsi3_free_registration( | |||
1264 | * count back to zero, and we release *pr_reg. | 1278 | * count back to zero, and we release *pr_reg. |
1265 | */ | 1279 | */ |
1266 | while (atomic_read(&pr_reg->pr_res_holders) != 0) { | 1280 | while (atomic_read(&pr_reg->pr_res_holders) != 0) { |
1267 | spin_unlock(&pr_tmpl->registration_lock); | ||
1268 | pr_debug("SPC-3 PR [%s] waiting for pr_res_holders\n", | 1281 | pr_debug("SPC-3 PR [%s] waiting for pr_res_holders\n", |
1269 | tfo->get_fabric_name()); | 1282 | tfo->get_fabric_name()); |
1270 | cpu_relax(); | 1283 | cpu_relax(); |
1271 | spin_lock(&pr_tmpl->registration_lock); | ||
1272 | } | 1284 | } |
1273 | 1285 | ||
1286 | rcu_read_lock(); | ||
1287 | deve = target_nacl_find_deve(nacl, pr_reg->pr_res_mapped_lun); | ||
1288 | if (deve) | ||
1289 | clear_bit(DEF_PR_REG_ACTIVE, &deve->deve_flags); | ||
1290 | rcu_read_unlock(); | ||
1291 | |||
1292 | spin_lock(&pr_tmpl->registration_lock); | ||
1274 | pr_debug("SPC-3 PR [%s] Service Action: UNREGISTER Initiator" | 1293 | pr_debug("SPC-3 PR [%s] Service Action: UNREGISTER Initiator" |
1275 | " Node: %s%s\n", tfo->get_fabric_name(), | 1294 | " Node: %s%s\n", tfo->get_fabric_name(), |
1276 | pr_reg->pr_reg_nacl->initiatorname, | 1295 | pr_reg->pr_reg_nacl->initiatorname, |
@@ -3421,13 +3440,14 @@ after_iport_check: | |||
3421 | dest_pr_reg = __core_scsi3_locate_pr_reg(dev, dest_node_acl, | 3440 | dest_pr_reg = __core_scsi3_locate_pr_reg(dev, dest_node_acl, |
3422 | iport_ptr); | 3441 | iport_ptr); |
3423 | if (!dest_pr_reg) { | 3442 | if (!dest_pr_reg) { |
3443 | spin_unlock(&dev->dev_reservation_lock); | ||
3424 | if (core_scsi3_alloc_registration(cmd->se_dev, | 3444 | if (core_scsi3_alloc_registration(cmd->se_dev, |
3425 | dest_node_acl, dest_se_deve, iport_ptr, | 3445 | dest_node_acl, dest_se_deve, iport_ptr, |
3426 | sa_res_key, 0, aptpl, 2, 1)) { | 3446 | sa_res_key, 0, aptpl, 2, 1)) { |
3427 | spin_unlock(&dev->dev_reservation_lock); | ||
3428 | ret = TCM_INVALID_PARAMETER_LIST; | 3447 | ret = TCM_INVALID_PARAMETER_LIST; |
3429 | goto out; | 3448 | goto out; |
3430 | } | 3449 | } |
3450 | spin_lock(&dev->dev_reservation_lock); | ||
3431 | dest_pr_reg = __core_scsi3_locate_pr_reg(dev, dest_node_acl, | 3451 | dest_pr_reg = __core_scsi3_locate_pr_reg(dev, dest_node_acl, |
3432 | iport_ptr); | 3452 | iport_ptr); |
3433 | new_reg = 1; | 3453 | new_reg = 1; |