|
| 1 | +cifs: distribute channels across interfaces based on speed |
| 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 a6d8fb54a515f0546ffdb7870102b1238917e567 |
| 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/a6d8fb54.failed |
| 10 | + |
| 11 | +Today, if the server interfaces RSS capable, we simply |
| 12 | +choose the fastest interface to setup a channel. This is not |
| 13 | +a scalable approach, and does not make a lot of attempt to |
| 14 | +distribute the connections. |
| 15 | + |
| 16 | +This change does a weighted distribution of channels across |
| 17 | +all the available server interfaces, where the weight is |
| 18 | +a function of the advertised interface speed. |
| 19 | + |
| 20 | +Also make sure that we don't mix rdma and non-rdma for channels. |
| 21 | + |
| 22 | + Signed-off-by: Shyam Prasad N <sprasad@microsoft.com> |
| 23 | + Signed-off-by: Steve French <stfrench@microsoft.com> |
| 24 | +(cherry picked from commit a6d8fb54a515f0546ffdb7870102b1238917e567) |
| 25 | + Signed-off-by: Jonathan Maple <jmaple@ciq.com> |
| 26 | + |
| 27 | +# Conflicts: |
| 28 | +# fs/cifs/sess.c |
| 29 | +diff --cc fs/cifs/sess.c |
| 30 | +index b9c9236e1312,336b64d93e41..000000000000 |
| 31 | +--- a/fs/cifs/sess.c |
| 32 | ++++ b/fs/cifs/sess.c |
| 33 | +@@@ -231,22 -298,39 +252,40 @@@ int cifs_try_adding_channels(struct cif |
| 34 | + int |
| 35 | + cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server) |
| 36 | + { |
| 37 | +++<<<<<<< HEAD:fs/cifs/sess.c |
| 38 | + + unsigned int chan_index = cifs_ses_get_chan_index(ses, server); |
| 39 | +++======= |
| 40 | ++ unsigned int chan_index; |
| 41 | ++ size_t iface_weight = 0, iface_min_speed = 0; |
| 42 | +++>>>>>>> a6d8fb54a515 (cifs: distribute channels across interfaces based on speed):fs/smb/client/sess.c |
| 43 | + struct cifs_server_iface *iface = NULL; |
| 44 | + struct cifs_server_iface *old_iface = NULL; |
| 45 | ++ struct cifs_server_iface *last_iface = NULL; |
| 46 | + int rc = 0; |
| 47 | + |
| 48 | + - spin_lock(&ses->chan_lock); |
| 49 | + - chan_index = cifs_ses_get_chan_index(ses, server); |
| 50 | + - if (chan_index == CIFS_INVAL_CHAN_INDEX) { |
| 51 | + - spin_unlock(&ses->chan_lock); |
| 52 | + + /* primary channel. This can never go away */ |
| 53 | + + if (!chan_index) |
| 54 | + return 0; |
| 55 | + - } |
| 56 | + |
| 57 | + if (ses->chans[chan_index].iface) { |
| 58 | + old_iface = ses->chans[chan_index].iface; |
| 59 | + - if (old_iface->is_active) { |
| 60 | + - spin_unlock(&ses->chan_lock); |
| 61 | + + if (old_iface->is_active) |
| 62 | + return 1; |
| 63 | + - } |
| 64 | + } |
| 65 | + - spin_unlock(&ses->chan_lock); |
| 66 | + |
| 67 | + spin_lock(&ses->iface_lock); |
| 68 | +++<<<<<<< HEAD:fs/cifs/sess.c |
| 69 | +++======= |
| 70 | ++ if (!ses->iface_count) { |
| 71 | ++ spin_unlock(&ses->iface_lock); |
| 72 | ++ cifs_dbg(VFS, "server %s does not advertise interfaces\n", ses->server->hostname); |
| 73 | ++ return 0; |
| 74 | ++ } |
| 75 | ++ |
| 76 | ++ last_iface = list_last_entry(&ses->iface_list, struct cifs_server_iface, |
| 77 | ++ iface_head); |
| 78 | ++ iface_min_speed = last_iface->speed; |
| 79 | +++>>>>>>> a6d8fb54a515 (cifs: distribute channels across interfaces based on speed):fs/smb/client/sess.c |
| 80 | + |
| 81 | + /* then look for a new one */ |
| 82 | + list_for_each_entry(iface, &ses->iface_list, iface_head) { |
| 83 | +diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c |
| 84 | +index eb8541c3298e..903f64652422 100644 |
| 85 | +--- a/fs/cifs/cifs_debug.c |
| 86 | ++++ b/fs/cifs/cifs_debug.c |
| 87 | +@@ -232,6 +232,8 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) |
| 88 | + struct cifs_ses *ses; |
| 89 | + struct cifs_tcon *tcon; |
| 90 | + struct cifs_server_iface *iface; |
| 91 | ++ size_t iface_weight = 0, iface_min_speed = 0; |
| 92 | ++ struct cifs_server_iface *last_iface = NULL; |
| 93 | + int c, i, j; |
| 94 | + |
| 95 | + seq_puts(m, |
| 96 | +@@ -472,11 +474,25 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) |
| 97 | + "\tLast updated: %lu seconds ago", |
| 98 | + ses->iface_count, |
| 99 | + (jiffies - ses->iface_last_update) / HZ); |
| 100 | ++ |
| 101 | ++ last_iface = list_last_entry(&ses->iface_list, |
| 102 | ++ struct cifs_server_iface, |
| 103 | ++ iface_head); |
| 104 | ++ iface_min_speed = last_iface->speed; |
| 105 | ++ |
| 106 | + j = 0; |
| 107 | + list_for_each_entry(iface, &ses->iface_list, |
| 108 | + iface_head) { |
| 109 | + seq_printf(m, "\n\t%d)", ++j); |
| 110 | + cifs_dump_iface(m, iface); |
| 111 | ++ |
| 112 | ++ iface_weight = iface->speed / iface_min_speed; |
| 113 | ++ seq_printf(m, "\t\tWeight (cur,total): (%zu,%zu)" |
| 114 | ++ "\n\t\tAllocated channels: %u\n", |
| 115 | ++ iface->weight_fulfilled, |
| 116 | ++ iface_weight, |
| 117 | ++ iface->num_channels); |
| 118 | ++ |
| 119 | + if (is_ses_using_iface(ses, iface)) |
| 120 | + seq_puts(m, "\t\t[CONNECTED]\n"); |
| 121 | + } |
| 122 | +diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h |
| 123 | +index 9e7f8c48e52c..a68c17d158ba 100644 |
| 124 | +--- a/fs/cifs/cifsglob.h |
| 125 | ++++ b/fs/cifs/cifsglob.h |
| 126 | +@@ -914,6 +914,8 @@ struct cifs_server_iface { |
| 127 | + struct list_head iface_head; |
| 128 | + struct kref refcount; |
| 129 | + size_t speed; |
| 130 | ++ size_t weight_fulfilled; |
| 131 | ++ unsigned int num_channels; |
| 132 | + unsigned int rdma_capable : 1; |
| 133 | + unsigned int rss_capable : 1; |
| 134 | + unsigned int is_active : 1; /* unset if non existent */ |
| 135 | +* Unmerged path fs/cifs/sess.c |
0 commit comments