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.14-rc1-smb3-fixes' of git://git.samba.org/sfrench/cifs-2.6

Pull cifs fixes from Steve French:
"Eight cifs/smb3 fixes, including three for stable.

Three are DFS related fixes, and two to fix problems pointed out by
static checkers"

* tag '5.14-rc1-smb3-fixes' of git://git.samba.org/sfrench/cifs-2.6:
cifs: do not share tcp sessions of dfs connections
SMB3.1.1: fix mount failure to some servers when compression enabled
cifs: added WARN_ON for all the count decrements
cifs: fix missing null session check in mount
cifs: handle reconnect of tcon when there is no cached dfs referral
cifs: fix the out of range assignment to bit fields in parse_server_interfaces
cifs: Do not use the original cruid when following DFS links for multiuser mounts
cifs: use the expiry output of dns_query to schedule next resolution

+124 -20
+5 -1
fs/cifs/cifs_dfs_ref.c
··· 176 176 } 177 177 } 178 178 179 - rc = dns_resolve_server_name_to_ip(name, &srvIP); 179 + rc = dns_resolve_server_name_to_ip(name, &srvIP, NULL); 180 180 if (rc < 0) { 181 181 cifs_dbg(FYI, "%s: Failed to resolve server part of %s to IP: %d\n", 182 182 __func__, name, rc); ··· 211 211 else 212 212 noff = tkn_e - (sb_mountdata + off) + 1; 213 213 214 + if (strncasecmp(sb_mountdata + off, "cruid=", 6) == 0) { 215 + off += noff; 216 + continue; 217 + } 214 218 if (strncasecmp(sb_mountdata + off, "unc=", 4) == 0) { 215 219 off += noff; 216 220 continue;
+7
fs/cifs/cifsglob.h
··· 75 75 #define SMB_ECHO_INTERVAL_MAX 600 76 76 #define SMB_ECHO_INTERVAL_DEFAULT 60 77 77 78 + /* dns resolution interval in seconds */ 79 + #define SMB_DNS_RESOLVE_INTERVAL_DEFAULT 600 80 + 78 81 /* maximum number of PDUs in one compound */ 79 82 #define MAX_COMPOUND 5 80 83 ··· 649 646 /* point to the SMBD connection if RDMA is used instead of socket */ 650 647 struct smbd_connection *smbd_conn; 651 648 struct delayed_work echo; /* echo ping workqueue job */ 649 + struct delayed_work resolve; /* dns resolution workqueue job */ 652 650 char *smallbuf; /* pointer to current "small" buffer */ 653 651 char *bigbuf; /* pointer to current "big" buffer */ 654 652 /* Total size of this PDU. Only valid from cifs_demultiplex_thread */ ··· 692 688 #ifdef CONFIG_CIFS_SWN_UPCALL 693 689 bool use_swn_dstaddr; 694 690 struct sockaddr_storage swn_dstaddr; 691 + #endif 692 + #ifdef CONFIG_CIFS_DFS_UPCALL 693 + bool is_dfs_conn; /* if a dfs connection */ 695 694 #endif 696 695 }; 697 696
+99 -11
fs/cifs/connect.c
··· 78 78 int rc; 79 79 int len; 80 80 char *unc, *ipaddr = NULL; 81 + time64_t expiry, now; 82 + unsigned long ttl = SMB_DNS_RESOLVE_INTERVAL_DEFAULT; 81 83 82 84 if (!server->hostname) 83 85 return -EINVAL; ··· 93 91 } 94 92 scnprintf(unc, len, "\\\\%s", server->hostname); 95 93 96 - rc = dns_resolve_server_name_to_ip(unc, &ipaddr); 94 + rc = dns_resolve_server_name_to_ip(unc, &ipaddr, &expiry); 97 95 kfree(unc); 98 96 99 97 if (rc < 0) { 100 98 cifs_dbg(FYI, "%s: failed to resolve server part of %s to IP: %d\n", 101 99 __func__, server->hostname, rc); 102 - return rc; 100 + goto requeue_resolve; 103 101 } 104 102 105 103 spin_lock(&cifs_tcp_ses_lock); ··· 108 106 spin_unlock(&cifs_tcp_ses_lock); 109 107 kfree(ipaddr); 110 108 111 - return !rc ? -1 : 0; 109 + /* rc == 1 means success here */ 110 + if (rc) { 111 + now = ktime_get_real_seconds(); 112 + if (expiry && expiry > now) 113 + /* 114 + * To make sure we don't use the cached entry, retry 1s 115 + * after expiry. 116 + */ 117 + ttl = (expiry - now + 1); 118 + } 119 + rc = !rc ? -1 : 0; 120 + 121 + requeue_resolve: 122 + cifs_dbg(FYI, "%s: next dns resolution scheduled for %lu seconds in the future\n", 123 + __func__, ttl); 124 + mod_delayed_work(cifsiod_wq, &server->resolve, (ttl * HZ)); 125 + 126 + return rc; 127 + } 128 + 129 + 130 + static void cifs_resolve_server(struct work_struct *work) 131 + { 132 + int rc; 133 + struct TCP_Server_Info *server = container_of(work, 134 + struct TCP_Server_Info, resolve.work); 135 + 136 + mutex_lock(&server->srv_mutex); 137 + 138 + /* 139 + * Resolve the hostname again to make sure that IP address is up-to-date. 140 + */ 141 + rc = reconn_set_ipaddr_from_hostname(server); 142 + if (rc) { 143 + cifs_dbg(FYI, "%s: failed to resolve hostname: %d\n", 144 + __func__, rc); 145 + } 146 + 147 + mutex_unlock(&server->srv_mutex); 112 148 } 113 149 114 150 #ifdef CONFIG_CIFS_DFS_UPCALL ··· 720 680 spin_unlock(&cifs_tcp_ses_lock); 721 681 722 682 cancel_delayed_work_sync(&server->echo); 683 + cancel_delayed_work_sync(&server->resolve); 723 684 724 685 spin_lock(&GlobalMid_Lock); 725 686 server->tcpStatus = CifsExiting; ··· 1268 1227 1269 1228 spin_lock(&cifs_tcp_ses_lock); 1270 1229 list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) { 1230 + #ifdef CONFIG_CIFS_DFS_UPCALL 1231 + /* 1232 + * DFS failover implementation in cifs_reconnect() requires unique tcp sessions for 1233 + * DFS connections to do failover properly, so avoid sharing them with regular 1234 + * shares or even links that may connect to same server but having completely 1235 + * different failover targets. 1236 + */ 1237 + if (server->is_dfs_conn) 1238 + continue; 1239 + #endif 1271 1240 /* 1272 1241 * Skip ses channels since they're only handled in lower layers 1273 1242 * (e.g. cifs_send_recv). ··· 1305 1254 return; 1306 1255 } 1307 1256 1257 + /* srv_count can never go negative */ 1258 + WARN_ON(server->srv_count < 0); 1259 + 1308 1260 put_net(cifs_net_ns(server)); 1309 1261 1310 1262 list_del_init(&server->tcp_ses_list); 1311 1263 spin_unlock(&cifs_tcp_ses_lock); 1312 1264 1313 1265 cancel_delayed_work_sync(&server->echo); 1266 + cancel_delayed_work_sync(&server->resolve); 1314 1267 1315 1268 if (from_reconnect) 1316 1269 /* ··· 1397 1342 INIT_LIST_HEAD(&tcp_ses->tcp_ses_list); 1398 1343 INIT_LIST_HEAD(&tcp_ses->smb_ses_list); 1399 1344 INIT_DELAYED_WORK(&tcp_ses->echo, cifs_echo_request); 1345 + INIT_DELAYED_WORK(&tcp_ses->resolve, cifs_resolve_server); 1400 1346 INIT_DELAYED_WORK(&tcp_ses->reconnect, smb2_reconnect_server); 1401 1347 mutex_init(&tcp_ses->reconnect_mutex); 1402 1348 memcpy(&tcp_ses->srcaddr, &ctx->srcaddr, ··· 1482 1426 1483 1427 /* queue echo request delayed work */ 1484 1428 queue_delayed_work(cifsiod_wq, &tcp_ses->echo, tcp_ses->echo_interval); 1429 + 1430 + /* queue dns resolution delayed work */ 1431 + cifs_dbg(FYI, "%s: next dns resolution scheduled for %d seconds in the future\n", 1432 + __func__, SMB_DNS_RESOLVE_INTERVAL_DEFAULT); 1433 + 1434 + queue_delayed_work(cifsiod_wq, &tcp_ses->resolve, (SMB_DNS_RESOLVE_INTERVAL_DEFAULT * HZ)); 1485 1435 1486 1436 return tcp_ses; 1487 1437 ··· 1666 1604 return; 1667 1605 } 1668 1606 spin_unlock(&cifs_tcp_ses_lock); 1607 + 1608 + /* ses_count can never go negative */ 1609 + WARN_ON(ses->ses_count < 0); 1669 1610 1670 1611 spin_lock(&GlobalMid_Lock); 1671 1612 if (ses->status == CifsGood) ··· 2036 1971 spin_unlock(&cifs_tcp_ses_lock); 2037 1972 return; 2038 1973 } 1974 + 1975 + /* tc_count can never go negative */ 1976 + WARN_ON(tcon->tc_count < 0); 2039 1977 2040 1978 if (tcon->use_witness) { 2041 1979 int rc; ··· 2978 2910 } 2979 2911 2980 2912 #ifdef CONFIG_CIFS_DFS_UPCALL 2913 + static int mount_get_dfs_conns(struct smb3_fs_context *ctx, struct cifs_sb_info *cifs_sb, 2914 + unsigned int *xid, struct TCP_Server_Info **nserver, 2915 + struct cifs_ses **nses, struct cifs_tcon **ntcon) 2916 + { 2917 + int rc; 2918 + 2919 + ctx->nosharesock = true; 2920 + rc = mount_get_conns(ctx, cifs_sb, xid, nserver, nses, ntcon); 2921 + if (*nserver) { 2922 + cifs_dbg(FYI, "%s: marking tcp session as a dfs connection\n", __func__); 2923 + spin_lock(&cifs_tcp_ses_lock); 2924 + (*nserver)->is_dfs_conn = true; 2925 + spin_unlock(&cifs_tcp_ses_lock); 2926 + } 2927 + return rc; 2928 + } 2929 + 2981 2930 /* 2982 2931 * cifs_build_path_to_root returns full path to root when we do not have an 2983 2932 * existing connection (tcon) ··· 3190 3105 tmp_ctx.prepath); 3191 3106 3192 3107 mount_put_conns(cifs_sb, *xid, *server, *ses, *tcon); 3193 - rc = mount_get_conns(&tmp_ctx, cifs_sb, xid, server, ses, tcon); 3108 + rc = mount_get_dfs_conns(&tmp_ctx, cifs_sb, xid, server, ses, tcon); 3194 3109 if (!rc || (*server && *ses)) { 3195 3110 /* 3196 3111 * We were able to connect to new target server. Update current context with ··· 3489 3404 goto error; 3490 3405 } 3491 3406 3492 - ctx->nosharesock = true; 3407 + mount_put_conns(cifs_sb, xid, server, ses, tcon); 3408 + /* 3409 + * Ignore error check here because we may failover to other targets from cached a 3410 + * referral. 3411 + */ 3412 + (void)mount_get_dfs_conns(ctx, cifs_sb, &xid, &server, &ses, &tcon); 3493 3413 3494 3414 /* Get path of DFS root */ 3495 3415 ref_path = build_unc_path_to_root(ctx, cifs_sb, false); ··· 3523 3433 /* Connect to new DFS target only if we were redirected */ 3524 3434 if (oldmnt != cifs_sb->ctx->mount_options) { 3525 3435 mount_put_conns(cifs_sb, xid, server, ses, tcon); 3526 - rc = mount_get_conns(ctx, cifs_sb, &xid, &server, &ses, &tcon); 3436 + rc = mount_get_dfs_conns(ctx, cifs_sb, &xid, &server, &ses, &tcon); 3527 3437 } 3528 3438 if (rc && !server && !ses) { 3529 3439 /* Failed to connect. Try to connect to other targets in the referral. */ ··· 3549 3459 rc = -ELOOP; 3550 3460 } while (rc == -EREMOTE); 3551 3461 3552 - if (rc || !tcon) 3462 + if (rc || !tcon || !ses) 3553 3463 goto error; 3554 3464 3555 3465 kfree(ref_path); ··· 4185 4095 if (!tree) 4186 4096 return -ENOMEM; 4187 4097 4188 - if (!tcon->dfs_path) { 4098 + /* If it is not dfs or there was no cached dfs referral, then reconnect to same share */ 4099 + if (!tcon->dfs_path || dfs_cache_noreq_find(tcon->dfs_path + 1, &ref, &tl)) { 4189 4100 if (tcon->ipc) { 4190 4101 scnprintf(tree, MAX_TREE_SIZE, "\\\\%s\\IPC$", server->hostname); 4191 4102 rc = ops->tree_connect(xid, tcon->ses, tree, tcon, nlsc); ··· 4196 4105 goto out; 4197 4106 } 4198 4107 4199 - rc = dfs_cache_noreq_find(tcon->dfs_path + 1, &ref, &tl); 4200 - if (rc) 4201 - goto out; 4202 4108 isroot = ref.server_type == DFS_TYPE_ROOT; 4203 4109 free_dfs_info_param(&ref); 4204 4110
+6 -4
fs/cifs/dns_resolve.c
··· 24 24 * dns_resolve_server_name_to_ip - Resolve UNC server name to ip address. 25 25 * @unc: UNC path specifying the server (with '/' as delimiter) 26 26 * @ip_addr: Where to return the IP address. 27 + * @expiry: Where to return the expiry time for the dns record. 27 28 * 28 29 * The IP address will be returned in string form, and the caller is 29 30 * responsible for freeing it. ··· 32 31 * Returns length of result on success, -ve on error. 33 32 */ 34 33 int 35 - dns_resolve_server_name_to_ip(const char *unc, char **ip_addr) 34 + dns_resolve_server_name_to_ip(const char *unc, char **ip_addr, time64_t *expiry) 36 35 { 37 36 struct sockaddr_storage ss; 38 37 const char *hostname, *sep; ··· 67 66 68 67 /* Perform the upcall */ 69 68 rc = dns_query(current->nsproxy->net_ns, NULL, hostname, len, 70 - NULL, ip_addr, NULL, false); 69 + NULL, ip_addr, expiry, false); 71 70 if (rc < 0) 72 71 cifs_dbg(FYI, "%s: unable to resolve: %*.*s\n", 73 72 __func__, len, len, hostname); 74 73 else 75 - cifs_dbg(FYI, "%s: resolved: %*.*s to %s\n", 76 - __func__, len, len, hostname, *ip_addr); 74 + cifs_dbg(FYI, "%s: resolved: %*.*s to %s expiry %llu\n", 75 + __func__, len, len, hostname, *ip_addr, 76 + expiry ? (*expiry) : 0); 77 77 return rc; 78 78 79 79 name_is_IP_address:
+1 -1
fs/cifs/dns_resolve.h
··· 12 12 #define _DNS_RESOLVE_H 13 13 14 14 #ifdef __KERNEL__ 15 - extern int dns_resolve_server_name_to_ip(const char *unc, char **ip_addr); 15 + extern int dns_resolve_server_name_to_ip(const char *unc, char **ip_addr, time64_t *expiry); 16 16 #endif /* KERNEL */ 17 17 18 18 #endif /* _DNS_RESOLVE_H */
+1 -1
fs/cifs/misc.c
··· 1187 1187 1188 1188 cifs_dbg(FYI, "%s: target name: %s\n", __func__, target + 2); 1189 1189 1190 - rc = dns_resolve_server_name_to_ip(target, &tip); 1190 + rc = dns_resolve_server_name_to_ip(target, &tip, NULL); 1191 1191 if (rc < 0) 1192 1192 goto out; 1193 1193
+4 -2
fs/cifs/smb2ops.c
··· 557 557 p = buf; 558 558 while (bytes_left >= sizeof(*p)) { 559 559 info->speed = le64_to_cpu(p->LinkSpeed); 560 - info->rdma_capable = le32_to_cpu(p->Capability & RDMA_CAPABLE); 561 - info->rss_capable = le32_to_cpu(p->Capability & RSS_CAPABLE); 560 + info->rdma_capable = le32_to_cpu(p->Capability & RDMA_CAPABLE) ? 1 : 0; 561 + info->rss_capable = le32_to_cpu(p->Capability & RSS_CAPABLE) ? 1 : 0; 562 562 563 563 cifs_dbg(FYI, "%s: adding iface %zu\n", __func__, *iface_count); 564 564 cifs_dbg(FYI, "%s: speed %zu bps\n", __func__, info->speed); ··· 2910 2910 /* ipc tcons are not refcounted */ 2911 2911 spin_lock(&cifs_tcp_ses_lock); 2912 2912 tcon->tc_count--; 2913 + /* tc_count can never go negative */ 2914 + WARN_ON(tcon->tc_count < 0); 2913 2915 spin_unlock(&cifs_tcp_ses_lock); 2914 2916 } 2915 2917 kfree(utf16_path);
+1
fs/cifs/smb2pdu.h
··· 394 394 __u16 Padding; 395 395 __u32 Flags; 396 396 __le16 CompressionAlgorithms[3]; 397 + __u16 Pad; /* Some servers require pad to DataLen multiple of 8 */ 397 398 /* Check if pad needed */ 398 399 } __packed; 399 400