diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-06-15 19:07:24 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-06-15 19:07:24 -0400 |
commit | a41b0e71563166762ee9d4905f3aa518a9348ed4 (patch) | |
tree | 80ba4cf938421776385b3771d81d2904fb83ac02 | |
parent | 718f58ad61810b7d4a6c9178185495f762e90807 (diff) | |
parent | 5134de2815ac723ecfba4a1c7b2a90fa4d8dcfd9 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending
Pull target updates from Nicholas Bellinger:
"This series contains post merge qla_target.c / tcm_qla2xxx bugfixes
from the past weeks, including the patch to allow target-core to use
an optional session shutdown callback to help address an active I/O
shutdown bug in tcm_qla2xxx code (Joern).
Also included is a target regression bugfix releated to explict ALUA
target port group CDB emulation that is CC'ed to stable (Roland)."
* git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending:
qla2xxx: Remove version.h header file inclusion
tcm_qla2xxx: Handle malformed wwn strings properly
tcm_qla2xxx: tcm_qla2xxx_handle_tmr() can be static
qla2xxx: Don't leak commands we give up on in qlt_do_work()
qla2xxx: Don't crash if we can't find cmd for failed CTIO
tcm_qla2xxx: Don't insert nacls without sessions into the btree
target: Return error to initiator if SET TARGET PORT GROUPS emulation fails
tcm_qla2xxx: Clear session s_id + loop_id earlier during shutdown
tcm_qla2xxx: Convert to TFO->put_session() usage
target: Add TFO->put_session() caller for HW fabric session shutdown
-rw-r--r-- | drivers/scsi/qla2xxx/qla_target.c | 11 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_target.h | 1 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/tcm_qla2xxx.c | 152 | ||||
-rw-r--r-- | drivers/target/target_core_alua.c | 5 | ||||
-rw-r--r-- | drivers/target/target_core_transport.c | 8 | ||||
-rw-r--r-- | include/target/target_core_fabric.h | 1 |
6 files changed, 74 insertions, 104 deletions
diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index 04f80ebf09eb..6986552b47e6 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c | |||
@@ -26,7 +26,6 @@ | |||
26 | #include <linux/module.h> | 26 | #include <linux/module.h> |
27 | #include <linux/init.h> | 27 | #include <linux/init.h> |
28 | #include <linux/types.h> | 28 | #include <linux/types.h> |
29 | #include <linux/version.h> | ||
30 | #include <linux/blkdev.h> | 29 | #include <linux/blkdev.h> |
31 | #include <linux/interrupt.h> | 30 | #include <linux/interrupt.h> |
32 | #include <linux/pci.h> | 31 | #include <linux/pci.h> |
@@ -2477,11 +2476,9 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, uint32_t handle, | |||
2477 | } | 2476 | } |
2478 | 2477 | ||
2479 | cmd = qlt_ctio_to_cmd(vha, handle, ctio); | 2478 | cmd = qlt_ctio_to_cmd(vha, handle, ctio); |
2480 | if (cmd == NULL) { | 2479 | if (cmd == NULL) |
2481 | if (status != CTIO_SUCCESS) | ||
2482 | qlt_term_ctio_exchange(vha, ctio, NULL, status); | ||
2483 | return; | 2480 | return; |
2484 | } | 2481 | |
2485 | se_cmd = &cmd->se_cmd; | 2482 | se_cmd = &cmd->se_cmd; |
2486 | tfo = se_cmd->se_tfo; | 2483 | tfo = se_cmd->se_tfo; |
2487 | 2484 | ||
@@ -2727,10 +2724,12 @@ static void qlt_do_work(struct work_struct *work) | |||
2727 | out_term: | 2724 | out_term: |
2728 | ql_dbg(ql_dbg_tgt_mgt, vha, 0xf020, "Terminating work cmd %p", cmd); | 2725 | ql_dbg(ql_dbg_tgt_mgt, vha, 0xf020, "Terminating work cmd %p", cmd); |
2729 | /* | 2726 | /* |
2730 | * cmd has not sent to target yet, so pass NULL as the second argument | 2727 | * cmd has not sent to target yet, so pass NULL as the second |
2728 | * argument to qlt_send_term_exchange() and free the memory here. | ||
2731 | */ | 2729 | */ |
2732 | spin_lock_irqsave(&ha->hardware_lock, flags); | 2730 | spin_lock_irqsave(&ha->hardware_lock, flags); |
2733 | qlt_send_term_exchange(vha, NULL, &cmd->atio, 1); | 2731 | qlt_send_term_exchange(vha, NULL, &cmd->atio, 1); |
2732 | kmem_cache_free(qla_tgt_cmd_cachep, cmd); | ||
2734 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | 2733 | spin_unlock_irqrestore(&ha->hardware_lock, flags); |
2735 | if (sess) | 2734 | if (sess) |
2736 | ha->tgt.tgt_ops->put_sess(sess); | 2735 | ha->tgt.tgt_ops->put_sess(sess); |
diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h index 9ec19bc2f0fe..9f9ef1644fd9 100644 --- a/drivers/scsi/qla2xxx/qla_target.h +++ b/drivers/scsi/qla2xxx/qla_target.h | |||
@@ -919,7 +919,6 @@ struct qla_tgt_srr_ctio { | |||
919 | #define QLA_TGT_XMIT_STATUS 2 | 919 | #define QLA_TGT_XMIT_STATUS 2 |
920 | #define QLA_TGT_XMIT_ALL (QLA_TGT_XMIT_STATUS|QLA_TGT_XMIT_DATA) | 920 | #define QLA_TGT_XMIT_ALL (QLA_TGT_XMIT_STATUS|QLA_TGT_XMIT_DATA) |
921 | 921 | ||
922 | #include <linux/version.h> | ||
923 | 922 | ||
924 | extern struct qla_tgt_data qla_target; | 923 | extern struct qla_tgt_data qla_target; |
925 | /* | 924 | /* |
diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index 436598f57404..6e64314dbbb3 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c | |||
@@ -137,13 +137,15 @@ static char *tcm_qla2xxx_get_fabric_name(void) | |||
137 | */ | 137 | */ |
138 | static int tcm_qla2xxx_npiv_extract_wwn(const char *ns, u64 *nm) | 138 | static int tcm_qla2xxx_npiv_extract_wwn(const char *ns, u64 *nm) |
139 | { | 139 | { |
140 | unsigned int i, j, value; | 140 | unsigned int i, j; |
141 | u8 wwn[8]; | 141 | u8 wwn[8]; |
142 | 142 | ||
143 | memset(wwn, 0, sizeof(wwn)); | 143 | memset(wwn, 0, sizeof(wwn)); |
144 | 144 | ||
145 | /* Validate and store the new name */ | 145 | /* Validate and store the new name */ |
146 | for (i = 0, j = 0; i < 16; i++) { | 146 | for (i = 0, j = 0; i < 16; i++) { |
147 | int value; | ||
148 | |||
147 | value = hex_to_bin(*ns++); | 149 | value = hex_to_bin(*ns++); |
148 | if (value >= 0) | 150 | if (value >= 0) |
149 | j = (j << 4) | value; | 151 | j = (j << 4) | value; |
@@ -652,8 +654,8 @@ static int tcm_qla2xxx_handle_data(struct qla_tgt_cmd *cmd) | |||
652 | /* | 654 | /* |
653 | * Called from qla_target.c:qlt_issue_task_mgmt() | 655 | * Called from qla_target.c:qlt_issue_task_mgmt() |
654 | */ | 656 | */ |
655 | int tcm_qla2xxx_handle_tmr(struct qla_tgt_mgmt_cmd *mcmd, uint32_t lun, | 657 | static int tcm_qla2xxx_handle_tmr(struct qla_tgt_mgmt_cmd *mcmd, uint32_t lun, |
656 | uint8_t tmr_func, uint32_t tag) | 658 | uint8_t tmr_func, uint32_t tag) |
657 | { | 659 | { |
658 | struct qla_tgt_sess *sess = mcmd->sess; | 660 | struct qla_tgt_sess *sess = mcmd->sess; |
659 | struct se_cmd *se_cmd = &mcmd->se_cmd; | 661 | struct se_cmd *se_cmd = &mcmd->se_cmd; |
@@ -762,65 +764,8 @@ static u16 tcm_qla2xxx_set_fabric_sense_len(struct se_cmd *se_cmd, | |||
762 | struct target_fabric_configfs *tcm_qla2xxx_fabric_configfs; | 764 | struct target_fabric_configfs *tcm_qla2xxx_fabric_configfs; |
763 | struct target_fabric_configfs *tcm_qla2xxx_npiv_fabric_configfs; | 765 | struct target_fabric_configfs *tcm_qla2xxx_npiv_fabric_configfs; |
764 | 766 | ||
765 | static int tcm_qla2xxx_setup_nacl_from_rport( | 767 | static void tcm_qla2xxx_clear_sess_lookup(struct tcm_qla2xxx_lport *, |
766 | struct se_portal_group *se_tpg, | 768 | struct tcm_qla2xxx_nacl *, struct qla_tgt_sess *); |
767 | struct se_node_acl *se_nacl, | ||
768 | struct tcm_qla2xxx_lport *lport, | ||
769 | struct tcm_qla2xxx_nacl *nacl, | ||
770 | u64 rport_wwnn) | ||
771 | { | ||
772 | struct scsi_qla_host *vha = lport->qla_vha; | ||
773 | struct Scsi_Host *sh = vha->host; | ||
774 | struct fc_host_attrs *fc_host = shost_to_fc_host(sh); | ||
775 | struct fc_rport *rport; | ||
776 | unsigned long flags; | ||
777 | void *node; | ||
778 | int rc; | ||
779 | |||
780 | /* | ||
781 | * Scan the existing rports, and create a session for the | ||
782 | * explict NodeACL is an matching rport->node_name already | ||
783 | * exists. | ||
784 | */ | ||
785 | spin_lock_irqsave(sh->host_lock, flags); | ||
786 | list_for_each_entry(rport, &fc_host->rports, peers) { | ||
787 | if (rport_wwnn != rport->node_name) | ||
788 | continue; | ||
789 | |||
790 | pr_debug("Located existing rport_wwpn and rport->node_name: 0x%016LX, port_id: 0x%04x\n", | ||
791 | rport->node_name, rport->port_id); | ||
792 | nacl->nport_id = rport->port_id; | ||
793 | |||
794 | spin_unlock_irqrestore(sh->host_lock, flags); | ||
795 | |||
796 | spin_lock_irqsave(&vha->hw->hardware_lock, flags); | ||
797 | node = btree_lookup32(&lport->lport_fcport_map, rport->port_id); | ||
798 | if (node) { | ||
799 | rc = btree_update32(&lport->lport_fcport_map, | ||
800 | rport->port_id, se_nacl); | ||
801 | } else { | ||
802 | rc = btree_insert32(&lport->lport_fcport_map, | ||
803 | rport->port_id, se_nacl, | ||
804 | GFP_ATOMIC); | ||
805 | } | ||
806 | spin_unlock_irqrestore(&vha->hw->hardware_lock, flags); | ||
807 | |||
808 | if (rc) { | ||
809 | pr_err("Unable to insert se_nacl into fcport_map"); | ||
810 | WARN_ON(rc > 0); | ||
811 | return rc; | ||
812 | } | ||
813 | |||
814 | pr_debug("Inserted into fcport_map: %p for WWNN: 0x%016LX, port_id: 0x%08x\n", | ||
815 | se_nacl, rport_wwnn, nacl->nport_id); | ||
816 | |||
817 | return 1; | ||
818 | } | ||
819 | spin_unlock_irqrestore(sh->host_lock, flags); | ||
820 | |||
821 | return 0; | ||
822 | } | ||
823 | |||
824 | /* | 769 | /* |
825 | * Expected to be called with struct qla_hw_data->hardware_lock held | 770 | * Expected to be called with struct qla_hw_data->hardware_lock held |
826 | */ | 771 | */ |
@@ -842,11 +787,40 @@ static void tcm_qla2xxx_clear_nacl_from_fcport_map(struct qla_tgt_sess *sess) | |||
842 | 787 | ||
843 | pr_debug("Removed from fcport_map: %p for WWNN: 0x%016LX, port_id: 0x%06x\n", | 788 | pr_debug("Removed from fcport_map: %p for WWNN: 0x%016LX, port_id: 0x%06x\n", |
844 | se_nacl, nacl->nport_wwnn, nacl->nport_id); | 789 | se_nacl, nacl->nport_wwnn, nacl->nport_id); |
790 | /* | ||
791 | * Now clear the se_nacl and session pointers from our HW lport lookup | ||
792 | * table mapping for this initiator's fabric S_ID and LOOP_ID entries. | ||
793 | * | ||
794 | * This is done ahead of callbacks into tcm_qla2xxx_free_session() -> | ||
795 | * target_wait_for_sess_cmds() before the session waits for outstanding | ||
796 | * I/O to complete, to avoid a race between session shutdown execution | ||
797 | * and incoming ATIOs or TMRs picking up a stale se_node_act reference. | ||
798 | */ | ||
799 | tcm_qla2xxx_clear_sess_lookup(lport, nacl, sess); | ||
800 | } | ||
801 | |||
802 | static void tcm_qla2xxx_release_session(struct kref *kref) | ||
803 | { | ||
804 | struct se_session *se_sess = container_of(kref, | ||
805 | struct se_session, sess_kref); | ||
806 | |||
807 | qlt_unreg_sess(se_sess->fabric_sess_ptr); | ||
808 | } | ||
809 | |||
810 | static void tcm_qla2xxx_put_session(struct se_session *se_sess) | ||
811 | { | ||
812 | struct qla_tgt_sess *sess = se_sess->fabric_sess_ptr; | ||
813 | struct qla_hw_data *ha = sess->vha->hw; | ||
814 | unsigned long flags; | ||
815 | |||
816 | spin_lock_irqsave(&ha->hardware_lock, flags); | ||
817 | kref_put(&se_sess->sess_kref, tcm_qla2xxx_release_session); | ||
818 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
845 | } | 819 | } |
846 | 820 | ||
847 | static void tcm_qla2xxx_put_sess(struct qla_tgt_sess *sess) | 821 | static void tcm_qla2xxx_put_sess(struct qla_tgt_sess *sess) |
848 | { | 822 | { |
849 | target_put_session(sess->se_sess); | 823 | tcm_qla2xxx_put_session(sess->se_sess); |
850 | } | 824 | } |
851 | 825 | ||
852 | static void tcm_qla2xxx_shutdown_sess(struct qla_tgt_sess *sess) | 826 | static void tcm_qla2xxx_shutdown_sess(struct qla_tgt_sess *sess) |
@@ -859,14 +833,10 @@ static struct se_node_acl *tcm_qla2xxx_make_nodeacl( | |||
859 | struct config_group *group, | 833 | struct config_group *group, |
860 | const char *name) | 834 | const char *name) |
861 | { | 835 | { |
862 | struct se_wwn *se_wwn = se_tpg->se_tpg_wwn; | ||
863 | struct tcm_qla2xxx_lport *lport = container_of(se_wwn, | ||
864 | struct tcm_qla2xxx_lport, lport_wwn); | ||
865 | struct se_node_acl *se_nacl, *se_nacl_new; | 836 | struct se_node_acl *se_nacl, *se_nacl_new; |
866 | struct tcm_qla2xxx_nacl *nacl; | 837 | struct tcm_qla2xxx_nacl *nacl; |
867 | u64 wwnn; | 838 | u64 wwnn; |
868 | u32 qla2xxx_nexus_depth; | 839 | u32 qla2xxx_nexus_depth; |
869 | int rc; | ||
870 | 840 | ||
871 | if (tcm_qla2xxx_parse_wwn(name, &wwnn, 1) < 0) | 841 | if (tcm_qla2xxx_parse_wwn(name, &wwnn, 1) < 0) |
872 | return ERR_PTR(-EINVAL); | 842 | return ERR_PTR(-EINVAL); |
@@ -893,16 +863,6 @@ static struct se_node_acl *tcm_qla2xxx_make_nodeacl( | |||
893 | nacl = container_of(se_nacl, struct tcm_qla2xxx_nacl, se_node_acl); | 863 | nacl = container_of(se_nacl, struct tcm_qla2xxx_nacl, se_node_acl); |
894 | nacl->nport_wwnn = wwnn; | 864 | nacl->nport_wwnn = wwnn; |
895 | tcm_qla2xxx_format_wwn(&nacl->nport_name[0], TCM_QLA2XXX_NAMELEN, wwnn); | 865 | tcm_qla2xxx_format_wwn(&nacl->nport_name[0], TCM_QLA2XXX_NAMELEN, wwnn); |
896 | /* | ||
897 | * Setup a se_nacl handle based on an a matching struct fc_rport setup | ||
898 | * via drivers/scsi/qla2xxx/qla_init.c:qla2x00_reg_remote_port() | ||
899 | */ | ||
900 | rc = tcm_qla2xxx_setup_nacl_from_rport(se_tpg, se_nacl, lport, | ||
901 | nacl, wwnn); | ||
902 | if (rc < 0) { | ||
903 | tcm_qla2xxx_release_fabric_acl(se_tpg, se_nacl_new); | ||
904 | return ERR_PTR(rc); | ||
905 | } | ||
906 | 866 | ||
907 | return se_nacl; | 867 | return se_nacl; |
908 | } | 868 | } |
@@ -1390,6 +1350,25 @@ static void tcm_qla2xxx_set_sess_by_loop_id( | |||
1390 | nacl->qla_tgt_sess, new_se_nacl, new_se_nacl->initiatorname); | 1350 | nacl->qla_tgt_sess, new_se_nacl, new_se_nacl->initiatorname); |
1391 | } | 1351 | } |
1392 | 1352 | ||
1353 | /* | ||
1354 | * Should always be called with qla_hw_data->hardware_lock held. | ||
1355 | */ | ||
1356 | static void tcm_qla2xxx_clear_sess_lookup(struct tcm_qla2xxx_lport *lport, | ||
1357 | struct tcm_qla2xxx_nacl *nacl, struct qla_tgt_sess *sess) | ||
1358 | { | ||
1359 | struct se_session *se_sess = sess->se_sess; | ||
1360 | unsigned char be_sid[3]; | ||
1361 | |||
1362 | be_sid[0] = sess->s_id.b.domain; | ||
1363 | be_sid[1] = sess->s_id.b.area; | ||
1364 | be_sid[2] = sess->s_id.b.al_pa; | ||
1365 | |||
1366 | tcm_qla2xxx_set_sess_by_s_id(lport, NULL, nacl, se_sess, | ||
1367 | sess, be_sid); | ||
1368 | tcm_qla2xxx_set_sess_by_loop_id(lport, NULL, nacl, se_sess, | ||
1369 | sess, sess->loop_id); | ||
1370 | } | ||
1371 | |||
1393 | static void tcm_qla2xxx_free_session(struct qla_tgt_sess *sess) | 1372 | static void tcm_qla2xxx_free_session(struct qla_tgt_sess *sess) |
1394 | { | 1373 | { |
1395 | struct qla_tgt *tgt = sess->tgt; | 1374 | struct qla_tgt *tgt = sess->tgt; |
@@ -1398,8 +1377,6 @@ static void tcm_qla2xxx_free_session(struct qla_tgt_sess *sess) | |||
1398 | struct se_node_acl *se_nacl; | 1377 | struct se_node_acl *se_nacl; |
1399 | struct tcm_qla2xxx_lport *lport; | 1378 | struct tcm_qla2xxx_lport *lport; |
1400 | struct tcm_qla2xxx_nacl *nacl; | 1379 | struct tcm_qla2xxx_nacl *nacl; |
1401 | unsigned char be_sid[3]; | ||
1402 | unsigned long flags; | ||
1403 | 1380 | ||
1404 | BUG_ON(in_interrupt()); | 1381 | BUG_ON(in_interrupt()); |
1405 | 1382 | ||
@@ -1419,21 +1396,6 @@ static void tcm_qla2xxx_free_session(struct qla_tgt_sess *sess) | |||
1419 | return; | 1396 | return; |
1420 | } | 1397 | } |
1421 | target_wait_for_sess_cmds(se_sess, 0); | 1398 | target_wait_for_sess_cmds(se_sess, 0); |
1422 | /* | ||
1423 | * And now clear the se_nacl and session pointers from our HW lport | ||
1424 | * mappings for fabric S_ID and LOOP_ID. | ||
1425 | */ | ||
1426 | memset(&be_sid, 0, 3); | ||
1427 | be_sid[0] = sess->s_id.b.domain; | ||
1428 | be_sid[1] = sess->s_id.b.area; | ||
1429 | be_sid[2] = sess->s_id.b.al_pa; | ||
1430 | |||
1431 | spin_lock_irqsave(&ha->hardware_lock, flags); | ||
1432 | tcm_qla2xxx_set_sess_by_s_id(lport, NULL, nacl, se_sess, | ||
1433 | sess, be_sid); | ||
1434 | tcm_qla2xxx_set_sess_by_loop_id(lport, NULL, nacl, se_sess, | ||
1435 | sess, sess->loop_id); | ||
1436 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
1437 | 1399 | ||
1438 | transport_deregister_session_configfs(sess->se_sess); | 1400 | transport_deregister_session_configfs(sess->se_sess); |
1439 | transport_deregister_session(sess->se_sess); | 1401 | transport_deregister_session(sess->se_sess); |
@@ -1731,6 +1693,7 @@ static struct target_core_fabric_ops tcm_qla2xxx_ops = { | |||
1731 | .new_cmd_map = NULL, | 1693 | .new_cmd_map = NULL, |
1732 | .check_stop_free = tcm_qla2xxx_check_stop_free, | 1694 | .check_stop_free = tcm_qla2xxx_check_stop_free, |
1733 | .release_cmd = tcm_qla2xxx_release_cmd, | 1695 | .release_cmd = tcm_qla2xxx_release_cmd, |
1696 | .put_session = tcm_qla2xxx_put_session, | ||
1734 | .shutdown_session = tcm_qla2xxx_shutdown_session, | 1697 | .shutdown_session = tcm_qla2xxx_shutdown_session, |
1735 | .close_session = tcm_qla2xxx_close_session, | 1698 | .close_session = tcm_qla2xxx_close_session, |
1736 | .sess_get_index = tcm_qla2xxx_sess_get_index, | 1699 | .sess_get_index = tcm_qla2xxx_sess_get_index, |
@@ -1779,6 +1742,7 @@ static struct target_core_fabric_ops tcm_qla2xxx_npiv_ops = { | |||
1779 | .tpg_release_fabric_acl = tcm_qla2xxx_release_fabric_acl, | 1742 | .tpg_release_fabric_acl = tcm_qla2xxx_release_fabric_acl, |
1780 | .tpg_get_inst_index = tcm_qla2xxx_tpg_get_inst_index, | 1743 | .tpg_get_inst_index = tcm_qla2xxx_tpg_get_inst_index, |
1781 | .release_cmd = tcm_qla2xxx_release_cmd, | 1744 | .release_cmd = tcm_qla2xxx_release_cmd, |
1745 | .put_session = tcm_qla2xxx_put_session, | ||
1782 | .shutdown_session = tcm_qla2xxx_shutdown_session, | 1746 | .shutdown_session = tcm_qla2xxx_shutdown_session, |
1783 | .close_session = tcm_qla2xxx_close_session, | 1747 | .close_session = tcm_qla2xxx_close_session, |
1784 | .sess_get_index = tcm_qla2xxx_sess_get_index, | 1748 | .sess_get_index = tcm_qla2xxx_sess_get_index, |
diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index e624b836469c..91799973081a 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c | |||
@@ -374,8 +374,9 @@ int target_emulate_set_target_port_groups(struct se_cmd *cmd) | |||
374 | 374 | ||
375 | out: | 375 | out: |
376 | transport_kunmap_data_sg(cmd); | 376 | transport_kunmap_data_sg(cmd); |
377 | target_complete_cmd(cmd, GOOD); | 377 | if (!rc) |
378 | return 0; | 378 | target_complete_cmd(cmd, GOOD); |
379 | return rc; | ||
379 | } | 380 | } |
380 | 381 | ||
381 | static inline int core_alua_state_nonoptimized( | 382 | static inline int core_alua_state_nonoptimized( |
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index b05fdc0c05d3..634d0f31a28c 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c | |||
@@ -315,7 +315,7 @@ void transport_register_session( | |||
315 | } | 315 | } |
316 | EXPORT_SYMBOL(transport_register_session); | 316 | EXPORT_SYMBOL(transport_register_session); |
317 | 317 | ||
318 | static void target_release_session(struct kref *kref) | 318 | void target_release_session(struct kref *kref) |
319 | { | 319 | { |
320 | struct se_session *se_sess = container_of(kref, | 320 | struct se_session *se_sess = container_of(kref, |
321 | struct se_session, sess_kref); | 321 | struct se_session, sess_kref); |
@@ -332,6 +332,12 @@ EXPORT_SYMBOL(target_get_session); | |||
332 | 332 | ||
333 | void target_put_session(struct se_session *se_sess) | 333 | void target_put_session(struct se_session *se_sess) |
334 | { | 334 | { |
335 | struct se_portal_group *tpg = se_sess->se_tpg; | ||
336 | |||
337 | if (tpg->se_tpg_tfo->put_session != NULL) { | ||
338 | tpg->se_tpg_tfo->put_session(se_sess); | ||
339 | return; | ||
340 | } | ||
335 | kref_put(&se_sess->sess_kref, target_release_session); | 341 | kref_put(&se_sess->sess_kref, target_release_session); |
336 | } | 342 | } |
337 | EXPORT_SYMBOL(target_put_session); | 343 | EXPORT_SYMBOL(target_put_session); |
diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index 116959933f46..c78a23333c4f 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h | |||
@@ -47,6 +47,7 @@ struct target_core_fabric_ops { | |||
47 | */ | 47 | */ |
48 | int (*check_stop_free)(struct se_cmd *); | 48 | int (*check_stop_free)(struct se_cmd *); |
49 | void (*release_cmd)(struct se_cmd *); | 49 | void (*release_cmd)(struct se_cmd *); |
50 | void (*put_session)(struct se_session *); | ||
50 | /* | 51 | /* |
51 | * Called with spin_lock_bh(struct se_portal_group->session_lock held. | 52 | * Called with spin_lock_bh(struct se_portal_group->session_lock held. |
52 | */ | 53 | */ |