Message ID | 20230310153211.10982-10-sprasad@microsoft.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | [01/11] cifs: fix tcon status change after tree connect | expand |
Hi Shyam,
I love your patch! Perhaps something to improve:
[auto build test WARNING on cifs/for-next]
[also build test WARNING on linus/master v6.3-rc2 next-20230310]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Shyam-Prasad-N/cifs-generate-signkey-for-the-channel-that-s-reconnecting/20230310-234711
base: git://git.samba.org/sfrench/cifs-2.6.git for-next
patch link: https://lore.kernel.org/r/20230310153211.10982-10-sprasad%40microsoft.com
patch subject: [PATCH 10/11] cifs: handle when server stops supporting multichannel
config: i386-randconfig-m021 (https://download.01.org/0day-ci/archive/20230313/202303131424.W2jbbLmc-lkp@intel.com/config)
compiler: gcc-11 (Debian 11.3.0-8) 11.3.0
If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>
| Link: https://lore.kernel.org/oe-kbuild-all/202303131424.W2jbbLmc-lkp@intel.com/
New smatch warnings:
fs/cifs/sess.c:299 cifs_disable_extra_channels() warn: unsigned '--iface->weight_fulfilled' is never less than zero.
Old smatch warnings:
fs/cifs/sess.c:401 cifs_chan_update_iface() warn: unsigned '--old_iface->weight_fulfilled' is never less than zero.
fs/cifs/sess.c:412 cifs_chan_update_iface() warn: unsigned '--old_iface->weight_fulfilled' is never less than zero.
vim +299 fs/cifs/sess.c
276
277 /*
278 * called when multichannel is disabled by the server
279 */
280 void
281 cifs_disable_extra_channels(struct cifs_ses *ses)
282 {
283 int i, chan_count;
284 struct cifs_server_iface *iface = NULL;
285 struct TCP_Server_Info *server = NULL;
286
287 spin_lock(&ses->chan_lock);
288 chan_count = ses->chan_count;
289 ses->chan_count = 1;
290 for (i = 1; i < chan_count; i++) {
291 iface = ses->chans[i].iface;
292 server = ses->chans[i].server;
293 spin_unlock(&ses->chan_lock);
294
295 if (iface) {
296 spin_lock(&ses->iface_lock);
297 kref_put(&iface->refcount, release_iface);
298 iface->num_channels--;
> 299 if (--iface->weight_fulfilled < 0)
300 iface->weight_fulfilled = 0;
301 spin_unlock(&ses->iface_lock);
302 }
303 cifs_put_tcp_session(server, 0);
304
305 spin_lock(&ses->chan_lock);
306 ses->chans[i].iface = NULL;
307 ses->chans[i].server = NULL;
308 }
309 spin_unlock(&ses->chan_lock);
310 }
311
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 30fd81268eb7..343e582672b9 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -638,6 +638,8 @@ cifs_chan_needs_reconnect(struct cifs_ses *ses, bool cifs_chan_is_iface_active(struct cifs_ses *ses, struct TCP_Server_Info *server); +void +cifs_disable_extra_channels(struct cifs_ses *ses); int cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server); int diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index b9af60417194..6375b08b9bcb 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -130,6 +130,12 @@ static void smb2_query_server_interfaces(struct work_struct *work) if (rc) { cifs_dbg(FYI, "%s: failed to query server interfaces: %d\n", __func__, rc); + + if (rc == -EOPNOTSUPP) { + /* cancel polling of interfaces and do not resched */ + cancel_delayed_work_sync(&tcon->query_interfaces); + return; + } } queue_delayed_work(cifsiod_wq, &tcon->query_interfaces, diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 9b51b2309e9c..34ae292bdff2 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -274,6 +274,41 @@ int cifs_try_adding_channels(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses) return new_chan_count - old_chan_count; } +/* + * called when multichannel is disabled by the server + */ +void +cifs_disable_extra_channels(struct cifs_ses *ses) +{ + int i, chan_count; + struct cifs_server_iface *iface = NULL; + struct TCP_Server_Info *server = NULL; + + spin_lock(&ses->chan_lock); + chan_count = ses->chan_count; + ses->chan_count = 1; + for (i = 1; i < chan_count; i++) { + iface = ses->chans[i].iface; + server = ses->chans[i].server; + spin_unlock(&ses->chan_lock); + + if (iface) { + spin_lock(&ses->iface_lock); + kref_put(&iface->refcount, release_iface); + iface->num_channels--; + if (--iface->weight_fulfilled < 0) + iface->weight_fulfilled = 0; + spin_unlock(&ses->iface_lock); + } + cifs_put_tcp_session(server, 0); + + spin_lock(&ses->chan_lock); + ses->chans[i].iface = NULL; + ses->chans[i].server = NULL; + } + spin_unlock(&ses->chan_lock); +} + /* * update the iface for the channel if necessary. * will return 0 when iface is updated, 1 if removed, 2 otherwise diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index a5e53cb1ac49..c7a8a6049291 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -411,6 +411,14 @@ smb2_negotiate(const unsigned int xid, /* BB we probably don't need to retry with modern servers */ if (rc == -EAGAIN) rc = -EHOSTDOWN; + + if (!rc && + ses->chan_count > 1 && + !(server->capabilities & SMB2_GLOBAL_CAP_MULTI_CHANNEL)) { + cifs_dbg(VFS, "server %s does not support multichannel anymore\n", ses->server->hostname); + cifs_disable_extra_channels(ses); + } + return rc; }
When a server stops supporting multichannel, we will keep attempting reconnects to the secondary channels today. Avoid this by freeing extra channels when negotiate returns no multichannel support. Signed-off-by: Shyam Prasad N <sprasad@microsoft.com> --- fs/cifs/cifsproto.h | 2 ++ fs/cifs/connect.c | 6 ++++++ fs/cifs/sess.c | 35 +++++++++++++++++++++++++++++++++++ fs/cifs/smb2ops.c | 8 ++++++++ 4 files changed, 51 insertions(+)