Skip to content

Commit a6d8fb5

Browse files
sprasad-microsoftSteve French
authored and
Steve French
committed
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. Also make sure that we don't mix rdma and non-rdma for channels. Signed-off-by: Shyam Prasad N <sprasad@microsoft.com> Signed-off-by: Steve French <stfrench@microsoft.com>
1 parent 0c51cc6 commit a6d8fb5

File tree

3 files changed

+88
-14
lines changed

3 files changed

+88
-14
lines changed

fs/smb/client/cifs_debug.c

+16
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,8 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
284284
struct cifs_ses *ses;
285285
struct cifs_tcon *tcon;
286286
struct cifs_server_iface *iface;
287+
size_t iface_weight = 0, iface_min_speed = 0;
288+
struct cifs_server_iface *last_iface = NULL;
287289
int c, i, j;
288290

289291
seq_puts(m,
@@ -549,11 +551,25 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
549551
"\tLast updated: %lu seconds ago",
550552
ses->iface_count,
551553
(jiffies - ses->iface_last_update) / HZ);
554+
555+
last_iface = list_last_entry(&ses->iface_list,
556+
struct cifs_server_iface,
557+
iface_head);
558+
iface_min_speed = last_iface->speed;
559+
552560
j = 0;
553561
list_for_each_entry(iface, &ses->iface_list,
554562
iface_head) {
555563
seq_printf(m, "\n\t%d)", ++j);
556564
cifs_dump_iface(m, iface);
565+
566+
iface_weight = iface->speed / iface_min_speed;
567+
seq_printf(m, "\t\tWeight (cur,total): (%zu,%zu)"
568+
"\n\t\tAllocated channels: %u\n",
569+
iface->weight_fulfilled,
570+
iface_weight,
571+
iface->num_channels);
572+
557573
if (is_ses_using_iface(ses, iface))
558574
seq_puts(m, "\t\t[CONNECTED]\n");
559575
}

fs/smb/client/cifsglob.h

+2
Original file line numberDiff line numberDiff line change
@@ -969,6 +969,8 @@ struct cifs_server_iface {
969969
struct list_head iface_head;
970970
struct kref refcount;
971971
size_t speed;
972+
size_t weight_fulfilled;
973+
unsigned int num_channels;
972974
unsigned int rdma_capable : 1;
973975
unsigned int rss_capable : 1;
974976
unsigned int is_active : 1; /* unset if non existent */

fs/smb/client/sess.c

+70-14
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,9 @@ int cifs_try_adding_channels(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses)
179179
int left;
180180
int rc = 0;
181181
int tries = 0;
182+
size_t iface_weight = 0, iface_min_speed = 0;
182183
struct cifs_server_iface *iface = NULL, *niface = NULL;
184+
struct cifs_server_iface *last_iface = NULL;
183185

184186
spin_lock(&ses->chan_lock);
185187

@@ -207,39 +209,47 @@ int cifs_try_adding_channels(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses)
207209
}
208210
spin_unlock(&ses->chan_lock);
209211

210-
/*
211-
* Keep connecting to same, fastest, iface for all channels as
212-
* long as its RSS. Try next fastest one if not RSS or channel
213-
* creation fails.
214-
*/
215-
spin_lock(&ses->iface_lock);
216-
iface = list_first_entry(&ses->iface_list, struct cifs_server_iface,
217-
iface_head);
218-
spin_unlock(&ses->iface_lock);
219-
220212
while (left > 0) {
221213

222214
tries++;
223215
if (tries > 3*ses->chan_max) {
224-
cifs_dbg(FYI, "too many channel open attempts (%d channels left to open)\n",
216+
cifs_dbg(VFS, "too many channel open attempts (%d channels left to open)\n",
225217
left);
226218
break;
227219
}
228220

229221
spin_lock(&ses->iface_lock);
230222
if (!ses->iface_count) {
231223
spin_unlock(&ses->iface_lock);
224+
cifs_dbg(VFS, "server %s does not advertise interfaces\n",
225+
ses->server->hostname);
232226
break;
233227
}
234228

229+
if (!iface)
230+
iface = list_first_entry(&ses->iface_list, struct cifs_server_iface,
231+
iface_head);
232+
last_iface = list_last_entry(&ses->iface_list, struct cifs_server_iface,
233+
iface_head);
234+
iface_min_speed = last_iface->speed;
235+
235236
list_for_each_entry_safe_from(iface, niface, &ses->iface_list,
236237
iface_head) {
238+
/* do not mix rdma and non-rdma interfaces */
239+
if (iface->rdma_capable != ses->server->rdma)
240+
continue;
241+
237242
/* skip ifaces that are unusable */
238243
if (!iface->is_active ||
239244
(is_ses_using_iface(ses, iface) &&
240-
!iface->rss_capable)) {
245+
!iface->rss_capable))
246+
continue;
247+
248+
/* check if we already allocated enough channels */
249+
iface_weight = iface->speed / iface_min_speed;
250+
251+
if (iface->weight_fulfilled >= iface_weight)
241252
continue;
242-
}
243253

244254
/* take ref before unlock */
245255
kref_get(&iface->refcount);
@@ -256,10 +266,21 @@ int cifs_try_adding_channels(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses)
256266
continue;
257267
}
258268

