Three multichannel patches from Shyam attached. On the patch below, I changed the debug text printed from "... seconds back" to "... seconds ago" >From 47326562bbe2896f8844db06882f4e09dc070a8e Mon Sep 17 00:00:00 2001 From: Shyam Prasad N <sprasad@xxxxxxxxxxxxx> Date: Fri, 23 Dec 2022 10:41:25 +0000 Subject: [PATCH 1/3] cifs: print last update time for interface list We store the last updated time for interface list while parsing the interfaces. This change is to just print that info in DebugData. Signed-off-by: Shyam Prasad N <sprasad@xxxxxxxxxxxxx> Signed-off-by: Steve French <stfrench@xxxxxxxxxxxxx> --- fs/cifs/cifs_debug.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 612f0bb284c9..4b2f7e7641ad 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -456,8 +456,10 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) spin_lock(&ses->iface_lock); if (ses->iface_count) - seq_printf(m, "\n\n\tServer interfaces: %zu", - ses->iface_count); + seq_printf(m, "\n\n\tServer interfaces: %zu" + "\tLast updated: %lu seconds ago", + ses->iface_count, + (jiffies - ses->iface_last_update) / HZ); j = 0; list_for_each_entry(iface, &ses->iface_list, iface_head) { -- 2.34.1 -- Thanks, Steve
From 1e584f4a0dca55a7999fb936e8b777d715fed6f9 Mon Sep 17 00:00:00 2001 From: Shyam Prasad N <sprasad@xxxxxxxxxxxxx> Date: Mon, 26 Dec 2022 11:24:56 +0000 Subject: [PATCH 2/3] cifs: distribute channels across interfaces based on speed Today, if the server interfaces RSS capable, we simply choose the fastest interface to setup a channel. This is not a scalable approach, and does not make a lot of attempt to distribute the connections. This change does a weighted distribution of channels across all the available server interfaces, where the weight is a function of the advertised interface speed. Signed-off-by: Shyam Prasad N <sprasad@xxxxxxxxxxxxx> Signed-off-by: Steve French <stfrench@xxxxxxxxxxxxx> --- fs/cifs/cifs_debug.c | 16 ++++++++++++ fs/cifs/cifsglob.h | 2 ++ fs/cifs/sess.c | 61 ++++++++++++++++++++++++++++++++++---------- 3 files changed, 65 insertions(+), 14 deletions(-) diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 4b2f7e7641ad..6cfa58027b09 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -219,6 +219,8 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) struct cifs_ses *ses; struct cifs_tcon *tcon; struct cifs_server_iface *iface; + size_t iface_weight = 0, iface_min_speed = 0; + struct cifs_server_iface *last_iface = NULL; int c, i, j; seq_puts(m, @@ -460,11 +462,25 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) "\tLast updated: %lu seconds ago", ses->iface_count, (jiffies - ses->iface_last_update) / HZ); + + last_iface = list_last_entry(&ses->iface_list, + struct cifs_server_iface, + iface_head); + iface_min_speed = last_iface->speed; + j = 0; list_for_each_entry(iface, &ses->iface_list, iface_head) { seq_printf(m, "\n\t%d)", ++j); cifs_dump_iface(m, iface); + + iface_weight = iface->speed / iface_min_speed; + seq_printf(m, "\t\tWeight (cur,total): (%lu,%lu)" + "\n\t\tAllocated channels: %u\n", + iface->weight_fulfilled, + iface_weight, + iface->num_channels); + if (is_ses_using_iface(ses, iface)) seq_puts(m, "\t\t[CONNECTED]\n"); } diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index cfdd5bf701a1..3da302ea9d76 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -953,6 +953,8 @@ struct cifs_server_iface { struct list_head iface_head; struct kref refcount; size_t speed; + size_t weight_fulfilled; + unsigned int num_channels; unsigned int rdma_capable : 1; unsigned int rss_capable : 1; unsigned int is_active : 1; /* unset if non existent */ diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index c47b254f0d1e..0df04231fe8b 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -163,7 +163,9 @@ int cifs_try_adding_channels(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses) int left; int rc = 0; int tries = 0; + size_t iface_weight = 0, iface_min_speed = 0; struct cifs_server_iface *iface = NULL, *niface = NULL; + struct cifs_server_iface *last_iface = NULL; spin_lock(&ses->chan_lock); @@ -192,16 +194,6 @@ int cifs_try_adding_channels(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses) } spin_unlock(&ses->chan_lock); - /* - * Keep connecting to same, fastest, iface for all channels as - * long as its RSS. Try next fastest one if not RSS or channel - * creation fails. - */ - spin_lock(&ses->iface_lock); - iface = list_first_entry(&ses->iface_list, struct cifs_server_iface, - iface_head); - spin_unlock(&ses->iface_lock); - while (left > 0) { tries++; @@ -214,17 +206,30 @@ int cifs_try_adding_channels(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses) spin_lock(&ses->iface_lock); if (!ses->iface_count) { spin_unlock(&ses->iface_lock); - break; + cifs_dbg(VFS, "server %s does not advertise interfaces\n", ses->server->hostname); + return 0; } + if (!iface) + iface = list_first_entry(&ses->iface_list, struct cifs_server_iface, + iface_head); + last_iface = list_last_entry(&ses->iface_list, struct cifs_server_iface, + iface_head); + iface_min_speed = last_iface->speed; + list_for_each_entry_safe_from(iface, niface, &ses->iface_list, iface_head) { /* skip ifaces that are unusable */ if (!iface->is_active || (is_ses_using_iface(ses, iface) && - !iface->rss_capable)) { + !iface->rss_capable)) + continue; + + /* check if we already allocated enough channels */ + iface_weight = iface->speed / iface_min_speed; + + if (iface->weight_fulfilled >= iface_weight) continue; - } /* take ref before unlock */ kref_get(&iface->refcount); @@ -241,10 +246,17 @@ int cifs_try_adding_channels(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses) continue; } - cifs_dbg(FYI, "successfully opened new channel on iface:%pIS\n", + iface->num_channels++; + iface->weight_fulfilled++; + cifs_dbg(VFS, "successfully opened new channel on iface:%pIS\n", &iface->sockaddr); break; } + + /* reached end of list. reset weight_fulfilled */ + if (iface == last_iface) + list_for_each_entry(iface, &ses->iface_list, iface_head) + iface->weight_fulfilled = 0; spin_unlock(&ses->iface_lock); left--; @@ -263,8 +275,10 @@ int cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server) { unsigned int chan_index; + size_t iface_weight = 0, iface_min_speed = 0; struct cifs_server_iface *iface = NULL; struct cifs_server_iface *old_iface = NULL; + struct cifs_server_iface *last_iface = NULL; int rc = 0; spin_lock(&ses->chan_lock); @@ -284,6 +298,16 @@ cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server) spin_unlock(&ses->chan_lock); spin_lock(&ses->iface_lock); + if (!ses->iface_count) { + spin_unlock(&ses->iface_lock); + cifs_dbg(VFS, "server %s does not advertise interfaces\n", ses->server->hostname); + return 0; + } + + last_iface = list_last_entry(&ses->iface_list, struct cifs_server_iface, + iface_head); + iface_min_speed = last_iface->speed; + /* then look for a new one */ list_for_each_entry(iface, &ses->iface_list, iface_head) { if (!iface->is_active || @@ -291,6 +315,15 @@ cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server) !iface->rss_capable)) { continue; } + + /* check if we already allocated enough channels */ + iface_weight = iface->speed / iface_min_speed; + + if (iface->rss_capable && + iface->num_channels && + (iface->num_channels % iface_weight) == 0) + continue; + kref_get(&iface->refcount); break; } -- 2.34.1
From 47326562bbe2896f8844db06882f4e09dc070a8e Mon Sep 17 00:00:00 2001 From: Shyam Prasad N <sprasad@xxxxxxxxxxxxx> Date: Fri, 23 Dec 2022 10:41:25 +0000 Subject: [PATCH 1/3] cifs: print last update time for interface list We store the last updated time for interface list while parsing the interfaces. This change is to just print that info in DebugData. Signed-off-by: Shyam Prasad N <sprasad@xxxxxxxxxxxxx> Signed-off-by: Steve French <stfrench@xxxxxxxxxxxxx> --- fs/cifs/cifs_debug.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 612f0bb284c9..4b2f7e7641ad 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -456,8 +456,10 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) spin_lock(&ses->iface_lock); if (ses->iface_count) - seq_printf(m, "\n\n\tServer interfaces: %zu", - ses->iface_count); + seq_printf(m, "\n\n\tServer interfaces: %zu" + "\tLast updated: %lu seconds ago", + ses->iface_count, + (jiffies - ses->iface_last_update) / HZ); j = 0; list_for_each_entry(iface, &ses->iface_list, iface_head) { -- 2.34.1
From f44b61bb03ebed47e14f56dc2bcbafd4e5728af3 Mon Sep 17 00:00:00 2001 From: Shyam Prasad N <sprasad@xxxxxxxxxxxxx> Date: Tue, 27 Dec 2022 09:22:08 +0000 Subject: [PATCH 3/3] cifs: account for primary channel in the interface list The refcounting of server interfaces should account for the primary channel too. Although this is not strictly necessary, doing so will account for the primary channel in DebugData. Signed-off-by: Shyam Prasad N <sprasad@xxxxxxxxxxxxx> Signed-off-by: Steve French <stfrench@xxxxxxxxxxxxx> --- fs/cifs/sess.c | 38 +++++++++++++++++++++++++++++++++----- fs/cifs/smb2ops.c | 6 ++++++ 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 0df04231fe8b..07822f2a5b7c 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -283,11 +283,6 @@ cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server) spin_lock(&ses->chan_lock); chan_index = cifs_ses_get_chan_index(ses, server); - if (!chan_index) { - spin_unlock(&ses->chan_lock); - return 0; - } - if (ses->chans[chan_index].iface) { old_iface = ses->chans[chan_index].iface; if (old_iface->is_active) { @@ -310,6 +305,16 @@ cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server) /* then look for a new one */ list_for_each_entry(iface, &ses->iface_list, iface_head) { + if (!chan_index) { + /* if we're trying to get the updated iface for primary channel */ + if (!cifs_match_ipaddr((struct sockaddr *) &server->dstaddr, + (struct sockaddr *) &iface->sockaddr)) + continue; + + kref_get(&iface->refcount); + break; + } + if (!iface->is_active || (is_ses_using_iface(ses, iface) && !iface->rss_capable)) { @@ -334,16 +339,39 @@ cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server) cifs_dbg(FYI, "unable to find a suitable iface\n"); } + if (!chan_index && !iface) { + cifs_dbg(VFS, "unable to get the interface matching: %pIS\n", + &server->dstaddr); + spin_unlock(&ses->iface_lock); + return 0; + } + /* now drop the ref to the current iface */ if (old_iface && iface) { cifs_dbg(FYI, "replacing iface: %pIS with %pIS\n", &old_iface->sockaddr, &iface->sockaddr); + if (!chan_index) { + old_iface->num_channels--; + old_iface->weight_fulfilled--; + iface->num_channels++; + iface->weight_fulfilled++; + } kref_put(&old_iface->refcount, release_iface); } else if (old_iface) { cifs_dbg(FYI, "releasing ref to iface: %pIS\n", &old_iface->sockaddr); + if (!chan_index) { + old_iface->num_channels--; + old_iface->weight_fulfilled--; + } kref_put(&old_iface->refcount, release_iface); + } else if (!chan_index) { + /* special case: update interface for primary channel */ + cifs_dbg(FYI, "referencing primary channel iface: %pIS\n", + &iface->sockaddr); + iface->num_channels++; + iface->weight_fulfilled++; } else { WARN_ON(!iface); cifs_dbg(FYI, "adding new iface: %pIS\n", &iface->sockaddr); diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index e6bcd2baf446..519e6124d73d 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -695,6 +695,7 @@ SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon, bool in_ unsigned int ret_data_len = 0; struct network_interface_info_ioctl_rsp *out_buf = NULL; struct cifs_ses *ses = tcon->ses; + struct TCP_Server_Info *pserver; rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID, FSCTL_QUERY_NETWORK_INTERFACE_INFO, @@ -713,6 +714,11 @@ SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon, bool in_ if (rc) goto out; + /* check if iface is still active */ + pserver = ses->chans[0].server; + if (pserver && !cifs_chan_is_iface_active(ses, pserver)) + cifs_chan_update_iface(ses, pserver); + out: kfree(out_buf); return rc; -- 2.34.1