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 'v6.17-rc-part1-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6

Pull smb client updates from Steve French:

- Fix network namespace refcount leak

- Multichannel reconnect fix

- Perf improvement to not do unneeded EA query on native symlinks

- Performance improvement for directory leases to allow extending lease
for actively queried directories

- Improve debugging of directory leases by adding pseudofile to show
them

- Five minor mount cleanup patches

- Minor directory lease cleanup patch

- Allow creating special files via reparse points over SMB1

- Two minor improvements to FindFirst over SMB1

- Two NTLMSSP session setup fixes

* tag 'v6.17-rc-part1-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6:
smb3 client: add way to show directory leases for improved debugging
smb: client: get rid of kstrdup() when parsing iocharset mount option
smb: client: get rid of kstrdup() when parsing domain mount option
smb: client: get rid of kstrdup() when parsing pass2 mount option
smb: client: get rid of kstrdup() when parsing pass mount option
smb: client: get rid of kstrdup() when parsing user mount option
cifs: Add support for creating reparse points over SMB1
cifs: Do not query WSL EAs for native SMB symlink
cifs: Optimize CIFSFindFirst() response when not searching
cifs: Fix calling CIFSFindFirst() for root path without msearch
smb: client: fix session setup against servers that require SPN
smb: client: allow parsing zero-length AV pairs
cifs: add new field to track the last access time of cfid
smb: change return type of cached_dir_lease_break() to bool
cifs: reset iface weights when we cannot find a candidate
smb: client: fix netns refcount leak after net_passive changes

