History

Merge tag '5.19-rc3-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6

Pull cifs client fixes from Steve French: "Fixes addressing important multichannel, and reconnect issues. Multichannel mounts when the server network interfaces changed, or ip addresses changed, uncovered problems, especially in reconnect, but the patches for this were held up until recently due to some lock conflicts that are now addressed. Included in this set of fixes: - three fixes relating to multichannel reconnect, dynamically adjusting the list of server interfaces to avoid problems during reconnect - a lock conflict fix related to the above - two important fixes for negotiate on secondary channels (null netname can unintentionally cause multichannel to be disabled to some servers) - a reconnect fix (reporting incorrect IP address in some cases)" * tag '5.19-rc3-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6: cifs: update cifs_ses::ip_addr after failover cifs: avoid deadlocks while updating iface cifs: periodically query network interfaces from server cifs: during reconnect, update interface if necessary cifs: change iface_list from array to sorted linked list smb3: use netname when available on secondary channels smb3: fix empty netname context on secondary channels

Linus Torvalds committed 4 years ago

Commit 918c30d2 parents 0840a79 af3a6d18 files · +366 −139Browse files

Unified · Split

8 files
  1. fs/cifs/cifs_debug.c +7 −5
  2. fs/cifs/cifsglob.h +57 −1
  3. fs/cifs/cifsproto.h +7 −0
  4. fs/cifs/connect.c +54 −5
  5. fs/cifs/misc.c +8 −1
  6. fs/cifs/sess.c +128 −38
  7. fs/cifs/smb2ops.c +90 −83
  8. fs/cifs/smb2pdu.c +15 −6
