Skip to content

Commit 8bc9f08

Browse files
committed
cifs: handle cases where a channel is closed
jira LE-4669 Rebuild_History Non-Buildable kernel-4.18.0-553.82.1.el8_10 commit-author Shyam Prasad N <sprasad@microsoft.com> commit 0c51cc6 Empty-Commit: Cherry-Pick Conflicts during history rebuild. Will be included in final tarball splat. Ref for failed cherry-pick at: ciq/ciq_backports/kernel-4.18.0-553.82.1.el8_10/0c51cc6f.failed So far, SMB multichannel could only scale up, but not scale down the number of channels. In this series of patch, we now allow the client to deal with the case of multichannel disabled on the server when the share is mounted. With that change, we now need the ability to scale down the channels. This change allows the client to deal with cases of missing channels more gracefully. Signed-off-by: Shyam Prasad N <sprasad@microsoft.com> Signed-off-by: Steve French <stfrench@microsoft.com> (cherry picked from commit 0c51cc6) Signed-off-by: Jonathan Maple <jmaple@ciq.com> # Conflicts: # fs/cifs/connect.c # fs/cifs/sess.c
1 parent 95335ab commit 8bc9f08

File tree

1 file changed

+311
-0
lines changed

1 file changed

+311
-0
lines changed
Lines changed: 311 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,311 @@
1+
cifs: handle cases where a channel is closed
2+
3+
jira LE-4669
4+
Rebuild_History Non-Buildable kernel-4.18.0-553.82.1.el8_10
5+
commit-author Shyam Prasad N <sprasad@microsoft.com>
6+
commit 0c51cc6f2cb0108e7d49805f6e089cd85caab279
7+
Empty-Commit: Cherry-Pick Conflicts during history rebuild.
8+
Will be included in final tarball splat. Ref for failed cherry-pick at:
9+
ciq/ciq_backports/kernel-4.18.0-553.82.1.el8_10/0c51cc6f.failed
10+
11+
So far, SMB multichannel could only scale up, but not
12+
scale down the number of channels. In this series of
13+
patch, we now allow the client to deal with the case
14+
of multichannel disabled on the server when the share
15+
is mounted. With that change, we now need the ability
16+
to scale down the channels.
17+
18+
This change allows the client to deal with cases of
19+
missing channels more gracefully.
20+
21+
Signed-off-by: Shyam Prasad N <sprasad@microsoft.com>
22+
Signed-off-by: Steve French <stfrench@microsoft.com>
23+
(cherry picked from commit 0c51cc6f2cb0108e7d49805f6e089cd85caab279)
24+
Signed-off-by: Jonathan Maple <jmaple@ciq.com>
25+
26+
# Conflicts:
27+
# fs/cifs/connect.c
28+
# fs/cifs/sess.c
29+
diff --cc fs/cifs/connect.c
30+
index ca2926c7b59e,3ff82f0aa00e..000000000000
31+
--- a/fs/cifs/connect.c
32+
+++ b/fs/cifs/connect.c
33+
@@@ -164,45 -140,70 +164,63 @@@ static void smb2_query_server_interface
34+
(SMB_INTERFACE_POLL_INTERVAL * HZ));
35+
}
36+
37+
-/*
38+
- * Update the tcpStatus for the server.
39+
- * This is used to signal the cifsd thread to call cifs_reconnect
40+
- * ONLY cifsd thread should call cifs_reconnect. For any other
41+
- * thread, use this function
42+
- *
43+
- * @server: the tcp ses for which reconnect is needed
44+
- * @all_channels: if this needs to be done for all channels
45+
- */
46+
-void
47+
-cifs_signal_cifsd_for_reconnect(struct TCP_Server_Info *server,
48+
- bool all_channels)
49+
+static void cifs_resolve_server(struct work_struct *work)
50+
{
51+
- struct TCP_Server_Info *pserver;
52+
- struct cifs_ses *ses;
53+
- int i;
54+
+ int rc;
55+
+ struct TCP_Server_Info *server = container_of(work,
56+
+ struct TCP_Server_Info, resolve.work);
57+
58+
- /* If server is a channel, select the primary channel */
59+
- pserver = SERVER_IS_CHAN(server) ? server->primary_server : server;
60+
+ mutex_lock(&server->srv_mutex);
61+
62+
- /* if we need to signal just this channel */
63+
- if (!all_channels) {
64+
- spin_lock(&server->srv_lock);
65+
- if (server->tcpStatus != CifsExiting)
66+
- server->tcpStatus = CifsNeedReconnect;
67+
- spin_unlock(&server->srv_lock);
68+
- return;
69+
+ /*
70+
+ * Resolve the hostname again to make sure that IP address is up-to-date.
71+
+ */
72+
+ rc = reconn_set_ipaddr_from_hostname(server);
73+
+ if (rc) {
74+
+ cifs_dbg(FYI, "%s: failed to resolve hostname: %d\n",
75+
+ __func__, rc);
76+
}
77+
78+
++<<<<<<< HEAD:fs/cifs/connect.c
79+
+ mutex_unlock(&server->srv_mutex);
80+
++=======
81+
+ spin_lock(&cifs_tcp_ses_lock);
82+
+ list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) {
83+
+ spin_lock(&ses->chan_lock);
84+
+ for (i = 0; i < ses->chan_count; i++) {
85+
+ if (!ses->chans[i].server)
86+
+ continue;
87+
+
88+
+ spin_lock(&ses->chans[i].server->srv_lock);
89+
+ if (ses->chans[i].server->tcpStatus != CifsExiting)
90+
+ ses->chans[i].server->tcpStatus = CifsNeedReconnect;
91+
+ spin_unlock(&ses->chans[i].server->srv_lock);
92+
+ }
93+
+ spin_unlock(&ses->chan_lock);
94+
+ }
95+
+ spin_unlock(&cifs_tcp_ses_lock);
96+
++>>>>>>> 0c51cc6f2cb0 (cifs: handle cases where a channel is closed):fs/smb/client/connect.c
97+
}
98+
99+
-/*
100+
+/**
101+
* Mark all sessions and tcons for reconnect.
102+
- * IMPORTANT: make sure that this gets called only from
103+
- * cifsd thread. For any other thread, use
104+
- * cifs_signal_cifsd_for_reconnect
105+
*
106+
- * @server: the tcp ses for which reconnect is needed
107+
* @server needs to be previously set to CifsNeedReconnect.
108+
- * @mark_smb_session: whether even sessions need to be marked
109+
*/
110+
-void
111+
-cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server,
112+
- bool mark_smb_session)
113+
+static void cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server)
114+
{
115+
- struct TCP_Server_Info *pserver;
116+
- struct cifs_ses *ses, *nses;
117+
+ unsigned int num_sessions = 0;
118+
+ struct cifs_ses *ses;
119+
struct cifs_tcon *tcon;
120+
+ struct mid_q_entry *mid, *nmid;
121+
+ struct list_head retry_list;
122+
+ struct TCP_Server_Info *pserver;
123+
124+
+ server->maxBuf = 0;
125+
+ server->max_read = 0;
126+
+
127+
+ cifs_dbg(FYI, "Mark tcp session as need reconnect\n");
128+
+ trace_smb3_reconnect(server->CurrentMid, server->conn_id, server->hostname);
129+
/*
130+
* before reconnecting the tcp session, mark the smb session (uid) and the tid bad so they
131+
* are not used until reconnected.
132+
diff --cc fs/cifs/sess.c
133+
index b9c9236e1312,d13a24613710..000000000000
134+
--- a/fs/cifs/sess.c
135+
+++ b/fs/cifs/sess.c
136+
@@@ -65,7 -67,9 +65,13 @@@ bool is_ses_using_iface(struct cifs_se
137+
return false;
138+
}
139+
140+
++<<<<<<< HEAD:fs/cifs/sess.c
141+
+unsigned int
142+
++=======
143+
+ /* channel helper functions. assumed that chan_lock is held by caller. */
144+
+
145+
+ int
146+
++>>>>>>> 0c51cc6f2cb0 (cifs: handle cases where a channel is closed):fs/smb/client/sess.c
147+
cifs_ses_get_chan_index(struct cifs_ses *ses,
148+
struct TCP_Server_Info *server)
149+
{
150+
@@@ -81,10 -85,44 +87,47 @@@
151+
cifs_dbg(VFS, "unable to get chan index for server: 0x%llx",
152+
server->conn_id);
153+
WARN_ON(1);
154+
- return 0;
155+
+ return CIFS_INVAL_CHAN_INDEX;
156+
+ }
157+
+
158+
+ void
159+
++<<<<<<< HEAD:fs/cifs/sess.c
160+
++=======
161+
+ cifs_chan_set_in_reconnect(struct cifs_ses *ses,
162+
+ struct TCP_Server_Info *server)
163+
+ {
164+
+ int chan_index = cifs_ses_get_chan_index(ses, server);
165+
+
166+
+ if (chan_index == CIFS_INVAL_CHAN_INDEX)
167+
+ return;
168+
+
169+
+ ses->chans[chan_index].in_reconnect = true;
170+
+ }
171+
+
172+
+ void
173+
+ cifs_chan_clear_in_reconnect(struct cifs_ses *ses,
174+
+ struct TCP_Server_Info *server)
175+
+ {
176+
+ unsigned int chan_index = cifs_ses_get_chan_index(ses, server);
177+
+ if (chan_index == CIFS_INVAL_CHAN_INDEX)
178+
+ return;
179+
+
180+
+ ses->chans[chan_index].in_reconnect = false;
181+
+ }
182+
+
183+
+ bool
184+
+ cifs_chan_in_reconnect(struct cifs_ses *ses,
185+
+ struct TCP_Server_Info *server)
186+
+ {
187+
+ unsigned int chan_index = cifs_ses_get_chan_index(ses, server);
188+
+ if (chan_index == CIFS_INVAL_CHAN_INDEX)
189+
+ return true; /* err on the safer side */
190+
+
191+
+ return CIFS_CHAN_IN_RECONNECT(ses, chan_index);
192+
}
193+
194+
void
195+
++>>>>>>> 0c51cc6f2cb0 (cifs: handle cases where a channel is closed):fs/smb/client/sess.c
196+
cifs_chan_set_need_reconnect(struct cifs_ses *ses,
197+
struct TCP_Server_Info *server)
198+
{
199+
@@@ -236,9 -282,12 +287,16 @@@ cifs_chan_update_iface(struct cifs_ses
200+
struct cifs_server_iface *old_iface = NULL;
201+
int rc = 0;
202+
203+
++<<<<<<< HEAD:fs/cifs/sess.c
204+
+ /* primary channel. This can never go away */
205+
+ if (!chan_index)
206+
++=======
207+
+ spin_lock(&ses->chan_lock);
208+
+ chan_index = cifs_ses_get_chan_index(ses, server);
209+
+ if (chan_index == CIFS_INVAL_CHAN_INDEX) {
210+
+ spin_unlock(&ses->chan_lock);
211+
++>>>>>>> 0c51cc6f2cb0 (cifs: handle cases where a channel is closed):fs/smb/client/sess.c
212+
return 0;
213+
- }
214+
215+
if (ses->chans[chan_index].iface) {
216+
old_iface = ses->chans[chan_index].iface;
217+
@@@ -281,14 -330,25 +339,26 @@@
218+
WARN_ON(!iface);
219+
cifs_dbg(FYI, "adding new iface: %pIS\n", &iface->sockaddr);
220+
}
221+
+
222+
spin_unlock(&ses->iface_lock);
223+
224+
++<<<<<<< HEAD:fs/cifs/sess.c
225+
++=======
226+
+ spin_lock(&ses->chan_lock);
227+
+ chan_index = cifs_ses_get_chan_index(ses, server);
228+
+ if (chan_index == CIFS_INVAL_CHAN_INDEX) {
229+
+ spin_unlock(&ses->chan_lock);
230+
+ return 0;
231+
+ }
232+
+
233+
+ ses->chans[chan_index].iface = iface;
234+
+
235+
++>>>>>>> 0c51cc6f2cb0 (cifs: handle cases where a channel is closed):fs/smb/client/sess.c
236+
/* No iface is found. if secondary chan, drop connection */
237+
- if (!iface && SERVER_IS_CHAN(server))
238+
- ses->chans[chan_index].server = NULL;
239+
-
240+
- spin_unlock(&ses->chan_lock);
241+
-
242+
- if (!iface && SERVER_IS_CHAN(server))
243+
+ if (!iface && CIFS_SERVER_IS_CHAN(server)) {
244+
cifs_put_tcp_session(server, false);
245+
+ ses->chans[chan_index].server = NULL;
246+
+ }
247+
248+
return rc;
249+
}
250+
diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c
251+
index eb8541c3298e..02c728536d29 100644
252+
--- a/fs/cifs/cifs_debug.c
253+
+++ b/fs/cifs/cifs_debug.c
254+
@@ -142,6 +142,11 @@ cifs_dump_channel(struct seq_file *m, int i, struct cifs_chan *chan)
255+
{
256+
struct TCP_Server_Info *server = chan->server;
257+
258+
+ if (!server) {
259+
+ seq_printf(m, "\n\n\t\tChannel: %d DISABLED", i+1);
260+
+ return;
261+
+ }
262+
+
263+
seq_printf(m, "\n\n\t\tChannel: %d ConnectionId: 0x%llx"
264+
"\n\t\tNumber of credits: %d Dialect 0x%x"
265+
"\n\t\tTCP status: %d Instance: %d"
266+
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
267+
index 9e7f8c48e52c..dd0fa3e31591 100644
268+
--- a/fs/cifs/cifsglob.h
269+
+++ b/fs/cifs/cifsglob.h
270+
@@ -1029,6 +1029,7 @@ struct cifs_ses {
271+
spinlock_t chan_lock;
272+
/* ========= begin: protected by chan_lock ======== */
273+
#define CIFS_MAX_CHANNELS 16
274+
+#define CIFS_INVAL_CHAN_INDEX (-1)
275+
#define CIFS_ALL_CHANNELS_SET(ses) \
276+
((1UL << (ses)->chan_count) - 1)
277+
#define CIFS_ALL_CHANS_NEED_RECONNECT(ses) \
278+
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
279+
index 76582fa73223..379a00836656 100644
280+
--- a/fs/cifs/cifsproto.h
281+
+++ b/fs/cifs/cifsproto.h
282+
@@ -599,7 +599,7 @@ bool is_server_using_iface(struct TCP_Server_Info *server,
283+
bool is_ses_using_iface(struct cifs_ses *ses, struct cifs_server_iface *iface);
284+
void cifs_ses_mark_for_reconnect(struct cifs_ses *ses);
285+
286+
-unsigned int
287+
+int
288+
cifs_ses_get_chan_index(struct cifs_ses *ses,
289+
struct TCP_Server_Info *server);
290+
void
291+
* Unmerged path fs/cifs/connect.c
292+
* Unmerged path fs/cifs/sess.c
293+
diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c
294+
index c6bf79f874d4..7e9a760af8b1 100644
295+
--- a/fs/cifs/smb2transport.c
296+
+++ b/fs/cifs/smb2transport.c
297+
@@ -412,7 +412,13 @@ generate_smb3signingkey(struct cifs_ses *ses,
298+
spin_lock(&ses->chan_lock);
299+
is_binding = !CIFS_ALL_CHANS_NEED_RECONNECT(ses);
300+
chan_index = cifs_ses_get_chan_index(ses, server);
301+
- /* TODO: introduce ref counting for channels when the can be freed */
302+
+ if (chan_index == CIFS_INVAL_CHAN_INDEX) {
303+
+ spin_unlock(&ses->chan_lock);
304+
+ spin_unlock(&ses->ses_lock);
305+
+
306+
+ return -EINVAL;
307+
+ }
308+
+
309+
spin_unlock(&ses->chan_lock);
310+
311+
/*

0 commit comments

Comments
 (0)