Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending

Pull SCSI target fixes from Nicholas Bellinger:
"This target series for v4.10 contains fixes which address a few
long-standing bugs that DATERA's QA + automation teams have uncovered
while putting v4.1.y target code into production usage.

We've been running the top three in our nightly automated regression
runs for the last two months, and the COMPARE_AND_WRITE fix Mr. Gary
Guo has been manually verifying against a four node ESX cluster this
past week.

Note all of them have CC' stable tags.

Summary:

- Fix a bug with ESX EXTENDED_COPY + SAM_STAT_RESERVATION_CONFLICT
status, where target_core_xcopy.c logic was incorrectly returning
SAM_STAT_CHECK_CONDITION for all non SAM_STAT_GOOD cases (Nixon
Vincent)

- Fix a TMR LUN_RESET hung task bug while other in-flight TMRs are
being aborted, before the new one had been dispatched into tmr_wq
(Rob Millner)

- Fix a long standing double free OOPs, where a dynamically generated
'demo-mode' NodeACL has multiple sessions associated with it, and
the /sys/kernel/config/target/$FABRIC/$WWN/ subsequently disables
demo-mode, but never converts the dynamic ACL into a explicit ACL
(Rob Millner)

- Fix a long standing reference leak with ESX VAAI COMPARE_AND_WRITE
when the second phase WRITE COMMIT command fails, resulting in
CHECK_CONDITION response never being sent and se_cmd->cmd_kref
never reaching zero (Gary Guo)

Beyond these items on v4.1.y we've reproduced, fixed, and run through
our regression test suite using iscsi-target exports, there are two
additional outstanding list items:

- Remove a >= v4.2 RCU conversion BUG_ON that would trigger when
dynamic node NodeACLs where being converted to explicit NodeACLs.
The patch drops the BUG_ON to follow how pre RCU conversion worked
for this special case (Benjamin Estrabaud)

- Add ibmvscsis target_core_fabric_ops->max_data_sg_nent assignment
to match what IBM's Virtual SCSI hypervisor is already enforcing at
transport layer. (Bryant Ly + Steven Royer)"

* git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending:
ibmvscsis: Add SGL limit
target: Fix COMPARE_AND_WRITE ref leak for non GOOD status
target: Fix multi-session dynamic se_node_acl double free OOPs
target: Fix early transport_generic_handle_tmr abort scenario
target: Use correct SCSI status during EXTENDED_COPY exception
target: Don't BUG_ON during NodeACL dynamic -> explicit conversion

