Merge tag 'v6.8-rc-part2-smb-client' of git://git.samba.org/sfrench/cifs-2.6

Pull smb client updates from Steve French:
"Various smb client fixes, including multichannel and for SMB3.1.1
POSIX extensions:

- debugging improvement (display start time for stats)

- two reparse point handling fixes

- various multichannel improvements and fixes

- SMB3.1.1 POSIX extensions open/create parsing fix

- retry (reconnect) improvement including new retrans mount parm, and
handling of two additional return codes that need to be retried on

- two minor cleanup patches and another to remove duplicate query
info code

- two documentation cleanup, and one reviewer email correction"

* tag 'v6.8-rc-part2-smb-client' of git://git.samba.org/sfrench/cifs-2.6:
cifs: update iface_last_update on each query-and-update
cifs: handle servers that still advertise multichannel after disabling
cifs: new mount option called retrans
cifs: reschedule periodic query for server interfaces
smb: client: don't clobber ->i_rdev from cached reparse points
smb: client: get rid of smb311_posix_query_path_info()
smb: client: parse owner/group when creating reparse points
smb: client: fix parsing of SMB3.1.1 POSIX create context
cifs: update known bugs mentioned in kernel docs for cifs
cifs: new nt status codes from MS-SMB2
cifs: pick channel for tcon and tdis
cifs: open_cached_dir should not rely on primary channel
smb3: minor documentation updates
Update MAINTAINERS email address
cifs: minor comment cleanup
smb3: show beginning time for per share stats
cifs: remove redundant variable tcon_exist

