FAILED: patch "[PATCH] cifs: avoid race conditions with parallel reconnects" failed to apply to 5.15-stable tree
[email protected]
maintainerThe patch below does not apply to the 5.15-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-5.15.y
git checkout FETCH_HEAD
git cherry-pick -x bc962159e8e326af634a506508034a375bf2b858
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '[email protected]' --subject-prefix 'PATCH 5.15.y' HEAD^..
Possible dependencies:
bc962159e8e3 ("cifs: avoid race conditions with parallel reconnects") 1bcd548d935a ("cifs: prevent data race in cifs_reconnect_tcon()") e77978de4765 ("cifs: update ip_addr for ses only for primary chan setup") 3c0070f54b31 ("cifs: prevent data race in smb2_reconnect()")25cf01b7c920 ("cifs: set correct status of tcon ipc when reconnecting") d7d7a66aacd6 ("cifs: avoid use of global locks for high contention data") 9543c8ab3016 ("cifs: list_for_each() -> list_for_each_entry()") af3a6d1018f0 ("cifs: update cifs_ses::ip_addr after failover")b54034a73baf ("cifs: during reconnect, update interface if necessary") cc391b694ff0 ("cifs: fix potential deadlock in direct reclaim") 5752bf645f9d ("cifs: avoid parallel session setups on same channel") dd3cd8709ed5 ("cifs: use new enum for ses_status")1a6a41d4cedd ("cifs: do not use tcpStatus after negotiate completes") cd70a3e8988a ("cifs: use correct lock type in cifs_reconnect()") fb39d30e2272 ("cifs: force new session setup and tcon for dfs") 9a005bea4f59 ("Merge tag '5.18-smb3-fixes-part2' of git://git.samba.org/sfrench/cifs-2.6")
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From bc962159e8e326af634a506508034a375bf2b858 Mon Sep 17 00:00:00 2001
From: Shyam Prasad N <[email protected]>
Date: Mon, 20 Mar 2023 06:08:19 +0000
Subject: [PATCH] cifs: avoid race conditions with parallel reconnects
When multiple processes/channels do reconnects in parallel we used to return success immediately negotiate/session-setup/tree-connect, causing race conditions between processes that enter the function in parallel. This caused several errors related to session not found to show up during parallel reconnects.
fs/cifs/connect.c +36 -12
@@ -212,31 +212,42 @@ cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server,cifs_chan_update_iface (ses, server);spin_lock (&ses->chan_lock); -if (!mark_smb_session &&cifs_chan_needs_reconnect (ses, server)) - goto next_session; +if (!mark_smb_session &&cifs_chan_needs_reconnect (ses, server)) { +spin_unlock (&ses->chan_lock); +continue ; + }if (mark_smb_session)CIFS_SET_ALL_CHANS_NEED_RECONNECT (ses);else cifs_chan_set_need_reconnect (ses, server); +cifs_dbg (FYI ,"%s: channel connect bitmap: 0x%lx\n" , + __func__, ses->chans_need_reconnect); +/* If all channels need reconnect, then tcon needs reconnect */ -if (!mark_smb_session && !CIFS_ALL_CHANS_NEED_RECONNECT (ses)) - goto next_session; +if (!mark_smb_session && !CIFS_ALL_CHANS_NEED_RECONNECT (ses)) { +spin_unlock (&ses->chan_lock); +continue ; + } +spin_unlock (&ses->chan_lock); +spin_lock (&ses->ses_lock); ses->ses_status =SES_NEED_RECON ; +spin_unlock (&ses->ses_lock);list_for_each_entry (tcon, &ses->tcon_list, tcon_list) { tcon->need_reconnect = true; +spin_lock (&tcon->tc_lock); tcon->status =TID_NEED_RECON ; +spin_unlock (&tcon->tc_lock); }if (ses->tcon_ipc) { ses->tcon_ipc->need_reconnect = true; +spin_lock (&ses->tcon_ipc->tc_lock); ses->tcon_ipc->status =TID_NEED_RECON ; +spin_unlock (&ses->tcon_ipc->tc_lock); } - -next_session: -spin_unlock (&ses->chan_lock); }spin_unlock (&cifs_tcp_ses_lock); }
@@ -3653,11 +3664,19 @@ cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses,/* only send once per connect */ spin_lock (&server->srv_lock); -if (!server->ops->need_neg (server) || +if (server->tcpStatus != CifsGood && + server->tcpStatus != CifsNew && server->tcpStatus != CifsNeedNegotiate) { +spin_unlock (&server->srv_lock); +return -EHOSTDOWN ; + } + +if (!server->ops->need_neg (server) && + server->tcpStatus == CifsGood) {spin_unlock (&server->srv_lock);return 0 ; } + server->tcpStatus = CifsInNegotiate;spin_unlock (&server->srv_lock);
@@ -3691,23 +3710,28 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,bool is_binding = false;spin_lock (&ses->ses_lock); +cifs_dbg (FYI ,"%s: channel connect bitmap: 0x%lx\n" , + __func__, ses->chans_need_reconnect); +if (ses->ses_status !=SES_GOOD && ses->ses_status !=SES_NEW && ses->ses_status !=SES_NEED_RECON ) {spin_unlock (&ses->ses_lock); -return 0 ; +return -EHOSTDOWN ; }/* only send once per connect */ spin_lock (&ses->chan_lock); -if (CIFS_ALL_CHANS_GOOD (ses) || -cifs_chan_in_reconnect (ses, server)) { +if (CIFS_ALL_CHANS_GOOD (ses)) { +if (ses->ses_status ==SES_NEED_RECON ) + ses->ses_status =SES_GOOD ;spin_unlock (&ses->chan_lock);spin_unlock (&ses->ses_lock);return 0 ; } - is_binding = !CIFS_ALL_CHANS_NEED_RECONNECT (ses); +cifs_chan_set_in_reconnect (ses, server); + is_binding = !CIFS_ALL_CHANS_NEED_RECONNECT (ses);spin_unlock (&ses->chan_lock);if (!is_binding)
fs/cifs/smb2pdu.c +26 -18
116 lines not on this page · raw message
fs/cifs/smb2transport.c +14 -3
@@ -81,6 +81,7 @@ int smb2_get_sign_key(__u64 ses_id, struct TCP_Server_Info *server, u8 *key)struct cifs_ses *ses =NULL ;int i;int rc =0 ; +bool is_binding = false;spin_lock (&cifs_tcp_ses_lock);
@@ -97,9 +98,12 @@ int smb2_get_sign_key(__u64 ses_id, struct TCP_Server_Info *server, u8 *key) goto out; found: +spin_lock (&ses->ses_lock);spin_lock (&ses->chan_lock); -if (cifs_chan_needs_reconnect (ses, server) && - !CIFS_ALL_CHANS_NEED_RECONNECT (ses)) { + + is_binding = (cifs_chan_needs_reconnect (ses, server) && + ses->ses_status ==SES_GOOD ); +if (is_binding) {/* * If we are in the process of binding a new channel * to an existing session, use the master connection
@@ -107,6 +111,7 @@ int smb2_get_sign_key(__u64 ses_id, struct TCP_Server_Info *server, u8 *key)*/ memcpy (key, ses->smb3signingkey,SMB3_SIGN_KEY_SIZE );spin_unlock (&ses->chan_lock); +spin_unlock (&ses->ses_lock); goto out; }
@@ -119,10 +124,12 @@ int smb2_get_sign_key(__u64 ses_id, struct TCP_Server_Info *server, u8 *key)if (chan->server == server) {memcpy (key, chan->signkey,SMB3_SIGN_KEY_SIZE );spin_unlock (&ses->chan_lock); +spin_unlock (&ses->ses_lock); goto out; } }spin_unlock (&ses->chan_lock); +spin_unlock (&ses->ses_lock); cifs_dbg(VFS, "%s: Could not find channel signing key for session 0x%llx\n",
@@ -392,11 +399,15 @@ generate_smb3signingkey(struct cifs_ses *ses,bool is_binding = false;int chan_index =0 ; +spin_lock (&ses->ses_lock);spin_lock (&ses->chan_lock); - is_binding = !CIFS_ALL_CHANS_NEED_RECONNECT (ses); + is_binding = (cifs_chan_needs_reconnect (ses, server) && + ses->ses_status ==SES_GOOD ); + chan_index =cifs_ses_get_chan_index (ses, server);/* TODO: introduce ref counting for channels when the can be freed */ spin_unlock (&ses->chan_lock); +spin_unlock (&ses->ses_lock);/* * All channels use the same encryption/decryption keys but