--- /dev/null
+From 6ee9927a9fef730a7d1d17ab614811b1852edee6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 13 Dec 2019 16:15:15 -0800
+Subject: kvm: x86: Host feature SSBD doesn't imply guest feature
+ SPEC_CTRL_SSBD
+
+From: Jim Mattson <jmattson@google.com>
+
+commit 396d2e878f92ec108e4293f1c77ea3bc90b414ff upstream.
+
+The host reports support for the synthetic feature X86_FEATURE_SSBD
+when any of the three following hardware features are set:
+ CPUID.(EAX=7,ECX=0):EDX.SSBD[bit 31]
+ CPUID.80000008H:EBX.AMD_SSBD[bit 24]
+ CPUID.80000008H:EBX.VIRT_SSBD[bit 25]
+
+Either of the first two hardware features implies the existence of the
+IA32_SPEC_CTRL MSR, but CPUID.80000008H:EBX.VIRT_SSBD[bit 25] does
+not. Therefore, CPUID.(EAX=7,ECX=0):EDX.SSBD[bit 31] should only be
+set in the guest if CPUID.(EAX=7,ECX=0):EDX.SSBD[bit 31] or
+CPUID.80000008H:EBX.AMD_SSBD[bit 24] is set on the host.
+
+Fixes: 0c54914d0c52a ("KVM: x86: use Intel speculation bugs and features as derived in generic x86 code")
+Signed-off-by: Jim Mattson <jmattson@google.com>
+Reviewed-by: Jacob Xu <jacobhxu@google.com>
+Reviewed-by: Peter Shier <pshier@google.com>
+Cc: Paolo Bonzini <pbonzini@redhat.com>
+Reported-by: Eric Biggers <ebiggers@kernel.org>
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+[bwh: Backported to 4.x: adjust indentation]
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/kvm/cpuid.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
+index 48c24d0e9e75c..1fe9ccabc082a 100644
+--- a/arch/x86/kvm/cpuid.c
++++ b/arch/x86/kvm/cpuid.c
+@@ -509,7 +509,8 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
+ entry->edx |= F(SPEC_CTRL);
+ if (boot_cpu_has(X86_FEATURE_STIBP))
+ entry->edx |= F(INTEL_STIBP);
+- if (boot_cpu_has(X86_FEATURE_SSBD))
++ if (boot_cpu_has(X86_FEATURE_SPEC_CTRL_SSBD) ||
++ boot_cpu_has(X86_FEATURE_AMD_SSBD))
+ entry->edx |= F(SPEC_CTRL_SSBD);
+ /*
+ * We emulate ARCH_CAPABILITIES in software even
+--
+2.20.1
+
--- /dev/null
+From f6aaf61a8f57675a0ddf62a56db4e29253f0242c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 13 Mar 2020 18:06:55 +0100
+Subject: scsi: target: fix hang when multiple threads try to destroy the same
+ iscsi session
+
+From: Maurizio Lombardi <mlombard@redhat.com>
+
+[ Upstream commit 57c46e9f33da530a2485fa01aa27b6d18c28c796 ]
+
+A number of hangs have been reported against the target driver; they are
+due to the fact that multiple threads may try to destroy the iscsi session
+at the same time. This may be reproduced for example when a "targetcli
+iscsi/iqn.../tpg1 disable" command is executed while a logout operation is
+underway.
+
+When this happens, two or more threads may end up sleeping and waiting for
+iscsit_close_connection() to execute "complete(session_wait_comp)". Only
+one of the threads will wake up and proceed to destroy the session
+structure, the remaining threads will hang forever.
+
+Note that if the blocked threads are somehow forced to wake up with
+complete_all(), they will try to free the same iscsi session structure
+destroyed by the first thread, causing double frees, memory corruptions
+etc...
+
+With this patch, the threads that want to destroy the iscsi session will
+increase the session refcount and will set the "session_close" flag to 1;
+then they wait for the driver to close the remaining active connections.
+When the last connection is closed, iscsit_close_connection() will wake up
+all the threads and will wait for the session's refcount to reach zero;
+when this happens, iscsit_close_connection() will destroy the session
+structure because no one is referencing it anymore.
+
+ INFO: task targetcli:5971 blocked for more than 120 seconds.
+ Tainted: P OE 4.15.0-72-generic #81~16.04.1
+ "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
+ targetcli D 0 5971 1 0x00000080
+ Call Trace:
+ __schedule+0x3d6/0x8b0
+ ? vprintk_func+0x44/0xe0
+ schedule+0x36/0x80
+ schedule_timeout+0x1db/0x370
+ ? __dynamic_pr_debug+0x8a/0xb0
+ wait_for_completion+0xb4/0x140
+ ? wake_up_q+0x70/0x70
+ iscsit_free_session+0x13d/0x1a0 [iscsi_target_mod]
+ iscsit_release_sessions_for_tpg+0x16b/0x1e0 [iscsi_target_mod]
+ iscsit_tpg_disable_portal_group+0xca/0x1c0 [iscsi_target_mod]
+ lio_target_tpg_enable_store+0x66/0xe0 [iscsi_target_mod]
+ configfs_write_file+0xb9/0x120
+ __vfs_write+0x1b/0x40
+ vfs_write+0xb8/0x1b0
+ SyS_write+0x5c/0xe0
+ do_syscall_64+0x73/0x130
+ entry_SYSCALL_64_after_hwframe+0x3d/0xa2
+
+Link: https://lore.kernel.org/r/20200313170656.9716-3-mlombard@redhat.com
+Reported-by: Matt Coleman <mcoleman@datto.com>
+Tested-by: Matt Coleman <mcoleman@datto.com>
+Tested-by: Rahul Kundu <rahul.kundu@chelsio.com>
+Signed-off-by: Maurizio Lombardi <mlombard@redhat.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/target/iscsi/iscsi_target.c | 35 ++++++++++++--------
+ drivers/target/iscsi/iscsi_target_configfs.c | 5 ++-
+ drivers/target/iscsi/iscsi_target_login.c | 5 +--
+ include/target/iscsi/iscsi_target_core.h | 2 +-
+ 4 files changed, 30 insertions(+), 17 deletions(-)
+
+diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
+index 82b46bab8aabe..1633e26662687 100644
+--- a/drivers/target/iscsi/iscsi_target.c
++++ b/drivers/target/iscsi/iscsi_target.c
+@@ -4275,30 +4275,37 @@ int iscsit_close_connection(
+ if (!atomic_read(&sess->session_reinstatement) &&
+ atomic_read(&sess->session_fall_back_to_erl0)) {
+ spin_unlock_bh(&sess->conn_lock);
++ complete_all(&sess->session_wait_comp);
+ iscsit_close_session(sess);
+
+ return 0;
+ } else if (atomic_read(&sess->session_logout)) {
+ pr_debug("Moving to TARG_SESS_STATE_FREE.\n");
+ sess->session_state = TARG_SESS_STATE_FREE;
+- spin_unlock_bh(&sess->conn_lock);
+
+- if (atomic_read(&sess->sleep_on_sess_wait_comp))
+- complete(&sess->session_wait_comp);
++ if (atomic_read(&sess->session_close)) {
++ spin_unlock_bh(&sess->conn_lock);
++ complete_all(&sess->session_wait_comp);
++ iscsit_close_session(sess);
++ } else {
++ spin_unlock_bh(&sess->conn_lock);
++ }
+
+ return 0;
+ } else {
+ pr_debug("Moving to TARG_SESS_STATE_FAILED.\n");
+ sess->session_state = TARG_SESS_STATE_FAILED;
+
+- if (!atomic_read(&sess->session_continuation)) {
+- spin_unlock_bh(&sess->conn_lock);
++ if (!atomic_read(&sess->session_continuation))
+ iscsit_start_time2retain_handler(sess);
+- } else
+- spin_unlock_bh(&sess->conn_lock);
+
+- if (atomic_read(&sess->sleep_on_sess_wait_comp))
+- complete(&sess->session_wait_comp);
++ if (atomic_read(&sess->session_close)) {
++ spin_unlock_bh(&sess->conn_lock);
++ complete_all(&sess->session_wait_comp);
++ iscsit_close_session(sess);
++ } else {
++ spin_unlock_bh(&sess->conn_lock);
++ }
+
+ return 0;
+ }
+@@ -4404,9 +4411,9 @@ static void iscsit_logout_post_handler_closesession(
+ complete(&conn->conn_logout_comp);
+
+ iscsit_dec_conn_usage_count(conn);
++ atomic_set(&sess->session_close, 1);
+ iscsit_stop_session(sess, sleep, sleep);
+ iscsit_dec_session_usage_count(sess);
+- iscsit_close_session(sess);
+ }
+
+ static void iscsit_logout_post_handler_samecid(
+@@ -4551,8 +4558,6 @@ void iscsit_stop_session(
+ int is_last;
+
+ spin_lock_bh(&sess->conn_lock);
+- if (session_sleep)
+- atomic_set(&sess->sleep_on_sess_wait_comp, 1);
+
+ if (connection_sleep) {
+ list_for_each_entry_safe(conn, conn_tmp, &sess->sess_conn_list,
+@@ -4610,12 +4615,15 @@ int iscsit_release_sessions_for_tpg(struct iscsi_portal_group *tpg, int force)
+ spin_lock(&sess->conn_lock);
+ if (atomic_read(&sess->session_fall_back_to_erl0) ||
+ atomic_read(&sess->session_logout) ||
++ atomic_read(&sess->session_close) ||
+ (sess->time2retain_timer_flags & ISCSI_TF_EXPIRED)) {
+ spin_unlock(&sess->conn_lock);
+ continue;
+ }
++ iscsit_inc_session_usage_count(sess);
+ atomic_set(&sess->session_reinstatement, 1);
+ atomic_set(&sess->session_fall_back_to_erl0, 1);
++ atomic_set(&sess->session_close, 1);
+ spin_unlock(&sess->conn_lock);
+
+ list_move_tail(&se_sess->sess_list, &free_list);
+@@ -4625,8 +4633,9 @@ int iscsit_release_sessions_for_tpg(struct iscsi_portal_group *tpg, int force)
+ list_for_each_entry_safe(se_sess, se_sess_tmp, &free_list, sess_list) {
+ sess = (struct iscsi_session *)se_sess->fabric_sess_ptr;
+
++ list_del_init(&se_sess->sess_list);
+ iscsit_stop_session(sess, 1, 1);
+- iscsit_close_session(sess);
++ iscsit_dec_session_usage_count(sess);
+ session_count++;
+ }
+
+diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c
+index 95d0a22b2ad61..d25cadc4f4f11 100644
+--- a/drivers/target/iscsi/iscsi_target_configfs.c
++++ b/drivers/target/iscsi/iscsi_target_configfs.c
+@@ -1501,20 +1501,23 @@ static void lio_tpg_close_session(struct se_session *se_sess)
+ spin_lock(&sess->conn_lock);
+ if (atomic_read(&sess->session_fall_back_to_erl0) ||
+ atomic_read(&sess->session_logout) ||
++ atomic_read(&sess->session_close) ||
+ (sess->time2retain_timer_flags & ISCSI_TF_EXPIRED)) {
+ spin_unlock(&sess->conn_lock);
+ spin_unlock_bh(&se_tpg->session_lock);
+ return;
+ }
++ iscsit_inc_session_usage_count(sess);
+ atomic_set(&sess->session_reinstatement, 1);
+ atomic_set(&sess->session_fall_back_to_erl0, 1);
++ atomic_set(&sess->session_close, 1);
+ spin_unlock(&sess->conn_lock);
+
+ iscsit_stop_time2retain_timer(sess);
+ spin_unlock_bh(&se_tpg->session_lock);
+
+ iscsit_stop_session(sess, 1, 1);
+- iscsit_close_session(sess);
++ iscsit_dec_session_usage_count(sess);
+ }
+
+ static u32 lio_tpg_get_inst_index(struct se_portal_group *se_tpg)
+diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c
+index bb90c80ff3889..f25049ba4a85b 100644
+--- a/drivers/target/iscsi/iscsi_target_login.c
++++ b/drivers/target/iscsi/iscsi_target_login.c
+@@ -164,6 +164,7 @@ int iscsi_check_for_session_reinstatement(struct iscsi_conn *conn)
+ spin_lock(&sess_p->conn_lock);
+ if (atomic_read(&sess_p->session_fall_back_to_erl0) ||
+ atomic_read(&sess_p->session_logout) ||
++ atomic_read(&sess_p->session_close) ||
+ (sess_p->time2retain_timer_flags & ISCSI_TF_EXPIRED)) {
+ spin_unlock(&sess_p->conn_lock);
+ continue;
+@@ -174,6 +175,7 @@ int iscsi_check_for_session_reinstatement(struct iscsi_conn *conn)
+ (sess_p->sess_ops->SessionType == sessiontype))) {
+ atomic_set(&sess_p->session_reinstatement, 1);
+ atomic_set(&sess_p->session_fall_back_to_erl0, 1);
++ atomic_set(&sess_p->session_close, 1);
+ spin_unlock(&sess_p->conn_lock);
+ iscsit_inc_session_usage_count(sess_p);
+ iscsit_stop_time2retain_timer(sess_p);
+@@ -198,7 +200,6 @@ int iscsi_check_for_session_reinstatement(struct iscsi_conn *conn)
+ if (sess->session_state == TARG_SESS_STATE_FAILED) {
+ spin_unlock_bh(&sess->conn_lock);
+ iscsit_dec_session_usage_count(sess);
+- iscsit_close_session(sess);
+ return 0;
+ }
+ spin_unlock_bh(&sess->conn_lock);
+@@ -206,7 +207,6 @@ int iscsi_check_for_session_reinstatement(struct iscsi_conn *conn)
+ iscsit_stop_session(sess, 1, 1);
+ iscsit_dec_session_usage_count(sess);
+
+- iscsit_close_session(sess);
+ return 0;
+ }
+
+@@ -494,6 +494,7 @@ static int iscsi_login_non_zero_tsih_s2(
+ sess_p = (struct iscsi_session *)se_sess->fabric_sess_ptr;
+ if (atomic_read(&sess_p->session_fall_back_to_erl0) ||
+ atomic_read(&sess_p->session_logout) ||
++ atomic_read(&sess_p->session_close) ||
+ (sess_p->time2retain_timer_flags & ISCSI_TF_EXPIRED))
+ continue;
+ if (!memcmp(sess_p->isid, pdu->isid, 6) &&
+diff --git a/include/target/iscsi/iscsi_target_core.h b/include/target/iscsi/iscsi_target_core.h
+index f2e6abea84905..70d18444d18d8 100644
+--- a/include/target/iscsi/iscsi_target_core.h
++++ b/include/target/iscsi/iscsi_target_core.h
+@@ -674,7 +674,7 @@ struct iscsi_session {
+ atomic_t session_logout;
+ atomic_t session_reinstatement;
+ atomic_t session_stop_active;
+- atomic_t sleep_on_sess_wait_comp;
++ atomic_t session_close;
+ /* connection list */
+ struct list_head sess_conn_list;
+ struct list_head cr_active_list;
+--
+2.20.1
+
--- /dev/null
+From 3d2e803fffbb7c8a51f1f2909f70aecf3849e6f4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 13 Mar 2020 18:06:54 +0100
+Subject: scsi: target: remove boilerplate code
+
+From: Maurizio Lombardi <mlombard@redhat.com>
+
+[ Upstream commit e49a7d994379278d3353d7ffc7994672752fb0ad ]
+
+iscsit_free_session() is equivalent to iscsit_stop_session() followed by a
+call to iscsit_close_session().
+
+Link: https://lore.kernel.org/r/20200313170656.9716-2-mlombard@redhat.com
+Tested-by: Rahul Kundu <rahul.kundu@chelsio.com>
+Signed-off-by: Maurizio Lombardi <mlombard@redhat.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/target/iscsi/iscsi_target.c | 46 ++---------------------------
+ drivers/target/iscsi/iscsi_target.h | 1 -
+ 2 files changed, 2 insertions(+), 45 deletions(-)
+
+diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
+index 03e9cb156df94..82b46bab8aabe 100644
+--- a/drivers/target/iscsi/iscsi_target.c
++++ b/drivers/target/iscsi/iscsi_target.c
+@@ -4541,49 +4541,6 @@ void iscsit_fail_session(struct iscsi_session *sess)
+ sess->session_state = TARG_SESS_STATE_FAILED;
+ }
+
+-int iscsit_free_session(struct iscsi_session *sess)
+-{
+- u16 conn_count = atomic_read(&sess->nconn);
+- struct iscsi_conn *conn, *conn_tmp = NULL;
+- int is_last;
+-
+- spin_lock_bh(&sess->conn_lock);
+- atomic_set(&sess->sleep_on_sess_wait_comp, 1);
+-
+- list_for_each_entry_safe(conn, conn_tmp, &sess->sess_conn_list,
+- conn_list) {
+- if (conn_count == 0)
+- break;
+-
+- if (list_is_last(&conn->conn_list, &sess->sess_conn_list)) {
+- is_last = 1;
+- } else {
+- iscsit_inc_conn_usage_count(conn_tmp);
+- is_last = 0;
+- }
+- iscsit_inc_conn_usage_count(conn);
+-
+- spin_unlock_bh(&sess->conn_lock);
+- iscsit_cause_connection_reinstatement(conn, 1);
+- spin_lock_bh(&sess->conn_lock);
+-
+- iscsit_dec_conn_usage_count(conn);
+- if (is_last == 0)
+- iscsit_dec_conn_usage_count(conn_tmp);
+-
+- conn_count--;
+- }
+-
+- if (atomic_read(&sess->nconn)) {
+- spin_unlock_bh(&sess->conn_lock);
+- wait_for_completion(&sess->session_wait_comp);
+- } else
+- spin_unlock_bh(&sess->conn_lock);
+-
+- iscsit_close_session(sess);
+- return 0;
+-}
+-
+ void iscsit_stop_session(
+ struct iscsi_session *sess,
+ int session_sleep,
+@@ -4668,7 +4625,8 @@ int iscsit_release_sessions_for_tpg(struct iscsi_portal_group *tpg, int force)
+ list_for_each_entry_safe(se_sess, se_sess_tmp, &free_list, sess_list) {
+ sess = (struct iscsi_session *)se_sess->fabric_sess_ptr;
+
+- iscsit_free_session(sess);
++ iscsit_stop_session(sess, 1, 1);
++ iscsit_close_session(sess);
+ session_count++;
+ }
+
+diff --git a/drivers/target/iscsi/iscsi_target.h b/drivers/target/iscsi/iscsi_target.h
+index 48bac0acf8c76..11a481cf6eade 100644
+--- a/drivers/target/iscsi/iscsi_target.h
++++ b/drivers/target/iscsi/iscsi_target.h
+@@ -43,7 +43,6 @@ extern int iscsi_target_rx_thread(void *);
+ extern int iscsit_close_connection(struct iscsi_conn *);
+ extern int iscsit_close_session(struct iscsi_session *);
+ extern void iscsit_fail_session(struct iscsi_session *);
+-extern int iscsit_free_session(struct iscsi_session *);
+ extern void iscsit_stop_session(struct iscsi_session *, int, int);
+ extern int iscsit_release_sessions_for_tpg(struct iscsi_portal_group *, int);
+
+--
+2.20.1
+