fs/cifs/cifs_debug.c+7−5
@@ -162,6 +162,8 @@ cifs_dump_iface(struct seq_file *m, struct cifs_server_iface *iface) · 161 unmodified lines
162162 seq_printf(m, "\t\tIPv4: %pI4\n", &ipv4->sin_addr);
163163 else if (iface->sockaddr.ss_family == AF_INET6)
164164 seq_printf(m, "\t\tIPv6: %pI6\n", &ipv6->sin6_addr);
165+ if (!iface->is_active)
166+ seq_puts(m, "\t\t[for-cleanup]\n");
165167 }
166168
167169 static int cifs_debug_files_proc_show(struct seq_file *m, void *v)
@@ -221,6 +223,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) · 53 unmodified lines
221223 struct TCP_Server_Info *server;
222224 struct cifs_ses *ses;
223225 struct cifs_tcon *tcon;
226+ struct cifs_server_iface *iface;
224227 int c, i, j;
225228
226229 seq_puts(m,
@@ -456,11 +459,10 @@ skip_rdma: · 229 unmodified lines
456459 if (ses->iface_count)
457460 seq_printf(m, "\n\n\tServer interfaces: %zu",
458461 ses->iface_count);
459− for (j = 0; j < ses->iface_count; j++) {
460− struct cifs_server_iface *iface;
461−
462− iface = &ses->iface_list[j];
463− seq_printf(m, "\n\t%d)", j+1);
462+ j = 0;
463+ list_for_each_entry(iface, &ses->iface_list,
464+ iface_head) {
465+ seq_printf(m, "\n\t%d)", ++j);
464466 cifs_dump_iface(m, iface);
465467 if (is_ses_using_iface(ses, iface))
466468 seq_puts(m, "\t\t[CONNECTED]\n");
fs/cifs/cifsglob.h+57−1
@@ -80,6 +80,9 @@ · 79 unmodified lines
8080 #define SMB_DNS_RESOLVE_INTERVAL_MIN 120
8181 #define SMB_DNS_RESOLVE_INTERVAL_DEFAULT 600
8282
83+/* smb multichannel query server interfaces interval in seconds */
84+#define SMB_INTERFACE_POLL_INTERVAL 600
85+
8386 /* maximum number of PDUs in one compound */
8487 #define MAX_COMPOUND 5
8588
@@ -933,15 +936,67 @@ static inline void cifs_set_net_ns(struct TCP_Server_Info *srv, struct net *net) · 847 unmodified lines
933936 #endif
934937
935938 struct cifs_server_iface {
939+ struct list_head iface_head;
940+ struct kref refcount;
936941 size_t speed;
937942 unsigned int rdma_capable : 1;
938943 unsigned int rss_capable : 1;
944+ unsigned int is_active : 1; /* unset if non existent */
939945 struct sockaddr_storage sockaddr;
940946 };
941947
948+/* release iface when last ref is dropped */
949+static inline void
950+release_iface(struct kref *ref)
951+{
952+ struct cifs_server_iface *iface = container_of(ref,
953+ struct cifs_server_iface,
954+ refcount);
955+ list_del_init(&iface->iface_head);
956+ kfree(iface);
957+}
958+
959+/*
960+ * compare two interfaces a and b
961+ * return 0 if everything matches.
962+ * return 1 if a has higher link speed, or rdma capable, or rss capable
963+ * return -1 otherwise.
964+ */
965+static inline int
966+iface_cmp(struct cifs_server_iface *a, struct cifs_server_iface *b)
967+{
968+ int cmp_ret = 0;
969+
970+ WARN_ON(!a || !b);
971+ if (a->speed == b->speed) {
972+ if (a->rdma_capable == b->rdma_capable) {
973+ if (a->rss_capable == b->rss_capable) {
974+ cmp_ret = memcmp(&a->sockaddr, &b->sockaddr,
975+ sizeof(a->sockaddr));
976+ if (!cmp_ret)
977+ return 0;
978+ else if (cmp_ret > 0)
979+ return 1;
980+ else
981+ return -1;
982+ } else if (a->rss_capable > b->rss_capable)
983+ return 1;
984+ else
985+ return -1;
986+ } else if (a->rdma_capable > b->rdma_capable)
987+ return 1;
988+ else
989+ return -1;
990+ } else if (a->speed > b->speed)
991+ return 1;
992+ else
993+ return -1;
994+}
995+
942996 struct cifs_chan {
943997 unsigned int in_reconnect : 1; /* if session setup in progress for this channel */
944998 struct TCP_Server_Info *server;
999+ struct cifs_server_iface *iface; /* interface in use */
9451000 __u8 signkey[SMB3_SIGN_KEY_SIZE];
9461001 };
9471002
@@ -993,7 +1048,7 @@ struct cifs_ses { · 45 unmodified lines
9931048 */
9941049 spinlock_t iface_lock;
9951050 /* ========= begin: protected by iface_lock ======== */
996− struct cifs_server_iface *iface_list;
1051+ struct list_head iface_list;
9971052 size_t iface_count;
9981053 unsigned long iface_last_update; /* jiffies */
9991054 /* ========= end: protected by iface_lock ======== */
@@ -1203,6 +1258,7 @@ struct cifs_tcon { · 203 unmodified lines
12031258 #ifdef CONFIG_CIFS_DFS_UPCALL
12041259 struct list_head ulist; /* cache update list */
12051260 #endif
1261+ struct delayed_work query_interfaces; /* query interfaces workqueue job */
12061262 };
12071263
12081264 /*
fs/cifs/cifsproto.h+7−0
@@ -636,6 +636,13 @@ cifs_chan_clear_need_reconnect(struct cifs_ses *ses, · 635 unmodified lines
636636 bool
637637 cifs_chan_needs_reconnect(struct cifs_ses *ses,
638638 struct TCP_Server_Info *server);
639+bool
640+cifs_chan_is_iface_active(struct cifs_ses *ses,
641+ struct TCP_Server_Info *server);
642+int
643+cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server);
644+int
645+SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon);
639646
640647 void extract_unc_hostname(const char *unc, const char **h, size_t *len);
641648 int copy_path_name(char *dst, const char *src);
fs/cifs/connect.c+54−5
@@ -145,6 +145,25 @@ requeue_resolve: · 144 unmodified lines
145145 return rc;
146146 }
147147
148+static void smb2_query_server_interfaces(struct work_struct *work)
149+{
150+ int rc;
151+ struct cifs_tcon *tcon = container_of(work,
152+ struct cifs_tcon,
153+ query_interfaces.work);
154+
155+ /*
156+ * query server network interfaces, in case they change
157+ */
158+ rc = SMB3_request_interfaces(0, tcon);
159+ if (rc) {
160+ cifs_dbg(FYI, "%s: failed to query server interfaces: %d\n",
161+ __func__, rc);
162+ }
163+
164+ queue_delayed_work(cifsiod_wq, &tcon->query_interfaces,
165+ (SMB_INTERFACE_POLL_INTERVAL * HZ));
166+}
148167
149168 static void cifs_resolve_server(struct work_struct *work)
150169 {
@@ -217,7 +236,7 @@ cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server, · 66 unmodified lines
217236 bool mark_smb_session)
218237 {
219238 struct TCP_Server_Info *pserver;
220− struct cifs_ses *ses;
239+ struct cifs_ses *ses, *nses;
221240 struct cifs_tcon *tcon;
222241
223242 /*
@@ -231,7 +250,20 @@ cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server, · 7 unmodified lines
231250
232251
233252 spin_lock(&cifs_tcp_ses_lock);
234− list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) {
253+ list_for_each_entry_safe(ses, nses, &pserver->smb_ses_list, smb_ses_list) {
254+ /* check if iface is still active */
255+ if (!cifs_chan_is_iface_active(ses, server)) {
256+ /*
257+ * HACK: drop the lock before calling
258+ * cifs_chan_update_iface to avoid deadlock
259+ */
260+ ses->ses_count++;
261+ spin_unlock(&cifs_tcp_ses_lock);
262+ cifs_chan_update_iface(ses, server);
263+ spin_lock(&cifs_tcp_ses_lock);
264+ ses->ses_count--;
265+ }
266+
235267 spin_lock(&ses->chan_lock);
236268 if (!mark_smb_session && cifs_chan_needs_reconnect(ses, server))
237269 goto next_session;
@@ -1894,9 +1926,11 @@ void cifs_put_smb_ses(struct cifs_ses *ses) · 1656 unmodified lines
18941926 int i;
18951927
18961928 for (i = 1; i < chan_count; i++) {
1897− spin_unlock(&ses->chan_lock);
1929+ if (ses->chans[i].iface) {
1930+ kref_put(&ses->chans[i].iface->refcount, release_iface);
1931+ ses->chans[i].iface = NULL;
1932+ }
18981933 cifs_put_tcp_session(ses->chans[i].server, 0);
1899− spin_lock(&ses->chan_lock);
19001934 ses->chans[i].server = NULL;
19011935 }
19021936 }
@@ -2270,6 +2304,9 @@ cifs_put_tcon(struct cifs_tcon *tcon) · 367 unmodified lines
22702304 list_del_init(&tcon->tcon_list);
22712305 spin_unlock(&cifs_tcp_ses_lock);
22722306
2307+ /* cancel polling of interfaces */
2308+ cancel_delayed_work_sync(&tcon->query_interfaces);
2309+
22732310 if (tcon->use_witness) {
22742311 int rc;
22752312
@@ -2507,6 +2544,12 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb3_fs_context *ctx) · 231 unmodified lines
25072544 tcon->local_lease = ctx->local_lease;
25082545 INIT_LIST_HEAD(&tcon->pending_opens);
25092546
2547+ /* schedule query interfaces poll */
2548+ INIT_DELAYED_WORK(&tcon->query_interfaces,
2549+ smb2_query_server_interfaces);
2550+ queue_delayed_work(cifsiod_wq, &tcon->query_interfaces,
2551+ (SMB_INTERFACE_POLL_INTERVAL * HZ));
2552+
25102553 spin_lock(&cifs_tcp_ses_lock);
25112554 list_add(&tcon->tcon_list, &ses->tcon_list);
25122555 spin_unlock(&cifs_tcp_ses_lock);
@@ -3982,10 +4025,16 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses, · 1469 unmodified lines
39824025 struct nls_table *nls_info)
39834026 {
39844027 int rc = -ENOSYS;
4028+ struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&server->dstaddr;
4029+ struct sockaddr_in *addr = (struct sockaddr_in *)&server->dstaddr;
39854030 bool is_binding = false;
39864031
3987−
39884032 spin_lock(&cifs_tcp_ses_lock);
4033+ if (server->dstaddr.ss_family == AF_INET6)
4034+ scnprintf(ses->ip_addr, sizeof(ses->ip_addr), "%pI6", &addr6->sin6_addr);
4035+ else
4036+ scnprintf(ses->ip_addr, sizeof(ses->ip_addr), "%pI4", &addr->sin_addr);
4037+
39894038 if (ses->ses_status != SES_GOOD &&
39904039 ses->ses_status != SES_NEW &&
39914040 ses->ses_status != SES_NEED_RECON) {
fs/cifs/misc.c+8−1
@@ -75,6 +75,7 @@ sesInfoAlloc(void) · 74 unmodified lines
7575 INIT_LIST_HEAD(&ret_buf->tcon_list);
7676 mutex_init(&ret_buf->session_mutex);
7777 spin_lock_init(&ret_buf->iface_lock);
78+ INIT_LIST_HEAD(&ret_buf->iface_list);
7879 spin_lock_init(&ret_buf->chan_lock);
7980 }
8081 return ret_buf;
@@ -83,6 +84,8 @@ sesInfoAlloc(void) · 2 unmodified lines
8384 void
8485 sesInfoFree(struct cifs_ses *buf_to_free)
8586 {
87+ struct cifs_server_iface *iface = NULL, *niface = NULL;
88+
8689 if (buf_to_free == NULL) {
8790 cifs_dbg(FYI, "Null buffer passed to sesInfoFree\n");
8891 return;
@@ -96,7 +99,11 @@ sesInfoFree(struct cifs_ses *buf_to_free) · 7 unmodified lines
9699 kfree(buf_to_free->user_name);
97100 kfree(buf_to_free->domainName);
98101 kfree_sensitive(buf_to_free->auth_key.response);
99− kfree(buf_to_free->iface_list);
102+ spin_lock(&buf_to_free->iface_lock);
103+ list_for_each_entry_safe(iface, niface, &buf_to_free->iface_list,
104+ iface_head)
105+ kref_put(&iface->refcount, release_iface);
106+ spin_unlock(&buf_to_free->iface_lock);
100107 kfree_sensitive(buf_to_free);
101108 }
102109
fs/cifs/sess.c+128−38
@@ -58,7 +58,7 @@ bool is_ses_using_iface(struct cifs_ses *ses, struct cifs_server_iface *iface) · 57 unmodified lines
5858
5959 spin_lock(&ses->chan_lock);
6060 for (i = 0; i < ses->chan_count; i++) {
61− if (is_server_using_iface(ses->chans[i].server, iface)) {
61+ if (ses->chans[i].iface == iface) {
6262 spin_unlock(&ses->chan_lock);
6363 return true;
6464 }
@@ -146,16 +146,24 @@ cifs_chan_needs_reconnect(struct cifs_ses *ses, · 81 unmodified lines
146146 return CIFS_CHAN_NEEDS_RECONNECT(ses, chan_index);
147147 }
148148
149+bool
150+cifs_chan_is_iface_active(struct cifs_ses *ses,
151+ struct TCP_Server_Info *server)
152+{
153+ unsigned int chan_index = cifs_ses_get_chan_index(ses, server);
154+
155+ return ses->chans[chan_index].iface &&
156+ ses->chans[chan_index].iface->is_active;
157+}
158+
149159 /* returns number of channels added */
150160 int cifs_try_adding_channels(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses)
151161 {
152162 int old_chan_count, new_chan_count;
153163 int left;
154− int i = 0;
155164 int rc = 0;
156165 int tries = 0;
157− struct cifs_server_iface *ifaces = NULL;
158− size_t iface_count;
166+ struct cifs_server_iface *iface = NULL, *niface = NULL;
159167
160168 spin_lock(&ses->chan_lock);
161169
@@ -184,33 +192,17 @@ int cifs_try_adding_channels(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses) · 22 unmodified lines
184192 }
185193 spin_unlock(&ses->chan_lock);
186194
187− /*
188− * Make a copy of the iface list at the time and use that
189− * instead so as to not hold the iface spinlock for opening
190− * channels
191− */
192− spin_lock(&ses->iface_lock);
193− iface_count = ses->iface_count;
194− if (iface_count <= 0) {
195− spin_unlock(&ses->iface_lock);
196− cifs_dbg(VFS, "no iface list available to open channels\n");
197− return 0;
198− }
199− ifaces = kmemdup(ses->iface_list, iface_count*sizeof(*ifaces),
200− GFP_ATOMIC);
201− if (!ifaces) {
202− spin_unlock(&ses->iface_lock);
203− return 0;
204− }
205− spin_unlock(&ses->iface_lock);
206−
207195 /*
208196 * Keep connecting to same, fastest, iface for all channels as
209197 * long as its RSS. Try next fastest one if not RSS or channel
210198 * creation fails.
211199 */
200+ spin_lock(&ses->iface_lock);
201+ iface = list_first_entry(&ses->iface_list, struct cifs_server_iface,
202+ iface_head);
203+ spin_unlock(&ses->iface_lock);
204+
212205 while (left > 0) {
213− struct cifs_server_iface *iface;
214206
215207 tries++;
216208 if (tries > 3*ses->chan_max) {
@@ -219,30 +211,127 @@ int cifs_try_adding_channels(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses) · 2 unmodified lines
219211 break;
220212 }
221213
222− iface = &ifaces[i];
223− if (is_ses_using_iface(ses, iface) && !iface->rss_capable) {
224− i = (i+1) % iface_count;
225− continue;
214+ spin_lock(&ses->iface_lock);
215+ if (!ses->iface_count) {
216+ spin_unlock(&ses->iface_lock);
217+ break;
226218 }
227219
228− rc = cifs_ses_add_channel(cifs_sb, ses, iface);
229− if (rc) {
230− cifs_dbg(FYI, "failed to open extra channel on iface#%d rc=%d\n",
231− i, rc);
232− i = (i+1) % iface_count;
233− continue;
220+ list_for_each_entry_safe_from(iface, niface, &ses->iface_list,
221+ iface_head) {
222+ /* skip ifaces that are unusable */
223+ if (!iface->is_active ||
224+ (is_ses_using_iface(ses, iface) &&
225+ !iface->rss_capable)) {
226+ continue;
227+ }
228+
229+ /* take ref before unlock */
230+ kref_get(&iface->refcount);
231+
232+ spin_unlock(&ses->iface_lock);
233+ rc = cifs_ses_add_channel(cifs_sb, ses, iface);
234+ spin_lock(&ses->iface_lock);
235+
236+ if (rc) {
237+ cifs_dbg(VFS, "failed to open extra channel on iface:%pIS rc=%d\n",
238+ &iface->sockaddr,
239+ rc);
240+ kref_put(&iface->refcount, release_iface);
241+ continue;
242+ }
243+
244+ cifs_dbg(FYI, "successfully opened new channel on iface:%pIS\n",
245+ &iface->sockaddr);
246+ break;
234247 }
248+ spin_unlock(&ses->iface_lock);
235249
236− cifs_dbg(FYI, "successfully opened new channel on iface#%d\n",
237− i);
238250 left--;
239251 new_chan_count++;
240252 }
241253
242− kfree(ifaces);
243254 return new_chan_count - old_chan_count;
244255 }
245256
257+/*
258+ * update the iface for the channel if necessary.
259+ * will return 0 when iface is updated, 1 if removed, 2 otherwise
260+ * Must be called with chan_lock held.
261+ */
262+int
263+cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server)
264+{
265+ unsigned int chan_index;
266+ struct cifs_server_iface *iface = NULL;
267+ struct cifs_server_iface *old_iface = NULL;
268+ int rc = 0;
269+
270+ spin_lock(&ses->chan_lock);
271+ chan_index = cifs_ses_get_chan_index(ses, server);
272+ if (!chan_index) {
273+ spin_unlock(&ses->chan_lock);
274+ return 0;
275+ }
276+
277+ if (ses->chans[chan_index].iface) {
278+ old_iface = ses->chans[chan_index].iface;
279+ if (old_iface->is_active) {
280+ spin_unlock(&ses->chan_lock);
281+ return 1;
282+ }
283+ }
284+ spin_unlock(&ses->chan_lock);
285+
286+ spin_lock(&ses->iface_lock);
287+ /* then look for a new one */
288+ list_for_each_entry(iface, &ses->iface_list, iface_head) {
289+ if (!iface->is_active ||
290+ (is_ses_using_iface(ses, iface) &&
291+ !iface->rss_capable)) {
292+ continue;
293+ }
294+ kref_get(&iface->refcount);
295+ }
296+
297+ if (!list_entry_is_head(iface, &ses->iface_list, iface_head)) {
298+ rc = 1;
299+ iface = NULL;
300+ cifs_dbg(FYI, "unable to find a suitable iface\n");
301+ }
302+
303+ /* now drop the ref to the current iface */
304+ if (old_iface && iface) {
305+ kref_put(&old_iface->refcount, release_iface);
306+ cifs_dbg(FYI, "replacing iface: %pIS with %pIS\n",
307+ &old_iface->sockaddr,
308+ &iface->sockaddr);
309+ } else if (old_iface) {
310+ kref_put(&old_iface->refcount, release_iface);
311+ cifs_dbg(FYI, "releasing ref to iface: %pIS\n",
312+ &old_iface->sockaddr);
313+ } else {
314+ WARN_ON(!iface);
315+ cifs_dbg(FYI, "adding new iface: %pIS\n", &iface->sockaddr);
316+ }
317+ spin_unlock(&ses->iface_lock);
318+
319+ spin_lock(&ses->chan_lock);
320+ chan_index = cifs_ses_get_chan_index(ses, server);
321+ ses->chans[chan_index].iface = iface;
322+
323+ /* No iface is found. if secondary chan, drop connection */
324+ if (!iface && CIFS_SERVER_IS_CHAN(server))
325+ ses->chans[chan_index].server = NULL;
326+
327+ spin_unlock(&ses->chan_lock);
328+
329+ if (!iface && CIFS_SERVER_IS_CHAN(server))
330+ cifs_put_tcp_session(server, false);
331+
332+ return rc;
333+}
334+
246335 /*
247336 * If server is a channel of ses, return the corresponding enclosing
248337 * cifs_chan otherwise return NULL.
@@ -355,6 +444,7 @@ cifs_ses_add_channel(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses, · 106 unmodified lines
355444 spin_unlock(&ses->chan_lock);
356445 goto out;
357446 }
447+ chan->iface = iface;
358448 ses->chan_count++;
359449 atomic_set(&ses->chan_seq, 0);
360450
fs/cifs/smb2ops.c+90−83
@@ -512,73 +512,41 @@ smb3_negotiate_rsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx) · 511 unmodified lines
512512 static int
513513 parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
514514 size_t buf_len,
515− struct cifs_server_iface **iface_list,
516− size_t *iface_count)
515+ struct cifs_ses *ses)
517516 {
518517 struct network_interface_info_ioctl_rsp *p;
519518 struct sockaddr_in *addr4;
520519 struct sockaddr_in6 *addr6;
521520 struct iface_info_ipv4 *p4;
522521 struct iface_info_ipv6 *p6;
523− struct cifs_server_iface *info;
522+ struct cifs_server_iface *info = NULL, *iface = NULL, *niface = NULL;
523+ struct cifs_server_iface tmp_iface;
524524 ssize_t bytes_left;
525525 size_t next = 0;
526526 int nb_iface = 0;
527− int rc = 0;
528−
529− *iface_list = NULL;
530− *iface_count = 0;
531−
532− /*
533− * Fist pass: count and sanity check
534− */
527+ int rc = 0, ret = 0;
535528
536529 bytes_left = buf_len;
537530 p = buf;
538− while (bytes_left >= sizeof(*p)) {
539− nb_iface++;
540− next = le32_to_cpu(p->Next);
541− if (!next) {
542− bytes_left -= sizeof(*p);
543− break;
544− }
545− p = (struct network_interface_info_ioctl_rsp *)((u8 *)p+next);
546− bytes_left -= next;
547− }
548−
549− if (!nb_iface) {
550− cifs_dbg(VFS, "%s: malformed interface info\n", __func__);
551− rc = -EINVAL;
552− goto out;
553− }
554−
555− /* Azure rounds the buffer size up 8, to a 16 byte boundary */
556− if ((bytes_left > 8) || p->Next)
557− cifs_dbg(VFS, "%s: incomplete interface info\n", __func__);
558−
559531
532+ spin_lock(&ses->iface_lock);
560533 /*
561− * Second pass: extract info to internal structure
534+ * Go through iface_list and do kref_put to remove
535+ * any unused ifaces. ifaces in use will be removed
536+ * when the last user calls a kref_put on it
562537 */
563−
564− *iface_list = kcalloc(nb_iface, sizeof(**iface_list), GFP_KERNEL);
565− if (!*iface_list) {
566− rc = -ENOMEM;
567− goto out;
538+ list_for_each_entry_safe(iface, niface, &ses->iface_list,
539+ iface_head) {
540+ iface->is_active = 0;
541+ kref_put(&iface->refcount, release_iface);
568542 }
543+ spin_unlock(&ses->iface_lock);
569544
570− info = *iface_list;
571− bytes_left = buf_len;
572− p = buf;
573545 while (bytes_left >= sizeof(*p)) {
574− info->speed = le64_to_cpu(p->LinkSpeed);
575− info->rdma_capable = le32_to_cpu(p->Capability & RDMA_CAPABLE) ? 1 : 0;
576− info->rss_capable = le32_to_cpu(p->Capability & RSS_CAPABLE) ? 1 : 0;
577−
578− cifs_dbg(FYI, "%s: adding iface %zu\n", __func__, *iface_count);
579− cifs_dbg(FYI, "%s: speed %zu bps\n", __func__, info->speed);
580− cifs_dbg(FYI, "%s: capabilities 0x%08x\n", __func__,
581− le32_to_cpu(p->Capability));
546+ memset(&tmp_iface, 0, sizeof(tmp_iface));
547+ tmp_iface.speed = le64_to_cpu(p->LinkSpeed);
548+ tmp_iface.rdma_capable = le32_to_cpu(p->Capability & RDMA_CAPABLE) ? 1 : 0;
549+ tmp_iface.rss_capable = le32_to_cpu(p->Capability & RSS_CAPABLE) ? 1 : 0;
582550
583551 switch (p->Family) {
584552 /*
@@ -587,7 +555,7 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf, · 2 unmodified lines
587555 * conversion explicit in case either one changes.
588556 */
589557 case INTERNETWORK:
590− addr4 = (struct sockaddr_in *)&info->sockaddr;
558+ addr4 = (struct sockaddr_in *)&tmp_iface.sockaddr;
591559 p4 = (struct iface_info_ipv4 *)p->Buffer;
592560 addr4->sin_family = AF_INET;
593561 memcpy(&addr4->sin_addr, &p4->IPv4Address, 4);
@@ -599,7 +567,7 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf, · 5 unmodified lines
599567 &addr4->sin_addr);
600568 break;
601569 case INTERNETWORKV6:
602− addr6 = (struct sockaddr_in6 *)&info->sockaddr;
570+ addr6 = (struct sockaddr_in6 *)&tmp_iface.sockaddr;
603571 p6 = (struct iface_info_ipv6 *)p->Buffer;
604572 addr6->sin6_family = AF_INET6;
605573 memcpy(&addr6->sin6_addr, &p6->IPv6Address, 16);
@@ -619,46 +587,96 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf, · 13 unmodified lines
619587 goto next_iface;
620588 }
621589
622− (*iface_count)++;
623− info++;
590+ /*
591+ * The iface_list is assumed to be sorted by speed.
592+ * Check if the new interface exists in that list.
593+ * NEVER change iface. it could be in use.
594+ * Add a new one instead
595+ */
596+ spin_lock(&ses->iface_lock);
597+ iface = niface = NULL;
598+ list_for_each_entry_safe(iface, niface, &ses->iface_list,
599+ iface_head) {
600+ ret = iface_cmp(iface, &tmp_iface);
601+ if (!ret) {
602+ /* just get a ref so that it doesn't get picked/freed */
603+ iface->is_active = 1;
604+ kref_get(&iface->refcount);
605+ spin_unlock(&ses->iface_lock);
606+ goto next_iface;
607+ } else if (ret < 0) {
608+ /* all remaining ifaces are slower */
609+ kref_get(&iface->refcount);
610+ break;
611+ }
612+ }
613+ spin_unlock(&ses->iface_lock);
614+
615+ /* no match. insert the entry in the list */
616+ info = kmalloc(sizeof(struct cifs_server_iface),
617+ GFP_KERNEL);
618+ if (!info) {
619+ rc = -ENOMEM;
620+ goto out;
621+ }
622+ memcpy(info, &tmp_iface, sizeof(tmp_iface));
623+
624+ /* add this new entry to the list */
625+ kref_init(&info->refcount);
626+ info->is_active = 1;
627+
628+ cifs_dbg(FYI, "%s: adding iface %zu\n", __func__, ses->iface_count);
629+ cifs_dbg(FYI, "%s: speed %zu bps\n", __func__, info->speed);
630+ cifs_dbg(FYI, "%s: capabilities 0x%08x\n", __func__,
631+ le32_to_cpu(p->Capability));
632+
633+ spin_lock(&ses->iface_lock);
634+ if (!list_entry_is_head(iface, &ses->iface_list, iface_head)) {
635+ list_add_tail(&info->iface_head, &iface->iface_head);
636+ kref_put(&iface->refcount, release_iface);
637+ } else
638+ list_add_tail(&info->iface_head, &ses->iface_list);
639+ spin_unlock(&ses->iface_lock);
640+
641+ ses->iface_count++;
642+ ses->iface_last_update = jiffies;
624643 next_iface:
644+ nb_iface++;
625645 next = le32_to_cpu(p->Next);
626− if (!next)
646+ if (!next) {
647+ bytes_left -= sizeof(*p);
627648 break;
649+ }
628650 p = (struct network_interface_info_ioctl_rsp *)((u8 *)p+next);
629651 bytes_left -= next;
630652 }
631653
632− if (!*iface_count) {
654+ if (!nb_iface) {
655+ cifs_dbg(VFS, "%s: malformed interface info\n", __func__);
633656 rc = -EINVAL;
634657 goto out;
635658 }
636659
637−out:
638− if (rc) {
639− kfree(*iface_list);
640− *iface_count = 0;
641− *iface_list = NULL;
642− }
643− return rc;
644−}
660+ /* Azure rounds the buffer size up 8, to a 16 byte boundary */
661+ if ((bytes_left > 8) || p->Next)
662+ cifs_dbg(VFS, "%s: incomplete interface info\n", __func__);
645663
646−static int compare_iface(const void *ia, const void *ib)
647−{
648− const struct cifs_server_iface *a = (struct cifs_server_iface *)ia;
649− const struct cifs_server_iface *b = (struct cifs_server_iface *)ib;
650664
651− return a->speed == b->speed ? 0 : (a->speed > b->speed ? -1 : 1);
665+ if (!ses->iface_count) {
666+ rc = -EINVAL;
667+ goto out;
668+ }
669+
670+out:
671+ return rc;
652672 }
653673
654−static int
674+int
655675 SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon)
656676 {
657677 int rc;
658678 unsigned int ret_data_len = 0;
659679 struct network_interface_info_ioctl_rsp *out_buf = NULL;
660− struct cifs_server_iface *iface_list;
661− size_t iface_count;
662680 struct cifs_ses *ses = tcon->ses;
663681
664682 rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID,
@@ -674,21 +692,10 @@ SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon) · 9 unmodified lines
674692 goto out;
675693 }
676694
677− rc = parse_server_interfaces(out_buf, ret_data_len,
678− &iface_list, &iface_count);
695+ rc = parse_server_interfaces(out_buf, ret_data_len, ses);
679696 if (rc)
680697 goto out;
681698
682− /* sort interfaces from fastest to slowest */
683− sort(iface_list, iface_count, sizeof(*iface_list), compare_iface, NULL);
684−
685− spin_lock(&ses->iface_lock);
686− kfree(ses->iface_list);
687− ses->iface_list = iface_list;
688− ses->iface_count = iface_count;
689− ses->iface_last_update = jiffies;
690− spin_unlock(&ses->iface_lock);
691−
692699 out:
693700 kfree(out_buf);
694701 return rc;
fs/cifs/smb2pdu.c+15−6
@@ -543,6 +543,7 @@ assemble_neg_contexts(struct smb2_negotiate_req *req, · 542 unmodified lines
543543 struct TCP_Server_Info *server, unsigned int *total_len)
544544 {
545545 char *pneg_ctxt;
546+ char *hostname = NULL;
546547 unsigned int ctxt_len, neg_context_count;
547548
548549 if (*total_len > 200) {
@@ -570,16 +571,24 @@ assemble_neg_contexts(struct smb2_negotiate_req *req, · 21 unmodified lines
570571 *total_len += ctxt_len;
571572 pneg_ctxt += ctxt_len;
572573
573− ctxt_len = build_netname_ctxt((struct smb2_netname_neg_context *)pneg_ctxt,
574− server->hostname);
575− *total_len += ctxt_len;
576− pneg_ctxt += ctxt_len;
577−
578574 build_posix_ctxt((struct smb2_posix_neg_context *)pneg_ctxt);
579575 *total_len += sizeof(struct smb2_posix_neg_context);
580576 pneg_ctxt += sizeof(struct smb2_posix_neg_context);
581577
582− neg_context_count = 4;
578+ /*
579+ * secondary channels don't have the hostname field populated
580+ * use the hostname field in the primary channel instead
581+ */
582+ hostname = CIFS_SERVER_IS_CHAN(server) ?
583+ server->primary_server->hostname : server->hostname;
584+ if (hostname && (hostname[0] != 0)) {
585+ ctxt_len = build_netname_ctxt((struct smb2_netname_neg_context *)pneg_ctxt,
586+ hostname);
587+ *total_len += ctxt_len;
588+ pneg_ctxt += ctxt_len;
589+ neg_context_count = 4;
590+ } else /* second channels do not have a hostname */
591+ neg_context_count = 3;
583592
584593 if (server->compress_algorithm) {
585594 build_compression_ctxt((struct smb2_compression_capabilities_context *)