+343 -105
+5 -3
fs/smb/client/cached_dir.c
··· 195 195 * from @cfids->entries. Caller will put last reference if the latter. 196 196 */ 197 197 if (cfid->has_lease && cfid->time) { 198 + cfid->last_access_time = jiffies; 198 199 spin_unlock(&cfids->cfid_list_lock); 199 200 *ret_cfid = cfid; 200 201 kfree(utf16_path); ··· 364 363 cfid->file_all_info_is_valid = true; 365 364 366 365 cfid->time = jiffies; 366 + cfid->last_access_time = jiffies; 367 367 spin_unlock(&cfids->cfid_list_lock); 368 368 /* At this point the directory handle is fully cached */ 369 369 rc = 0; ··· 619 617 queue_work(serverclose_wq, &cfid->close_work); 620 618 } 621 619 622 - int cached_dir_lease_break(struct cifs_tcon *tcon, __u8 lease_key[16]) 620 + bool cached_dir_lease_break(struct cifs_tcon *tcon, __u8 lease_key[16]) 623 621 { 624 622 struct cached_fids *cfids = tcon->cfids; 625 623 struct cached_fid *cfid; ··· 732 730 733 731 spin_lock(&cfids->cfid_list_lock); 734 732 list_for_each_entry_safe(cfid, q, &cfids->entries, entry) { 735 - if (cfid->time && 736 - time_after(jiffies, cfid->time + HZ * dir_cache_timeout)) { 733 + if (cfid->last_access_time && 734 + time_after(jiffies, cfid->last_access_time + HZ * dir_cache_timeout)) { 737 735 cfid->on_list = false; 738 736 list_move(&cfid->entry, &entry); 739 737 cfids->num_entries--;
+2 -2
fs/smb/client/cached_dir.h
··· 14 14 char *name; 15 15 int namelen; 16 16 loff_t pos; 17 - 18 17 struct cifs_fattr fattr; 19 18 }; 20 19 ··· 38 39 bool on_list:1; 39 40 bool file_all_info_is_valid:1; 40 41 unsigned long time; /* jiffies of when lease was taken */ 42 + unsigned long last_access_time; /* jiffies of when last accessed */ 41 43 struct kref refcount; 42 44 struct cifs_fid fid; 43 45 spinlock_t fid_lock; ··· 80 80 struct cifs_sb_info *cifs_sb); 81 81 extern void close_all_cached_dirs(struct cifs_sb_info *cifs_sb); 82 82 extern void invalidate_all_cached_dirs(struct cifs_tcon *tcon); 83 - extern int cached_dir_lease_break(struct cifs_tcon *tcon, __u8 lease_key[16]); 83 + extern bool cached_dir_lease_break(struct cifs_tcon *tcon, __u8 lease_key[16]); 84 84 85 85 #endif /* _CACHED_DIR_H */
+53
fs/smb/client/cifs_debug.c
··· 26 26 #include "smbdirect.h" 27 27 #endif 28 28 #include "cifs_swn.h" 29 + #include "cached_dir.h" 29 30 30 31 void 31 32 cifs_dump_mem(char *label, void *data, int length) ··· 273 272 #endif /* CIFS_DEBUG2 */ 274 273 } 275 274 spin_unlock(&tcon->open_file_lock); 275 + } 276 + } 277 + } 278 + spin_unlock(&cifs_tcp_ses_lock); 279 + seq_putc(m, '\n'); 280 + return 0; 281 + } 282 + 283 + static int cifs_debug_dirs_proc_show(struct seq_file *m, void *v) 284 + { 285 + struct list_head *stmp, *tmp, *tmp1; 286 + struct TCP_Server_Info *server; 287 + struct cifs_ses *ses; 288 + struct cifs_tcon *tcon; 289 + struct cached_fids *cfids; 290 + struct cached_fid *cfid; 291 + LIST_HEAD(entry); 292 + 293 + seq_puts(m, "# Version:1\n"); 294 + seq_puts(m, "# Format:\n"); 295 + seq_puts(m, "# <tree id> <sess id> <persistent fid> <path>\n"); 296 + 297 + spin_lock(&cifs_tcp_ses_lock); 298 + list_for_each(stmp, &cifs_tcp_ses_list) { 299 + server = list_entry(stmp, struct TCP_Server_Info, 300 + tcp_ses_list); 301 + list_for_each(tmp, &server->smb_ses_list) { 302 + ses = list_entry(tmp, struct cifs_ses, smb_ses_list); 303 + list_for_each(tmp1, &ses->tcon_list) { 304 + tcon = list_entry(tmp1, struct cifs_tcon, tcon_list); 305 + cfids = tcon->cfids; 306 + spin_lock(&cfids->cfid_list_lock); /* check lock ordering */ 307 + seq_printf(m, "Num entries: %d\n", cfids->num_entries); 308 + list_for_each_entry(cfid, &cfids->entries, entry) { 309 + seq_printf(m, "0x%x 0x%llx 0x%llx %s", 310 + tcon->tid, 311 + ses->Suid, 312 + cfid->fid.persistent_fid, 313 + cfid->path); 314 + if (cfid->file_all_info_is_valid) 315 + seq_printf(m, "\tvalid file info"); 316 + if (cfid->dirents.is_valid) 317 + seq_printf(m, ", valid dirents"); 318 + seq_printf(m, "\n"); 319 + } 320 + spin_unlock(&cfids->cfid_list_lock); 321 + 322 + 276 323 } 277 324 } 278 325 } ··· 912 863 proc_create_single("open_files", 0400, proc_fs_cifs, 913 864 cifs_debug_files_proc_show); 914 865 866 + proc_create_single("open_dirs", 0400, proc_fs_cifs, 867 + cifs_debug_dirs_proc_show); 868 + 915 869 proc_create("Stats", 0644, proc_fs_cifs, &cifs_stats_proc_ops); 916 870 proc_create("cifsFYI", 0644, proc_fs_cifs, &cifsFYI_proc_ops); 917 871 proc_create("traceSMB", 0644, proc_fs_cifs, &traceSMB_proc_ops); ··· 959 907 960 908 remove_proc_entry("DebugData", proc_fs_cifs); 961 909 remove_proc_entry("open_files", proc_fs_cifs); 910 + remove_proc_entry("open_dirs", proc_fs_cifs); 962 911 remove_proc_entry("cifsFYI", proc_fs_cifs); 963 912 remove_proc_entry("traceSMB", proc_fs_cifs); 964 913 remove_proc_entry("Stats", proc_fs_cifs);
+63 -20
fs/smb/client/cifsencrypt.c
··· 343 343 len = AV_LEN(av); 344 344 if (AV_TYPE(av) == NTLMSSP_AV_EOL) 345 345 return NULL; 346 - if (!len || (u8 *)av + sizeof(*av) + len > end) 346 + if ((u8 *)av + sizeof(*av) + len > end) 347 347 return NULL; 348 348 return av; 349 349 } ··· 363 363 364 364 av_for_each_entry(ses, av) { 365 365 len = AV_LEN(av); 366 - if (AV_TYPE(av) != type) 366 + if (AV_TYPE(av) != type || !len) 367 367 continue; 368 368 if (!IS_ALIGNED(len, sizeof(__le16))) { 369 369 cifs_dbg(VFS | ONCE, "%s: bad length(%u) for type %u\n", ··· 532 532 return rc; 533 533 } 534 534 535 + /* 536 + * Set up NTLMv2 response blob with SPN (cifs/<hostname>) appended to the 537 + * existing list of AV pairs. 538 + */ 539 + static int set_auth_key_response(struct cifs_ses *ses) 540 + { 541 + size_t baselen = CIFS_SESS_KEY_SIZE + sizeof(struct ntlmv2_resp); 542 + size_t len, spnlen, tilen = 0, num_avs = 2 /* SPN + EOL */; 543 + struct TCP_Server_Info *server = ses->server; 544 + char *spn __free(kfree) = NULL; 545 + struct ntlmssp2_name *av; 546 + char *rsp = NULL; 547 + int rc; 548 + 549 + spnlen = strlen(server->hostname); 550 + len = sizeof("cifs/") + spnlen; 551 + spn = kmalloc(len, GFP_KERNEL); 552 + if (!spn) { 553 + rc = -ENOMEM; 554 + goto out; 555 + } 556 + 557 + spnlen = scnprintf(spn, len, "cifs/%.*s", 558 + (int)spnlen, server->hostname); 559 + 560 + av_for_each_entry(ses, av) 561 + tilen += sizeof(*av) + AV_LEN(av); 562 + 563 + len = baselen + tilen + spnlen * sizeof(__le16) + num_avs * sizeof(*av); 564 + rsp = kmalloc(len, GFP_KERNEL); 565 + if (!rsp) { 566 + rc = -ENOMEM; 567 + goto out; 568 + } 569 + 570 + memcpy(rsp + baselen, ses->auth_key.response, tilen); 571 + av = (void *)(rsp + baselen + tilen); 572 + av->type = cpu_to_le16(NTLMSSP_AV_TARGET_NAME); 573 + av->length = cpu_to_le16(spnlen * sizeof(__le16)); 574 + cifs_strtoUTF16((__le16 *)av->data, spn, spnlen, ses->local_nls); 575 + av = (void *)((__u8 *)av + sizeof(*av) + AV_LEN(av)); 576 + av->type = cpu_to_le16(NTLMSSP_AV_EOL); 577 + av->length = 0; 578 + 579 + rc = 0; 580 + ses->auth_key.len = len; 581 + out: 582 + ses->auth_key.response = rsp; 583 + return rc; 584 + } 585 + 535 586 int 536 587 setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp) 537 588 { 538 589 struct shash_desc *hmacmd5 = NULL; 539 - int rc; 540 - int baselen; 541 - unsigned int tilen; 590 + unsigned char *tiblob = NULL; /* target info blob */ 542 591 struct ntlmv2_resp *ntlmv2; 543 592 char ntlmv2_hash[16]; 544 - unsigned char *tiblob = NULL; /* target info blob */ 545 593 __le64 rsp_timestamp; 594 + __u64 cc; 595 + int rc; 546 596 547 597 if (nls_cp == NULL) { 548 598 cifs_dbg(VFS, "%s called with nls_cp==NULL\n", __func__); ··· 638 588 * (as Windows 7 does) 639 589 */ 640 590 rsp_timestamp = find_timestamp(ses); 591 + get_random_bytes(&cc, sizeof(cc)); 641 592 642 - baselen = CIFS_SESS_KEY_SIZE + sizeof(struct ntlmv2_resp); 643 - tilen = ses->auth_key.len; 593 + cifs_server_lock(ses->server); 594 + 644 595 tiblob = ses->auth_key.response; 645 - 646 - ses->auth_key.response = kmalloc(baselen + tilen, GFP_KERNEL); 647 - if (!ses->auth_key.response) { 648 - rc = -ENOMEM; 596 + rc = set_auth_key_response(ses); 597 + if (rc) { 649 598 ses->auth_key.len = 0; 650 - goto setup_ntlmv2_rsp_ret; 599 + goto unlock; 651 600 } 652 - ses->auth_key.len += baselen; 653 601 654 602 ntlmv2 = (struct ntlmv2_resp *) 655 603 (ses->auth_key.response + CIFS_SESS_KEY_SIZE); 656 604 ntlmv2->blob_signature = cpu_to_le32(0x00000101); 657 605 ntlmv2->reserved = 0; 658 606 ntlmv2->time = rsp_timestamp; 659 - 660 - get_random_bytes(&ntlmv2->client_chal, sizeof(ntlmv2->client_chal)); 607 + ntlmv2->client_chal = cc; 661 608 ntlmv2->reserved2 = 0; 662 - 663 - memcpy(ses->auth_key.response + baselen, tiblob, tilen); 664 - 665 - cifs_server_lock(ses->server); 666 609 667 610 rc = cifs_alloc_hash("hmac(md5)", &hmacmd5); 668 611 if (rc) {
+8 -6
fs/smb/client/cifsglob.h
··· 627 627 bool (*is_network_name_deleted)(char *buf, struct TCP_Server_Info *srv); 628 628 struct reparse_data_buffer * (*get_reparse_point_buffer)(const struct kvec *rsp_iov, 629 629 u32 *plen); 630 - int (*create_reparse_symlink)(const unsigned int xid, 631 - struct inode *inode, 632 - struct dentry *dentry, 633 - struct cifs_tcon *tcon, 634 - const char *full_path, 635 - const char *symname); 630 + struct inode * (*create_reparse_inode)(struct cifs_open_info_data *data, 631 + struct super_block *sb, 632 + const unsigned int xid, 633 + struct cifs_tcon *tcon, 634 + const char *full_path, 635 + bool directory, 636 + struct kvec *reparse_iov, 637 + struct kvec *xattr_iov); 636 638 }; 637 639 638 640 struct smb_version_values {
+8
fs/smb/client/cifsproto.h
··· 483 483 const char *full_path, 484 484 u32 *tag, struct kvec *rsp, 485 485 int *rsp_buftype); 486 + extern struct inode *cifs_create_reparse_inode(struct cifs_open_info_data *data, 487 + struct super_block *sb, 488 + const unsigned int xid, 489 + struct cifs_tcon *tcon, 490 + const char *full_path, 491 + bool directory, 492 + struct kvec *reparse_iov, 493 + struct kvec *xattr_iov); 486 494 extern int CIFSSMB_set_compression(const unsigned int xid, 487 495 struct cifs_tcon *tcon, __u16 fid); 488 496 extern int CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms,
+139 -1
fs/smb/client/cifssmb.c
··· 2851 2851 return rc; 2852 2852 } 2853 2853 2854 + struct inode *cifs_create_reparse_inode(struct cifs_open_info_data *data, 2855 + struct super_block *sb, 2856 + const unsigned int xid, 2857 + struct cifs_tcon *tcon, 2858 + const char *full_path, 2859 + bool directory, 2860 + struct kvec *reparse_iov, 2861 + struct kvec *xattr_iov) 2862 + { 2863 + struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 2864 + struct cifs_open_parms oparms; 2865 + TRANSACT_IOCTL_REQ *io_req; 2866 + struct inode *new = NULL; 2867 + struct kvec in_iov[2]; 2868 + struct kvec out_iov; 2869 + struct cifs_fid fid; 2870 + int io_req_len; 2871 + int oplock = 0; 2872 + int buf_type = 0; 2873 + int rc; 2874 + 2875 + cifs_tcon_dbg(FYI, "%s: path=%s\n", __func__, full_path); 2876 + 2877 + /* 2878 + * If server filesystem does not support reparse points then do not 2879 + * attempt to create reparse point. This will prevent creating unusable 2880 + * empty object on the server. 2881 + */ 2882 + if (!(le32_to_cpu(tcon->fsAttrInfo.Attributes) & FILE_SUPPORTS_REPARSE_POINTS)) 2883 + return ERR_PTR(-EOPNOTSUPP); 2884 + 2885 + #ifndef CONFIG_CIFS_XATTR 2886 + if (xattr_iov) 2887 + return ERR_PTR(-EOPNOTSUPP); 2888 + #endif 2889 + 2890 + oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, 2891 + FILE_READ_ATTRIBUTES | FILE_WRITE_DATA | FILE_WRITE_EA, 2892 + FILE_CREATE, 2893 + (directory ? CREATE_NOT_FILE : CREATE_NOT_DIR) | OPEN_REPARSE_POINT, 2894 + ACL_NO_MODE); 2895 + oparms.fid = &fid; 2896 + 2897 + rc = CIFS_open(xid, &oparms, &oplock, NULL); 2898 + if (rc) 2899 + return ERR_PTR(rc); 2900 + 2901 + #ifdef CONFIG_CIFS_XATTR 2902 + if (xattr_iov) { 2903 + struct smb2_file_full_ea_info *ea; 2904 + 2905 + ea = &((struct smb2_create_ea_ctx *)xattr_iov->iov_base)->ea; 2906 + while (1) { 2907 + rc = CIFSSMBSetEA(xid, 2908 + tcon, 2909 + full_path, 2910 + &ea->ea_data[0], 2911 + &ea->ea_data[ea->ea_name_length+1], 2912 + le16_to_cpu(ea->ea_value_length), 2913 + cifs_sb->local_nls, 2914 + cifs_sb); 2915 + if (rc) 2916 + goto out_close; 2917 + if (le32_to_cpu(ea->next_entry_offset) == 0) 2918 + break; 2919 + ea = (struct smb2_file_full_ea_info *)((u8 *)ea + 2920 + le32_to_cpu(ea->next_entry_offset)); 2921 + } 2922 + } 2923 + #endif 2924 + 2925 + rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **)&io_req, NULL); 2926 + if (rc) 2927 + goto out_close; 2928 + 2929 + inc_rfc1001_len(io_req, sizeof(io_req->Pad)); 2930 + 2931 + io_req_len = be32_to_cpu(io_req->hdr.smb_buf_length) + sizeof(io_req->hdr.smb_buf_length); 2932 + 2933 + /* NT IOCTL response contains one-word long output setup buffer with size of output data. */ 2934 + io_req->MaxSetupCount = 1; 2935 + /* NT IOCTL response does not contain output parameters. */ 2936 + io_req->MaxParameterCount = cpu_to_le32(0); 2937 + /* FSCTL_SET_REPARSE_POINT response contains empty output data. */ 2938 + io_req->MaxDataCount = cpu_to_le32(0); 2939 + 2940 + io_req->TotalParameterCount = cpu_to_le32(0); 2941 + io_req->TotalDataCount = cpu_to_le32(reparse_iov->iov_len); 2942 + io_req->ParameterCount = io_req->TotalParameterCount; 2943 + io_req->ParameterOffset = cpu_to_le32(0); 2944 + io_req->DataCount = io_req->TotalDataCount; 2945 + io_req->DataOffset = cpu_to_le32(offsetof(typeof(*io_req), Data) - 2946 + sizeof(io_req->hdr.smb_buf_length)); 2947 + io_req->SetupCount = 4; 2948 + io_req->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL); 2949 + io_req->FunctionCode = cpu_to_le32(FSCTL_SET_REPARSE_POINT); 2950 + io_req->Fid = fid.netfid; 2951 + io_req->IsFsctl = 1; 2952 + io_req->IsRootFlag = 0; 2953 + io_req->ByteCount = cpu_to_le16(le32_to_cpu(io_req->DataCount) + sizeof(io_req->Pad)); 2954 + 2955 + inc_rfc1001_len(io_req, reparse_iov->iov_len); 2956 + 2957 + in_iov[0].iov_base = (char *)io_req; 2958 + in_iov[0].iov_len = io_req_len; 2959 + in_iov[1] = *reparse_iov; 2960 + rc = SendReceive2(xid, tcon->ses, in_iov, ARRAY_SIZE(in_iov), &buf_type, 2961 + CIFS_NO_RSP_BUF, &out_iov); 2962 + 2963 + cifs_buf_release(io_req); 2964 + 2965 + if (!rc) 2966 + rc = cifs_get_inode_info(&new, full_path, data, sb, xid, NULL); 2967 + 2968 + out_close: 2969 + CIFSSMBClose(xid, tcon, fid.netfid); 2970 + 2971 + /* 2972 + * If CREATE was successful but FSCTL_SET_REPARSE_POINT failed then 2973 + * remove the intermediate object created by CREATE. Otherwise 2974 + * empty object stay on the server when reparse call failed. 2975 + */ 2976 + if (rc) 2977 + CIFSSMBDelFile(xid, tcon, full_path, cifs_sb, NULL); 2978 + 2979 + return rc ? ERR_PTR(rc) : new; 2980 + } 2981 + 2854 2982 int 2855 2983 CIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon, 2856 2984 __u16 fid) ··· 4148 4020 pSMB->FileName[name_len] = 0; 4149 4021 pSMB->FileName[name_len+1] = 0; 4150 4022 name_len += 2; 4023 + } else if (!searchName[0]) { 4024 + pSMB->FileName[0] = CIFS_DIR_SEP(cifs_sb); 4025 + pSMB->FileName[1] = 0; 4026 + pSMB->FileName[2] = 0; 4027 + pSMB->FileName[3] = 0; 4028 + name_len = 4; 4151 4029 } 4152 4030 } else { 4153 4031 name_len = copy_path_name(pSMB->FileName, searchName); ··· 4165 4031 pSMB->FileName[name_len] = '*'; 4166 4032 pSMB->FileName[name_len+1] = 0; 4167 4033 name_len += 2; 4034 + } else if (!searchName[0]) { 4035 + pSMB->FileName[0] = CIFS_DIR_SEP(cifs_sb); 4036 + pSMB->FileName[1] = 0; 4037 + name_len = 2; 4168 4038 } 4169 4039 } 4170 4040 ··· 4195 4057 pSMB->SearchAttributes = 4196 4058 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | 4197 4059 ATTR_DIRECTORY); 4198 - pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO)); 4060 + pSMB->SearchCount = cpu_to_le16(msearch ? CIFSMaxBufSize/sizeof(FILE_UNIX_INFO) : 1); 4199 4061 pSMB->SearchFlags = cpu_to_le16(search_flags); 4200 4062 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level); 4201 4063
+3 -6
fs/smb/client/connect.c
··· 3362 3362 struct net *net = cifs_net_ns(server); 3363 3363 struct sock *sk; 3364 3364 3365 - rc = __sock_create(net, sfamily, SOCK_STREAM, 3366 - IPPROTO_TCP, &server->ssocket, 1); 3365 + rc = sock_create_kern(net, sfamily, SOCK_STREAM, 3366 + IPPROTO_TCP, &server->ssocket); 3367 3367 if (rc < 0) { 3368 3368 cifs_server_dbg(VFS, "Error %d creating socket\n", rc); 3369 3369 return rc; 3370 3370 } 3371 3371 3372 3372 sk = server->ssocket->sk; 3373 - __netns_tracker_free(net, &sk->ns_tracker, false); 3374 - sk->sk_net_refcnt = 1; 3375 - get_net_track(net, &sk->ns_tracker, GFP_KERNEL); 3376 - sock_inuse_add(net, 1); 3373 + sk_net_refcnt_upgrade(sk); 3377 3374 3378 3375 /* BB other socket options to set KEEPALIVE, NODELAY? */ 3379 3376 cifs_dbg(FYI, "Socket created\n");
+5 -27
fs/smb/client/fs_context.c
··· 1475 1475 pr_warn("username too long\n"); 1476 1476 goto cifs_parse_mount_err; 1477 1477 } 1478 - ctx->username = kstrdup(param->string, GFP_KERNEL); 1479 - if (ctx->username == NULL) { 1480 - cifs_errorf(fc, "OOM when copying username string\n"); 1481 - goto cifs_parse_mount_err; 1482 - } 1478 + ctx->username = no_free_ptr(param->string); 1483 1479 break; 1484 1480 case Opt_pass: 1485 1481 kfree_sensitive(ctx->password); 1486 1482 ctx->password = NULL; 1487 1483 if (strlen(param->string) == 0) 1488 1484 break; 1489 - 1490 - ctx->password = kstrdup(param->string, GFP_KERNEL); 1491 - if (ctx->password == NULL) { 1492 - cifs_errorf(fc, "OOM when copying password string\n"); 1493 - goto cifs_parse_mount_err; 1494 - } 1485 + ctx->password = no_free_ptr(param->string); 1495 1486 break; 1496 1487 case Opt_pass2: 1497 1488 kfree_sensitive(ctx->password2); 1498 1489 ctx->password2 = NULL; 1499 1490 if (strlen(param->string) == 0) 1500 1491 break; 1501 - 1502 - ctx->password2 = kstrdup(param->string, GFP_KERNEL); 1503 - if (ctx->password2 == NULL) { 1504 - cifs_errorf(fc, "OOM when copying password2 string\n"); 1505 - goto cifs_parse_mount_err; 1506 - } 1492 + ctx->password2 = no_free_ptr(param->string); 1507 1493 break; 1508 1494 case Opt_ip: 1509 1495 if (strlen(param->string) == 0) { ··· 1512 1526 } 1513 1527 1514 1528 kfree(ctx->domainname); 1515 - ctx->domainname = kstrdup(param->string, GFP_KERNEL); 1516 - if (ctx->domainname == NULL) { 1517 - cifs_errorf(fc, "OOM when copying domainname string\n"); 1518 - goto cifs_parse_mount_err; 1519 - } 1529 + ctx->domainname = no_free_ptr(param->string); 1520 1530 cifs_dbg(FYI, "Domain name set\n"); 1521 1531 break; 1522 1532 case Opt_srcaddr: ··· 1532 1550 1533 1551 if (strncasecmp(param->string, "default", 7) != 0) { 1534 1552 kfree(ctx->iocharset); 1535 - ctx->iocharset = kstrdup(param->string, GFP_KERNEL); 1536 - if (ctx->iocharset == NULL) { 1537 - cifs_errorf(fc, "OOM when copying iocharset string\n"); 1538 - goto cifs_parse_mount_err; 1539 - } 1553 + ctx->iocharset = no_free_ptr(param->string); 1540 1554 } 1541 1555 /* if iocharset not set then load_nls_default 1542 1556 * is used by caller
+4 -9
fs/smb/client/link.c
··· 19 19 #include "smb2proto.h" 20 20 #include "cifs_ioctl.h" 21 21 #include "fs_context.h" 22 + #include "reparse.h" 22 23 23 24 /* 24 25 * M-F Symlink Functions - Begin ··· 571 570 int rc = -EOPNOTSUPP; 572 571 unsigned int xid; 573 572 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 574 - struct TCP_Server_Info *server; 575 573 struct tcon_link *tlink; 576 574 struct cifs_tcon *pTcon; 577 575 const char *full_path; ··· 593 593 goto symlink_exit; 594 594 } 595 595 pTcon = tlink_tcon(tlink); 596 - server = cifs_pick_channel(pTcon->ses); 597 596 598 597 full_path = build_path_from_dentry(direntry, page); 599 598 if (IS_ERR(full_path)) { ··· 642 643 case CIFS_SYMLINK_TYPE_NATIVE: 643 644 case CIFS_SYMLINK_TYPE_NFS: 644 645 case CIFS_SYMLINK_TYPE_WSL: 645 - if (server->ops->create_reparse_symlink && 646 - (le32_to_cpu(pTcon->fsAttrInfo.Attributes) & FILE_SUPPORTS_REPARSE_POINTS)) { 647 - rc = server->ops->create_reparse_symlink(xid, inode, 648 - direntry, 649 - pTcon, 650 - full_path, 651 - symname); 646 + if (le32_to_cpu(pTcon->fsAttrInfo.Attributes) & FILE_SUPPORTS_REPARSE_POINTS) { 647 + rc = create_reparse_symlink(xid, inode, direntry, pTcon, 648 + full_path, symname); 652 649 goto symlink_exit; 653 650 } 654 651 break;
+10 -6
fs/smb/client/reparse.c
··· 34 34 const char *symname, 35 35 bool *directory); 36 36 37 - int smb2_create_reparse_symlink(const unsigned int xid, struct inode *inode, 37 + int create_reparse_symlink(const unsigned int xid, struct inode *inode, 38 38 struct dentry *dentry, struct cifs_tcon *tcon, 39 39 const char *full_path, const char *symname) 40 40 { ··· 227 227 228 228 iov.iov_base = buf; 229 229 iov.iov_len = len; 230 - new = smb2_get_reparse_inode(&data, inode->i_sb, xid, 230 + new = tcon->ses->server->ops->create_reparse_inode( 231 + &data, inode->i_sb, xid, 231 232 tcon, full_path, directory, 232 233 &iov, NULL); 233 234 if (!IS_ERR(new)) ··· 400 399 struct inode *new; 401 400 int rc = 0; 402 401 403 - new = smb2_get_reparse_inode(&data, inode->i_sb, xid, 402 + new = tcon->ses->server->ops->create_reparse_inode( 403 + &data, inode->i_sb, xid, 404 404 tcon, full_path, false, &iov, NULL); 405 405 if (!IS_ERR(new)) 406 406 d_instantiate(dentry, new); ··· 494 492 .symlink_target = kstrdup(symname, GFP_KERNEL), 495 493 }; 496 494 497 - new = smb2_get_reparse_inode(&data, inode->i_sb, xid, 495 + new = tcon->ses->server->ops->create_reparse_inode( 496 + &data, inode->i_sb, xid, 498 497 tcon, full_path, false, &iov, NULL); 499 498 if (!IS_ERR(new)) 500 499 d_instantiate(dentry, new); ··· 688 685 memcpy(data.wsl.eas, &cc->ea, len); 689 686 data.wsl.eas_len = len; 690 687 691 - new = smb2_get_reparse_inode(&data, inode->i_sb, 688 + new = tcon->ses->server->ops->create_reparse_inode( 689 + &data, inode->i_sb, 692 690 xid, tcon, full_path, false, 693 691 &reparse_iov, &xattr_iov); 694 692 if (!IS_ERR(new)) ··· 702 698 return rc; 703 699 } 704 700 705 - int smb2_mknod_reparse(unsigned int xid, struct inode *inode, 701 + int mknod_reparse(unsigned int xid, struct inode *inode, 706 702 struct dentry *dentry, struct cifs_tcon *tcon, 707 703 const char *full_path, umode_t mode, dev_t dev) 708 704 {
+2 -2
fs/smb/client/reparse.h
··· 129 129 bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb, 130 130 struct cifs_fattr *fattr, 131 131 struct cifs_open_info_data *data); 132 - int smb2_create_reparse_symlink(const unsigned int xid, struct inode *inode, 132 + int create_reparse_symlink(const unsigned int xid, struct inode *inode, 133 133 struct dentry *dentry, struct cifs_tcon *tcon, 134 134 const char *full_path, const char *symname); 135 - int smb2_mknod_reparse(unsigned int xid, struct inode *inode, 135 + int mknod_reparse(unsigned int xid, struct inode *inode, 136 136 struct dentry *dentry, struct cifs_tcon *tcon, 137 137 const char *full_path, umode_t mode, dev_t dev); 138 138 struct reparse_data_buffer *smb2_get_reparse_point_buffer(const struct kvec *rsp_iov, u32 *len);
+9
fs/smb/client/sess.c
··· 332 332 struct cifs_server_iface *old_iface = NULL; 333 333 struct cifs_server_iface *last_iface = NULL; 334 334 struct sockaddr_storage ss; 335 + int retry = 0; 335 336 336 337 spin_lock(&ses->chan_lock); 337 338 chan_index = cifs_ses_get_chan_index(ses, server); ··· 361 360 return; 362 361 } 363 362 363 + try_again: 364 364 last_iface = list_last_entry(&ses->iface_list, struct cifs_server_iface, 365 365 iface_head); 366 366 iface_min_speed = last_iface->speed; ··· 399 397 } 400 398 401 399 if (list_entry_is_head(iface, &ses->iface_list, iface_head)) { 400 + list_for_each_entry(iface, &ses->iface_list, iface_head) 401 + iface->weight_fulfilled = 0; 402 + 403 + /* see if it can be satisfied in second attempt */ 404 + if (!retry++) 405 + goto try_again; 406 + 402 407 iface = NULL; 403 408 cifs_dbg(FYI, "unable to find a suitable iface\n"); 404 409 }
+21 -10
fs/smb/client/smb1ops.c
··· 16 16 #include "fs_context.h" 17 17 #include "nterr.h" 18 18 #include "smberr.h" 19 + #include "reparse.h" 19 20 20 21 /* 21 22 * An NT cancel request header looks just like the original request except: ··· 1264 1263 if (rc == 0) 1265 1264 d_instantiate(dentry, newinode); 1266 1265 return rc; 1266 + } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { 1267 + /* 1268 + * Check if mounted with mount parm 'sfu' mount parm. 1269 + * SFU emulation should work with all servers 1270 + * and was used by default in earlier versions of Windows. 1271 + */ 1272 + return cifs_sfu_make_node(xid, inode, dentry, tcon, 1273 + full_path, mode, dev); 1274 + } else if (le32_to_cpu(tcon->fsAttrInfo.Attributes) & FILE_SUPPORTS_REPARSE_POINTS) { 1275 + /* 1276 + * mknod via reparse points requires server support for 1277 + * storing reparse points, which is available since 1278 + * Windows 2000, but was not widely used until release 1279 + * of Windows Server 2012 by the Windows NFS server. 1280 + */ 1281 + return mknod_reparse(xid, inode, dentry, tcon, 1282 + full_path, mode, dev); 1283 + } else { 1284 + return -EOPNOTSUPP; 1267 1285 } 1268 - /* 1269 - * Check if mounted with mount parm 'sfu' mount parm. 1270 - * SFU emulation should work with all servers, but only 1271 - * supports block and char device, socket & fifo, 1272 - * and was used by default in earlier versions of Windows 1273 - */ 1274 - if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) 1275 - return -EPERM; 1276 - return cifs_sfu_make_node(xid, inode, dentry, tcon, 1277 - full_path, mode, dev); 1278 1286 } 1279 1287 1280 1288 static bool ··· 1380 1370 .create_hardlink = CIFSCreateHardLink, 1381 1371 .query_symlink = cifs_query_symlink, 1382 1372 .get_reparse_point_buffer = cifs_get_reparse_point_buffer, 1373 + .create_reparse_inode = cifs_create_reparse_inode, 1383 1374 .open = cifs_open_file, 1384 1375 .set_fid = cifs_set_fid, 1385 1376 .close = cifs_close_file,
+5 -4
fs/smb/client/smb2inode.c
··· 1058 1058 * Skip SMB2_OP_GET_REPARSE if symlink already parsed in create 1059 1059 * response. 1060 1060 */ 1061 - if (data->reparse.tag != IO_REPARSE_TAG_SYMLINK) 1061 + if (data->reparse.tag != IO_REPARSE_TAG_SYMLINK) { 1062 1062 cmds[num_cmds++] = SMB2_OP_GET_REPARSE; 1063 - if (!tcon->posix_extensions) 1064 - cmds[num_cmds++] = SMB2_OP_QUERY_WSL_EA; 1063 + if (!tcon->posix_extensions) 1064 + cmds[num_cmds++] = SMB2_OP_QUERY_WSL_EA; 1065 + } 1065 1066 1066 1067 oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, 1067 1068 FILE_READ_ATTRIBUTES | ··· 1321 1320 return rc; 1322 1321 } 1323 1322 1324 - struct inode *smb2_get_reparse_inode(struct cifs_open_info_data *data, 1323 + struct inode *smb2_create_reparse_inode(struct cifs_open_info_data *data, 1325 1324 struct super_block *sb, 1326 1325 const unsigned int xid, 1327 1326 struct cifs_tcon *tcon,
+5 -5
fs/smb/client/smb2ops.c
··· 5262 5262 full_path, mode, dev); 5263 5263 } else if ((le32_to_cpu(tcon->fsAttrInfo.Attributes) & FILE_SUPPORTS_REPARSE_POINTS) 5264 5264 || (tcon->posix_extensions)) { 5265 - rc = smb2_mknod_reparse(xid, inode, dentry, tcon, 5265 + rc = mknod_reparse(xid, inode, dentry, tcon, 5266 5266 full_path, mode, dev); 5267 5267 } 5268 5268 return rc; ··· 5321 5321 .get_reparse_point_buffer = smb2_get_reparse_point_buffer, 5322 5322 .query_mf_symlink = smb3_query_mf_symlink, 5323 5323 .create_mf_symlink = smb3_create_mf_symlink, 5324 - .create_reparse_symlink = smb2_create_reparse_symlink, 5324 + .create_reparse_inode = smb2_create_reparse_inode, 5325 5325 .open = smb2_open_file, 5326 5326 .set_fid = smb2_set_fid, 5327 5327 .close = smb2_close_file, ··· 5424 5424 .get_reparse_point_buffer = smb2_get_reparse_point_buffer, 5425 5425 .query_mf_symlink = smb3_query_mf_symlink, 5426 5426 .create_mf_symlink = smb3_create_mf_symlink, 5427 - .create_reparse_symlink = smb2_create_reparse_symlink, 5427 + .create_reparse_inode = smb2_create_reparse_inode, 5428 5428 .open = smb2_open_file, 5429 5429 .set_fid = smb2_set_fid, 5430 5430 .close = smb2_close_file, ··· 5531 5531 .get_reparse_point_buffer = smb2_get_reparse_point_buffer, 5532 5532 .query_mf_symlink = smb3_query_mf_symlink, 5533 5533 .create_mf_symlink = smb3_create_mf_symlink, 5534 - .create_reparse_symlink = smb2_create_reparse_symlink, 5534 + .create_reparse_inode = smb2_create_reparse_inode, 5535 5535 .open = smb2_open_file, 5536 5536 .set_fid = smb2_set_fid, 5537 5537 .close = smb2_close_file, ··· 5647 5647 .get_reparse_point_buffer = smb2_get_reparse_point_buffer, 5648 5648 .query_mf_symlink = smb3_query_mf_symlink, 5649 5649 .create_mf_symlink = smb3_create_mf_symlink, 5650 - .create_reparse_symlink = smb2_create_reparse_symlink, 5650 + .create_reparse_inode = smb2_create_reparse_inode, 5651 5651 .open = smb2_open_file, 5652 5652 .set_fid = smb2_set_fid, 5653 5653 .close = smb2_close_file,
+1 -4
fs/smb/client/smb2proto.h
··· 54 54 extern int smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon, 55 55 struct cifs_sb_info *cifs_sb, const char *path, 56 56 __u32 *reparse_tag); 57 - struct inode *smb2_get_reparse_inode(struct cifs_open_info_data *data, 57 + struct inode *smb2_create_reparse_inode(struct cifs_open_info_data *data, 58 58 struct super_block *sb, 59 59 const unsigned int xid, 60 60 struct cifs_tcon *tcon, ··· 314 314 int posix_info_parse(const void *beg, const void *end, 315 315 struct smb2_posix_info_parsed *out); 316 316 int posix_info_sid_size(const void *beg, const void *end); 317 - int smb2_create_reparse_symlink(const unsigned int xid, struct inode *inode, 318 - struct dentry *dentry, struct cifs_tcon *tcon, 319 - const char *full_path, const char *symname); 320 317 int smb2_make_nfs_node(unsigned int xid, struct inode *inode, 321 318 struct dentry *dentry, struct cifs_tcon *tcon, 322 319 const char *full_path, umode_t mode, dev_t dev);