diff options
| -rw-r--r-- | drivers/target/target_core_pr.c | 87 |
1 files changed, 65 insertions, 22 deletions
diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index c4a8da5415c5..703890c12071 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c | |||
| @@ -76,7 +76,7 @@ enum preempt_type { | |||
| 76 | }; | 76 | }; |
| 77 | 77 | ||
| 78 | static void __core_scsi3_complete_pro_release(struct se_device *, struct se_node_acl *, | 78 | static void __core_scsi3_complete_pro_release(struct se_device *, struct se_node_acl *, |
| 79 | struct t10_pr_registration *, int); | 79 | struct t10_pr_registration *, int, int); |
| 80 | 80 | ||
| 81 | static sense_reason_t | 81 | static sense_reason_t |
| 82 | target_scsi2_reservation_check(struct se_cmd *cmd) | 82 | target_scsi2_reservation_check(struct se_cmd *cmd) |
| @@ -1177,7 +1177,7 @@ static int core_scsi3_check_implicit_release( | |||
| 1177 | * service action with the SERVICE ACTION RESERVATION KEY | 1177 | * service action with the SERVICE ACTION RESERVATION KEY |
| 1178 | * field set to zero (see 5.7.11.3). | 1178 | * field set to zero (see 5.7.11.3). |
| 1179 | */ | 1179 | */ |
| 1180 | __core_scsi3_complete_pro_release(dev, nacl, pr_reg, 0); | 1180 | __core_scsi3_complete_pro_release(dev, nacl, pr_reg, 0, 1); |
| 1181 | ret = 1; | 1181 | ret = 1; |
| 1182 | /* | 1182 | /* |
| 1183 | * For 'All Registrants' reservation types, all existing | 1183 | * For 'All Registrants' reservation types, all existing |
| @@ -1219,7 +1219,8 @@ static void __core_scsi3_free_registration( | |||
| 1219 | 1219 | ||
| 1220 | pr_reg->pr_reg_deve->def_pr_registered = 0; | 1220 | pr_reg->pr_reg_deve->def_pr_registered = 0; |
| 1221 | pr_reg->pr_reg_deve->pr_res_key = 0; | 1221 | pr_reg->pr_reg_deve->pr_res_key = 0; |
| 1222 | list_del(&pr_reg->pr_reg_list); | 1222 | if (!list_empty(&pr_reg->pr_reg_list)) |
| 1223 | list_del(&pr_reg->pr_reg_list); | ||
| 1223 | /* | 1224 | /* |
| 1224 | * Caller accessing *pr_reg using core_scsi3_locate_pr_reg(), | 1225 | * Caller accessing *pr_reg using core_scsi3_locate_pr_reg(), |
| 1225 | * so call core_scsi3_put_pr_reg() to decrement our reference. | 1226 | * so call core_scsi3_put_pr_reg() to decrement our reference. |
| @@ -1271,6 +1272,7 @@ void core_scsi3_free_pr_reg_from_nacl( | |||
| 1271 | { | 1272 | { |
| 1272 | struct t10_reservation *pr_tmpl = &dev->t10_pr; | 1273 | struct t10_reservation *pr_tmpl = &dev->t10_pr; |
| 1273 | struct t10_pr_registration *pr_reg, *pr_reg_tmp, *pr_res_holder; | 1274 | struct t10_pr_registration *pr_reg, *pr_reg_tmp, *pr_res_holder; |
| 1275 | bool free_reg = false; | ||
| 1274 | /* | 1276 | /* |
| 1275 | * If the passed se_node_acl matches the reservation holder, | 1277 | * If the passed se_node_acl matches the reservation holder, |
| 1276 | * release the reservation. | 1278 | * release the reservation. |
| @@ -1278,13 +1280,18 @@ void core_scsi3_free_pr_reg_from_nacl( | |||
| 1278 | spin_lock(&dev->dev_reservation_lock); | 1280 | spin_lock(&dev->dev_reservation_lock); |
| 1279 | pr_res_holder = dev->dev_pr_res_holder; | 1281 | pr_res_holder = dev->dev_pr_res_holder; |
| 1280 | if ((pr_res_holder != NULL) && | 1282 | if ((pr_res_holder != NULL) && |
| 1281 | (pr_res_holder->pr_reg_nacl == nacl)) | 1283 | (pr_res_holder->pr_reg_nacl == nacl)) { |
| 1282 | __core_scsi3_complete_pro_release(dev, nacl, pr_res_holder, 0); | 1284 | __core_scsi3_complete_pro_release(dev, nacl, pr_res_holder, 0, 1); |
| 1285 | free_reg = true; | ||
| 1286 | } | ||
| 1283 | spin_unlock(&dev->dev_reservation_lock); | 1287 | spin_unlock(&dev->dev_reservation_lock); |
| 1284 | /* | 1288 | /* |
| 1285 | * Release any registration associated with the struct se_node_acl. | 1289 | * Release any registration associated with the struct se_node_acl. |
| 1286 | */ | 1290 | */ |
| 1287 | spin_lock(&pr_tmpl->registration_lock); | 1291 | spin_lock(&pr_tmpl->registration_lock); |
| 1292 | if (pr_res_holder && free_reg) | ||
| 1293 | __core_scsi3_free_registration(dev, pr_res_holder, NULL, 0); | ||
| 1294 | |||
| 1288 | list_for_each_entry_safe(pr_reg, pr_reg_tmp, | 1295 | list_for_each_entry_safe(pr_reg, pr_reg_tmp, |
| 1289 | &pr_tmpl->registration_list, pr_reg_list) { | 1296 | &pr_tmpl->registration_list, pr_reg_list) { |
| 1290 | 1297 | ||
| @@ -1307,7 +1314,7 @@ void core_scsi3_free_all_registrations( | |||
| 1307 | if (pr_res_holder != NULL) { | 1314 | if (pr_res_holder != NULL) { |
| 1308 | struct se_node_acl *pr_res_nacl = pr_res_holder->pr_reg_nacl; | 1315 | struct se_node_acl *pr_res_nacl = pr_res_holder->pr_reg_nacl; |
| 1309 | __core_scsi3_complete_pro_release(dev, pr_res_nacl, | 1316 | __core_scsi3_complete_pro_release(dev, pr_res_nacl, |
| 1310 | pr_res_holder, 0); | 1317 | pr_res_holder, 0, 0); |
| 1311 | } | 1318 | } |
| 1312 | spin_unlock(&dev->dev_reservation_lock); | 1319 | spin_unlock(&dev->dev_reservation_lock); |
| 1313 | 1320 | ||
| @@ -2103,13 +2110,13 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key, | |||
| 2103 | /* | 2110 | /* |
| 2104 | * sa_res_key=0 Unregister Reservation Key for registered I_T Nexus. | 2111 | * sa_res_key=0 Unregister Reservation Key for registered I_T Nexus. |
| 2105 | */ | 2112 | */ |
| 2106 | pr_holder = core_scsi3_check_implicit_release( | 2113 | type = pr_reg->pr_res_type; |
| 2107 | cmd->se_dev, pr_reg); | 2114 | pr_holder = core_scsi3_check_implicit_release(cmd->se_dev, |
| 2115 | pr_reg); | ||
| 2108 | if (pr_holder < 0) { | 2116 | if (pr_holder < 0) { |
| 2109 | ret = TCM_RESERVATION_CONFLICT; | 2117 | ret = TCM_RESERVATION_CONFLICT; |
| 2110 | goto out; | 2118 | goto out; |
| 2111 | } | 2119 | } |
| 2112 | type = pr_reg->pr_res_type; | ||
| 2113 | 2120 | ||
| 2114 | spin_lock(&pr_tmpl->registration_lock); | 2121 | spin_lock(&pr_tmpl->registration_lock); |
| 2115 | /* | 2122 | /* |
| @@ -2383,23 +2390,59 @@ static void __core_scsi3_complete_pro_release( | |||
| 2383 | struct se_device *dev, | 2390 | struct se_device *dev, |
| 2384 | struct se_node_acl *se_nacl, | 2391 | struct se_node_acl *se_nacl, |
| 2385 | struct t10_pr_registration *pr_reg, | 2392 | struct t10_pr_registration *pr_reg, |
| 2386 | int explicit) | 2393 | int explicit, |
| 2394 | int unreg) | ||
| 2387 | { | 2395 | { |
| 2388 | struct target_core_fabric_ops *tfo = se_nacl->se_tpg->se_tpg_tfo; | 2396 | struct target_core_fabric_ops *tfo = se_nacl->se_tpg->se_tpg_tfo; |
| 2389 | char i_buf[PR_REG_ISID_ID_LEN]; | 2397 | char i_buf[PR_REG_ISID_ID_LEN]; |
| 2398 | int pr_res_type = 0, pr_res_scope = 0; | ||
| 2390 | 2399 | ||
| 2391 | memset(i_buf, 0, PR_REG_ISID_ID_LEN); | 2400 | memset(i_buf, 0, PR_REG_ISID_ID_LEN); |
| 2392 | core_pr_dump_initiator_port(pr_reg, i_buf, PR_REG_ISID_ID_LEN); | 2401 | core_pr_dump_initiator_port(pr_reg, i_buf, PR_REG_ISID_ID_LEN); |
| 2393 | /* | 2402 | /* |
| 2394 | * Go ahead and release the current PR reservation holder. | 2403 | * Go ahead and release the current PR reservation holder. |
| 2404 | * If an All Registrants reservation is currently active and | ||
| 2405 | * a unregister operation is requested, replace the current | ||
| 2406 | * dev_pr_res_holder with another active registration. | ||
| 2395 | */ | 2407 | */ |
| 2396 | dev->dev_pr_res_holder = NULL; | 2408 | if (dev->dev_pr_res_holder) { |
| 2409 | pr_res_type = dev->dev_pr_res_holder->pr_res_type; | ||
| 2410 | pr_res_scope = dev->dev_pr_res_holder->pr_res_scope; | ||
| 2411 | dev->dev_pr_res_holder->pr_res_type = 0; | ||
| 2412 | dev->dev_pr_res_holder->pr_res_scope = 0; | ||
| 2413 | dev->dev_pr_res_holder->pr_res_holder = 0; | ||
| 2414 | dev->dev_pr_res_holder = NULL; | ||
| 2415 | } | ||
| 2416 | if (!unreg) | ||
| 2417 | goto out; | ||
| 2397 | 2418 | ||
| 2398 | pr_debug("SPC-3 PR [%s] Service Action: %s RELEASE cleared" | 2419 | spin_lock(&dev->t10_pr.registration_lock); |
| 2399 | " reservation holder TYPE: %s ALL_TG_PT: %d\n", | 2420 | list_del_init(&pr_reg->pr_reg_list); |
| 2400 | tfo->get_fabric_name(), (explicit) ? "explicit" : "implicit", | 2421 | /* |
| 2401 | core_scsi3_pr_dump_type(pr_reg->pr_res_type), | 2422 | * If the I_T nexus is a reservation holder, the persistent reservation |
| 2402 | (pr_reg->pr_reg_all_tg_pt) ? 1 : 0); | 2423 | * is of an all registrants type, and the I_T nexus is the last remaining |
| 2424 | * registered I_T nexus, then the device server shall also release the | ||
| 2425 | * persistent reservation. | ||
| 2426 | */ | ||
| 2427 | if (!list_empty(&dev->t10_pr.registration_list) && | ||
| 2428 | ((pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG) || | ||
| 2429 | (pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG))) { | ||
| 2430 | dev->dev_pr_res_holder = | ||
| 2431 | list_entry(dev->t10_pr.registration_list.next, | ||
| 2432 | struct t10_pr_registration, pr_reg_list); | ||
| 2433 | dev->dev_pr_res_holder->pr_res_type = pr_res_type; | ||
| 2434 | dev->dev_pr_res_holder->pr_res_scope = pr_res_scope; | ||
| 2435 | dev->dev_pr_res_holder->pr_res_holder = 1; | ||
| 2436 | } | ||
| 2437 | spin_unlock(&dev->t10_pr.registration_lock); | ||
| 2438 | out: | ||
| 2439 | if (!dev->dev_pr_res_holder) { | ||
| 2440 | pr_debug("SPC-3 PR [%s] Service Action: %s RELEASE cleared" | ||
| 2441 | " reservation holder TYPE: %s ALL_TG_PT: %d\n", | ||
| 2442 | tfo->get_fabric_name(), (explicit) ? "explicit" : | ||
| 2443 | "implicit", core_scsi3_pr_dump_type(pr_res_type), | ||
| 2444 | (pr_reg->pr_reg_all_tg_pt) ? 1 : 0); | ||
| 2445 | } | ||
| 2403 | pr_debug("SPC-3 PR [%s] RELEASE Node: %s%s\n", | 2446 | pr_debug("SPC-3 PR [%s] RELEASE Node: %s%s\n", |
| 2404 | tfo->get_fabric_name(), se_nacl->initiatorname, | 2447 | tfo->get_fabric_name(), se_nacl->initiatorname, |
| 2405 | i_buf); | 2448 | i_buf); |
| @@ -2530,7 +2573,7 @@ core_scsi3_emulate_pro_release(struct se_cmd *cmd, int type, int scope, | |||
| 2530 | * server shall not establish a unit attention condition. | 2573 | * server shall not establish a unit attention condition. |
| 2531 | */ | 2574 | */ |
| 2532 | __core_scsi3_complete_pro_release(dev, se_sess->se_node_acl, | 2575 | __core_scsi3_complete_pro_release(dev, se_sess->se_node_acl, |
| 2533 | pr_reg, 1); | 2576 | pr_reg, 1, 0); |
| 2534 | 2577 | ||
| 2535 | spin_unlock(&dev->dev_reservation_lock); | 2578 | spin_unlock(&dev->dev_reservation_lock); |
| 2536 | 2579 | ||
| @@ -2618,7 +2661,7 @@ core_scsi3_emulate_pro_clear(struct se_cmd *cmd, u64 res_key) | |||
| 2618 | if (pr_res_holder) { | 2661 | if (pr_res_holder) { |
| 2619 | struct se_node_acl *pr_res_nacl = pr_res_holder->pr_reg_nacl; | 2662 | struct se_node_acl *pr_res_nacl = pr_res_holder->pr_reg_nacl; |
| 2620 | __core_scsi3_complete_pro_release(dev, pr_res_nacl, | 2663 | __core_scsi3_complete_pro_release(dev, pr_res_nacl, |
| 2621 | pr_res_holder, 0); | 2664 | pr_res_holder, 0, 0); |
| 2622 | } | 2665 | } |
| 2623 | spin_unlock(&dev->dev_reservation_lock); | 2666 | spin_unlock(&dev->dev_reservation_lock); |
| 2624 | /* | 2667 | /* |
| @@ -2677,7 +2720,7 @@ static void __core_scsi3_complete_pro_preempt( | |||
| 2677 | */ | 2720 | */ |
| 2678 | if (dev->dev_pr_res_holder) | 2721 | if (dev->dev_pr_res_holder) |
| 2679 | __core_scsi3_complete_pro_release(dev, nacl, | 2722 | __core_scsi3_complete_pro_release(dev, nacl, |
| 2680 | dev->dev_pr_res_holder, 0); | 2723 | dev->dev_pr_res_holder, 0, 0); |
| 2681 | 2724 | ||
| 2682 | dev->dev_pr_res_holder = pr_reg; | 2725 | dev->dev_pr_res_holder = pr_reg; |
| 2683 | pr_reg->pr_res_holder = 1; | 2726 | pr_reg->pr_res_holder = 1; |
| @@ -2922,8 +2965,8 @@ core_scsi3_pro_preempt(struct se_cmd *cmd, int type, int scope, u64 res_key, | |||
| 2922 | */ | 2965 | */ |
| 2923 | if (pr_reg_n != pr_res_holder) | 2966 | if (pr_reg_n != pr_res_holder) |
| 2924 | __core_scsi3_complete_pro_release(dev, | 2967 | __core_scsi3_complete_pro_release(dev, |
| 2925 | pr_res_holder->pr_reg_nacl, | 2968 | pr_res_holder->pr_reg_nacl, |
| 2926 | dev->dev_pr_res_holder, 0); | 2969 | dev->dev_pr_res_holder, 0, 0); |
| 2927 | /* | 2970 | /* |
| 2928 | * b) Remove the registrations for all I_T nexuses identified | 2971 | * b) Remove the registrations for all I_T nexuses identified |
| 2929 | * by the SERVICE ACTION RESERVATION KEY field, except the | 2972 | * by the SERVICE ACTION RESERVATION KEY field, except the |
| @@ -3386,7 +3429,7 @@ after_iport_check: | |||
| 3386 | * holder (i.e., the I_T nexus on which the | 3429 | * holder (i.e., the I_T nexus on which the |
| 3387 | */ | 3430 | */ |
| 3388 | __core_scsi3_complete_pro_release(dev, pr_res_nacl, | 3431 | __core_scsi3_complete_pro_release(dev, pr_res_nacl, |
| 3389 | dev->dev_pr_res_holder, 0); | 3432 | dev->dev_pr_res_holder, 0, 0); |
| 3390 | /* | 3433 | /* |
| 3391 | * g) Move the persistent reservation to the specified I_T nexus using | 3434 | * g) Move the persistent reservation to the specified I_T nexus using |
| 3392 | * the same scope and type as the persistent reservation released in | 3435 | * the same scope and type as the persistent reservation released in |