+21 -23
Documentation/admin-guide/cifs/todo.rst
··· 2 2 TODO 3 3 ==== 4 4 5 - Version 2.14 December 21, 2018 5 + As of 6.7 kernel. See https://wiki.samba.org/index.php/LinuxCIFSKernel 6 + for list of features added by release 6 7 7 8 A Partial List of Missing Features 8 9 ================================== ··· 13 12 is a partial list of the known problems and missing features: 14 13 15 14 a) SMB3 (and SMB3.1.1) missing optional features: 15 + multichannel performance optimizations, algorithmic channel selection, 16 + directory leases optimizations, 17 + support for faster packet signing (GMAC), 18 + support for compression over the network, 19 + T10 copy offload ie "ODX" (copy chunk, and "Duplicate Extents" ioctl 20 + are currently the only two server side copy mechanisms supported) 16 21 17 - - multichannel (partially integrated), integration of multichannel with RDMA 18 - - directory leases (improved metadata caching). Currently only implemented for root dir 19 - - T10 copy offload ie "ODX" (copy chunk, and "Duplicate Extents" ioctl 20 - currently the only two server side copy mechanisms supported) 22 + b) Better optimized compounding and error handling for sparse file support, 23 + perhaps addition of new optional SMB3.1.1 fsctls to make collapse range 24 + and insert range more atomic 21 25 22 - b) improved sparse file support (fiemap and SEEK_HOLE are implemented 23 - but additional features would be supportable by the protocol such 24 - as FALLOC_FL_COLLAPSE_RANGE and FALLOC_FL_INSERT_RANGE) 25 - 26 - c) Directory entry caching relies on a 1 second timer, rather than 27 - using Directory Leases, currently only the root file handle is cached longer 28 - by leveraging Directory Leases 26 + c) Support for SMB3.1.1 over QUIC (and perhaps other socket based protocols 27 + like SCTP) 29 28 30 29 d) quota support (needs minor kernel change since quota calls otherwise 31 - won't make it to network filesystems or deviceless filesystems). 30 + won't make it to network filesystems or deviceless filesystems). 32 31 33 32 e) Additional use cases can be optimized to use "compounding" (e.g. 34 33 open/query/close and open/setinfo/close) to reduce the number of ··· 93 92 94 93 v) Additional testing of POSIX Extensions for SMB3.1.1 95 94 96 - w) Add support for additional strong encryption types, and additional spnego 97 - authentication mechanisms (see MS-SMB2). GCM-256 is now partially implemented. 95 + w) Support for the Mac SMB3.1.1 extensions to improve interop with Apple servers 98 96 99 - x) Finish support for SMB3.1.1 compression 97 + x) Support for additional authentication options (e.g. IAKERB, peer-to-peer 98 + Kerberos, SCRAM and others supported by existing servers) 99 + 100 + y) Improved tracing, more eBPF trace points, better scripts for performance 101 + analysis 100 102 101 103 Known Bugs 102 104 ========== 103 105 104 106 See https://bugzilla.samba.org - search on product "CifsVFS" for 105 107 current bug list. Also check http://bugzilla.kernel.org (Product = File System, Component = CIFS) 106 - 107 - 1) existing symbolic links (Windows reparse points) are recognized but 108 - can not be created remotely. They are implemented for Samba and those that 109 - support the CIFS Unix extensions, although earlier versions of Samba 110 - overly restrict the pathnames. 111 - 2) follow_link and readdir code does not follow dfs junctions 112 - but recognizes them 108 + and xfstest results e.g. https://wiki.samba.org/index.php/Xfstest-results-smb3 113 109 114 110 Misc testing to do 115 111 ==================
+7 -1
Documentation/admin-guide/cifs/usage.rst
··· 81 81 many advanced security features such as downgrade attack detection 82 82 and encrypted shares and stronger signing and authentication algorithms. 83 83 There are additional mount options that may be helpful for SMB3 to get 84 - improved POSIX behavior (NB: can use vers=3.0 to force only SMB3, never 2.1): 84 + improved POSIX behavior (NB: can use vers=3 to force SMB3 or later, never 2.1): 85 85 86 86 ``mfsymlinks`` and either ``cifsacl`` or ``modefromsid`` (usually with ``idsfromsid``) 87 87 ··· 715 715 Stats Lists summary resource usage information as well as per 716 716 share statistics. 717 717 open_files List all the open file handles on all active SMB sessions. 718 + mount_params List of all mount parameters available for the module 718 719 ======================= ======================================================= 719 720 720 721 Configuration pseudo-files: ··· 864 863 i.e.:: 865 864 866 865 echo "value" > /sys/module/cifs/parameters/<param> 866 + 867 + More detailed descriptions of the available module parameters and their values 868 + can be seen by doing: 869 + 870 + modinfo cifs (or modinfo smb3) 867 871 868 872 ================= ========================================================== 869 873 1. enable_oplocks Enable or disable oplocks. Oplocks are enabled by default.
+1 -1
MAINTAINERS
··· 5236 5236 COMMON INTERNET FILE SYSTEM CLIENT (CIFS and SMB3) 5237 5237 M: Steve French <sfrench@samba.org> 5238 5238 R: Paulo Alcantara <pc@manguebit.com> (DFS, global name space) 5239 - R: Ronnie Sahlberg <lsahlber@redhat.com> (directory leases, sparse files) 5239 + R: Ronnie Sahlberg <ronniesahlberg@gmail.com> (directory leases, sparse files) 5240 5240 R: Shyam Prasad N <sprasad@microsoft.com> (multichannel) 5241 5241 R: Tom Talpey <tom@talpey.com> (RDMA, smbdirect) 5242 5242 L: linux-cifs@vger.kernel.org
+1 -1
fs/smb/client/cached_dir.c
··· 151 151 return -EOPNOTSUPP; 152 152 153 153 ses = tcon->ses; 154 - server = ses->server; 154 + server = cifs_pick_channel(ses); 155 155 cfids = tcon->cfids; 156 156 157 157 if (!server->ops->new_lease_key)
+4 -2
fs/smb/client/cifs_debug.c
··· 659 659 spin_lock(&tcon->stat_lock); 660 660 tcon->bytes_read = 0; 661 661 tcon->bytes_written = 0; 662 + tcon->stats_from_time = ktime_get_real_seconds(); 662 663 spin_unlock(&tcon->stat_lock); 663 664 if (server->ops->clear_stats) 664 665 server->ops->clear_stats(tcon); ··· 738 737 seq_printf(m, "\n%d) %s", i, tcon->tree_name); 739 738 if (tcon->need_reconnect) 740 739 seq_puts(m, "\tDISCONNECTED "); 741 - seq_printf(m, "\nSMBs: %d", 742 - atomic_read(&tcon->num_smbs_sent)); 740 + seq_printf(m, "\nSMBs: %d since %ptTs UTC", 741 + atomic_read(&tcon->num_smbs_sent), 742 + &tcon->stats_from_time); 743 743 if (server->ops->print_stats) 744 744 server->ops->print_stats(m, tcon); 745 745 }
+2
fs/smb/client/cifsfs.c
··· 681 681 seq_printf(s, ",rasize=%u", cifs_sb->ctx->rasize); 682 682 if (tcon->ses->server->min_offload) 683 683 seq_printf(s, ",esize=%u", tcon->ses->server->min_offload); 684 + if (tcon->ses->server->retrans) 685 + seq_printf(s, ",retrans=%u", tcon->ses->server->retrans); 684 686 seq_printf(s, ",echo_interval=%lu", 685 687 tcon->ses->server->echo_interval / HZ); 686 688
+4
fs/smb/client/cifsglob.h
··· 204 204 }; 205 205 } reparse; 206 206 char *symlink_target; 207 + struct cifs_sid posix_owner; 208 + struct cifs_sid posix_group; 207 209 union { 208 210 struct smb2_file_all_info fi; 209 211 struct smb311_posix_qinfo posix_fi; ··· 753 751 unsigned int max_read; 754 752 unsigned int max_write; 755 753 unsigned int min_offload; 754 + unsigned int retrans; 756 755 __le16 compress_algorithm; 757 756 __u16 signing_algorithm; 758 757 __le16 cipher_type; ··· 1210 1207 __u64 bytes_read; 1211 1208 __u64 bytes_written; 1212 1209 spinlock_t stat_lock; /* protects the two fields above */ 1210 + time64_t stats_from_time; 1213 1211 FILE_SYSTEM_DEVICE_INFO fsDevInfo; 1214 1212 FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* ok if fs name truncated */ 1215 1213 FILE_SYSTEM_UNIX_INFO fsUnixInfo;
+4
fs/smb/client/connect.c
··· 1574 1574 if (server->min_offload != ctx->min_offload) 1575 1575 return 0; 1576 1576 1577 + if (server->retrans != ctx->retrans) 1578 + return 0; 1579 + 1577 1580 return 1; 1578 1581 } 1579 1582 ··· 1801 1798 goto out_err_crypto_release; 1802 1799 } 1803 1800 tcp_ses->min_offload = ctx->min_offload; 1801 + tcp_ses->retrans = ctx->retrans; 1804 1802 /* 1805 1803 * at this point we are the only ones with the pointer 1806 1804 * to the struct since the kernel thread not created yet
+6
fs/smb/client/fs_context.c
··· 139 139 fsparam_u32("dir_mode", Opt_dirmode), 140 140 fsparam_u32("port", Opt_port), 141 141 fsparam_u32("min_enc_offload", Opt_min_enc_offload), 142 + fsparam_u32("retrans", Opt_retrans), 142 143 fsparam_u32("esize", Opt_min_enc_offload), 143 144 fsparam_u32("bsize", Opt_blocksize), 144 145 fsparam_u32("rasize", Opt_rasize), ··· 1065 1064 case Opt_min_enc_offload: 1066 1065 ctx->min_offload = result.uint_32; 1067 1066 break; 1067 + case Opt_retrans: 1068 + ctx->retrans = result.uint_32; 1069 + break; 1068 1070 case Opt_blocksize: 1069 1071 /* 1070 1072 * inode blocksize realistically should never need to be ··· 1622 1618 1623 1619 ctx->backupuid_specified = false; /* no backup intent for a user */ 1624 1620 ctx->backupgid_specified = false; /* no backup intent for a group */ 1621 + 1622 + ctx->retrans = 1; 1625 1623 1626 1624 /* 1627 1625 * short int override_uid = -1;
+2
fs/smb/client/fs_context.h
··· 118 118 Opt_file_mode, 119 119 Opt_dirmode, 120 120 Opt_min_enc_offload, 121 + Opt_retrans, 121 122 Opt_blocksize, 122 123 Opt_rasize, 123 124 Opt_rsize, ··· 246 245 unsigned int rsize; 247 246 unsigned int wsize; 248 247 unsigned int min_offload; 248 + unsigned int retrans; 249 249 bool sockopt_tcp_nodelay:1; 250 250 /* attribute cache timemout for files and directories in jiffies */ 251 251 unsigned long acregmax;
+11 -18
fs/smb/client/inode.c
··· 665 665 /* Fill a cifs_fattr struct with info from POSIX info struct */ 666 666 static void smb311_posix_info_to_fattr(struct cifs_fattr *fattr, 667 667 struct cifs_open_info_data *data, 668 - struct cifs_sid *owner, 669 - struct cifs_sid *group, 670 668 struct super_block *sb) 671 669 { 672 670 struct smb311_posix_qinfo *info = &data->posix_fi; ··· 720 722 fattr->cf_symlink_target = data->symlink_target; 721 723 data->symlink_target = NULL; 722 724 } 723 - sid_to_id(cifs_sb, owner, fattr, SIDOWNER); 724 - sid_to_id(cifs_sb, group, fattr, SIDGROUP); 725 + sid_to_id(cifs_sb, &data->posix_owner, fattr, SIDOWNER); 726 + sid_to_id(cifs_sb, &data->posix_group, fattr, SIDGROUP); 725 727 726 728 cifs_dbg(FYI, "POSIX query info: mode 0x%x uniqueid 0x%llx nlink %d\n", 727 729 fattr->cf_mode, fattr->cf_uniqueid, fattr->cf_nlink); ··· 1068 1070 const unsigned int xid, 1069 1071 struct cifs_tcon *tcon, 1070 1072 const char *full_path, 1071 - struct cifs_fattr *fattr, 1072 - struct cifs_sid *owner, 1073 - struct cifs_sid *group) 1073 + struct cifs_fattr *fattr) 1074 1074 { 1075 1075 struct TCP_Server_Info *server = tcon->ses->server; 1076 1076 struct cifs_sb_info *cifs_sb = CIFS_SB(sb); ··· 1113 1117 } 1114 1118 1115 1119 if (tcon->posix_extensions) 1116 - smb311_posix_info_to_fattr(fattr, data, owner, group, sb); 1120 + smb311_posix_info_to_fattr(fattr, data, sb); 1117 1121 else 1118 1122 cifs_open_info_to_fattr(fattr, data, sb); 1119 1123 out: ··· 1167 1171 */ 1168 1172 if (cifs_open_data_reparse(data)) { 1169 1173 rc = reparse_info_to_fattr(data, sb, xid, tcon, 1170 - full_path, fattr, 1171 - NULL, NULL); 1174 + full_path, fattr); 1172 1175 } else { 1173 1176 cifs_open_info_to_fattr(fattr, data, sb); 1174 1177 } ··· 1312 1317 const unsigned int xid) 1313 1318 { 1314 1319 struct cifs_open_info_data tmp_data = {}; 1320 + struct TCP_Server_Info *server; 1315 1321 struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 1316 1322 struct cifs_tcon *tcon; 1317 1323 struct tcon_link *tlink; 1318 - struct cifs_sid owner, group; 1319 1324 int tmprc; 1320 1325 int rc = 0; 1321 1326 ··· 1323 1328 if (IS_ERR(tlink)) 1324 1329 return PTR_ERR(tlink); 1325 1330 tcon = tlink_tcon(tlink); 1331 + server = tcon->ses->server; 1326 1332 1327 1333 /* 1328 1334 * 1. Fetch file metadata if not provided (data) 1329 1335 */ 1330 1336 if (!data) { 1331 - rc = smb311_posix_query_path_info(xid, tcon, cifs_sb, 1332 - full_path, &tmp_data, 1333 - &owner, &group); 1337 + rc = server->ops->query_path_info(xid, tcon, cifs_sb, 1338 + full_path, &tmp_data); 1334 1339 data = &tmp_data; 1335 1340 } 1336 1341 ··· 1342 1347 case 0: 1343 1348 if (cifs_open_data_reparse(data)) { 1344 1349 rc = reparse_info_to_fattr(data, sb, xid, tcon, 1345 - full_path, fattr, 1346 - &owner, &group); 1350 + full_path, fattr); 1347 1351 } else { 1348 - smb311_posix_info_to_fattr(fattr, data, 1349 - &owner, &group, sb); 1352 + smb311_posix_info_to_fattr(fattr, data, sb); 1350 1353 } 1351 1354 break; 1352 1355 case -EREMOTE:
+1
fs/smb/client/misc.c
··· 140 140 spin_lock_init(&ret_buf->stat_lock); 141 141 atomic_set(&ret_buf->num_local_opens, 0); 142 142 atomic_set(&ret_buf->num_remote_opens, 0); 143 + ret_buf->stats_from_time = ktime_get_real_seconds(); 143 144 #ifdef CONFIG_CIFS_DFS_UPCALL 144 145 INIT_LIST_HEAD(&ret_buf->dfs_ses_list); 145 146 #endif
+6 -6
fs/smb/client/readdir.c
··· 133 133 * Query dir responses don't provide enough 134 134 * information about reparse points other than 135 135 * their reparse tags. Save an invalidation by 136 - * not clobbering the existing mode, size and 137 - * symlink target (if any) when reparse tag and 138 - * ctime haven't changed. 136 + * not clobbering some existing attributes when 137 + * reparse tag and ctime haven't changed. 139 138 */ 140 139 rc = 0; 141 140 if (fattr->cf_cifsattrs & ATTR_REPARSE) { 142 141 if (likely(reparse_inode_match(inode, fattr))) { 143 142 fattr->cf_mode = inode->i_mode; 143 + fattr->cf_rdev = inode->i_rdev; 144 144 fattr->cf_eof = CIFS_I(inode)->server_eof; 145 145 fattr->cf_symlink_target = NULL; 146 146 } else { ··· 645 645 static int is_dir_changed(struct file *file) 646 646 { 647 647 struct inode *inode = file_inode(file); 648 - struct cifsInodeInfo *cifsInfo = CIFS_I(inode); 648 + struct cifsInodeInfo *cifs_inode_info = CIFS_I(inode); 649 649 650 - if (cifsInfo->time == 0) 651 - return 1; /* directory was changed, perhaps due to unlink */ 650 + if (cifs_inode_info->time == 0) 651 + return 1; /* directory was changed, e.g. unlink or new file */ 652 652 else 653 653 return 0; 654 654
+87 -145
fs/smb/client/smb2inode.c
··· 56 56 return 0; 57 57 } 58 58 59 + /* Parse owner and group from SMB3.1.1 POSIX query info */ 60 + static int parse_posix_sids(struct cifs_open_info_data *data, 61 + struct kvec *rsp_iov) 62 + { 63 + struct smb2_query_info_rsp *qi = rsp_iov->iov_base; 64 + unsigned int out_len = le32_to_cpu(qi->OutputBufferLength); 65 + unsigned int qi_len = sizeof(data->posix_fi); 66 + int owner_len, group_len; 67 + u8 *sidsbuf, *sidsbuf_end; 68 + 69 + if (out_len <= qi_len) 70 + return -EINVAL; 71 + 72 + sidsbuf = (u8 *)qi + le16_to_cpu(qi->OutputBufferOffset) + qi_len; 73 + sidsbuf_end = sidsbuf + out_len - qi_len; 74 + 75 + owner_len = posix_info_sid_size(sidsbuf, sidsbuf_end); 76 + if (owner_len == -1) 77 + return -EINVAL; 78 + 79 + memcpy(&data->posix_owner, sidsbuf, owner_len); 80 + group_len = posix_info_sid_size(sidsbuf + owner_len, sidsbuf_end); 81 + if (group_len == -1) 82 + return -EINVAL; 83 + 84 + memcpy(&data->posix_group, sidsbuf + owner_len, group_len); 85 + return 0; 86 + } 87 + 59 88 /* 60 89 * note: If cfile is passed, the reference to it is dropped here. 61 90 * So make sure that you do not reuse cfile after return from this func. ··· 98 69 __u32 desired_access, __u32 create_disposition, 99 70 __u32 create_options, umode_t mode, struct kvec *in_iov, 100 71 int *cmds, int num_cmds, struct cifsFileInfo *cfile, 101 - __u8 **extbuf, size_t *extbuflen, 102 72 struct kvec *out_iov, int *out_buftype) 103 73 { 104 74 ··· 522 494 &rsp_iov[i + 1], sizeof(idata->posix_fi) /* add SIDs */, 523 495 (char *)&idata->posix_fi); 524 496 } 525 - if (rc == 0) { 526 - unsigned int length = le32_to_cpu(qi_rsp->OutputBufferLength); 497 + if (rc == 0) 498 + rc = parse_posix_sids(idata, &rsp_iov[i + 1]); 527 499 528 - if (length > sizeof(idata->posix_fi)) { 529 - char *base = (char *)rsp_iov[i + 1].iov_base + 530 - le16_to_cpu(qi_rsp->OutputBufferOffset) + 531 - sizeof(idata->posix_fi); 532 - *extbuflen = length - sizeof(idata->posix_fi); 533 - *extbuf = kmemdup(base, *extbuflen, GFP_KERNEL); 534 - if (!*extbuf) 535 - rc = -ENOMEM; 536 - } else { 537 - rc = -EINVAL; 538 - } 539 - } 540 500 SMB2_query_info_free(&rqst[num_rqst++]); 541 501 if (rc) 542 502 trace_smb3_posix_query_info_compound_err(xid, ses->Suid, ··· 678 662 struct smb2_hdr *hdr; 679 663 struct kvec in_iov[2], out_iov[3] = {}; 680 664 int out_buftype[3] = {}; 681 - int cmds[2] = { SMB2_OP_QUERY_INFO, }; 665 + int cmds[2]; 682 666 bool islink; 683 667 int i, num_cmds; 684 668 int rc, rc2; ··· 686 670 data->adjust_tz = false; 687 671 data->reparse_point = false; 688 672 689 - if (strcmp(full_path, "")) 690 - rc = -ENOENT; 691 - else 692 - rc = open_cached_dir(xid, tcon, full_path, cifs_sb, false, &cfid); 693 - /* If it is a root and its handle is cached then use it */ 694 - if (!rc) { 695 - if (cfid->file_all_info_is_valid) { 696 - memcpy(&data->fi, &cfid->file_all_info, sizeof(data->fi)); 673 + /* 674 + * BB TODO: Add support for using cached root handle in SMB3.1.1 POSIX. 675 + * Create SMB2_query_posix_info worker function to do non-compounded 676 + * query when we already have an open file handle for this. For now this 677 + * is fast enough (always using the compounded version). 678 + */ 679 + if (!tcon->posix_extensions) { 680 + if (*full_path) { 681 + rc = -ENOENT; 697 682 } else { 698 - rc = SMB2_query_info(xid, tcon, cfid->fid.persistent_fid, 699 - cfid->fid.volatile_fid, &data->fi); 683 + rc = open_cached_dir(xid, tcon, full_path, 684 + cifs_sb, false, &cfid); 700 685 } 701 - close_cached_dir(cfid); 702 - return rc; 686 + /* If it is a root and its handle is cached then use it */ 687 + if (!rc) { 688 + if (cfid->file_all_info_is_valid) { 689 + memcpy(&data->fi, &cfid->file_all_info, 690 + sizeof(data->fi)); 691 + } else { 692 + rc = SMB2_query_info(xid, tcon, 693 + cfid->fid.persistent_fid, 694 + cfid->fid.volatile_fid, 695 + &data->fi); 696 + } 697 + close_cached_dir(cfid); 698 + return rc; 699 + } 700 + cmds[0] = SMB2_OP_QUERY_INFO; 701 + } else { 702 + cmds[0] = SMB2_OP_POSIX_QUERY_INFO; 703 703 } 704 704 705 705 in_iov[0].iov_base = data; ··· 725 693 cifs_get_readable_path(tcon, full_path, &cfile); 726 694 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, 727 695 FILE_READ_ATTRIBUTES, FILE_OPEN, 728 - create_options, ACL_NO_MODE, 729 - in_iov, cmds, 1, cfile, 730 - NULL, NULL, out_iov, out_buftype); 696 + create_options, ACL_NO_MODE, in_iov, 697 + cmds, 1, cfile, out_iov, out_buftype); 731 698 hdr = out_iov[0].iov_base; 732 699 /* 733 700 * If first iov is unset, then SMB session was dropped or we've got a ··· 738 707 switch (rc) { 739 708 case 0: 740 709 case -EOPNOTSUPP: 710 + /* 711 + * BB TODO: When support for special files added to Samba 712 + * re-verify this path. 713 + */ 741 714 rc = parse_create_response(data, cifs_sb, &out_iov[0]); 742 715 if (rc || !data->reparse_point) 743 716 goto out; ··· 757 722 cifs_get_readable_path(tcon, full_path, &cfile); 758 723 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, 759 724 FILE_READ_ATTRIBUTES, FILE_OPEN, 760 - create_options, ACL_NO_MODE, in_iov, cmds, 761 - num_cmds, cfile, NULL, NULL, NULL, NULL); 725 + create_options, ACL_NO_MODE, in_iov, 726 + cmds, num_cmds, cfile, NULL, NULL); 762 727 break; 763 728 case -EREMOTE: 764 729 break; ··· 781 746 return rc; 782 747 } 783 748 784 - int smb311_posix_query_path_info(const unsigned int xid, 785 - struct cifs_tcon *tcon, 786 - struct cifs_sb_info *cifs_sb, 787 - const char *full_path, 788 - struct cifs_open_info_data *data, 789 - struct cifs_sid *owner, 790 - struct cifs_sid *group) 791 - { 792 - int rc; 793 - __u32 create_options = 0; 794 - struct cifsFileInfo *cfile; 795 - struct kvec in_iov[2], out_iov[3] = {}; 796 - int out_buftype[3] = {}; 797 - __u8 *sidsbuf = NULL; 798 - __u8 *sidsbuf_end = NULL; 799 - size_t sidsbuflen = 0; 800 - size_t owner_len, group_len; 801 - int cmds[2] = { SMB2_OP_POSIX_QUERY_INFO, }; 802 - int i, num_cmds; 803 - 804 - data->adjust_tz = false; 805 - data->reparse_point = false; 806 - 807 - /* 808 - * BB TODO: Add support for using the cached root handle. 809 - * Create SMB2_query_posix_info worker function to do non-compounded query 810 - * when we already have an open file handle for this. For now this is fast enough 811 - * (always using the compounded version). 812 - */ 813 - in_iov[0].iov_base = data; 814 - in_iov[0].iov_len = sizeof(*data); 815 - in_iov[1] = in_iov[0]; 816 - 817 - cifs_get_readable_path(tcon, full_path, &cfile); 818 - rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, 819 - FILE_READ_ATTRIBUTES, FILE_OPEN, 820 - create_options, ACL_NO_MODE, in_iov, cmds, 1, 821 - cfile, &sidsbuf, &sidsbuflen, out_iov, out_buftype); 822 - /* 823 - * If first iov is unset, then SMB session was dropped or we've got a 824 - * cached open file (@cfile). 825 - */ 826 - if (!out_iov[0].iov_base || out_buftype[0] == CIFS_NO_BUFFER) 827 - goto out; 828 - 829 - switch (rc) { 830 - case 0: 831 - case -EOPNOTSUPP: 832 - /* BB TODO: When support for special files added to Samba re-verify this path */ 833 - rc = parse_create_response(data, cifs_sb, &out_iov[0]); 834 - if (rc || !data->reparse_point) 835 - goto out; 836 - 837 - if (data->reparse.tag == IO_REPARSE_TAG_SYMLINK) { 838 - /* symlink already parsed in create response */ 839 - num_cmds = 1; 840 - } else { 841 - cmds[1] = SMB2_OP_GET_REPARSE; 842 - num_cmds = 2; 843 - } 844 - create_options |= OPEN_REPARSE_POINT; 845 - cifs_get_readable_path(tcon, full_path, &cfile); 846 - rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, 847 - FILE_READ_ATTRIBUTES, FILE_OPEN, 848 - create_options, ACL_NO_MODE, in_iov, cmds, 849 - num_cmds, cfile, &sidsbuf, &sidsbuflen, NULL, NULL); 850 - break; 851 - } 852 - 853 - out: 854 - if (rc == 0) { 855 - sidsbuf_end = sidsbuf + sidsbuflen; 856 - 857 - owner_len = posix_info_sid_size(sidsbuf, sidsbuf_end); 858 - if (owner_len == -1) { 859 - rc = -EINVAL; 860 - goto out; 861 - } 862 - memcpy(owner, sidsbuf, owner_len); 863 - 864 - group_len = posix_info_sid_size( 865 - sidsbuf + owner_len, sidsbuf_end); 866 - if (group_len == -1) { 867 - rc = -EINVAL; 868 - goto out; 869 - } 870 - memcpy(group, sidsbuf + owner_len, group_len); 871 - } 872 - 873 - kfree(sidsbuf); 874 - for (i = 0; i < ARRAY_SIZE(out_buftype); i++) 875 - free_rsp_buf(out_buftype[i], out_iov[i].iov_base); 876 - return rc; 877 - } 878 - 879 749 int 880 750 smb2_mkdir(const unsigned int xid, struct inode *parent_inode, umode_t mode, 881 751 struct cifs_tcon *tcon, const char *name, ··· 788 848 { 789 849 return smb2_compound_op(xid, tcon, cifs_sb, name, 790 850 FILE_WRITE_ATTRIBUTES, FILE_CREATE, 791 - CREATE_NOT_FILE, mode, NULL, 792 - &(int){SMB2_OP_MKDIR}, 1, 793 - NULL, NULL, NULL, NULL, NULL); 851 + CREATE_NOT_FILE, mode, 852 + NULL, &(int){SMB2_OP_MKDIR}, 1, 853 + NULL, NULL, NULL); 794 854 } 795 855 796 856 void ··· 815 875 FILE_WRITE_ATTRIBUTES, FILE_CREATE, 816 876 CREATE_NOT_FILE, ACL_NO_MODE, &in_iov, 817 877 &(int){SMB2_OP_SET_INFO}, 1, 818 - cfile, NULL, NULL, NULL, NULL); 878 + cfile, NULL, NULL); 819 879 if (tmprc == 0) 820 880 cifs_i->cifsAttrs = dosattrs; 821 881 } ··· 827 887 drop_cached_dir_by_name(xid, tcon, name, cifs_sb); 828 888 return smb2_compound_op(xid, tcon, cifs_sb, name, 829 889 DELETE, FILE_OPEN, CREATE_NOT_FILE, 830 - ACL_NO_MODE, NULL, &(int){SMB2_OP_RMDIR}, 1, 831 - NULL, NULL, NULL, NULL, NULL); 890 + ACL_NO_MODE, NULL, 891 + &(int){SMB2_OP_RMDIR}, 1, 892 + NULL, NULL, NULL); 832 893 } 833 894 834 895 int ··· 838 897 { 839 898 return smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN, 840 899 CREATE_DELETE_ON_CLOSE | OPEN_REPARSE_POINT, 841 - ACL_NO_MODE, NULL, &(int){SMB2_OP_DELETE}, 1, 842 - NULL, NULL, NULL, NULL, NULL); 900 + ACL_NO_MODE, NULL, 901 + &(int){SMB2_OP_DELETE}, 1, 902 + NULL, NULL, NULL); 843 903 } 844 904 845 905 static int smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon, ··· 861 919 in_iov.iov_base = smb2_to_name; 862 920 in_iov.iov_len = 2 * UniStrnlen((wchar_t *)smb2_to_name, PATH_MAX); 863 921 rc = smb2_compound_op(xid, tcon, cifs_sb, from_name, access, 864 - FILE_OPEN, create_options, ACL_NO_MODE, &in_iov, 865 - &command, 1, cfile, NULL, NULL, NULL, NULL); 922 + FILE_OPEN, create_options, ACL_NO_MODE, 923 + &in_iov, &command, 1, cfile, NULL, NULL); 866 924 smb2_rename_path: 867 925 kfree(smb2_to_name); 868 926 return rc; ··· 913 971 FILE_WRITE_DATA, FILE_OPEN, 914 972 0, ACL_NO_MODE, &in_iov, 915 973 &(int){SMB2_OP_SET_EOF}, 1, 916 - cfile, NULL, NULL, NULL, NULL); 974 + cfile, NULL, NULL); 917 975 } 918 976 919 977 int ··· 941 999 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, 942 1000 FILE_WRITE_ATTRIBUTES, FILE_OPEN, 943 1001 0, ACL_NO_MODE, &in_iov, 944 - &(int){SMB2_OP_SET_INFO}, 1, cfile, 945 - NULL, NULL, NULL, NULL); 1002 + &(int){SMB2_OP_SET_INFO}, 1, 1003 + cfile, NULL, NULL); 946 1004 cifs_put_tlink(tlink); 947 1005 return rc; 948 1006 } ··· 977 1035 cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile); 978 1036 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, 979 1037 da, cd, co, ACL_NO_MODE, in_iov, 980 - cmds, 2, cfile, NULL, NULL, NULL, NULL); 1038 + cmds, 2, cfile, NULL, NULL); 981 1039 if (!rc) { 982 1040 rc = smb311_posix_get_inode_info(&new, full_path, 983 1041 data, sb, xid); ··· 987 1045 cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile); 988 1046 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, 989 1047 da, cd, co, ACL_NO_MODE, in_iov, 990 - cmds, 2, cfile, NULL, NULL, NULL, NULL); 1048 + cmds, 2, cfile, NULL, NULL); 991 1049 if (!rc) { 992 1050 rc = cifs_get_inode_info(&new, full_path, 993 1051 data, sb, xid, NULL); ··· 1014 1072 rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, 1015 1073 FILE_READ_ATTRIBUTES, FILE_OPEN, 1016 1074 OPEN_REPARSE_POINT, ACL_NO_MODE, &in_iov, 1017 - &(int){SMB2_OP_GET_REPARSE}, 1, cfile, 1018 - NULL, NULL, NULL, NULL); 1075 + &(int){SMB2_OP_GET_REPARSE}, 1, 1076 + cfile, NULL, NULL); 1019 1077 if (rc) 1020 1078 goto out; 1021 1079
+2
fs/smb/client/smb2maperror.c
··· 1210 1210 {STATUS_INVALID_TASK_INDEX, -EIO, "STATUS_INVALID_TASK_INDEX"}, 1211 1211 {STATUS_THREAD_ALREADY_IN_TASK, -EIO, "STATUS_THREAD_ALREADY_IN_TASK"}, 1212 1212 {STATUS_CALLBACK_BYPASS, -EIO, "STATUS_CALLBACK_BYPASS"}, 1213 + {STATUS_SERVER_UNAVAILABLE, -EAGAIN, "STATUS_SERVER_UNAVAILABLE"}, 1214 + {STATUS_FILE_NOT_AVAILABLE, -EAGAIN, "STATUS_FILE_NOT_AVAILABLE"}, 1213 1215 {STATUS_PORT_CLOSED, -EIO, "STATUS_PORT_CLOSED"}, 1214 1216 {STATUS_MESSAGE_LOST, -EIO, "STATUS_MESSAGE_LOST"}, 1215 1217 {STATUS_INVALID_MESSAGE, -EIO, "STATUS_INVALID_MESSAGE"},
+3 -7
fs/smb/client/smb2ops.c
··· 614 614 "multichannel not available\n" 615 615 "Empty network interface list returned by server %s\n", 616 616 ses->server->hostname); 617 - rc = -EINVAL; 617 + rc = -EOPNOTSUPP; 618 + ses->iface_last_update = jiffies; 618 619 goto out; 619 620 } 620 621 ··· 713 712 714 713 ses->iface_count++; 715 714 spin_unlock(&ses->iface_lock); 716 - ses->iface_last_update = jiffies; 717 715 next_iface: 718 716 nb_iface++; 719 717 next = le32_to_cpu(p->Next); ··· 734 734 if ((bytes_left > 8) || p->Next) 735 735 cifs_dbg(VFS, "%s: incomplete interface info\n", __func__); 736 736 737 - 738 - if (!ses->iface_count) { 739 - rc = -EINVAL; 740 - goto out; 741 - } 737 + ses->iface_last_update = jiffies; 742 738 743 739 out: 744 740 /*
+78 -49
fs/smb/client/smb2pdu.c
··· 156 156 return; 157 157 } 158 158 159 + /* helper function for code reuse */ 160 + static int 161 + cifs_chan_skip_or_disable(struct cifs_ses *ses, 162 + struct TCP_Server_Info *server, 163 + bool from_reconnect) 164 + { 165 + struct TCP_Server_Info *pserver; 166 + unsigned int chan_index; 167 + 168 + if (SERVER_IS_CHAN(server)) { 169 + cifs_dbg(VFS, 170 + "server %s does not support multichannel anymore. Skip secondary channel\n", 171 + ses->server->hostname); 172 + 173 + spin_lock(&ses->chan_lock); 174 + chan_index = cifs_ses_get_chan_index(ses, server); 175 + if (chan_index == CIFS_INVAL_CHAN_INDEX) { 176 + spin_unlock(&ses->chan_lock); 177 + goto skip_terminate; 178 + } 179 + 180 + ses->chans[chan_index].server = NULL; 181 + spin_unlock(&ses->chan_lock); 182 + 183 + /* 184 + * the above reference of server by channel 185 + * needs to be dropped without holding chan_lock 186 + * as cifs_put_tcp_session takes a higher lock 187 + * i.e. cifs_tcp_ses_lock 188 + */ 189 + cifs_put_tcp_session(server, from_reconnect); 190 + 191 + server->terminate = true; 192 + cifs_signal_cifsd_for_reconnect(server, false); 193 + 194 + /* mark primary server as needing reconnect */ 195 + pserver = server->primary_server; 196 + cifs_signal_cifsd_for_reconnect(pserver, false); 197 + skip_terminate: 198 + mutex_unlock(&ses->session_mutex); 199 + return -EHOSTDOWN; 200 + } 201 + 202 + cifs_server_dbg(VFS, 203 + "server does not support multichannel anymore. Disable all other channels\n"); 204 + cifs_disable_secondary_channels(ses); 205 + 206 + 207 + return 0; 208 + } 209 + 159 210 static int 160 211 smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon, 161 212 struct TCP_Server_Info *server, bool from_reconnect) ··· 215 164 struct nls_table *nls_codepage = NULL; 216 165 struct cifs_ses *ses; 217 166 int xid; 218 - struct TCP_Server_Info *pserver; 219 - unsigned int chan_index; 220 167 221 168 /* 222 169 * SMB2s NegProt, SessSetup, Logoff do not have tcon yet so ··· 359 310 */ 360 311 if (ses->chan_count > 1 && 361 312 !(server->capabilities & SMB2_GLOBAL_CAP_MULTI_CHANNEL)) { 362 - if (SERVER_IS_CHAN(server)) { 363 - cifs_dbg(VFS, "server %s does not support " \ 364 - "multichannel anymore. skipping secondary channel\n", 365 - ses->server->hostname); 366 - 367 - spin_lock(&ses->chan_lock); 368 - chan_index = cifs_ses_get_chan_index(ses, server); 369 - if (chan_index == CIFS_INVAL_CHAN_INDEX) { 370 - spin_unlock(&ses->chan_lock); 371 - goto skip_terminate; 372 - } 373 - 374 - ses->chans[chan_index].server = NULL; 375 - spin_unlock(&ses->chan_lock); 376 - 377 - /* 378 - * the above reference of server by channel 379 - * needs to be dropped without holding chan_lock 380 - * as cifs_put_tcp_session takes a higher lock 381 - * i.e. cifs_tcp_ses_lock 382 - */ 383 - cifs_put_tcp_session(server, from_reconnect); 384 - 385 - server->terminate = true; 386 - cifs_signal_cifsd_for_reconnect(server, false); 387 - 388 - /* mark primary server as needing reconnect */ 389 - pserver = server->primary_server; 390 - cifs_signal_cifsd_for_reconnect(pserver, false); 391 - 392 - skip_terminate: 313 + rc = cifs_chan_skip_or_disable(ses, server, 314 + from_reconnect); 315 + if (rc) { 393 316 mutex_unlock(&ses->session_mutex); 394 - rc = -EHOSTDOWN; 395 317 goto out; 396 - } else { 397 - cifs_server_dbg(VFS, "does not support " \ 398 - "multichannel anymore. disabling all other channels\n"); 399 - cifs_disable_secondary_channels(ses); 400 318 } 401 319 } 402 320 ··· 411 395 rc = SMB3_request_interfaces(xid, tcon, false); 412 396 free_xid(xid); 413 397 414 - if (rc) 398 + if (rc == -EOPNOTSUPP) { 399 + /* 400 + * some servers like Azure SMB server do not advertise 401 + * that multichannel has been disabled with server 402 + * capabilities, rather return STATUS_NOT_IMPLEMENTED. 403 + * treat this as server not supporting multichannel 404 + */ 405 + 406 + rc = cifs_chan_skip_or_disable(ses, server, 407 + from_reconnect); 408 + goto skip_add_channels; 409 + } else if (rc) 415 410 cifs_dbg(FYI, "%s: failed to query server interfaces: %d\n", 416 411 __func__, rc); 417 412 418 413 if (ses->chan_max > ses->chan_count && 414 + ses->iface_count && 419 415 !SERVER_IS_CHAN(server)) { 420 416 if (ses->chan_count == 1) 421 417 cifs_server_dbg(VFS, "supports multichannel now\n"); 422 418 423 419 cifs_try_adding_channels(ses); 420 + queue_delayed_work(cifsiod_wq, &tcon->query_interfaces, 421 + (SMB_INTERFACE_POLL_INTERVAL * HZ)); 424 422 } 425 423 } else { 426 424 mutex_unlock(&ses->session_mutex); 427 425 } 426 + skip_add_channels: 428 427 429 428 if (smb2_command != SMB2_INTERNAL_CMD) 430 429 mod_delayed_work(cifsiod_wq, &server->reconnect, 0); ··· 1989 1958 __le16 *unc_path = NULL; 1990 1959 int flags = 0; 1991 1960 unsigned int total_len; 1992 - struct TCP_Server_Info *server; 1993 - 1994 - /* always use master channel */ 1995 - server = ses->server; 1961 + struct TCP_Server_Info *server = cifs_pick_channel(ses); 1996 1962 1997 1963 cifs_dbg(FYI, "TCON\n"); 1998 1964 ··· 2122 2094 struct smb2_tree_disconnect_req *req; /* response is trivial */ 2123 2095 int rc = 0; 2124 2096 struct cifs_ses *ses = tcon->ses; 2097 + struct TCP_Server_Info *server = cifs_pick_channel(ses); 2125 2098 int flags = 0; 2126 2099 unsigned int total_len; 2127 2100 struct kvec iov[1]; ··· 2145 2116 2146 2117 invalidate_all_cached_dirs(tcon); 2147 2118 2148 - rc = smb2_plain_req_init(SMB2_TREE_DISCONNECT, tcon, ses->server, 2119 + rc = smb2_plain_req_init(SMB2_TREE_DISCONNECT, tcon, server, 2149 2120 (void **) &req, 2150 2121 &total_len); 2151 2122 if (rc) ··· 2163 2134 rqst.rq_iov = iov; 2164 2135 rqst.rq_nvec = 1; 2165 2136 2166 - rc = cifs_send_recv(xid, ses, ses->server, 2137 + rc = cifs_send_recv(xid, ses, server, 2167 2138 &rqst, &resp_buf_type, flags, &rsp_iov); 2168 2139 cifs_small_buf_release(req); 2169 2140 if (rc) { ··· 2308 2279 2309 2280 noff = le16_to_cpu(cc->NameOffset); 2310 2281 nlen = le16_to_cpu(cc->NameLength); 2311 - if (noff + nlen >= doff) 2282 + if (noff + nlen > doff) 2312 2283 return -EINVAL; 2313 2284 2314 2285 name = (char *)cc + noff; ··· 3947 3918 struct cifs_ses *ses, *ses2; 3948 3919 struct cifs_tcon *tcon, *tcon2; 3949 3920 struct list_head tmp_list, tmp_ses_list; 3950 - bool tcon_exist = false, ses_exist = false; 3921 + bool ses_exist = false; 3951 3922 bool tcon_selected = false; 3952 3923 int rc; 3953 3924 bool resched = false; ··· 3993 3964 if (tcon->need_reconnect || tcon->need_reopen_files) { 3994 3965 tcon->tc_count++; 3995 3966 list_add_tail(&tcon->rlist, &tmp_list); 3996 - tcon_selected = tcon_exist = true; 3967 + tcon_selected = true; 3997 3968 } 3998 3969 } 3999 3970 /* ··· 4002 3973 */ 4003 3974 if (ses->tcon_ipc && ses->tcon_ipc->need_reconnect) { 4004 3975 list_add_tail(&ses->tcon_ipc->rlist, &tmp_list); 4005 - tcon_selected = tcon_exist = true; 3976 + tcon_selected = true; 4006 3977 cifs_smb_ses_inc_refcount(ses); 4007 3978 } 4008 3979 /*
+1 -3
fs/smb/client/smb2proto.h
··· 299 299 struct cifs_tcon *tcon, 300 300 struct cifs_sb_info *cifs_sb, 301 301 const char *full_path, 302 - struct cifs_open_info_data *data, 303 - struct cifs_sid *owner, 304 - struct cifs_sid *group); 302 + struct cifs_open_info_data *data); 305 303 int posix_info_parse(const void *beg, const void *end, 306 304 struct smb2_posix_info_parsed *out); 307 305 int posix_info_sid_size(const void *beg, const void *end);
+2
fs/smb/client/smb2status.h
··· 982 982 #define STATUS_INVALID_TASK_INDEX cpu_to_le32(0xC0000501) 983 983 #define STATUS_THREAD_ALREADY_IN_TASK cpu_to_le32(0xC0000502) 984 984 #define STATUS_CALLBACK_BYPASS cpu_to_le32(0xC0000503) 985 + #define STATUS_SERVER_UNAVAILABLE cpu_to_le32(0xC0000466) 986 + #define STATUS_FILE_NOT_AVAILABLE cpu_to_le32(0xC0000467) 985 987 #define STATUS_PORT_CLOSED cpu_to_le32(0xC0000700) 986 988 #define STATUS_MESSAGE_LOST cpu_to_le32(0xC0000701) 987 989 #define STATUS_INVALID_MESSAGE cpu_to_le32(0xC0000702)