259-
cifs_dbg(FYI, "successfully opened new channel on iface:%pIS\n",
269+
iface->num_channels++;
270+
iface->weight_fulfilled++;
271+
cifs_dbg(VFS, "successfully opened new channel on iface:%pIS\n",
260272
&iface->sockaddr);
261273
break;
262274
}
275+
276+
/* reached end of list. reset weight_fulfilled and start over */
277+
if (list_entry_is_head(iface, &ses->iface_list, iface_head)) {
278+
list_for_each_entry(iface, &ses->iface_list, iface_head)
279+
iface->weight_fulfilled = 0;
280+
spin_unlock(&ses->iface_lock);
281+
iface = NULL;
282+
continue;
283+
}
263284
spin_unlock(&ses->iface_lock);
264285

265286
left--;
@@ -278,8 +299,10 @@ int
278299
cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server)
279300
{
280301
unsigned int chan_index;
302+
size_t iface_weight = 0, iface_min_speed = 0;
281303
struct cifs_server_iface *iface = NULL;
282304
struct cifs_server_iface *old_iface = NULL;
305+
struct cifs_server_iface *last_iface = NULL;
283306
int rc = 0;
284307

285308
spin_lock(&ses->chan_lock);
@@ -299,13 +322,34 @@ cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server)
299322
spin_unlock(&ses->chan_lock);
300323

301324
spin_lock(&ses->iface_lock);
325+
if (!ses->iface_count) {
326+
spin_unlock(&ses->iface_lock);
327+
cifs_dbg(VFS, "server %s does not advertise interfaces\n", ses->server->hostname);
328+
return 0;
329+
}
330+
331+
last_iface = list_last_entry(&ses->iface_list, struct cifs_server_iface,
332+
iface_head);
333+
iface_min_speed = last_iface->speed;
334+
302335
/* then look for a new one */
303336
list_for_each_entry(iface, &ses->iface_list, iface_head) {
337+
/* do not mix rdma and non-rdma interfaces */
338+
if (iface->rdma_capable != server->rdma)
339+
continue;
340+
304341
if (!iface->is_active ||
305342
(is_ses_using_iface(ses, iface) &&
306343
!iface->rss_capable)) {
307344
continue;
308345
}
346+
347+
/* check if we already allocated enough channels */
348+
iface_weight = iface->speed / iface_min_speed;
349+
350+
if (iface->weight_fulfilled >= iface_weight)
351+
continue;
352+
309353
kref_get(&iface->refcount);
310354
break;
311355
}
@@ -321,10 +365,22 @@ cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server)
321365
cifs_dbg(FYI, "replacing iface: %pIS with %pIS\n",
322366
&old_iface->sockaddr,
323367
&iface->sockaddr);
368+
369+
old_iface->num_channels--;
370+
if (old_iface->weight_fulfilled)
371+
old_iface->weight_fulfilled--;
372+
iface->num_channels++;
373+
iface->weight_fulfilled++;
374+
324375
kref_put(&old_iface->refcount, release_iface);
325376
} else if (old_iface) {
326377
cifs_dbg(FYI, "releasing ref to iface: %pIS\n",
327378
&old_iface->sockaddr);
379+
380+
old_iface->num_channels--;
381+
if (old_iface->weight_fulfilled)
382+
old_iface->weight_fulfilled--;
383+
328384
kref_put(&old_iface->refcount, release_iface);
329385
} else {
330386
WARN_ON(!iface);

0 commit comments

Comments
 (0)