+76 -32
+1
drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c
··· 3816 3816 static const struct target_core_fabric_ops ibmvscsis_ops = { 3817 3817 .module = THIS_MODULE, 3818 3818 .name = "ibmvscsis", 3819 + .max_data_sg_nents = MAX_TXU / PAGE_SIZE, 3819 3820 .get_fabric_name = ibmvscsis_get_fabric_name, 3820 3821 .tpg_get_wwn = ibmvscsis_get_fabric_wwn, 3821 3822 .tpg_get_tag = ibmvscsis_get_tag,
+9 -1
drivers/target/target_core_device.c
··· 352 352 kfree(new); 353 353 return -EINVAL; 354 354 } 355 - BUG_ON(orig->se_lun_acl != NULL); 355 + if (orig->se_lun_acl != NULL) { 356 + pr_warn_ratelimited("Detected existing explicit" 357 + " se_lun_acl->se_lun_group reference for %s" 358 + " mapped_lun: %llu, failing\n", 359 + nacl->initiatorname, mapped_lun); 360 + mutex_unlock(&nacl->lun_entry_mutex); 361 + kfree(new); 362 + return -EINVAL; 363 + } 356 364 357 365 rcu_assign_pointer(new->se_lun, lun); 358 366 rcu_assign_pointer(new->se_lun_acl, lun_acl);
+6 -2
drivers/target/target_core_sbc.c
··· 451 451 int *post_ret) 452 452 { 453 453 struct se_device *dev = cmd->se_dev; 454 + sense_reason_t ret = TCM_NO_SENSE; 454 455 455 456 /* 456 457 * Only set SCF_COMPARE_AND_WRITE_POST to force a response fall-through ··· 459 458 * sent to the backend driver. 460 459 */ 461 460 spin_lock_irq(&cmd->t_state_lock); 462 - if ((cmd->transport_state & CMD_T_SENT) && !cmd->scsi_status) { 461 + if (cmd->transport_state & CMD_T_SENT) { 463 462 cmd->se_cmd_flags |= SCF_COMPARE_AND_WRITE_POST; 464 463 *post_ret = 1; 464 + 465 + if (cmd->scsi_status == SAM_STAT_CHECK_CONDITION) 466 + ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; 465 467 } 466 468 spin_unlock_irq(&cmd->t_state_lock); 467 469 ··· 474 470 */ 475 471 up(&dev->caw_sem); 476 472 477 - return TCM_NO_SENSE; 473 + return ret; 478 474 } 479 475 480 476 static sense_reason_t compare_and_write_callback(struct se_cmd *cmd, bool success,
+58 -28
drivers/target/target_core_transport.c
··· 457 457 { 458 458 struct se_node_acl *nacl = container_of(kref, 459 459 struct se_node_acl, acl_kref); 460 + struct se_portal_group *se_tpg = nacl->se_tpg; 460 461 461 - complete(&nacl->acl_free_comp); 462 + if (!nacl->dynamic_stop) { 463 + complete(&nacl->acl_free_comp); 464 + return; 465 + } 466 + 467 + mutex_lock(&se_tpg->acl_node_mutex); 468 + list_del(&nacl->acl_list); 469 + mutex_unlock(&se_tpg->acl_node_mutex); 470 + 471 + core_tpg_wait_for_nacl_pr_ref(nacl); 472 + core_free_device_list_for_node(nacl, se_tpg); 473 + kfree(nacl); 462 474 } 463 475 464 476 void target_put_nacl(struct se_node_acl *nacl) ··· 511 499 void transport_free_session(struct se_session *se_sess) 512 500 { 513 501 struct se_node_acl *se_nacl = se_sess->se_node_acl; 502 + 514 503 /* 515 504 * Drop the se_node_acl->nacl_kref obtained from within 516 505 * core_tpg_get_initiator_node_acl(). 517 506 */ 518 507 if (se_nacl) { 508 + struct se_portal_group *se_tpg = se_nacl->se_tpg; 509 + const struct target_core_fabric_ops *se_tfo = se_tpg->se_tpg_tfo; 510 + unsigned long flags; 511 + 519 512 se_sess->se_node_acl = NULL; 513 + 514 + /* 515 + * Also determine if we need to drop the extra ->cmd_kref if 516 + * it had been previously dynamically generated, and 517 + * the endpoint is not caching dynamic ACLs. 518 + */ 519 + mutex_lock(&se_tpg->acl_node_mutex); 520 + if (se_nacl->dynamic_node_acl && 521 + !se_tfo->tpg_check_demo_mode_cache(se_tpg)) { 522 + spin_lock_irqsave(&se_nacl->nacl_sess_lock, flags); 523 + if (list_empty(&se_nacl->acl_sess_list)) 524 + se_nacl->dynamic_stop = true; 525 + spin_unlock_irqrestore(&se_nacl->nacl_sess_lock, flags); 526 + 527 + if (se_nacl->dynamic_stop) 528 + list_del(&se_nacl->acl_list); 529 + } 530 + mutex_unlock(&se_tpg->acl_node_mutex); 531 + 532 + if (se_nacl->dynamic_stop) 533 + target_put_nacl(se_nacl); 534 + 520 535 target_put_nacl(se_nacl); 521 536 } 522 537 if (se_sess->sess_cmd_map) { ··· 557 518 void transport_deregister_session(struct se_session *se_sess) 558 519 { 559 520 struct se_portal_group *se_tpg = se_sess->se_tpg; 560 - const struct target_core_fabric_ops *se_tfo; 561 - struct se_node_acl *se_nacl; 562 521 unsigned long flags; 563 - bool drop_nacl = false; 564 522 565 523 if (!se_tpg) { 566 524 transport_free_session(se_sess); 567 525 return; 568 526 } 569 - se_tfo = se_tpg->se_tpg_tfo; 570 527 571 528 spin_lock_irqsave(&se_tpg->session_lock, flags); 572 529 list_del(&se_sess->sess_list); ··· 570 535 se_sess->fabric_sess_ptr = NULL; 571 536 spin_unlock_irqrestore(&se_tpg->session_lock, flags); 572 537 573 - /* 574 - * Determine if we need to do extra work for this initiator node's 575 - * struct se_node_acl if it had been previously dynamically generated. 576 - */ 577 - se_nacl = se_sess->se_node_acl; 578 - 579 - mutex_lock(&se_tpg->acl_node_mutex); 580 - if (se_nacl && se_nacl->dynamic_node_acl) { 581 - if (!se_tfo->tpg_check_demo_mode_cache(se_tpg)) { 582 - list_del(&se_nacl->acl_list); 583 - drop_nacl = true; 584 - } 585 - } 586 - mutex_unlock(&se_tpg->acl_node_mutex); 587 - 588 - if (drop_nacl) { 589 - core_tpg_wait_for_nacl_pr_ref(se_nacl); 590 - core_free_device_list_for_node(se_nacl, se_tpg); 591 - se_sess->se_node_acl = NULL; 592 - kfree(se_nacl); 593 - } 594 538 pr_debug("TARGET_CORE[%s]: Deregistered fabric_sess\n", 595 539 se_tpg->se_tpg_tfo->get_fabric_name()); 596 540 /* 597 541 * If last kref is dropping now for an explicit NodeACL, awake sleeping 598 542 * ->acl_free_comp caller to wakeup configfs se_node_acl->acl_group 599 543 * removal context from within transport_free_session() code. 544 + * 545 + * For dynamic ACL, target_put_nacl() uses target_complete_nacl() 546 + * to release all remaining generate_node_acl=1 created ACL resources. 600 547 */ 601 548 602 549 transport_free_session(se_sess); ··· 3127 3110 spin_unlock_irqrestore(&cmd->t_state_lock, flags); 3128 3111 goto check_stop; 3129 3112 } 3130 - cmd->t_state = TRANSPORT_ISTATE_PROCESSING; 3131 3113 spin_unlock_irqrestore(&cmd->t_state_lock, flags); 3132 3114 3133 3115 cmd->se_tfo->queue_tm_rsp(cmd); ··· 3139 3123 struct se_cmd *cmd) 3140 3124 { 3141 3125 unsigned long flags; 3126 + bool aborted = false; 3142 3127 3143 3128 spin_lock_irqsave(&cmd->t_state_lock, flags); 3144 - cmd->transport_state |= CMD_T_ACTIVE; 3129 + if (cmd->transport_state & CMD_T_ABORTED) { 3130 + aborted = true; 3131 + } else { 3132 + cmd->t_state = TRANSPORT_ISTATE_PROCESSING; 3133 + cmd->transport_state |= CMD_T_ACTIVE; 3134 + } 3145 3135 spin_unlock_irqrestore(&cmd->t_state_lock, flags); 3136 + 3137 + if (aborted) { 3138 + pr_warn_ratelimited("handle_tmr caught CMD_T_ABORTED TMR %d" 3139 + "ref_tag: %llu tag: %llu\n", cmd->se_tmr_req->function, 3140 + cmd->se_tmr_req->ref_task_tag, cmd->tag); 3141 + transport_cmd_check_stop_to_fabric(cmd); 3142 + return 0; 3143 + } 3146 3144 3147 3145 INIT_WORK(&cmd->work, target_tmr_work); 3148 3146 queue_work(cmd->se_dev->tmr_wq, &cmd->work);
+1 -1
drivers/target/target_core_xcopy.c
··· 864 864 " CHECK_CONDITION -> sending response\n", rc); 865 865 ec_cmd->scsi_status = SAM_STAT_CHECK_CONDITION; 866 866 } 867 - target_complete_cmd(ec_cmd, SAM_STAT_CHECK_CONDITION); 867 + target_complete_cmd(ec_cmd, ec_cmd->scsi_status); 868 868 } 869 869 870 870 sense_reason_t target_do_xcopy(struct se_cmd *se_cmd)
+1
include/target/target_core_base.h
··· 538 538 char initiatorname[TRANSPORT_IQN_LEN]; 539 539 /* Used to signal demo mode created ACL, disabled by default */ 540 540 bool dynamic_node_acl; 541 + bool dynamic_stop; 541 542 u32 queue_depth; 542 543 u32 acl_index; 543 544 enum target_prot_type saved_prot_type;