Pull cifs fixes from Steve French: "cifs/smb3 client fixes: - two multichannel fixes - three reconnect fixes - unmap fix" * tag '6.2-rc2-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6: cifs: fix interface count calculation during refresh cifs: refcount only the selected iface during interface update cifs: protect access of TCP_Server_Info::{dstaddr,hostname} cifs: fix race in assemble_neg_contexts() cifs: ignore ipc reconnect failures during dfs failover cifs: Fix kmap_local_page() unmapping
Unified · Split
| @@ -327,8 +327,8 @@ static int update_server_fullpath(struct TCP_Server_Info *server, struct cifs_sb · 326 unmodified lines | ||
| 327 | 327 | return rc; |
| 328 | 328 | } |
| 329 | 329 | |
| 330 | −static int target_share_matches_server(struct TCP_Server_Info *server, const char *tcp_host, | |
| 331 | − size_t tcp_host_len, char *share, bool *target_match) | |
| 330 | +static int target_share_matches_server(struct TCP_Server_Info *server, char *share, | |
| 331 | + bool *target_match) | |
| 332 | 332 | { |
| 333 | 333 | int rc = 0; |
| 334 | 334 | const char *dfs_host; |
| @@ -338,13 +338,16 @@ static int target_share_matches_server(struct TCP_Server_Info *server, const cha · 3 unmodified lines | ||
| 338 | 338 | extract_unc_hostname(share, &dfs_host, &dfs_host_len); |
| 339 | 339 | |
| 340 | 340 | /* Check if hostnames or addresses match */ |
| 341 | − if (dfs_host_len != tcp_host_len || strncasecmp(dfs_host, tcp_host, dfs_host_len) != 0) { | |
| 342 | − cifs_dbg(FYI, "%s: %.*s doesn't match %.*s\n", __func__, (int)dfs_host_len, | |
| 343 | − dfs_host, (int)tcp_host_len, tcp_host); | |
| 341 | + cifs_server_lock(server); | |
| 342 | + if (dfs_host_len != strlen(server->hostname) || | |
| 343 | + strncasecmp(dfs_host, server->hostname, dfs_host_len)) { | |
| 344 | + cifs_dbg(FYI, "%s: %.*s doesn't match %s\n", __func__, | |
| 345 | + (int)dfs_host_len, dfs_host, server->hostname); | |
| 344 | 346 | rc = match_target_ip(server, dfs_host, dfs_host_len, target_match); |
| 345 | 347 | if (rc) |
| 346 | 348 | cifs_dbg(VFS, "%s: failed to match target ip: %d\n", __func__, rc); |
| 347 | 349 | } |
| 350 | + cifs_server_unlock(server); | |
| 348 | 351 | return rc; |
| 349 | 352 | } |
| 350 | 353 | |
| @@ -358,13 +361,9 @@ static int __tree_connect_dfs_target(const unsigned int xid, struct cifs_tcon *t · 7 unmodified lines | ||
| 358 | 361 | struct cifs_ses *root_ses = CIFS_DFS_ROOT_SES(tcon->ses); |
| 359 | 362 | struct cifs_tcon *ipc = root_ses->tcon_ipc; |
| 360 | 363 | char *share = NULL, *prefix = NULL; |
| 361 | − const char *tcp_host; | |
| 362 | − size_t tcp_host_len; | |
| 363 | 364 | struct dfs_cache_tgt_iterator *tit; |
| 364 | 365 | bool target_match; |
| 365 | 366 | |
| 366 | − extract_unc_hostname(server->hostname, &tcp_host, &tcp_host_len); | |
| 367 | − | |
| 368 | 367 | tit = dfs_cache_get_tgt_iterator(tl); |
| 369 | 368 | if (!tit) { |
| 370 | 369 | rc = -ENOENT; |
| @@ -387,8 +386,7 @@ static int __tree_connect_dfs_target(const unsigned int xid, struct cifs_tcon *t · 16 unmodified lines | ||
| 387 | 386 | break; |
| 388 | 387 | } |
| 389 | 388 | |
| 390 | − rc = target_share_matches_server(server, tcp_host, tcp_host_len, share, | |
| 391 | − &target_match); | |
| 389 | + rc = target_share_matches_server(server, share, &target_match); | |
| 392 | 390 | if (rc) |
| 393 | 391 | break; |
| 394 | 392 | if (!target_match) { |
| @@ -401,8 +399,7 @@ static int __tree_connect_dfs_target(const unsigned int xid, struct cifs_tcon *t · 6 unmodified lines | ||
| 401 | 399 | if (ipc->need_reconnect) { |
| 402 | 400 | scnprintf(tree, MAX_TREE_SIZE, "\\\\%s\\IPC$", server->hostname); |
| 403 | 401 | rc = ops->tree_connect(xid, ipc->ses, tree, ipc, cifs_sb->local_nls); |
| 404 | − if (rc) | |
| 405 | − break; | |
| 402 | + cifs_dbg(FYI, "%s: reconnect ipc: %d\n", __func__, rc); | |
| 406 | 403 | } |
| 407 | 404 | |
| 408 | 405 | scnprintf(tree, MAX_TREE_SIZE, "\\%s", share); |
| @@ -498,7 +495,9 @@ int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, const stru · 89 unmodified lines | ||
| 498 | 495 | } |
| 499 | 496 | |
| 500 | 497 | if (tcon->ipc) { |
| 498 | + cifs_server_lock(server); | |
| 501 | 499 | scnprintf(tree, MAX_TREE_SIZE, "\\\\%s\\IPC$", server->hostname); |
| 500 | + cifs_server_unlock(server); | |
| 502 | 501 | rc = ops->tree_connect(xid, tcon->ses, tree, tcon, nlsc); |
| 503 | 502 | goto out; |
| 504 | 503 | } |
| @@ -1277,7 +1277,9 @@ int match_target_ip(struct TCP_Server_Info *server, · 1276 unmodified lines | ||
| 1277 | 1277 | if (rc < 0) |
| 1278 | 1278 | return rc; |
| 1279 | 1279 | |
| 1280 | + spin_lock(&server->srv_lock); | |
| 1280 | 1281 | *result = cifs_match_ipaddr((struct sockaddr *)&server->dstaddr, (struct sockaddr *)&ss); |
| 1282 | + spin_unlock(&server->srv_lock); | |
| 1281 | 1283 | cifs_dbg(FYI, "%s: ip addresses match: %u\n", __func__, *result); |
| 1282 | 1284 | return 0; |
| 1283 | 1285 | } |
| @@ -292,9 +292,10 @@ cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server) · 291 unmodified lines | ||
| 292 | 292 | continue; |
| 293 | 293 | } |
| 294 | 294 | kref_get(&iface->refcount); |
| 295 | + break; | |
| 295 | 296 | } |
| 296 | 297 | |
| 297 | − if (!list_entry_is_head(iface, &ses->iface_list, iface_head)) { | |
| 298 | + if (list_entry_is_head(iface, &ses->iface_list, iface_head)) { | |
| 298 | 299 | rc = 1; |
| 299 | 300 | iface = NULL; |
| 300 | 301 | cifs_dbg(FYI, "unable to find a suitable iface\n"); |
| @@ -530,7 +530,6 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf, · 529 unmodified lines | ||
| 530 | 530 | p = buf; |
| 531 | 531 | |
| 532 | 532 | spin_lock(&ses->iface_lock); |
| 533 | − ses->iface_count = 0; | |
| 534 | 533 | /* |
| 535 | 534 | * Go through iface_list and do kref_put to remove |
| 536 | 535 | * any unused ifaces. ifaces in use will be removed |
| @@ -540,6 +539,7 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf, · 3 unmodified lines | ||
| 540 | 539 | iface_head) { |
| 541 | 540 | iface->is_active = 0; |
| 542 | 541 | kref_put(&iface->refcount, release_iface); |
| 542 | + ses->iface_count--; | |
| 543 | 543 | } |
| 544 | 544 | spin_unlock(&ses->iface_lock); |
| 545 | 545 | |
| @@ -618,6 +618,7 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf, · 72 unmodified lines | ||
| 618 | 618 | /* just get a ref so that it doesn't get picked/freed */ |
| 619 | 619 | iface->is_active = 1; |
| 620 | 620 | kref_get(&iface->refcount); |
| 621 | + ses->iface_count++; | |
| 621 | 622 | spin_unlock(&ses->iface_lock); |
| 622 | 623 | goto next_iface; |
| 623 | 624 | } else if (ret < 0) { |
| @@ -4488,17 +4489,12 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, int num_rqst, · 3864 unmodified lines | ||
| 4488 | 4489 | |
| 4489 | 4490 | /* copy pages form the old */ |
| 4490 | 4491 | for (j = 0; j < npages; j++) { |
| 4491 | − char *dst, *src; | |
| 4492 | 4492 | unsigned int offset, len; |
| 4493 | 4493 | |
| 4494 | 4494 | rqst_page_get_length(new, j, &len, &offset); |
| 4495 | 4495 | |
| 4496 | − dst = kmap_local_page(new->rq_pages[j]) + offset; | |
| 4497 | − src = kmap_local_page(old->rq_pages[j]) + offset; | |
| 4498 | − | |
| 4499 | − memcpy(dst, src, len); | |
| 4500 | − kunmap(new->rq_pages[j]); | |
| 4501 | − kunmap(old->rq_pages[j]); | |
| 4496 | + memcpy_page(new->rq_pages[j], offset, | |
| 4497 | + old->rq_pages[j], offset, len); | |
| 4502 | 4498 | } |
| 4503 | 4499 | } |
| 4504 | 4500 | |
| @@ -541,9 +541,10 @@ static void · 540 unmodified lines | ||
| 541 | 541 | assemble_neg_contexts(struct smb2_negotiate_req *req, |
| 542 | 542 | struct TCP_Server_Info *server, unsigned int *total_len) |
| 543 | 543 | { |
| 544 | − char *pneg_ctxt; | |
| 545 | − char *hostname = NULL; | |
| 546 | 544 | unsigned int ctxt_len, neg_context_count; |
| 545 | + struct TCP_Server_Info *pserver; | |
| 546 | + char *pneg_ctxt; | |
| 547 | + char *hostname; | |
| 547 | 548 | |
| 548 | 549 | if (*total_len > 200) { |
| 549 | 550 | /* In case length corrupted don't want to overrun smb buffer */ |
| @@ -574,8 +575,9 @@ assemble_neg_contexts(struct smb2_negotiate_req *req, · 24 unmodified lines | ||
| 574 | 575 | * secondary channels don't have the hostname field populated |
| 575 | 576 | * use the hostname field in the primary channel instead |
| 576 | 577 | */ |
| 577 | − hostname = CIFS_SERVER_IS_CHAN(server) ? | |
| 578 | − server->primary_server->hostname : server->hostname; | |
| 578 | + pserver = CIFS_SERVER_IS_CHAN(server) ? server->primary_server : server; | |
| 579 | + cifs_server_lock(pserver); | |
| 580 | + hostname = pserver->hostname; | |
| 579 | 581 | if (hostname && (hostname[0] != 0)) { |
| 580 | 582 | ctxt_len = build_netname_ctxt((struct smb2_netname_neg_context *)pneg_ctxt, |
| 581 | 583 | hostname); |
| @@ -584,6 +586,7 @@ assemble_neg_contexts(struct smb2_negotiate_req *req, · 2 unmodified lines | ||
| 584 | 586 | neg_context_count = 3; |
| 585 | 587 | } else |
| 586 | 588 | neg_context_count = 2; |
| 589 | + cifs_server_unlock(pserver); | |
| 587 | 590 | |
| 588 | 591 | build_posix_ctxt((struct smb2_posix_neg_context *)pneg_ctxt); |
| 589 | 592 | *total_len += sizeof(struct smb2_posix_neg_context); |