Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

+396 -169
+7 -5
fs/cifs/cifs_debug.c
··· 162 162 seq_printf(m, "\t\tIPv4: %pI4\n", &ipv4->sin_addr); 163 163 else if (iface->sockaddr.ss_family == AF_INET6) 164 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 167 169 static int cifs_debug_files_proc_show(struct seq_file *m, void *v) ··· 223 221 struct TCP_Server_Info *server; 224 222 struct cifs_ses *ses; 225 223 struct cifs_tcon *tcon; 224 + struct cifs_server_iface *iface; 226 225 int c, i, j; 227 226 228 227 seq_puts(m, ··· 459 456 if (ses->iface_count) 460 457 seq_printf(m, "\n\n\tServer interfaces: %zu", 461 458 ses->iface_count); 462 - for (j = 0; j < ses->iface_count; j++) { 463 - struct cifs_server_iface *iface; 464 - 465 - iface = &ses->iface_list[j]; 466 - seq_printf(m, "\n\t%d)", j+1); 459 + j = 0; 460 + list_for_each_entry(iface, &ses->iface_list, 461 + iface_head) { 462 + seq_printf(m, "\n\t%d)", ++j); 467 463 cifs_dump_iface(m, iface); 468 464 if (is_ses_using_iface(ses, iface)) 469 465 seq_puts(m, "\t\t[CONNECTED]\n");
+57 -1
fs/cifs/cifsglob.h
··· 80 80 #define SMB_DNS_RESOLVE_INTERVAL_MIN 120 81 81 #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 86 /* maximum number of PDUs in one compound */ 84 87 #define MAX_COMPOUND 5 85 88 ··· 936 933 #endif 937 934 938 935 struct cifs_server_iface { 936 + struct list_head iface_head; 937 + struct kref refcount; 939 938 size_t speed; 940 939 unsigned int rdma_capable : 1; 941 940 unsigned int rss_capable : 1; 941 + unsigned int is_active : 1; /* unset if non existent */ 942 942 struct sockaddr_storage sockaddr; 943 943 }; 944 + 945 + /* release iface when last ref is dropped */ 946 + static inline void 947 + release_iface(struct kref *ref) 948 + { 949 + struct cifs_server_iface *iface = container_of(ref, 950 + struct cifs_server_iface, 951 + refcount); 952 + list_del_init(&iface->iface_head); 953 + kfree(iface); 954 + } 955 + 956 + /* 957 + * compare two interfaces a and b 958 + * return 0 if everything matches. 959 + * return 1 if a has higher link speed, or rdma capable, or rss capable 960 + * return -1 otherwise. 961 + */ 962 + static inline int 963 + iface_cmp(struct cifs_server_iface *a, struct cifs_server_iface *b) 964 + { 965 + int cmp_ret = 0; 966 + 967 + WARN_ON(!a || !b); 968 + if (a->speed == b->speed) { 969 + if (a->rdma_capable == b->rdma_capable) { 970 + if (a->rss_capable == b->rss_capable) { 971 + cmp_ret = memcmp(&a->sockaddr, &b->sockaddr, 972 + sizeof(a->sockaddr)); 973 + if (!cmp_ret) 974 + return 0; 975 + else if (cmp_ret > 0) 976 + return 1; 977 + else 978 + return -1; 979 + } else if (a->rss_capable > b->rss_capable) 980 + return 1; 981 + else 982 + return -1; 983 + } else if (a->rdma_capable > b->rdma_capable) 984 + return 1; 985 + else 986 + return -1; 987 + } else if (a->speed > b->speed) 988 + return 1; 989 + else 990 + return -1; 991 + } 944 992 945 993 struct cifs_chan { 946 994 unsigned int in_reconnect : 1; /* if session setup in progress for this channel */ 947 995 struct TCP_Server_Info *server; 996 + struct cifs_server_iface *iface; /* interface in use */ 948 997 __u8 signkey[SMB3_SIGN_KEY_SIZE]; 949 998 }; 950 999 ··· 1048 993 */ 1049 994 spinlock_t iface_lock; 1050 995 /* ========= begin: protected by iface_lock ======== */ 1051 - struct cifs_server_iface *iface_list; 996 + struct list_head iface_list; 1052 997 size_t iface_count; 1053 998 unsigned long iface_last_update; /* jiffies */ 1054 999 /* ========= end: protected by iface_lock ======== */ ··· 1258 1203 #ifdef CONFIG_CIFS_DFS_UPCALL 1259 1204 struct list_head ulist; /* cache update list */ 1260 1205 #endif 1206 + struct delayed_work query_interfaces; /* query interfaces workqueue job */ 1261 1207 }; 1262 1208 1263 1209 /*
+7
fs/cifs/cifsproto.h
··· 636 636 bool 637 637 cifs_chan_needs_reconnect(struct cifs_ses *ses, 638 638 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); 639 646 640 647 void extract_unc_hostname(const char *unc, const char **h, size_t *len); 641 648 int copy_path_name(char *dst, const char *src);
+54 -5
fs/cifs/connect.c
··· 145 145 return rc; 146 146 } 147 147 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 + } 148 167 149 168 static void cifs_resolve_server(struct work_struct *work) 150 169 { ··· 236 217 bool mark_smb_session) 237 218 { 238 219 struct TCP_Server_Info *pserver; 239 - struct cifs_ses *ses; 220 + struct cifs_ses *ses, *nses; 240 221 struct cifs_tcon *tcon; 241 222 242 223 /* ··· 250 231 251 232 252 233 spin_lock(&cifs_tcp_ses_lock); 253 - list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) { 234 + list_for_each_entry_safe(ses, nses, &pserver->smb_ses_list, smb_ses_list) { 235 + /* check if iface is still active */ 236 + if (!cifs_chan_is_iface_active(ses, server)) { 237 + /* 238 + * HACK: drop the lock before calling 239 + * cifs_chan_update_iface to avoid deadlock 240 + */ 241 + ses->ses_count++; 242 + spin_unlock(&cifs_tcp_ses_lock); 243 + cifs_chan_update_iface(ses, server); 244 + spin_lock(&cifs_tcp_ses_lock); 245 + ses->ses_count--; 246 + } 247 + 254 248 spin_lock(&ses->chan_lock); 255 249 if (!mark_smb_session && cifs_chan_needs_reconnect(ses, server)) 256 250 goto next_session; ··· 1926 1894 int i; 1927 1895 1928 1896 for (i = 1; i < chan_count; i++) { 1929 - spin_unlock(&ses->chan_lock); 1897 + if (ses->chans[i].iface) { 1898 + kref_put(&ses->chans[i].iface->refcount, release_iface); 1899 + ses->chans[i].iface = NULL; 1900 + } 1930 1901 cifs_put_tcp_session(ses->chans[i].server, 0); 1931 - spin_lock(&ses->chan_lock); 1932 1902 ses->chans[i].server = NULL; 1933 1903 } 1934 1904 } ··· 2304 2270 list_del_init(&tcon->tcon_list); 2305 2271 spin_unlock(&cifs_tcp_ses_lock); 2306 2272 2273 + /* cancel polling of interfaces */ 2274 + cancel_delayed_work_sync(&tcon->query_interfaces); 2275 + 2307 2276 if (tcon->use_witness) { 2308 2277 int rc; 2309 2278 ··· 2543 2506 tcon->nodelete = ctx->nodelete; 2544 2507 tcon->local_lease = ctx->local_lease; 2545 2508 INIT_LIST_HEAD(&tcon->pending_opens); 2509 + 2510 + /* schedule query interfaces poll */ 2511 + INIT_DELAYED_WORK(&tcon->query_interfaces, 2512 + smb2_query_server_interfaces); 2513 + queue_delayed_work(cifsiod_wq, &tcon->query_interfaces, 2514 + (SMB_INTERFACE_POLL_INTERVAL * HZ)); 2546 2515 2547 2516 spin_lock(&cifs_tcp_ses_lock); 2548 2517 list_add(&tcon->tcon_list, &ses->tcon_list); ··· 4025 3982 struct nls_table *nls_info) 4026 3983 { 4027 3984 int rc = -ENOSYS; 3985 + struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&server->dstaddr; 3986 + struct sockaddr_in *addr = (struct sockaddr_in *)&server->dstaddr; 4028 3987 bool is_binding = false; 4029 3988 4030 - 4031 3989 spin_lock(&cifs_tcp_ses_lock); 3990 + if (server->dstaddr.ss_family == AF_INET6) 3991 + scnprintf(ses->ip_addr, sizeof(ses->ip_addr), "%pI6", &addr6->sin6_addr); 3992 + else 3993 + scnprintf(ses->ip_addr, sizeof(ses->ip_addr), "%pI4", &addr->sin_addr); 3994 + 4032 3995 if (ses->ses_status != SES_GOOD && 4033 3996 ses->ses_status != SES_NEW && 4034 3997 ses->ses_status != SES_NEED_RECON) {
+8 -1
fs/cifs/misc.c
··· 75 75 INIT_LIST_HEAD(&ret_buf->tcon_list); 76 76 mutex_init(&ret_buf->session_mutex); 77 77 spin_lock_init(&ret_buf->iface_lock); 78 + INIT_LIST_HEAD(&ret_buf->iface_list); 78 79 spin_lock_init(&ret_buf->chan_lock); 79 80 } 80 81 return ret_buf; ··· 84 83 void 85 84 sesInfoFree(struct cifs_ses *buf_to_free) 86 85 { 86 + struct cifs_server_iface *iface = NULL, *niface = NULL; 87 + 87 88 if (buf_to_free == NULL) { 88 89 cifs_dbg(FYI, "Null buffer passed to sesInfoFree\n"); 89 90 return; ··· 99 96 kfree(buf_to_free->user_name); 100 97 kfree(buf_to_free->domainName); 101 98 kfree_sensitive(buf_to_free->auth_key.response); 102 - kfree(buf_to_free->iface_list); 99 + spin_lock(&buf_to_free->iface_lock); 100 + list_for_each_entry_safe(iface, niface, &buf_to_free->iface_list, 101 + iface_head) 102 + kref_put(&iface->refcount, release_iface); 103 + spin_unlock(&buf_to_free->iface_lock); 103 104 kfree_sensitive(buf_to_free); 104 105 } 105 106
+129 -39
fs/cifs/sess.c
··· 58 58 59 59 spin_lock(&ses->chan_lock); 60 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 62 spin_unlock(&ses->chan_lock); 63 63 return true; 64 64 } ··· 146 146 return CIFS_CHAN_NEEDS_RECONNECT(ses, chan_index); 147 147 } 148 148 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 + 149 159 /* returns number of channels added */ 150 160 int cifs_try_adding_channels(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses) 151 161 { 152 162 int old_chan_count, new_chan_count; 153 163 int left; 154 - int i = 0; 155 164 int rc = 0; 156 165 int tries = 0; 157 - struct cifs_server_iface *ifaces = NULL; 158 - size_t iface_count; 166 + struct cifs_server_iface *iface = NULL, *niface = NULL; 159 167 160 168 spin_lock(&ses->chan_lock); 161 169 ··· 193 185 spin_unlock(&ses->chan_lock); 194 186 195 187 /* 196 - * Make a copy of the iface list at the time and use that 197 - * instead so as to not hold the iface spinlock for opening 198 - * channels 199 - */ 200 - spin_lock(&ses->iface_lock); 201 - iface_count = ses->iface_count; 202 - if (iface_count <= 0) { 203 - spin_unlock(&ses->iface_lock); 204 - cifs_dbg(VFS, "no iface list available to open channels\n"); 205 - return 0; 206 - } 207 - ifaces = kmemdup(ses->iface_list, iface_count*sizeof(*ifaces), 208 - GFP_ATOMIC); 209 - if (!ifaces) { 210 - spin_unlock(&ses->iface_lock); 211 - return 0; 212 - } 213 - spin_unlock(&ses->iface_lock); 214 - 215 - /* 216 188 * Keep connecting to same, fastest, iface for all channels as 217 189 * long as its RSS. Try next fastest one if not RSS or channel 218 190 * creation fails. 219 191 */ 192 + spin_lock(&ses->iface_lock); 193 + iface = list_first_entry(&ses->iface_list, struct cifs_server_iface, 194 + iface_head); 195 + spin_unlock(&ses->iface_lock); 196 + 220 197 while (left > 0) { 221 - struct cifs_server_iface *iface; 222 198 223 199 tries++; 224 200 if (tries > 3*ses->chan_max) { ··· 211 219 break; 212 220 } 213 221 214 - iface = &ifaces[i]; 215 - if (is_ses_using_iface(ses, iface) && !iface->rss_capable) { 216 - i = (i+1) % iface_count; 217 - continue; 222 + spin_lock(&ses->iface_lock); 223 + if (!ses->iface_count) { 224 + spin_unlock(&ses->iface_lock); 225 + break; 218 226 } 219 227 220 - rc = cifs_ses_add_channel(cifs_sb, ses, iface); 221 - if (rc) { 222 - cifs_dbg(FYI, "failed to open extra channel on iface#%d rc=%d\n", 223 - i, rc); 224 - i = (i+1) % iface_count; 225 - continue; 226 - } 228 + list_for_each_entry_safe_from(iface, niface, &ses->iface_list, 229 + iface_head) { 230 + /* skip ifaces that are unusable */ 231 + if (!iface->is_active || 232 + (is_ses_using_iface(ses, iface) && 233 + !iface->rss_capable)) { 234 + continue; 235 + } 227 236 228 - cifs_dbg(FYI, "successfully opened new channel on iface#%d\n", 229 - i); 237 + /* take ref before unlock */ 238 + kref_get(&iface->refcount); 239 + 240 + spin_unlock(&ses->iface_lock); 241 + rc = cifs_ses_add_channel(cifs_sb, ses, iface); 242 + spin_lock(&ses->iface_lock); 243 + 244 + if (rc) { 245 + cifs_dbg(VFS, "failed to open extra channel on iface:%pIS rc=%d\n", 246 + &iface->sockaddr, 247 + rc); 248 + kref_put(&iface->refcount, release_iface); 249 + continue; 250 + } 251 + 252 + cifs_dbg(FYI, "successfully opened new channel on iface:%pIS\n", 253 + &iface->sockaddr); 254 + break; 255 + } 256 + spin_unlock(&ses->iface_lock); 257 + 230 258 left--; 231 259 new_chan_count++; 232 260 } 233 261 234 - kfree(ifaces); 235 262 return new_chan_count - old_chan_count; 263 + } 264 + 265 + /* 266 + * update the iface for the channel if necessary. 267 + * will return 0 when iface is updated, 1 if removed, 2 otherwise 268 + * Must be called with chan_lock held. 269 + */ 270 + int 271 + cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server) 272 + { 273 + unsigned int chan_index; 274 + struct cifs_server_iface *iface = NULL; 275 + struct cifs_server_iface *old_iface = NULL; 276 + int rc = 0; 277 + 278 + spin_lock(&ses->chan_lock); 279 + chan_index = cifs_ses_get_chan_index(ses, server); 280 + if (!chan_index) { 281 + spin_unlock(&ses->chan_lock); 282 + return 0; 283 + } 284 + 285 + if (ses->chans[chan_index].iface) { 286 + old_iface = ses->chans[chan_index].iface; 287 + if (old_iface->is_active) { 288 + spin_unlock(&ses->chan_lock); 289 + return 1; 290 + } 291 + } 292 + spin_unlock(&ses->chan_lock); 293 + 294 + spin_lock(&ses->iface_lock); 295 + /* then look for a new one */ 296 + list_for_each_entry(iface, &ses->iface_list, iface_head) { 297 + if (!iface->is_active || 298 + (is_ses_using_iface(ses, iface) && 299 + !iface->rss_capable)) { 300 + continue; 301 + } 302 + kref_get(&iface->refcount); 303 + } 304 + 305 + if (!list_entry_is_head(iface, &ses->iface_list, iface_head)) { 306 + rc = 1; 307 + iface = NULL; 308 + cifs_dbg(FYI, "unable to find a suitable iface\n"); 309 + } 310 + 311 + /* now drop the ref to the current iface */ 312 + if (old_iface && iface) { 313 + kref_put(&old_iface->refcount, release_iface); 314 + cifs_dbg(FYI, "replacing iface: %pIS with %pIS\n", 315 + &old_iface->sockaddr, 316 + &iface->sockaddr); 317 + } else if (old_iface) { 318 + kref_put(&old_iface->refcount, release_iface); 319 + cifs_dbg(FYI, "releasing ref to iface: %pIS\n", 320 + &old_iface->sockaddr); 321 + } else { 322 + WARN_ON(!iface); 323 + cifs_dbg(FYI, "adding new iface: %pIS\n", &iface->sockaddr); 324 + } 325 + spin_unlock(&ses->iface_lock); 326 + 327 + spin_lock(&ses->chan_lock); 328 + chan_index = cifs_ses_get_chan_index(ses, server); 329 + ses->chans[chan_index].iface = iface; 330 + 331 + /* No iface is found. if secondary chan, drop connection */ 332 + if (!iface && CIFS_SERVER_IS_CHAN(server)) 333 + ses->chans[chan_index].server = NULL; 334 + 335 + spin_unlock(&ses->chan_lock); 336 + 337 + if (!iface && CIFS_SERVER_IS_CHAN(server)) 338 + cifs_put_tcp_session(server, false); 339 + 340 + return rc; 236 341 } 237 342 238 343 /* ··· 444 355 spin_unlock(&ses->chan_lock); 445 356 goto out; 446 357 } 358 + chan->iface = iface; 447 359 ses->chan_count++; 448 360 atomic_set(&ses->chan_seq, 0); 449 361
+119 -112
fs/cifs/smb2ops.c
··· 512 512 static int 513 513 parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf, 514 514 size_t buf_len, 515 - struct cifs_server_iface **iface_list, 516 - size_t *iface_count) 515 + struct cifs_ses *ses) 517 516 { 518 517 struct network_interface_info_ioctl_rsp *p; 519 518 struct sockaddr_in *addr4; 520 519 struct sockaddr_in6 *addr6; 521 520 struct iface_info_ipv4 *p4; 522 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 524 ssize_t bytes_left; 525 525 size_t next = 0; 526 526 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; 535 528 536 529 bytes_left = buf_len; 537 530 p = buf; 531 + 532 + spin_lock(&ses->iface_lock); 533 + /* 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 537 + */ 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); 542 + } 543 + spin_unlock(&ses->iface_lock); 544 + 538 545 while (bytes_left >= sizeof(*p)) { 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; 550 + 551 + switch (p->Family) { 552 + /* 553 + * The kernel and wire socket structures have the same 554 + * layout and use network byte order but make the 555 + * conversion explicit in case either one changes. 556 + */ 557 + case INTERNETWORK: 558 + addr4 = (struct sockaddr_in *)&tmp_iface.sockaddr; 559 + p4 = (struct iface_info_ipv4 *)p->Buffer; 560 + addr4->sin_family = AF_INET; 561 + memcpy(&addr4->sin_addr, &p4->IPv4Address, 4); 562 + 563 + /* [MS-SMB2] 2.2.32.5.1.1 Clients MUST ignore these */ 564 + addr4->sin_port = cpu_to_be16(CIFS_PORT); 565 + 566 + cifs_dbg(FYI, "%s: ipv4 %pI4\n", __func__, 567 + &addr4->sin_addr); 568 + break; 569 + case INTERNETWORKV6: 570 + addr6 = (struct sockaddr_in6 *)&tmp_iface.sockaddr; 571 + p6 = (struct iface_info_ipv6 *)p->Buffer; 572 + addr6->sin6_family = AF_INET6; 573 + memcpy(&addr6->sin6_addr, &p6->IPv6Address, 16); 574 + 575 + /* [MS-SMB2] 2.2.32.5.1.2 Clients MUST ignore these */ 576 + addr6->sin6_flowinfo = 0; 577 + addr6->sin6_scope_id = 0; 578 + addr6->sin6_port = cpu_to_be16(CIFS_PORT); 579 + 580 + cifs_dbg(FYI, "%s: ipv6 %pI6\n", __func__, 581 + &addr6->sin6_addr); 582 + break; 583 + default: 584 + cifs_dbg(VFS, 585 + "%s: skipping unsupported socket family\n", 586 + __func__); 587 + goto next_iface; 588 + } 589 + 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; 643 + next_iface: 539 644 nb_iface++; 540 645 next = le32_to_cpu(p->Next); 541 646 if (!next) { ··· 662 557 cifs_dbg(VFS, "%s: incomplete interface info\n", __func__); 663 558 664 559 665 - /* 666 - * Second pass: extract info to internal structure 667 - */ 668 - 669 - *iface_list = kcalloc(nb_iface, sizeof(**iface_list), GFP_KERNEL); 670 - if (!*iface_list) { 671 - rc = -ENOMEM; 672 - goto out; 673 - } 674 - 675 - info = *iface_list; 676 - bytes_left = buf_len; 677 - p = buf; 678 - while (bytes_left >= sizeof(*p)) { 679 - info->speed = le64_to_cpu(p->LinkSpeed); 680 - info->rdma_capable = le32_to_cpu(p->Capability & RDMA_CAPABLE) ? 1 : 0; 681 - info->rss_capable = le32_to_cpu(p->Capability & RSS_CAPABLE) ? 1 : 0; 682 - 683 - cifs_dbg(FYI, "%s: adding iface %zu\n", __func__, *iface_count); 684 - cifs_dbg(FYI, "%s: speed %zu bps\n", __func__, info->speed); 685 - cifs_dbg(FYI, "%s: capabilities 0x%08x\n", __func__, 686 - le32_to_cpu(p->Capability)); 687 - 688 - switch (p->Family) { 689 - /* 690 - * The kernel and wire socket structures have the same 691 - * layout and use network byte order but make the 692 - * conversion explicit in case either one changes. 693 - */ 694 - case INTERNETWORK: 695 - addr4 = (struct sockaddr_in *)&info->sockaddr; 696 - p4 = (struct iface_info_ipv4 *)p->Buffer; 697 - addr4->sin_family = AF_INET; 698 - memcpy(&addr4->sin_addr, &p4->IPv4Address, 4); 699 - 700 - /* [MS-SMB2] 2.2.32.5.1.1 Clients MUST ignore these */ 701 - addr4->sin_port = cpu_to_be16(CIFS_PORT); 702 - 703 - cifs_dbg(FYI, "%s: ipv4 %pI4\n", __func__, 704 - &addr4->sin_addr); 705 - break; 706 - case INTERNETWORKV6: 707 - addr6 = (struct sockaddr_in6 *)&info->sockaddr; 708 - p6 = (struct iface_info_ipv6 *)p->Buffer; 709 - addr6->sin6_family = AF_INET6; 710 - memcpy(&addr6->sin6_addr, &p6->IPv6Address, 16); 711 - 712 - /* [MS-SMB2] 2.2.32.5.1.2 Clients MUST ignore these */ 713 - addr6->sin6_flowinfo = 0; 714 - addr6->sin6_scope_id = 0; 715 - addr6->sin6_port = cpu_to_be16(CIFS_PORT); 716 - 717 - cifs_dbg(FYI, "%s: ipv6 %pI6\n", __func__, 718 - &addr6->sin6_addr); 719 - break; 720 - default: 721 - cifs_dbg(VFS, 722 - "%s: skipping unsupported socket family\n", 723 - __func__); 724 - goto next_iface; 725 - } 726 - 727 - (*iface_count)++; 728 - info++; 729 - next_iface: 730 - next = le32_to_cpu(p->Next); 731 - if (!next) 732 - break; 733 - p = (struct network_interface_info_ioctl_rsp *)((u8 *)p+next); 734 - bytes_left -= next; 735 - } 736 - 737 - if (!*iface_count) { 560 + if (!ses->iface_count) { 738 561 rc = -EINVAL; 739 562 goto out; 740 563 } 741 564 742 565 out: 743 - if (rc) { 744 - kfree(*iface_list); 745 - *iface_count = 0; 746 - *iface_list = NULL; 747 - } 748 566 return rc; 749 567 } 750 568 751 - static int compare_iface(const void *ia, const void *ib) 752 - { 753 - const struct cifs_server_iface *a = (struct cifs_server_iface *)ia; 754 - const struct cifs_server_iface *b = (struct cifs_server_iface *)ib; 755 - 756 - return a->speed == b->speed ? 0 : (a->speed > b->speed ? -1 : 1); 757 - } 758 - 759 - static int 569 + int 760 570 SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon) 761 571 { 762 572 int rc; 763 573 unsigned int ret_data_len = 0; 764 574 struct network_interface_info_ioctl_rsp *out_buf = NULL; 765 - struct cifs_server_iface *iface_list; 766 - size_t iface_count; 767 575 struct cifs_ses *ses = tcon->ses; 768 576 769 577 rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID, ··· 692 674 goto out; 693 675 } 694 676 695 - rc = parse_server_interfaces(out_buf, ret_data_len, 696 - &iface_list, &iface_count); 677 + rc = parse_server_interfaces(out_buf, ret_data_len, ses); 697 678 if (rc) 698 679 goto out; 699 - 700 - /* sort interfaces from fastest to slowest */ 701 - sort(iface_list, iface_count, sizeof(*iface_list), compare_iface, NULL); 702 - 703 - spin_lock(&ses->iface_lock); 704 - kfree(ses->iface_list); 705 - ses->iface_list = iface_list; 706 - ses->iface_count = iface_count; 707 - ses->iface_last_update = jiffies; 708 - spin_unlock(&ses->iface_lock); 709 680 710 681 out: 711 682 kfree(out_buf);
+15 -6
fs/cifs/smb2pdu.c
··· 543 543 struct TCP_Server_Info *server, unsigned int *total_len) 544 544 { 545 545 char *pneg_ctxt; 546 + char *hostname = NULL; 546 547 unsigned int ctxt_len, neg_context_count; 547 548 548 549 if (*total_len > 200) { ··· 571 570 *total_len += ctxt_len; 572 571 pneg_ctxt += ctxt_len; 573 572 574 - ctxt_len = build_netname_ctxt((struct smb2_netname_neg_context *)pneg_ctxt, 575 - server->hostname); 576 - *total_len += ctxt_len; 577 - pneg_ctxt += ctxt_len; 578 - 579 573 build_posix_ctxt((struct smb2_posix_neg_context *)pneg_ctxt); 580 574 *total_len += sizeof(struct smb2_posix_neg_context); 581 575 pneg_ctxt += sizeof(struct smb2_posix_neg_context); 582 576 583 - neg_context_count = 4; 577 + /* 578 + * secondary channels don't have the hostname field populated 579 + * use the hostname field in the primary channel instead 580 + */ 581 + hostname = CIFS_SERVER_IS_CHAN(server) ? 582 + server->primary_server->hostname : server->hostname; 583 + if (hostname && (hostname[0] != 0)) { 584 + ctxt_len = build_netname_ctxt((struct smb2_netname_neg_context *)pneg_ctxt, 585 + hostname); 586 + *total_len += ctxt_len; 587 + pneg_ctxt += ctxt_len; 588 + neg_context_count = 4; 589 + } else /* second channels do not have a hostname */ 590 + neg_context_count = 3; 584 591 585 592 if (server->compress_algorithm) { 586 593 build_compression_ctxt((struct smb2_compression_capabilities_context *)