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
162 seq_printf(m, "\t\tIPv4: %pI4\n", &ipv4->sin_addr);162 seq_printf(m, "\t\tIPv4: %pI4\n", &ipv4->sin_addr);
163 else if (iface->sockaddr.ss_family == AF_INET6)163 else if (iface->sockaddr.ss_family == AF_INET6)
164 seq_printf(m, "\t\tIPv6: %pI6\n", &ipv6->sin6_addr);164 seq_printf(m, "\t\tIPv6: %pI6\n", &ipv6->sin6_addr);
165 if (!iface->is_active)
166 seq_puts(m, "\t\t[for-cleanup]\n");
165}167}
166 168
167static int cifs_debug_files_proc_show(struct seq_file *m, void *v)169static 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
221 struct TCP_Server_Info *server;223 struct TCP_Server_Info *server;
222 struct cifs_ses *ses;224 struct cifs_ses *ses;
223 struct cifs_tcon *tcon;225 struct cifs_tcon *tcon;
226 struct cifs_server_iface *iface;
224 int c, i, j;227 int c, i, j;
225 228
226 seq_puts(m,229 seq_puts(m,
@@ -456,11 +459,10 @@ skip_rdma: · 229 unmodified lines
456 if (ses->iface_count)459 if (ses->iface_count)
457 seq_printf(m, "\n\n\tServer interfaces: %zu",460 seq_printf(m, "\n\n\tServer interfaces: %zu",
458 ses->iface_count);461 ses->iface_count);
459 for (j = 0; j < ses->iface_count; j++) {462 j = 0;
460 struct cifs_server_iface *iface;463 list_for_each_entry(iface, &ses->iface_list,
461 464 iface_head) {
462 iface = &ses->iface_list[j];465 seq_printf(m, "\n\t%d)", ++j);
463 seq_printf(m, "\n\t%d)", j+1);
464 cifs_dump_iface(m, iface);466 cifs_dump_iface(m, iface);
465 if (is_ses_using_iface(ses, iface))467 if (is_ses_using_iface(ses, iface))
466 seq_puts(m, "\t\t[CONNECTED]\n");468 seq_puts(m, "\t\t[CONNECTED]\n");
fs/cifs/cifsglob.h+57−1
@@ -80,6 +80,9 @@ · 79 unmodified lines
80#define SMB_DNS_RESOLVE_INTERVAL_MIN 12080#define SMB_DNS_RESOLVE_INTERVAL_MIN 120
81#define SMB_DNS_RESOLVE_INTERVAL_DEFAULT 60081#define SMB_DNS_RESOLVE_INTERVAL_DEFAULT 600
82 82
83/* smb multichannel query server interfaces interval in seconds */
84#define SMB_INTERFACE_POLL_INTERVAL 600
85
83/* maximum number of PDUs in one compound */86/* maximum number of PDUs in one compound */
84#define MAX_COMPOUND 587#define MAX_COMPOUND 5
85 88
@@ -933,15 +936,67 @@ static inline void cifs_set_net_ns(struct TCP_Server_Info *srv, struct net *net) · 847 unmodified lines
933#endif936#endif
934 937
935struct cifs_server_iface {938struct cifs_server_iface {
939 struct list_head iface_head;
940 struct kref refcount;
936 size_t speed;941 size_t speed;
937 unsigned int rdma_capable : 1;942 unsigned int rdma_capable : 1;
938 unsigned int rss_capable : 1;943 unsigned int rss_capable : 1;
944 unsigned int is_active : 1; /* unset if non existent */
939 struct sockaddr_storage sockaddr;945 struct sockaddr_storage sockaddr;
940};946};
941 947
948/* release iface when last ref is dropped */
949static inline void
950release_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 */
965static inline int
966iface_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
942struct cifs_chan {996struct cifs_chan {
943 unsigned int in_reconnect : 1; /* if session setup in progress for this channel */997 unsigned int in_reconnect : 1; /* if session setup in progress for this channel */
944 struct TCP_Server_Info *server;998 struct TCP_Server_Info *server;
999 struct cifs_server_iface *iface; /* interface in use */
945 __u8 signkey[SMB3_SIGN_KEY_SIZE];1000 __u8 signkey[SMB3_SIGN_KEY_SIZE];
946};1001};
947 1002
@@ -993,7 +1048,7 @@ struct cifs_ses { · 45 unmodified lines
993 */1048 */
994 spinlock_t iface_lock;1049 spinlock_t iface_lock;
995 /* ========= begin: protected by iface_lock ======== */1050 /* ========= begin: protected by iface_lock ======== */
996 struct cifs_server_iface *iface_list;1051 struct list_head iface_list;
997 size_t iface_count;1052 size_t iface_count;
998 unsigned long iface_last_update; /* jiffies */1053 unsigned long iface_last_update; /* jiffies */
999 /* ========= end: protected by iface_lock ======== */1054 /* ========= end: protected by iface_lock ======== */
@@ -1203,6 +1258,7 @@ struct cifs_tcon { · 203 unmodified lines
1203#ifdef CONFIG_CIFS_DFS_UPCALL1258#ifdef CONFIG_CIFS_DFS_UPCALL
1204 struct list_head ulist; /* cache update list */1259 struct list_head ulist; /* cache update list */
1205#endif1260#endif
1261 struct delayed_work query_interfaces; /* query interfaces workqueue job */
1206};1262};
1207 1263
1208/*1264/*
fs/cifs/cifsproto.h+7−0
@@ -636,6 +636,13 @@ cifs_chan_clear_need_reconnect(struct cifs_ses *ses, · 635 unmodified lines
636bool636bool
637cifs_chan_needs_reconnect(struct cifs_ses *ses,637cifs_chan_needs_reconnect(struct cifs_ses *ses,
638 struct TCP_Server_Info *server);638 struct TCP_Server_Info *server);
639bool
640cifs_chan_is_iface_active(struct cifs_ses *ses,
641 struct TCP_Server_Info *server);
642int
643cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server);
644int
645SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon);
639 646
640void extract_unc_hostname(const char *unc, const char **h, size_t *len);647void extract_unc_hostname(const char *unc, const char **h, size_t *len);
641int copy_path_name(char *dst, const char *src);648int copy_path_name(char *dst, const char *src);
fs/cifs/connect.c+54−5
@@ -145,6 +145,25 @@ requeue_resolve: · 144 unmodified lines
145 return rc;145 return rc;
146}146}
147 147
148static 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}
148 167
149static void cifs_resolve_server(struct work_struct *work)168static void cifs_resolve_server(struct work_struct *work)
150{169{
@@ -217,7 +236,7 @@ cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server, · 66 unmodified lines
217 bool mark_smb_session)236 bool mark_smb_session)
218{237{
219 struct TCP_Server_Info *pserver;238 struct TCP_Server_Info *pserver;
220 struct cifs_ses *ses;239 struct cifs_ses *ses, *nses;
221 struct cifs_tcon *tcon;240 struct cifs_tcon *tcon;
222 241
223 /*242 /*
@@ -231,7 +250,20 @@ cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server, · 7 unmodified lines
231 250
232 251
233 spin_lock(&cifs_tcp_ses_lock);252 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
235 spin_lock(&ses->chan_lock);267 spin_lock(&ses->chan_lock);
236 if (!mark_smb_session && cifs_chan_needs_reconnect(ses, server))268 if (!mark_smb_session && cifs_chan_needs_reconnect(ses, server))
237 goto next_session;269 goto next_session;
@@ -1894,9 +1926,11 @@ void cifs_put_smb_ses(struct cifs_ses *ses) · 1656 unmodified lines
1894 int i;1926 int i;
1895 1927
1896 for (i = 1; i < chan_count; i++) {1928 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 }
1898 cifs_put_tcp_session(ses->chans[i].server, 0);1933 cifs_put_tcp_session(ses->chans[i].server, 0);
1899 spin_lock(&ses->chan_lock);
1900 ses->chans[i].server = NULL;1934 ses->chans[i].server = NULL;
1901 }1935 }
1902 }1936 }
@@ -2270,6 +2304,9 @@ cifs_put_tcon(struct cifs_tcon *tcon) · 367 unmodified lines
2270 list_del_init(&tcon->tcon_list);2304 list_del_init(&tcon->tcon_list);
2271 spin_unlock(&cifs_tcp_ses_lock);2305 spin_unlock(&cifs_tcp_ses_lock);
2272 2306
2307 /* cancel polling of interfaces */
2308 cancel_delayed_work_sync(&tcon->query_interfaces);
2309
2273 if (tcon->use_witness) {2310 if (tcon->use_witness) {
2274 int rc;2311 int rc;
2275 2312
@@ -2507,6 +2544,12 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb3_fs_context *ctx) · 231 unmodified lines
2507 tcon->local_lease = ctx->local_lease;2544 tcon->local_lease = ctx->local_lease;
2508 INIT_LIST_HEAD(&tcon->pending_opens);2545 INIT_LIST_HEAD(&tcon->pending_opens);
2509 2546
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
2510 spin_lock(&cifs_tcp_ses_lock);2553 spin_lock(&cifs_tcp_ses_lock);
2511 list_add(&tcon->tcon_list, &ses->tcon_list);2554 list_add(&tcon->tcon_list, &ses->tcon_list);
2512 spin_unlock(&cifs_tcp_ses_lock);2555 spin_unlock(&cifs_tcp_ses_lock);
@@ -3982,10 +4025,16 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses, · 1469 unmodified lines
3982 struct nls_table *nls_info)4025 struct nls_table *nls_info)
3983{4026{
3984 int rc = -ENOSYS;4027 int rc = -ENOSYS;
4028 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&server->dstaddr;
4029 struct sockaddr_in *addr = (struct sockaddr_in *)&server->dstaddr;
3985 bool is_binding = false;4030 bool is_binding = false;
3986 4031
3987
3988 spin_lock(&cifs_tcp_ses_lock);4032 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
3989 if (ses->ses_status != SES_GOOD &&4038 if (ses->ses_status != SES_GOOD &&
3990 ses->ses_status != SES_NEW &&4039 ses->ses_status != SES_NEW &&
3991 ses->ses_status != SES_NEED_RECON) {4040 ses->ses_status != SES_NEED_RECON) {
fs/cifs/misc.c+8−1
@@ -75,6 +75,7 @@ sesInfoAlloc(void) · 74 unmodified lines
75 INIT_LIST_HEAD(&ret_buf->tcon_list);75 INIT_LIST_HEAD(&ret_buf->tcon_list);
76 mutex_init(&ret_buf->session_mutex);76 mutex_init(&ret_buf->session_mutex);
77 spin_lock_init(&ret_buf->iface_lock);77 spin_lock_init(&ret_buf->iface_lock);
78 INIT_LIST_HEAD(&ret_buf->iface_list);
78 spin_lock_init(&ret_buf->chan_lock);79 spin_lock_init(&ret_buf->chan_lock);
79 }80 }
80 return ret_buf;81 return ret_buf;
@@ -83,6 +84,8 @@ sesInfoAlloc(void) · 2 unmodified lines
83void84void
84sesInfoFree(struct cifs_ses *buf_to_free)85sesInfoFree(struct cifs_ses *buf_to_free)
85{86{
87 struct cifs_server_iface *iface = NULL, *niface = NULL;
88
86 if (buf_to_free == NULL) {89 if (buf_to_free == NULL) {
87 cifs_dbg(FYI, "Null buffer passed to sesInfoFree\n");90 cifs_dbg(FYI, "Null buffer passed to sesInfoFree\n");
88 return;91 return;
@@ -96,7 +99,11 @@ sesInfoFree(struct cifs_ses *buf_to_free) · 7 unmodified lines
96 kfree(buf_to_free->user_name);99 kfree(buf_to_free->user_name);
97 kfree(buf_to_free->domainName);100 kfree(buf_to_free->domainName);
98 kfree_sensitive(buf_to_free->auth_key.response);101 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);
100 kfree_sensitive(buf_to_free);107 kfree_sensitive(buf_to_free);
101}108}
102 109
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
58 58
59 spin_lock(&ses->chan_lock);59 spin_lock(&ses->chan_lock);
60 for (i = 0; i < ses->chan_count; i++) {60 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) {
62 spin_unlock(&ses->chan_lock);62 spin_unlock(&ses->chan_lock);
63 return true;63 return true;
64 }64 }
@@ -146,16 +146,24 @@ cifs_chan_needs_reconnect(struct cifs_ses *ses, · 81 unmodified lines
146 return CIFS_CHAN_NEEDS_RECONNECT(ses, chan_index);146 return CIFS_CHAN_NEEDS_RECONNECT(ses, chan_index);
147}147}
148 148
149bool
150cifs_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
149/* returns number of channels added */159/* returns number of channels added */
150int cifs_try_adding_channels(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses)160int cifs_try_adding_channels(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses)
151{161{
152 int old_chan_count, new_chan_count;162 int old_chan_count, new_chan_count;
153 int left;163 int left;
154 int i = 0;
155 int rc = 0;164 int rc = 0;
156 int tries = 0;165 int tries = 0;
157 struct cifs_server_iface *ifaces = NULL;166 struct cifs_server_iface *iface = NULL, *niface = NULL;
158 size_t iface_count;
159 167
160 spin_lock(&ses->chan_lock);168 spin_lock(&ses->chan_lock);
161 169
@@ -184,33 +192,17 @@ int cifs_try_adding_channels(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses) · 22 unmodified lines
184 }192 }
185 spin_unlock(&ses->chan_lock);193 spin_unlock(&ses->chan_lock);
186 194
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
207 /*195 /*
208 * Keep connecting to same, fastest, iface for all channels as196 * Keep connecting to same, fastest, iface for all channels as
209 * long as its RSS. Try next fastest one if not RSS or channel197 * long as its RSS. Try next fastest one if not RSS or channel
210 * creation fails.198 * creation fails.
211 */199 */
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
212 while (left > 0) {205 while (left > 0) {
213 struct cifs_server_iface *iface;
214 206
215 tries++;207 tries++;
216 if (tries > 3*ses->chan_max) {208 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
219 break;211 break;
220 }212 }
221 213
222 iface = &ifaces[i];214 spin_lock(&ses->iface_lock);
223 if (is_ses_using_iface(ses, iface) && !iface->rss_capable) {215 if (!ses->iface_count) {
224 i = (i+1) % iface_count;216 spin_unlock(&ses->iface_lock);
225 continue;217 break;
226 }218 }
227 219
228 rc = cifs_ses_add_channel(cifs_sb, ses, iface);220 list_for_each_entry_safe_from(iface, niface, &ses->iface_list,
229 if (rc) {221 iface_head) {
230 cifs_dbg(FYI, "failed to open extra channel on iface#%d rc=%d\n",222 /* skip ifaces that are unusable */
231 i, rc);223 if (!iface->is_active ||
232 i = (i+1) % iface_count;224 (is_ses_using_iface(ses, iface) &&
233 continue;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;
234 }247 }
248 spin_unlock(&ses->iface_lock);
235 249
236 cifs_dbg(FYI, "successfully opened new channel on iface#%d\n",
237 i);
238 left--;250 left--;
239 new_chan_count++;251 new_chan_count++;
240 }252 }
241 253
242 kfree(ifaces);
243 return new_chan_count - old_chan_count;254 return new_chan_count - old_chan_count;
244}255}
245 256
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 */
262int
263cifs_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
246/*335/*
247 * If server is a channel of ses, return the corresponding enclosing336 * If server is a channel of ses, return the corresponding enclosing
248 * cifs_chan otherwise return NULL.337 * 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
355 spin_unlock(&ses->chan_lock);444 spin_unlock(&ses->chan_lock);
356 goto out;445 goto out;
357 }446 }
447 chan->iface = iface;
358 ses->chan_count++;448 ses->chan_count++;
359 atomic_set(&ses->chan_seq, 0);449 atomic_set(&ses->chan_seq, 0);
360 450
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
512static int512static int
513parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,513parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
514 size_t buf_len,514 size_t buf_len,
515 struct cifs_server_iface **iface_list,515 struct cifs_ses *ses)
516 size_t *iface_count)
517{516{
518 struct network_interface_info_ioctl_rsp *p;517 struct network_interface_info_ioctl_rsp *p;
519 struct sockaddr_in *addr4;518 struct sockaddr_in *addr4;
520 struct sockaddr_in6 *addr6;519 struct sockaddr_in6 *addr6;
521 struct iface_info_ipv4 *p4;520 struct iface_info_ipv4 *p4;
522 struct iface_info_ipv6 *p6;521 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;
524 ssize_t bytes_left;524 ssize_t bytes_left;
525 size_t next = 0;525 size_t next = 0;
526 int nb_iface = 0;526 int nb_iface = 0;
527 int rc = 0;527 int rc = 0, ret = 0;
528
529 *iface_list = NULL;
530 *iface_count = 0;
531
532 /*
533 * Fist pass: count and sanity check
534 */
535 528
536 bytes_left = buf_len;529 bytes_left = buf_len;
537 p = buf;530 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
559 531
532 spin_lock(&ses->iface_lock);
560 /*533 /*
561 * Second pass: extract info to internal structure534 * 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
562 */537 */
563 538 list_for_each_entry_safe(iface, niface, &ses->iface_list,
564 *iface_list = kcalloc(nb_iface, sizeof(**iface_list), GFP_KERNEL);539 iface_head) {
565 if (!*iface_list) {540 iface->is_active = 0;
566 rc = -ENOMEM;541 kref_put(&iface->refcount, release_iface);
567 goto out;
568 }542 }
543 spin_unlock(&ses->iface_lock);
569 544
570 info = *iface_list;
571 bytes_left = buf_len;
572 p = buf;
573 while (bytes_left >= sizeof(*p)) {545 while (bytes_left >= sizeof(*p)) {
574 info->speed = le64_to_cpu(p->LinkSpeed);546 memset(&tmp_iface, 0, sizeof(tmp_iface));
575 info->rdma_capable = le32_to_cpu(p->Capability & RDMA_CAPABLE) ? 1 : 0;547 tmp_iface.speed = le64_to_cpu(p->LinkSpeed);
576 info->rss_capable = le32_to_cpu(p->Capability & RSS_CAPABLE) ? 1 : 0;548 tmp_iface.rdma_capable = le32_to_cpu(p->Capability & RDMA_CAPABLE) ? 1 : 0;
577 549 tmp_iface.rss_capable = le32_to_cpu(p->Capability & RSS_CAPABLE) ? 1 : 0;
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));
582 550
583 switch (p->Family) {551 switch (p->Family) {
584 /*552 /*
@@ -587,7 +555,7 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf, · 2 unmodified lines
587 * conversion explicit in case either one changes.555 * conversion explicit in case either one changes.
588 */556 */
589 case INTERNETWORK:557 case INTERNETWORK:
590 addr4 = (struct sockaddr_in *)&info->sockaddr;558 addr4 = (struct sockaddr_in *)&tmp_iface.sockaddr;
591 p4 = (struct iface_info_ipv4 *)p->Buffer;559 p4 = (struct iface_info_ipv4 *)p->Buffer;
592 addr4->sin_family = AF_INET;560 addr4->sin_family = AF_INET;
593 memcpy(&addr4->sin_addr, &p4->IPv4Address, 4);561 memcpy(&addr4->sin_addr, &p4->IPv4Address, 4);
@@ -599,7 +567,7 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf, · 5 unmodified lines
599 &addr4->sin_addr);567 &addr4->sin_addr);
600 break;568 break;
601 case INTERNETWORKV6:569 case INTERNETWORKV6:
602 addr6 = (struct sockaddr_in6 *)&info->sockaddr;570 addr6 = (struct sockaddr_in6 *)&tmp_iface.sockaddr;
603 p6 = (struct iface_info_ipv6 *)p->Buffer;571 p6 = (struct iface_info_ipv6 *)p->Buffer;
604 addr6->sin6_family = AF_INET6;572 addr6->sin6_family = AF_INET6;
605 memcpy(&addr6->sin6_addr, &p6->IPv6Address, 16);573 memcpy(&addr6->sin6_addr, &p6->IPv6Address, 16);
@@ -619,46 +587,96 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf, · 13 unmodified lines
619 goto next_iface;587 goto next_iface;
620 }588 }
621 589
622 (*iface_count)++;590 /*
623 info++;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;
624next_iface:643next_iface:
644 nb_iface++;
625 next = le32_to_cpu(p->Next);645 next = le32_to_cpu(p->Next);
626 if (!next)646 if (!next) {
647 bytes_left -= sizeof(*p);
627 break;648 break;
649 }
628 p = (struct network_interface_info_ioctl_rsp *)((u8 *)p+next);650 p = (struct network_interface_info_ioctl_rsp *)((u8 *)p+next);
629 bytes_left -= next;651 bytes_left -= next;
630 }652 }
631 653
632 if (!*iface_count) {654 if (!nb_iface) {
655 cifs_dbg(VFS, "%s: malformed interface info\n", __func__);
633 rc = -EINVAL;656 rc = -EINVAL;
634 goto out;657 goto out;
635 }658 }
636 659
637out:660 /* Azure rounds the buffer size up 8, to a 16 byte boundary */
638 if (rc) {661 if ((bytes_left > 8) || p->Next)
639 kfree(*iface_list);662 cifs_dbg(VFS, "%s: incomplete interface info\n", __func__);
640 *iface_count = 0;
641 *iface_list = NULL;
642 }
643 return rc;
644}
645 663
646static 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;
650 664
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
670out:
671 return rc;
652}672}
653 673
654static int674int
655SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon)675SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon)
656{676{
657 int rc;677 int rc;
658 unsigned int ret_data_len = 0;678 unsigned int ret_data_len = 0;
659 struct network_interface_info_ioctl_rsp *out_buf = NULL;679 struct network_interface_info_ioctl_rsp *out_buf = NULL;
660 struct cifs_server_iface *iface_list;
661 size_t iface_count;
662 struct cifs_ses *ses = tcon->ses;680 struct cifs_ses *ses = tcon->ses;
663 681
664 rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID,682 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
674 goto out;692 goto out;
675 }693 }
676 694
677 rc = parse_server_interfaces(out_buf, ret_data_len,695 rc = parse_server_interfaces(out_buf, ret_data_len, ses);
678 &iface_list, &iface_count);
679 if (rc)696 if (rc)
680 goto out;697 goto out;
681 698
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
692out:699out:
693 kfree(out_buf);700 kfree(out_buf);
694 return rc;701 return rc;
fs/cifs/smb2pdu.c+15−6
@@ -543,6 +543,7 @@ assemble_neg_contexts(struct smb2_negotiate_req *req, · 542 unmodified lines
543 struct TCP_Server_Info *server, unsigned int *total_len)543 struct TCP_Server_Info *server, unsigned int *total_len)
544{544{
545 char *pneg_ctxt;545 char *pneg_ctxt;
546 char *hostname = NULL;
546 unsigned int ctxt_len, neg_context_count;547 unsigned int ctxt_len, neg_context_count;
547 548
548 if (*total_len > 200) {549 if (*total_len > 200) {
@@ -570,16 +571,24 @@ assemble_neg_contexts(struct smb2_negotiate_req *req, · 21 unmodified lines
570 *total_len += ctxt_len;571 *total_len += ctxt_len;
571 pneg_ctxt += ctxt_len;572 pneg_ctxt += ctxt_len;
572 573
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
578 build_posix_ctxt((struct smb2_posix_neg_context *)pneg_ctxt);574 build_posix_ctxt((struct smb2_posix_neg_context *)pneg_ctxt);
579 *total_len += sizeof(struct smb2_posix_neg_context);575 *total_len += sizeof(struct smb2_posix_neg_context);
580 pneg_ctxt += sizeof(struct smb2_posix_neg_context);576 pneg_ctxt += sizeof(struct smb2_posix_neg_context);
581 577
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;
583 592
584 if (server->compress_algorithm) {593 if (server->compress_algorithm) {
585 build_compression_ctxt((struct smb2_compression_capabilities_context *)594 build_compression_ctxt((struct smb2_compression_capabilities_context *)