summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-01-02 15:08:29 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2019-01-02 15:08:29 -0500
commitcacf02df4b84d261d76db3d290ccb6b951df28c0 (patch)
tree5f0655ff89210626854c747566b934e2e562830a
parent74673fc50babc9be22b32c4ce697fceb51c7671a (diff)
parentfea170804b4dc44cd79f8cb1ce236f3a824951cd (diff)
Merge tag '4.21-smb3-fixes' of git://git.samba.org/sfrench/cifs-2.6
Pull cifs updates from Steve French: - four fixes for stable - improvements to DFS including allowing failover to alternate targets - some small performance improvements * tag '4.21-smb3-fixes' of git://git.samba.org/sfrench/cifs-2.6: (39 commits) cifs: update internal module version number cifs: we can not use small padding iovs together with encryption cifs: Minor Kconfig clarification cifs: Always resolve hostname before reconnecting cifs: Add support for failover in cifs_reconnect_tcon() cifs: Add support for failover in smb2_reconnect() cifs: Only free DFS target list if we actually got one cifs: start DFS cache refresher in cifs_mount() cifs: Use GFP_ATOMIC when a lock is held in cifs_mount() cifs: Add support for failover in cifs_reconnect() cifs: Add support for failover in cifs_mount() cifs: remove set but not used variable 'sep' cifs: Make use of DFS cache to get new DFS referrals cifs: minor updates to documentation cifs: check kzalloc return cifs: remove set but not used variable 'server' cifs: Use kzfree() to free password cifs: Fix to use kmem_cache_free() instead of kfree() cifs: update for current_kernel_time64() removal cifs: Add DFS cache routines ...
-rw-r--r--Documentation/filesystems/cifs/TODO26
-rw-r--r--fs/cifs/Kconfig5
-rw-r--r--fs/cifs/Makefile2
-rw-r--r--fs/cifs/cifs_debug.c12
-rw-r--r--fs/cifs/cifs_dfs_ref.c138
-rw-r--r--fs/cifs/cifs_fs_sb.h9
-rw-r--r--fs/cifs/cifsencrypt.c13
-rw-r--r--fs/cifs/cifsfs.c17
-rw-r--r--fs/cifs/cifsfs.h2
-rw-r--r--fs/cifs/cifsglob.h15
-rw-r--r--fs/cifs/cifsproto.h28
-rw-r--r--fs/cifs/cifssmb.c88
-rw-r--r--fs/cifs/connect.c924
-rw-r--r--fs/cifs/dfs_cache.c1367
-rw-r--r--fs/cifs/dfs_cache.h97
-rw-r--r--fs/cifs/file.c12
-rw-r--r--fs/cifs/inode.c44
-rw-r--r--fs/cifs/misc.c68
-rw-r--r--fs/cifs/readdir.c9
-rw-r--r--fs/cifs/sess.c4
-rw-r--r--fs/cifs/smb1ops.c15
-rw-r--r--fs/cifs/smb2inode.c16
-rw-r--r--fs/cifs/smb2maperror.c4
-rw-r--r--fs/cifs/smb2ops.c322
-rw-r--r--fs/cifs/smb2pdu.c108
-rw-r--r--fs/cifs/smb2pdu.h1
-rw-r--r--fs/cifs/smb2proto.h15
-rw-r--r--fs/cifs/transport.c8
28 files changed, 2862 insertions, 507 deletions
diff --git a/Documentation/filesystems/cifs/TODO b/Documentation/filesystems/cifs/TODO
index 852499aed64b..66b3f54aa6dc 100644
--- a/Documentation/filesystems/cifs/TODO
+++ b/Documentation/filesystems/cifs/TODO
@@ -1,4 +1,4 @@
1Version 2.11 September 13, 2017 1Version 2.14 December 21, 2018
2 2
3A Partial List of Missing Features 3A Partial List of Missing Features
4================================== 4==================================
@@ -7,7 +7,7 @@ Contributions are welcome. There are plenty of opportunities
7for visible, important contributions to this module. Here 7for visible, important contributions to this module. Here
8is a partial list of the known problems and missing features: 8is a partial list of the known problems and missing features:
9 9
10a) SMB3 (and SMB3.02) missing optional features: 10a) SMB3 (and SMB3.1.1) missing optional features:
11 - multichannel (started), integration with RDMA 11 - multichannel (started), integration with RDMA
12 - directory leases (improved metadata caching), started (root dir only) 12 - directory leases (improved metadata caching), started (root dir only)
13 - T10 copy offload ie "ODX" (copy chunk, and "Duplicate Extents" ioctl 13 - T10 copy offload ie "ODX" (copy chunk, and "Duplicate Extents" ioctl
@@ -21,8 +21,9 @@ using Directory Leases, currently only the root file handle is cached longer
21d) quota support (needs minor kernel change since quota calls 21d) quota support (needs minor kernel change since quota calls
22to make it to network filesystems or deviceless filesystems) 22to make it to network filesystems or deviceless filesystems)
23 23
24e) Compounding (in progress) to reduce number of roundtrips, and also 24e) Additional use cases where we use "compoounding" (e.g. open/query/close
25better optimize open to reduce redundant opens (using reference counts more). 25and open/setinfo/close) to reduce the number of roundtrips, and also
26open to reduce redundant opens (using deferred close and reference counts more).
26 27
27f) Finish inotify support so kde and gnome file list windows 28f) Finish inotify support so kde and gnome file list windows
28will autorefresh (partially complete by Asser). Needs minor kernel 29will autorefresh (partially complete by Asser). Needs minor kernel
@@ -43,11 +44,13 @@ exists. Also better integration with winbind for resolving SID owners
43 44
44k) Add tools to take advantage of more smb3 specific ioctls and features 45k) Add tools to take advantage of more smb3 specific ioctls and features
45(passthrough ioctl/fsctl for sending various SMB3 fsctls to the server 46(passthrough ioctl/fsctl for sending various SMB3 fsctls to the server
46is in progress) 47is in progress, and a passthrough query_info call is already implemented
48in cifs.ko to allow smb3 info levels queries to be sent from userspace)
47 49
48l) encrypted file support 50l) encrypted file support
49 51
50m) improved stats gathering, tools (perhaps integration with nfsometer?) 52m) improved stats gathering tools (perhaps integration with nfsometer?)
53to extend and make easier to use what is currently in /proc/fs/cifs/Stats
51 54
52n) allow setting more NTFS/SMB3 file attributes remotely (currently limited to compressed 55n) allow setting more NTFS/SMB3 file attributes remotely (currently limited to compressed
53file attribute via chflags) and improve user space tools for managing and 56file attribute via chflags) and improve user space tools for managing and
@@ -76,6 +79,9 @@ and simplify the code.
76v) POSIX Extensions for SMB3.1.1 (started, create and mkdir support added 79v) POSIX Extensions for SMB3.1.1 (started, create and mkdir support added
77so far). 80so far).
78 81
82w) Add support for additional strong encryption types, and additional spnego
83authentication mechanisms (see MS-SMB2)
84
79KNOWN BUGS 85KNOWN BUGS
80==================================== 86====================================
81See http://bugzilla.samba.org - search on product "CifsVFS" for 87See http://bugzilla.samba.org - search on product "CifsVFS" for
@@ -102,3 +108,11 @@ and when signing is disabled to request larger read sizes (larger than
102negotiated size) and send larger write sizes to modern servers. 108negotiated size) and send larger write sizes to modern servers.
103 109
1044) More exhaustively test against less common servers 1104) More exhaustively test against less common servers
111
1125) Continue to extend the smb3 "buildbot" which does automated xfstesting
113against Windows, Samba and Azure currently - to add additional tests and
114to allow the buildbot to execute the tests faster.
115
1166) Address various coverity warnings (most are not bugs per-se, but
117the more warnings are addressed, the easier it is to spot real
118problems that static analyzers will point out in the future).
diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig
index 85dadb93c992..f1ddc9d03c10 100644
--- a/fs/cifs/Kconfig
+++ b/fs/cifs/Kconfig
@@ -190,8 +190,9 @@ config CIFS_DFS_UPCALL
190 moves to a different server. This feature also enables 190 moves to a different server. This feature also enables
191 an upcall mechanism for CIFS which contacts userspace helper 191 an upcall mechanism for CIFS which contacts userspace helper
192 utilities to provide server name resolution (host names to 192 utilities to provide server name resolution (host names to
193 IP addresses) which is needed for implicit mounts of DFS junction 193 IP addresses) which is needed in order to reconnect to
194 points. If unsure, say Y. 194 servers if their addresses change or for implicit mounts of
195 DFS junction points. If unsure, say Y.
195 196
196config CIFS_NFSD_EXPORT 197config CIFS_NFSD_EXPORT
197 bool "Allow nfsd to export CIFS file system" 198 bool "Allow nfsd to export CIFS file system"
diff --git a/fs/cifs/Makefile b/fs/cifs/Makefile
index 85817991ee68..51af69a1a328 100644
--- a/fs/cifs/Makefile
+++ b/fs/cifs/Makefile
@@ -17,7 +17,7 @@ cifs-$(CONFIG_CIFS_ACL) += cifsacl.o
17 17
18cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o 18cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o
19 19
20cifs-$(CONFIG_CIFS_DFS_UPCALL) += dns_resolve.o cifs_dfs_ref.o 20cifs-$(CONFIG_CIFS_DFS_UPCALL) += dns_resolve.o cifs_dfs_ref.o dfs_cache.o
21 21
22cifs-$(CONFIG_CIFS_FSCACHE) += fscache.o cache.o 22cifs-$(CONFIG_CIFS_FSCACHE) += fscache.o cache.o
23 23
diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c
index ba178b09de0b..593fb422d0f3 100644
--- a/fs/cifs/cifs_debug.c
+++ b/fs/cifs/cifs_debug.c
@@ -30,6 +30,9 @@
30#include "cifsproto.h" 30#include "cifsproto.h"
31#include "cifs_debug.h" 31#include "cifs_debug.h"
32#include "cifsfs.h" 32#include "cifsfs.h"
33#ifdef CONFIG_CIFS_DFS_UPCALL
34#include "dfs_cache.h"
35#endif
33#ifdef CONFIG_CIFS_SMB_DIRECT 36#ifdef CONFIG_CIFS_SMB_DIRECT
34#include "smbdirect.h" 37#include "smbdirect.h"
35#endif 38#endif
@@ -629,6 +632,11 @@ cifs_proc_init(void)
629 &cifs_security_flags_proc_fops); 632 &cifs_security_flags_proc_fops);
630 proc_create("LookupCacheEnabled", 0644, proc_fs_cifs, 633 proc_create("LookupCacheEnabled", 0644, proc_fs_cifs,
631 &cifs_lookup_cache_proc_fops); 634 &cifs_lookup_cache_proc_fops);
635
636#ifdef CONFIG_CIFS_DFS_UPCALL
637 proc_create("dfscache", 0644, proc_fs_cifs, &dfscache_proc_fops);
638#endif
639
632#ifdef CONFIG_CIFS_SMB_DIRECT 640#ifdef CONFIG_CIFS_SMB_DIRECT
633 proc_create("rdma_readwrite_threshold", 0644, proc_fs_cifs, 641 proc_create("rdma_readwrite_threshold", 0644, proc_fs_cifs,
634 &cifs_rdma_readwrite_threshold_proc_fops); 642 &cifs_rdma_readwrite_threshold_proc_fops);
@@ -663,6 +671,10 @@ cifs_proc_clean(void)
663 remove_proc_entry("SecurityFlags", proc_fs_cifs); 671 remove_proc_entry("SecurityFlags", proc_fs_cifs);
664 remove_proc_entry("LinuxExtensionsEnabled", proc_fs_cifs); 672 remove_proc_entry("LinuxExtensionsEnabled", proc_fs_cifs);
665 remove_proc_entry("LookupCacheEnabled", proc_fs_cifs); 673 remove_proc_entry("LookupCacheEnabled", proc_fs_cifs);
674
675#ifdef CONFIG_CIFS_DFS_UPCALL
676 remove_proc_entry("dfscache", proc_fs_cifs);
677#endif
666#ifdef CONFIG_CIFS_SMB_DIRECT 678#ifdef CONFIG_CIFS_SMB_DIRECT
667 remove_proc_entry("rdma_readwrite_threshold", proc_fs_cifs); 679 remove_proc_entry("rdma_readwrite_threshold", proc_fs_cifs);
668 remove_proc_entry("smbd_max_frmr_depth", proc_fs_cifs); 680 remove_proc_entry("smbd_max_frmr_depth", proc_fs_cifs);
diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c
index b97c74efd04a..d9b99abe1243 100644
--- a/fs/cifs/cifs_dfs_ref.c
+++ b/fs/cifs/cifs_dfs_ref.c
@@ -25,6 +25,7 @@
25#include "dns_resolve.h" 25#include "dns_resolve.h"
26#include "cifs_debug.h" 26#include "cifs_debug.h"
27#include "cifs_unicode.h" 27#include "cifs_unicode.h"
28#include "dfs_cache.h"
28 29
29static LIST_HEAD(cifs_dfs_automount_list); 30static LIST_HEAD(cifs_dfs_automount_list);
30 31
@@ -126,7 +127,7 @@ cifs_build_devname(char *nodename, const char *prepath)
126 * @sb_mountdata: parent/root DFS mount options (template) 127 * @sb_mountdata: parent/root DFS mount options (template)
127 * @fullpath: full path in UNC format 128 * @fullpath: full path in UNC format
128 * @ref: server's referral 129 * @ref: server's referral
129 * @devname: pointer for saving device name 130 * @devname: optional pointer for saving device name
130 * 131 *
131 * creates mount options for submount based on template options sb_mountdata 132 * creates mount options for submount based on template options sb_mountdata
132 * and replacing unc,ip,prefixpath options with ones we've got form ref_unc. 133 * and replacing unc,ip,prefixpath options with ones we've got form ref_unc.
@@ -140,6 +141,7 @@ char *cifs_compose_mount_options(const char *sb_mountdata,
140 char **devname) 141 char **devname)
141{ 142{
142 int rc; 143 int rc;
144 char *name;
143 char *mountdata = NULL; 145 char *mountdata = NULL;
144 const char *prepath = NULL; 146 const char *prepath = NULL;
145 int md_len; 147 int md_len;
@@ -158,17 +160,17 @@ char *cifs_compose_mount_options(const char *sb_mountdata,
158 prepath++; 160 prepath++;
159 } 161 }
160 162
161 *devname = cifs_build_devname(ref->node_name, prepath); 163 name = cifs_build_devname(ref->node_name, prepath);
162 if (IS_ERR(*devname)) { 164 if (IS_ERR(name)) {
163 rc = PTR_ERR(*devname); 165 rc = PTR_ERR(name);
164 *devname = NULL; 166 name = NULL;
165 goto compose_mount_options_err; 167 goto compose_mount_options_err;
166 } 168 }
167 169
168 rc = dns_resolve_server_name_to_ip(*devname, &srvIP); 170 rc = dns_resolve_server_name_to_ip(name, &srvIP);
169 if (rc < 0) { 171 if (rc < 0) {
170 cifs_dbg(FYI, "%s: Failed to resolve server part of %s to IP: %d\n", 172 cifs_dbg(FYI, "%s: Failed to resolve server part of %s to IP: %d\n",
171 __func__, *devname, rc); 173 __func__, name, rc);
172 goto compose_mount_options_err; 174 goto compose_mount_options_err;
173 } 175 }
174 176
@@ -224,6 +226,9 @@ char *cifs_compose_mount_options(const char *sb_mountdata,
224 strcat(mountdata, "ip="); 226 strcat(mountdata, "ip=");
225 strcat(mountdata, srvIP); 227 strcat(mountdata, srvIP);
226 228
229 if (devname)
230 *devname = name;
231
227 /*cifs_dbg(FYI, "%s: parent mountdata: %s\n", __func__, sb_mountdata);*/ 232 /*cifs_dbg(FYI, "%s: parent mountdata: %s\n", __func__, sb_mountdata);*/
228 /*cifs_dbg(FYI, "%s: submount mountdata: %s\n", __func__, mountdata );*/ 233 /*cifs_dbg(FYI, "%s: submount mountdata: %s\n", __func__, mountdata );*/
229 234
@@ -234,8 +239,7 @@ compose_mount_options_out:
234compose_mount_options_err: 239compose_mount_options_err:
235 kfree(mountdata); 240 kfree(mountdata);
236 mountdata = ERR_PTR(rc); 241 mountdata = ERR_PTR(rc);
237 kfree(*devname); 242 kfree(name);
238 *devname = NULL;
239 goto compose_mount_options_out; 243 goto compose_mount_options_out;
240} 244}
241 245
@@ -251,20 +255,30 @@ static struct vfsmount *cifs_dfs_do_refmount(struct dentry *mntpt,
251{ 255{
252 struct vfsmount *mnt; 256 struct vfsmount *mnt;
253 char *mountdata; 257 char *mountdata;
254 char *devname = NULL; 258 char *devname;
259
260 /*
261 * Always pass down the DFS full path to smb3_do_mount() so we
262 * can use it later for failover.
263 */
264 devname = kstrndup(fullpath, strlen(fullpath), GFP_KERNEL);
265 if (!devname)
266 return ERR_PTR(-ENOMEM);
267
268 convert_delimiter(devname, '/');
255 269
256 /* strip first '\' from fullpath */ 270 /* strip first '\' from fullpath */
257 mountdata = cifs_compose_mount_options(cifs_sb->mountdata, 271 mountdata = cifs_compose_mount_options(cifs_sb->mountdata,
258 fullpath + 1, ref, &devname); 272 fullpath + 1, ref, NULL);
259 273 if (IS_ERR(mountdata)) {
260 if (IS_ERR(mountdata)) 274 kfree(devname);
261 return (struct vfsmount *)mountdata; 275 return (struct vfsmount *)mountdata;
276 }
262 277
263 mnt = vfs_submount(mntpt, &cifs_fs_type, devname, mountdata); 278 mnt = vfs_submount(mntpt, &cifs_fs_type, devname, mountdata);
264 kfree(mountdata); 279 kfree(mountdata);
265 kfree(devname); 280 kfree(devname);
266 return mnt; 281 return mnt;
267
268} 282}
269 283
270static void dump_referral(const struct dfs_info3_param *ref) 284static void dump_referral(const struct dfs_info3_param *ref)
@@ -282,16 +296,15 @@ static void dump_referral(const struct dfs_info3_param *ref)
282 */ 296 */
283static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt) 297static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
284{ 298{
285 struct dfs_info3_param *referrals = NULL; 299 struct dfs_info3_param referral = {0};
286 unsigned int num_referrals = 0;
287 struct cifs_sb_info *cifs_sb; 300 struct cifs_sb_info *cifs_sb;
288 struct cifs_ses *ses; 301 struct cifs_ses *ses;
289 char *full_path; 302 struct cifs_tcon *tcon;
303 char *full_path, *root_path;
290 unsigned int xid; 304 unsigned int xid;
291 int i; 305 int len;
292 int rc; 306 int rc;
293 struct vfsmount *mnt; 307 struct vfsmount *mnt;
294 struct tcon_link *tlink;
295 308
296 cifs_dbg(FYI, "in %s\n", __func__); 309 cifs_dbg(FYI, "in %s\n", __func__);
297 BUG_ON(IS_ROOT(mntpt)); 310 BUG_ON(IS_ROOT(mntpt));
@@ -315,48 +328,69 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
315 if (full_path == NULL) 328 if (full_path == NULL)
316 goto cdda_exit; 329 goto cdda_exit;
317 330
318 tlink = cifs_sb_tlink(cifs_sb); 331 cifs_dbg(FYI, "%s: full_path: %s\n", __func__, full_path);
319 if (IS_ERR(tlink)) { 332
320 mnt = ERR_CAST(tlink); 333 if (!cifs_sb_master_tlink(cifs_sb)) {
334 cifs_dbg(FYI, "%s: master tlink is NULL\n", __func__);
321 goto free_full_path; 335 goto free_full_path;
322 } 336 }
323 ses = tlink_tcon(tlink)->ses;
324 337
338 tcon = cifs_sb_master_tcon(cifs_sb);
339 if (!tcon) {
340 cifs_dbg(FYI, "%s: master tcon is NULL\n", __func__);
341 goto free_full_path;
342 }
343
344 root_path = kstrdup(tcon->treeName, GFP_KERNEL);
345 if (!root_path) {
346 mnt = ERR_PTR(-ENOMEM);
347 goto free_full_path;
348 }
349 cifs_dbg(FYI, "%s: root path: %s\n", __func__, root_path);
350
351 ses = tcon->ses;
325 xid = get_xid(); 352 xid = get_xid();
326 rc = get_dfs_path(xid, ses, full_path + 1, cifs_sb->local_nls,
327 &num_referrals, &referrals,
328 cifs_remap(cifs_sb));
329 free_xid(xid);
330 353
331 cifs_put_tlink(tlink); 354 /*
332 355 * If DFS root has been expired, then unconditionally fetch it again to
333 mnt = ERR_PTR(-ENOENT); 356 * refresh DFS referral cache.
334 for (i = 0; i < num_referrals; i++) { 357 */
335 int len; 358 rc = dfs_cache_find(xid, ses, cifs_sb->local_nls, cifs_remap(cifs_sb),
336 dump_referral(referrals + i); 359 root_path + 1, NULL, NULL);
337 /* connect to a node */ 360 if (!rc) {
338 len = strlen(referrals[i].node_name); 361 rc = dfs_cache_find(xid, ses, cifs_sb->local_nls,
339 if (len < 2) { 362 cifs_remap(cifs_sb), full_path + 1,
340 cifs_dbg(VFS, "%s: Net Address path too short: %s\n", 363 &referral, NULL);
341 __func__, referrals[i].node_name);
342 mnt = ERR_PTR(-EINVAL);
343 break;
344 }
345 mnt = cifs_dfs_do_refmount(mntpt, cifs_sb,
346 full_path, referrals + i);
347 cifs_dbg(FYI, "%s: cifs_dfs_do_refmount:%s , mnt:%p\n",
348 __func__, referrals[i].node_name, mnt);
349 if (!IS_ERR(mnt))
350 goto success;
351 } 364 }
352 365
353 /* no valid submounts were found; return error from get_dfs_path() by 366 free_xid(xid);
354 * preference */ 367
355 if (rc != 0) 368 if (rc) {
356 mnt = ERR_PTR(rc); 369 mnt = ERR_PTR(rc);
370 goto free_root_path;
371 }
372
373 dump_referral(&referral);
357 374
358success: 375 len = strlen(referral.node_name);
359 free_dfs_info_array(referrals, num_referrals); 376 if (len < 2) {
377 cifs_dbg(VFS, "%s: Net Address path too short: %s\n",
378 __func__, referral.node_name);
379 mnt = ERR_PTR(-EINVAL);
380 goto free_dfs_ref;
381 }
382 /*
383 * cifs_mount() will retry every available node server in case
384 * of failures.
385 */
386 mnt = cifs_dfs_do_refmount(mntpt, cifs_sb, full_path, &referral);
387 cifs_dbg(FYI, "%s: cifs_dfs_do_refmount:%s , mnt:%p\n", __func__,
388 referral.node_name, mnt);
389
390free_dfs_ref:
391 free_dfs_info_param(&referral);
392free_root_path:
393 kfree(root_path);
360free_full_path: 394free_full_path:
361 kfree(full_path); 395 kfree(full_path);
362cdda_exit: 396cdda_exit:
diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h
index 63d7530f2e1d..42f0d67f1054 100644
--- a/fs/cifs/cifs_fs_sb.h
+++ b/fs/cifs/cifs_fs_sb.h
@@ -72,6 +72,15 @@ struct cifs_sb_info {
72 char *mountdata; /* options received at mount time or via DFS refs */ 72 char *mountdata; /* options received at mount time or via DFS refs */
73 struct delayed_work prune_tlinks; 73 struct delayed_work prune_tlinks;
74 struct rcu_head rcu; 74 struct rcu_head rcu;
75
76 /* only used when CIFS_MOUNT_USE_PREFIX_PATH is set */
75 char *prepath; 77 char *prepath;
78
79 /*
80 * Path initially provided by the mount call. We might connect
81 * to something different via DFS but we want to keep it to do
82 * failover properly.
83 */
84 char *origin_fullpath; /* \\HOST\SHARE\[OPTIONAL PATH] */
76}; 85};
77#endif /* _CIFS_FS_SB_H */ 86#endif /* _CIFS_FS_SB_H */
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
index 85b31cfa2f3c..d2a05e46d6f5 100644
--- a/fs/cifs/cifsencrypt.c
+++ b/fs/cifs/cifsencrypt.c
@@ -224,7 +224,7 @@ int cifs_verify_signature(struct smb_rqst *rqst,
224 if (cifs_pdu->Command == SMB_COM_LOCKING_ANDX) { 224 if (cifs_pdu->Command == SMB_COM_LOCKING_ANDX) {
225 struct smb_com_lock_req *pSMB = 225 struct smb_com_lock_req *pSMB =
226 (struct smb_com_lock_req *)cifs_pdu; 226 (struct smb_com_lock_req *)cifs_pdu;
227 if (pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE) 227 if (pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE)
228 return 0; 228 return 0;
229 } 229 }
230 230
@@ -304,12 +304,17 @@ int setup_ntlm_response(struct cifs_ses *ses, const struct nls_table *nls_cp)
304int calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt, 304int calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt,
305 char *lnm_session_key) 305 char *lnm_session_key)
306{ 306{
307 int i; 307 int i, len;
308 int rc; 308 int rc;
309 char password_with_pad[CIFS_ENCPWD_SIZE] = {0}; 309 char password_with_pad[CIFS_ENCPWD_SIZE] = {0};
310 310
311 if (password) 311 if (password) {
312 strncpy(password_with_pad, password, CIFS_ENCPWD_SIZE); 312 for (len = 0; len < CIFS_ENCPWD_SIZE; len++)
313 if (!password[len])
314 break;
315
316 memcpy(password_with_pad, password, len);
317 }
313 318
314 if (!encrypt && global_secflags & CIFSSEC_MAY_PLNTXT) { 319 if (!encrypt && global_secflags & CIFSSEC_MAY_PLNTXT) {
315 memcpy(lnm_session_key, password_with_pad, 320 memcpy(lnm_session_key, password_with_pad,
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 865706edb307..62d48d486d8f 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -52,6 +52,9 @@
52#include "cifs_spnego.h" 52#include "cifs_spnego.h"
53#include "fscache.h" 53#include "fscache.h"
54#include "smb2pdu.h" 54#include "smb2pdu.h"
55#ifdef CONFIG_CIFS_DFS_UPCALL
56#include "dfs_cache.h"
57#endif
55 58
56int cifsFYI = 0; 59int cifsFYI = 0;
57bool traceSMB; 60bool traceSMB;
@@ -1494,10 +1497,15 @@ init_cifs(void)
1494 if (rc) 1497 if (rc)
1495 goto out_destroy_mids; 1498 goto out_destroy_mids;
1496 1499
1500#ifdef CONFIG_CIFS_DFS_UPCALL
1501 rc = dfs_cache_init();
1502 if (rc)
1503 goto out_destroy_request_bufs;
1504#endif /* CONFIG_CIFS_DFS_UPCALL */
1497#ifdef CONFIG_CIFS_UPCALL 1505#ifdef CONFIG_CIFS_UPCALL
1498 rc = init_cifs_spnego(); 1506 rc = init_cifs_spnego();
1499 if (rc) 1507 if (rc)
1500 goto out_destroy_request_bufs; 1508 goto out_destroy_dfs_cache;
1501#endif /* CONFIG_CIFS_UPCALL */ 1509#endif /* CONFIG_CIFS_UPCALL */
1502 1510
1503#ifdef CONFIG_CIFS_ACL 1511#ifdef CONFIG_CIFS_ACL
@@ -1525,6 +1533,10 @@ out_register_key_type:
1525#endif 1533#endif
1526#ifdef CONFIG_CIFS_UPCALL 1534#ifdef CONFIG_CIFS_UPCALL
1527 exit_cifs_spnego(); 1535 exit_cifs_spnego();
1536out_destroy_dfs_cache:
1537#endif
1538#ifdef CONFIG_CIFS_DFS_UPCALL
1539 dfs_cache_destroy();
1528out_destroy_request_bufs: 1540out_destroy_request_bufs:
1529#endif 1541#endif
1530 cifs_destroy_request_bufs(); 1542 cifs_destroy_request_bufs();
@@ -1556,6 +1568,9 @@ exit_cifs(void)
1556#ifdef CONFIG_CIFS_UPCALL 1568#ifdef CONFIG_CIFS_UPCALL
1557 exit_cifs_spnego(); 1569 exit_cifs_spnego();
1558#endif 1570#endif
1571#ifdef CONFIG_CIFS_DFS_UPCALL
1572 dfs_cache_destroy();
1573#endif
1559 cifs_destroy_request_bufs(); 1574 cifs_destroy_request_bufs();
1560 cifs_destroy_mids(); 1575 cifs_destroy_mids();
1561 cifs_destroy_inodecache(); 1576 cifs_destroy_inodecache();
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index 4c3b5cfccc49..26776eddd85d 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -150,5 +150,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
150extern const struct export_operations cifs_export_ops; 150extern const struct export_operations cifs_export_ops;
151#endif /* CONFIG_CIFS_NFSD_EXPORT */ 151#endif /* CONFIG_CIFS_NFSD_EXPORT */
152 152
153#define CIFS_VERSION "2.14" 153#define CIFS_VERSION "2.15"
154#endif /* _CIFSFS_H */ 154#endif /* _CIFSFS_H */
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 38ab0fca49e1..01ded7038b19 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -701,6 +701,13 @@ struct TCP_Server_Info {
701 struct delayed_work reconnect; /* reconnect workqueue job */ 701 struct delayed_work reconnect; /* reconnect workqueue job */
702 struct mutex reconnect_mutex; /* prevent simultaneous reconnects */ 702 struct mutex reconnect_mutex; /* prevent simultaneous reconnects */
703 unsigned long echo_interval; 703 unsigned long echo_interval;
704
705 /*
706 * Number of targets available for reconnect. The more targets
707 * the more tasks have to wait to let the demultiplex thread
708 * reconnect.
709 */
710 int nr_targets;
704}; 711};
705 712
706static inline unsigned int 713static inline unsigned int
@@ -1014,6 +1021,11 @@ struct cifs_tcon {
1014 struct list_head pending_opens; /* list of incomplete opens */ 1021 struct list_head pending_opens; /* list of incomplete opens */
1015 struct cached_fid crfid; /* Cached root fid */ 1022 struct cached_fid crfid; /* Cached root fid */
1016 /* BB add field for back pointer to sb struct(s)? */ 1023 /* BB add field for back pointer to sb struct(s)? */
1024#ifdef CONFIG_CIFS_DFS_UPCALL
1025 char *dfs_path;
1026 int remap:2;
1027 struct list_head ulist; /* cache update list */
1028#endif
1017}; 1029};
1018 1030
1019/* 1031/*
@@ -1508,6 +1520,7 @@ struct dfs_info3_param {
1508 int ref_flag; 1520 int ref_flag;
1509 char *path_name; 1521 char *path_name;
1510 char *node_name; 1522 char *node_name;
1523 int ttl;
1511}; 1524};
1512 1525
1513/* 1526/*
@@ -1545,7 +1558,6 @@ static inline void free_dfs_info_param(struct dfs_info3_param *param)
1545 if (param) { 1558 if (param) {
1546 kfree(param->path_name); 1559 kfree(param->path_name);
1547 kfree(param->node_name); 1560 kfree(param->node_name);
1548 kfree(param);
1549 } 1561 }
1550} 1562}
1551 1563
@@ -1790,6 +1802,7 @@ extern struct smb_version_values smb3any_values;
1790extern struct smb_version_operations smb30_operations; 1802extern struct smb_version_operations smb30_operations;
1791extern struct smb_version_values smb30_values; 1803extern struct smb_version_values smb30_values;
1792#define SMB302_VERSION_STRING "3.02" 1804#define SMB302_VERSION_STRING "3.02"
1805#define ALT_SMB302_VERSION_STRING "3.0.2"
1793/*extern struct smb_version_operations smb302_operations;*/ /* not needed yet */ 1806/*extern struct smb_version_operations smb302_operations;*/ /* not needed yet */
1794extern struct smb_version_values smb302_values; 1807extern struct smb_version_values smb302_values;
1795#define SMB311_VERSION_STRING "3.1.1" 1808#define SMB311_VERSION_STRING "3.1.1"
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index fa361bc00602..336c116995d7 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -22,6 +22,9 @@
22#define _CIFSPROTO_H 22#define _CIFSPROTO_H
23#include <linux/nls.h> 23#include <linux/nls.h>
24#include "trace.h" 24#include "trace.h"
25#ifdef CONFIG_CIFS_DFS_UPCALL
26#include "dfs_cache.h"
27#endif
25 28
26struct statfs; 29struct statfs;
27struct smb_vol; 30struct smb_vol;
@@ -213,7 +216,7 @@ extern int cifs_match_super(struct super_block *, void *);
213extern void cifs_cleanup_volume_info(struct smb_vol *pvolume_info); 216extern void cifs_cleanup_volume_info(struct smb_vol *pvolume_info);
214extern struct smb_vol *cifs_get_volume_info(char *mount_data, 217extern struct smb_vol *cifs_get_volume_info(char *mount_data,
215 const char *devname, bool is_smb3); 218 const char *devname, bool is_smb3);
216extern int cifs_mount(struct cifs_sb_info *, struct smb_vol *); 219extern int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *vol);
217extern void cifs_umount(struct cifs_sb_info *); 220extern void cifs_umount(struct cifs_sb_info *);
218extern void cifs_mark_open_files_invalid(struct cifs_tcon *tcon); 221extern void cifs_mark_open_files_invalid(struct cifs_tcon *tcon);
219extern void cifs_reopen_persistent_handles(struct cifs_tcon *tcon); 222extern void cifs_reopen_persistent_handles(struct cifs_tcon *tcon);
@@ -294,11 +297,6 @@ extern int CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
294 unsigned int *num_of_nodes, 297 unsigned int *num_of_nodes,
295 const struct nls_table *nls_codepage, int remap); 298 const struct nls_table *nls_codepage, int remap);
296 299
297extern int get_dfs_path(const unsigned int xid, struct cifs_ses *ses,
298 const char *old_path,
299 const struct nls_table *nls_codepage,
300 unsigned int *num_referrals,
301 struct dfs_info3_param **referrals, int remap);
302extern int parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size, 300extern int parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size,
303 unsigned int *num_of_nodes, 301 unsigned int *num_of_nodes,
304 struct dfs_info3_param **target_nodes, 302 struct dfs_info3_param **target_nodes,
@@ -524,6 +522,11 @@ extern int E_md4hash(const unsigned char *passwd, unsigned char *p16,
524 const struct nls_table *codepage); 522 const struct nls_table *codepage);
525extern int SMBencrypt(unsigned char *passwd, const unsigned char *c8, 523extern int SMBencrypt(unsigned char *passwd, const unsigned char *c8,
526 unsigned char *p24); 524 unsigned char *p24);
525extern void
526cifs_cleanup_volume_info_contents(struct smb_vol *volume_info);
527
528extern struct TCP_Server_Info *
529cifs_find_tcp_session(struct smb_vol *vol);
527 530
528void cifs_readdata_release(struct kref *refcount); 531void cifs_readdata_release(struct kref *refcount);
529int cifs_async_readv(struct cifs_readdata *rdata); 532int cifs_async_readv(struct cifs_readdata *rdata);
@@ -562,4 +565,17 @@ void cifs_free_hash(struct crypto_shash **shash, struct sdesc **sdesc);
562extern void rqst_page_get_length(struct smb_rqst *rqst, unsigned int page, 565extern void rqst_page_get_length(struct smb_rqst *rqst, unsigned int page,
563 unsigned int *len, unsigned int *offset); 566 unsigned int *len, unsigned int *offset);
564 567
568void extract_unc_hostname(const char *unc, const char **h, size_t *len);
569
570#ifdef CONFIG_CIFS_DFS_UPCALL
571static inline int get_dfs_path(const unsigned int xid, struct cifs_ses *ses,
572 const char *old_path,
573 const struct nls_table *nls_codepage,
574 struct dfs_info3_param *referral, int remap)
575{
576 return dfs_cache_find(xid, ses, nls_codepage, remap, old_path,
577 referral, NULL);
578}
579#endif
580
565#endif /* _CIFSPROTO_H */ 581#endif /* _CIFSPROTO_H */
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index f82fd342bca5..b1f49c1c543a 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -44,6 +44,9 @@
44#include "cifs_debug.h" 44#include "cifs_debug.h"
45#include "fscache.h" 45#include "fscache.h"
46#include "smbdirect.h" 46#include "smbdirect.h"
47#ifdef CONFIG_CIFS_DFS_UPCALL
48#include "dfs_cache.h"
49#endif
47 50
48#ifdef CONFIG_CIFS_POSIX 51#ifdef CONFIG_CIFS_POSIX
49static struct { 52static struct {
@@ -118,6 +121,77 @@ cifs_mark_open_files_invalid(struct cifs_tcon *tcon)
118 */ 121 */
119} 122}
120 123
124#ifdef CONFIG_CIFS_DFS_UPCALL
125static int __cifs_reconnect_tcon(const struct nls_table *nlsc,
126 struct cifs_tcon *tcon)
127{
128 int rc;
129 struct dfs_cache_tgt_list tl;
130 struct dfs_cache_tgt_iterator *it = NULL;
131 char tree[MAX_TREE_SIZE + 1];
132 const char *tcp_host;
133 size_t tcp_host_len;
134 const char *dfs_host;
135 size_t dfs_host_len;
136
137 if (tcon->ipc) {
138 snprintf(tree, sizeof(tree), "\\\\%s\\IPC$",
139 tcon->ses->server->hostname);
140 return CIFSTCon(0, tcon->ses, tree, tcon, nlsc);
141 }
142
143 if (!tcon->dfs_path)
144 return CIFSTCon(0, tcon->ses, tcon->treeName, tcon, nlsc);
145
146 rc = dfs_cache_noreq_find(tcon->dfs_path + 1, NULL, &tl);
147 if (rc)
148 return rc;
149
150 extract_unc_hostname(tcon->ses->server->hostname, &tcp_host,
151 &tcp_host_len);
152
153 for (it = dfs_cache_get_tgt_iterator(&tl); it;
154 it = dfs_cache_get_next_tgt(&tl, it)) {
155 const char *tgt = dfs_cache_get_tgt_name(it);
156
157 extract_unc_hostname(tgt, &dfs_host, &dfs_host_len);
158
159 if (dfs_host_len != tcp_host_len
160 || strncasecmp(dfs_host, tcp_host, dfs_host_len) != 0) {
161 cifs_dbg(FYI, "%s: skipping %.*s, doesn't match %.*s",
162 __func__,
163 (int)dfs_host_len, dfs_host,
164 (int)tcp_host_len, tcp_host);
165 continue;
166 }
167
168 snprintf(tree, sizeof(tree), "\\%s", tgt);
169
170 rc = CIFSTCon(0, tcon->ses, tree, tcon, nlsc);
171 if (!rc)
172 break;
173 if (rc == -EREMOTE)
174 break;
175 }
176
177 if (!rc) {
178 if (it)
179 rc = dfs_cache_noreq_update_tgthint(tcon->dfs_path + 1,
180 it);
181 else
182 rc = -ENOENT;
183 }
184 dfs_cache_free_tgts(&tl);
185 return rc;
186}
187#else
188static inline int __cifs_reconnect_tcon(const struct nls_table *nlsc,
189 struct cifs_tcon *tcon)
190{
191 return CIFSTCon(0, tcon->ses, tcon->treeName, tcon, nlsc);
192}
193#endif
194
121/* reconnect the socket, tcon, and smb session if needed */ 195/* reconnect the socket, tcon, and smb session if needed */
122static int 196static int
123cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command) 197cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
@@ -126,6 +200,7 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
126 struct cifs_ses *ses; 200 struct cifs_ses *ses;
127 struct TCP_Server_Info *server; 201 struct TCP_Server_Info *server;
128 struct nls_table *nls_codepage; 202 struct nls_table *nls_codepage;
203 int retries;
129 204
130 /* 205 /*
131 * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for 206 * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
@@ -152,9 +227,12 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
152 } 227 }
153 } 228 }
154 229
230 retries = server->nr_targets;
231
155 /* 232 /*
156 * Give demultiplex thread up to 10 seconds to reconnect, should be 233 * Give demultiplex thread up to 10 seconds to each target available for
157 * greater than cifs socket timeout which is 7 seconds 234 * reconnect -- should be greater than cifs socket timeout which is 7
235 * seconds.
158 */ 236 */
159 while (server->tcpStatus == CifsNeedReconnect) { 237 while (server->tcpStatus == CifsNeedReconnect) {
160 rc = wait_event_interruptible_timeout(server->response_q, 238 rc = wait_event_interruptible_timeout(server->response_q,
@@ -170,6 +248,9 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
170 if (server->tcpStatus != CifsNeedReconnect) 248 if (server->tcpStatus != CifsNeedReconnect)
171 break; 249 break;
172 250
251 if (--retries)
252 continue;
253
173 /* 254 /*
174 * on "soft" mounts we wait once. Hard mounts keep 255 * on "soft" mounts we wait once. Hard mounts keep
175 * retrying until process is killed or server comes 256 * retrying until process is killed or server comes
@@ -179,6 +260,7 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
179 cifs_dbg(FYI, "gave up waiting on reconnect in smb_init\n"); 260 cifs_dbg(FYI, "gave up waiting on reconnect in smb_init\n");
180 return -EHOSTDOWN; 261 return -EHOSTDOWN;
181 } 262 }
263 retries = server->nr_targets;
182 } 264 }
183 265
184 if (!ses->need_reconnect && !tcon->need_reconnect) 266 if (!ses->need_reconnect && !tcon->need_reconnect)
@@ -214,7 +296,7 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
214 } 296 }
215 297
216 cifs_mark_open_files_invalid(tcon); 298 cifs_mark_open_files_invalid(tcon);
217 rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage); 299 rc = __cifs_reconnect_tcon(nls_codepage, tcon);
218 mutex_unlock(&ses->session_mutex); 300 mutex_unlock(&ses->session_mutex);
219 cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc); 301 cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc);
220 302
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 6f24f129a751..69b9d5606eba 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -56,6 +56,11 @@
56#include "fscache.h" 56#include "fscache.h"
57#include "smb2proto.h" 57#include "smb2proto.h"
58#include "smbdirect.h" 58#include "smbdirect.h"
59#include "dns_resolve.h"
60#include "cifsfs.h"
61#ifdef CONFIG_CIFS_DFS_UPCALL
62#include "dfs_cache.h"
63#endif
59 64
60extern mempool_t *cifs_req_poolp; 65extern mempool_t *cifs_req_poolp;
61extern bool disable_legacy_dialects; 66extern bool disable_legacy_dialects;
@@ -304,6 +309,7 @@ static const match_table_t cifs_smb_version_tokens = {
304 { Smb_21, SMB21_VERSION_STRING }, 309 { Smb_21, SMB21_VERSION_STRING },
305 { Smb_30, SMB30_VERSION_STRING }, 310 { Smb_30, SMB30_VERSION_STRING },
306 { Smb_302, SMB302_VERSION_STRING }, 311 { Smb_302, SMB302_VERSION_STRING },
312 { Smb_302, ALT_SMB302_VERSION_STRING },
307 { Smb_311, SMB311_VERSION_STRING }, 313 { Smb_311, SMB311_VERSION_STRING },
308 { Smb_311, ALT_SMB311_VERSION_STRING }, 314 { Smb_311, ALT_SMB311_VERSION_STRING },
309 { Smb_3any, SMB3ANY_VERSION_STRING }, 315 { Smb_3any, SMB3ANY_VERSION_STRING },
@@ -317,6 +323,131 @@ static void tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink);
317static void cifs_prune_tlinks(struct work_struct *work); 323static void cifs_prune_tlinks(struct work_struct *work);
318static int cifs_setup_volume_info(struct smb_vol *volume_info, char *mount_data, 324static int cifs_setup_volume_info(struct smb_vol *volume_info, char *mount_data,
319 const char *devname, bool is_smb3); 325 const char *devname, bool is_smb3);
326static char *extract_hostname(const char *unc);
327
328/*
329 * Resolve hostname and set ip addr in tcp ses. Useful for hostnames that may
330 * get their ip addresses changed at some point.
331 *
332 * This should be called with server->srv_mutex held.
333 */
334#ifdef CONFIG_CIFS_DFS_UPCALL
335static int reconn_set_ipaddr(struct TCP_Server_Info *server)
336{
337 int rc;
338 int len;
339 char *unc, *ipaddr = NULL;
340
341 if (!server->hostname)
342 return -EINVAL;
343
344 len = strlen(server->hostname) + 3;
345
346 unc = kmalloc(len, GFP_KERNEL);
347 if (!unc) {
348 cifs_dbg(FYI, "%s: failed to create UNC path\n", __func__);
349 return -ENOMEM;
350 }
351 snprintf(unc, len, "\\\\%s", server->hostname);
352
353 rc = dns_resolve_server_name_to_ip(unc, &ipaddr);
354 kfree(unc);
355
356 if (rc < 0) {
357 cifs_dbg(FYI, "%s: failed to resolve server part of %s to IP: %d\n",
358 __func__, server->hostname, rc);
359 return rc;
360 }
361
362 rc = cifs_convert_address((struct sockaddr *)&server->dstaddr, ipaddr,
363 strlen(ipaddr));
364 kfree(ipaddr);
365
366 return !rc ? -1 : 0;
367}
368#else
369static inline int reconn_set_ipaddr(struct TCP_Server_Info *server)
370{
371 return 0;
372}
373#endif
374
375#ifdef CONFIG_CIFS_DFS_UPCALL
376struct super_cb_data {
377 struct TCP_Server_Info *server;
378 struct cifs_sb_info *cifs_sb;
379};
380
381/* These functions must be called with server->srv_mutex held */
382
383static void super_cb(struct super_block *sb, void *arg)
384{
385 struct super_cb_data *d = arg;
386 struct cifs_sb_info *cifs_sb;
387 struct cifs_tcon *tcon;
388
389 if (d->cifs_sb)
390 return;
391
392 cifs_sb = CIFS_SB(sb);
393 tcon = cifs_sb_master_tcon(cifs_sb);
394 if (tcon->ses->server == d->server)
395 d->cifs_sb = cifs_sb;
396}
397
398static inline struct cifs_sb_info *
399find_super_by_tcp(struct TCP_Server_Info *server)
400{
401 struct super_cb_data d = {
402 .server = server,
403 .cifs_sb = NULL,
404 };
405
406 iterate_supers_type(&cifs_fs_type, super_cb, &d);
407 return d.cifs_sb ? d.cifs_sb : ERR_PTR(-ENOENT);
408}
409
410static void reconn_inval_dfs_target(struct TCP_Server_Info *server,
411 struct cifs_sb_info *cifs_sb,
412 struct dfs_cache_tgt_list *tgt_list,
413 struct dfs_cache_tgt_iterator **tgt_it)
414{
415 const char *name;
416
417 if (!cifs_sb || !cifs_sb->origin_fullpath || !tgt_list ||
418 !server->nr_targets)
419 return;
420
421 if (!*tgt_it) {
422 *tgt_it = dfs_cache_get_tgt_iterator(tgt_list);
423 } else {
424 *tgt_it = dfs_cache_get_next_tgt(tgt_list, *tgt_it);
425 if (!*tgt_it)
426 *tgt_it = dfs_cache_get_tgt_iterator(tgt_list);
427 }
428
429 cifs_dbg(FYI, "%s: UNC: %s\n", __func__, cifs_sb->origin_fullpath);
430
431 name = dfs_cache_get_tgt_name(*tgt_it);
432
433 kfree(server->hostname);
434
435 server->hostname = extract_hostname(name);
436 if (!server->hostname) {
437 cifs_dbg(FYI, "%s: failed to extract hostname from target: %d\n",
438 __func__, -ENOMEM);
439 }
440}
441
442static inline int reconn_setup_dfs_targets(struct cifs_sb_info *cifs_sb,
443 struct dfs_cache_tgt_list *tl,
444 struct dfs_cache_tgt_iterator **it)
445{
446 if (!cifs_sb->origin_fullpath)
447 return -EOPNOTSUPP;
448 return dfs_cache_noreq_find(cifs_sb->origin_fullpath + 1, NULL, tl);
449}
450#endif
320 451
321/* 452/*
322 * cifs tcp session reconnection 453 * cifs tcp session reconnection
@@ -335,8 +466,33 @@ cifs_reconnect(struct TCP_Server_Info *server)
335 struct cifs_tcon *tcon; 466 struct cifs_tcon *tcon;
336 struct mid_q_entry *mid_entry; 467 struct mid_q_entry *mid_entry;
337 struct list_head retry_list; 468 struct list_head retry_list;
469#ifdef CONFIG_CIFS_DFS_UPCALL
470 struct cifs_sb_info *cifs_sb = NULL;
471 struct dfs_cache_tgt_list tgt_list = {0};
472 struct dfs_cache_tgt_iterator *tgt_it = NULL;
473#endif
338 474
339 spin_lock(&GlobalMid_Lock); 475 spin_lock(&GlobalMid_Lock);
476 server->nr_targets = 1;
477#ifdef CONFIG_CIFS_DFS_UPCALL
478 cifs_sb = find_super_by_tcp(server);
479 if (IS_ERR(cifs_sb)) {
480 rc = PTR_ERR(cifs_sb);
481 cifs_dbg(FYI, "%s: will not do DFS failover: rc = %d\n",
482 __func__, rc);
483 cifs_sb = NULL;
484 } else {
485 rc = reconn_setup_dfs_targets(cifs_sb, &tgt_list, &tgt_it);
486 if (rc) {
487 cifs_dbg(VFS, "%s: no target servers for DFS failover\n",
488 __func__);
489 } else {
490 server->nr_targets = dfs_cache_get_nr_tgts(&tgt_list);
491 }
492 }
493 cifs_dbg(FYI, "%s: will retry %d target(s)\n", __func__,
494 server->nr_targets);
495#endif
340 if (server->tcpStatus == CifsExiting) { 496 if (server->tcpStatus == CifsExiting) {
341 /* the demux thread will exit normally 497 /* the demux thread will exit normally
342 next time through the loop */ 498 next time through the loop */
@@ -410,14 +566,27 @@ cifs_reconnect(struct TCP_Server_Info *server)
410 do { 566 do {
411 try_to_freeze(); 567 try_to_freeze();
412 568
413 /* we should try only the port we connected to before */
414 mutex_lock(&server->srv_mutex); 569 mutex_lock(&server->srv_mutex);
570 /*
571 * Set up next DFS target server (if any) for reconnect. If DFS
572 * feature is disabled, then we will retry last server we
573 * connected to before.
574 */
415 if (cifs_rdma_enabled(server)) 575 if (cifs_rdma_enabled(server))
416 rc = smbd_reconnect(server); 576 rc = smbd_reconnect(server);
417 else 577 else
418 rc = generic_ip_connect(server); 578 rc = generic_ip_connect(server);
419 if (rc) { 579 if (rc) {
420 cifs_dbg(FYI, "reconnect error %d\n", rc); 580 cifs_dbg(FYI, "reconnect error %d\n", rc);
581#ifdef CONFIG_CIFS_DFS_UPCALL
582 reconn_inval_dfs_target(server, cifs_sb, &tgt_list,
583 &tgt_it);
584#endif
585 rc = reconn_set_ipaddr(server);
586 if (rc) {
587 cifs_dbg(FYI, "%s: failed to resolve hostname: %d\n",
588 __func__, rc);
589 }
421 mutex_unlock(&server->srv_mutex); 590 mutex_unlock(&server->srv_mutex);
422 msleep(3000); 591 msleep(3000);
423 } else { 592 } else {
@@ -430,6 +599,22 @@ cifs_reconnect(struct TCP_Server_Info *server)
430 } 599 }
431 } while (server->tcpStatus == CifsNeedReconnect); 600 } while (server->tcpStatus == CifsNeedReconnect);
432 601
602#ifdef CONFIG_CIFS_DFS_UPCALL
603 if (tgt_it) {
604 rc = dfs_cache_noreq_update_tgthint(cifs_sb->origin_fullpath + 1,
605 tgt_it);
606 if (rc) {
607 cifs_dbg(VFS, "%s: failed to update DFS target hint: rc = %d\n",
608 __func__, rc);
609 }
610 rc = dfs_cache_update_vol(cifs_sb->origin_fullpath, server);
611 if (rc) {
612 cifs_dbg(VFS, "%s: failed to update vol info in DFS cache: rc = %d\n",
613 __func__, rc);
614 }
615 dfs_cache_free_tgts(&tgt_list);
616 }
617#endif
433 if (server->tcpStatus == CifsNeedNegotiate) 618 if (server->tcpStatus == CifsNeedNegotiate)
434 mod_delayed_work(cifsiod_wq, &server->echo, 0); 619 mod_delayed_work(cifsiod_wq, &server->echo, 0);
435 620
@@ -1043,7 +1228,12 @@ extract_hostname(const char *unc)
1043 1228
1044 /* skip double chars at beginning of string */ 1229 /* skip double chars at beginning of string */
1045 /* BB: check validity of these bytes? */ 1230 /* BB: check validity of these bytes? */
1046 src = unc + 2; 1231 if (strlen(unc) < 3)
1232 return ERR_PTR(-EINVAL);
1233 for (src = unc; *src && *src == '\\'; src++)
1234 ;
1235 if (!*src)
1236 return ERR_PTR(-EINVAL);
1047 1237
1048 /* delimiter between hostname and sharename is always '\\' now */ 1238 /* delimiter between hostname and sharename is always '\\' now */
1049 delim = strchr(src, '\\'); 1239 delim = strchr(src, '\\');
@@ -1827,7 +2017,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
1827 vol->password = NULL; 2017 vol->password = NULL;
1828 break; 2018 break;
1829 } 2019 }
1830 /* Yes it is. Drop down to Opt_pass below.*/ 2020 /* Fallthrough - to Opt_pass below.*/
1831 case Opt_pass: 2021 case Opt_pass:
1832 /* Obtain the value string */ 2022 /* Obtain the value string */
1833 value = strchr(data, '='); 2023 value = strchr(data, '=');
@@ -2289,7 +2479,7 @@ static int match_server(struct TCP_Server_Info *server, struct smb_vol *vol)
2289 return 1; 2479 return 1;
2290} 2480}
2291 2481
2292static struct TCP_Server_Info * 2482struct TCP_Server_Info *
2293cifs_find_tcp_session(struct smb_vol *vol) 2483cifs_find_tcp_session(struct smb_vol *vol)
2294{ 2484{
2295 struct TCP_Server_Info *server; 2485 struct TCP_Server_Info *server;
@@ -2461,6 +2651,8 @@ smbd_connected:
2461 } 2651 }
2462 tcp_ses->tcpStatus = CifsNeedNegotiate; 2652 tcp_ses->tcpStatus = CifsNeedNegotiate;
2463 2653
2654 tcp_ses->nr_targets = 1;
2655
2464 /* thread spawned, put it on the list */ 2656 /* thread spawned, put it on the list */
2465 spin_lock(&cifs_tcp_ses_lock); 2657 spin_lock(&cifs_tcp_ses_lock);
2466 list_add(&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list); 2658 list_add(&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list);
@@ -3256,25 +3448,6 @@ out:
3256 return rc; 3448 return rc;
3257} 3449}
3258 3450
3259int
3260get_dfs_path(const unsigned int xid, struct cifs_ses *ses, const char *old_path,
3261 const struct nls_table *nls_codepage, unsigned int *num_referrals,
3262 struct dfs_info3_param **referrals, int remap)
3263{
3264 int rc = 0;
3265
3266 if (!ses->server->ops->get_dfs_refer)
3267 return -ENOSYS;
3268
3269 *num_referrals = 0;
3270 *referrals = NULL;
3271
3272 rc = ses->server->ops->get_dfs_refer(xid, ses, old_path,
3273 referrals, num_referrals,
3274 nls_codepage, remap);
3275 return rc;
3276}
3277
3278#ifdef CONFIG_DEBUG_LOCK_ALLOC 3451#ifdef CONFIG_DEBUG_LOCK_ALLOC
3279static struct lock_class_key cifs_key[2]; 3452static struct lock_class_key cifs_key[2];
3280static struct lock_class_key cifs_slock_key[2]; 3453static struct lock_class_key cifs_slock_key[2];
@@ -3746,8 +3919,8 @@ int cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
3746 return 0; 3919 return 0;
3747} 3920}
3748 3921
3749static void 3922void
3750cleanup_volume_info_contents(struct smb_vol *volume_info) 3923cifs_cleanup_volume_info_contents(struct smb_vol *volume_info)
3751{ 3924{
3752 kfree(volume_info->username); 3925 kfree(volume_info->username);
3753 kzfree(volume_info->password); 3926 kzfree(volume_info->password);
@@ -3762,10 +3935,136 @@ cifs_cleanup_volume_info(struct smb_vol *volume_info)
3762{ 3935{
3763 if (!volume_info) 3936 if (!volume_info)
3764 return; 3937 return;
3765 cleanup_volume_info_contents(volume_info); 3938 cifs_cleanup_volume_info_contents(volume_info);
3766 kfree(volume_info); 3939 kfree(volume_info);
3767} 3940}
3768 3941
3942/* Release all succeed connections */
3943static inline void mount_put_conns(struct cifs_sb_info *cifs_sb,
3944 unsigned int xid,
3945 struct TCP_Server_Info *server,
3946 struct cifs_ses *ses, struct cifs_tcon *tcon)
3947{
3948 int rc = 0;
3949
3950 if (tcon)
3951 cifs_put_tcon(tcon);
3952 else if (ses)
3953 cifs_put_smb_ses(ses);
3954 else if (server)
3955 cifs_put_tcp_session(server, 0);
3956 cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_POSIX_PATHS;
3957 free_xid(xid);
3958}
3959
3960/* Get connections for tcp, ses and tcon */
3961static int mount_get_conns(struct smb_vol *vol, struct cifs_sb_info *cifs_sb,
3962 unsigned int *xid,
3963 struct TCP_Server_Info **nserver,
3964 struct cifs_ses **nses, struct cifs_tcon **ntcon)
3965{
3966 int rc = 0;
3967 struct TCP_Server_Info *server;
3968 struct cifs_ses *ses;
3969 struct cifs_tcon *tcon;
3970
3971 *nserver = NULL;
3972 *nses = NULL;
3973 *ntcon = NULL;
3974
3975 *xid = get_xid();
3976
3977 /* get a reference to a tcp session */
3978 server = cifs_get_tcp_session(vol);
3979 if (IS_ERR(server)) {
3980 rc = PTR_ERR(server);
3981 return rc;
3982 }
3983
3984 *nserver = server;
3985
3986 if ((vol->max_credits < 20) || (vol->max_credits > 60000))
3987 server->max_credits = SMB2_MAX_CREDITS_AVAILABLE;
3988 else
3989 server->max_credits = vol->max_credits;
3990
3991 /* get a reference to a SMB session */
3992 ses = cifs_get_smb_ses(server, vol);
3993 if (IS_ERR(ses)) {
3994 rc = PTR_ERR(ses);
3995 return rc;
3996 }
3997
3998 *nses = ses;
3999
4000 if ((vol->persistent == true) && (!(ses->server->capabilities &
4001 SMB2_GLOBAL_CAP_PERSISTENT_HANDLES))) {
4002 cifs_dbg(VFS, "persistent handles not supported by server\n");
4003 return -EOPNOTSUPP;
4004 }
4005
4006 /* search for existing tcon to this server share */
4007 tcon = cifs_get_tcon(ses, vol);
4008 if (IS_ERR(tcon)) {
4009 rc = PTR_ERR(tcon);
4010 return rc;
4011 }
4012
4013 *ntcon = tcon;
4014
4015 /* if new SMB3.11 POSIX extensions are supported do not remap / and \ */
4016 if (tcon->posix_extensions)
4017 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_POSIX_PATHS;
4018
4019 /* tell server which Unix caps we support */
4020 if (cap_unix(tcon->ses)) {
4021 /*
4022 * reset of caps checks mount to see if unix extensions disabled
4023 * for just this mount.
4024 */
4025 reset_cifs_unix_caps(*xid, tcon, cifs_sb, vol);
4026 if ((tcon->ses->server->tcpStatus == CifsNeedReconnect) &&
4027 (le64_to_cpu(tcon->fsUnixInfo.Capability) &
4028 CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP))
4029 return -EACCES;
4030 } else
4031 tcon->unix_ext = 0; /* server does not support them */
4032
4033 /* do not care if a following call succeed - informational */
4034 if (!tcon->pipe && server->ops->qfs_tcon)
4035 server->ops->qfs_tcon(*xid, tcon);
4036
4037 cifs_sb->wsize = server->ops->negotiate_wsize(tcon, vol);
4038 cifs_sb->rsize = server->ops->negotiate_rsize(tcon, vol);
4039
4040 return 0;
4041}
4042
4043static int mount_setup_tlink(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses,
4044 struct cifs_tcon *tcon)
4045{
4046 struct tcon_link *tlink;
4047
4048 /* hang the tcon off of the superblock */
4049 tlink = kzalloc(sizeof(*tlink), GFP_KERNEL);
4050 if (tlink == NULL)
4051 return -ENOMEM;
4052
4053 tlink->tl_uid = ses->linux_uid;
4054 tlink->tl_tcon = tcon;
4055 tlink->tl_time = jiffies;
4056 set_bit(TCON_LINK_MASTER, &tlink->tl_flags);
4057 set_bit(TCON_LINK_IN_TREE, &tlink->tl_flags);
4058
4059 cifs_sb->master_tlink = tlink;
4060 spin_lock(&cifs_sb->tlink_tree_lock);
4061 tlink_rb_insert(&cifs_sb->tlink_tree, tlink);
4062 spin_unlock(&cifs_sb->tlink_tree_lock);
4063
4064 queue_delayed_work(cifsiod_wq, &cifs_sb->prune_tlinks,
4065 TLINK_IDLE_EXPIRE);
4066 return 0;
4067}
3769 4068
3770#ifdef CONFIG_CIFS_DFS_UPCALL 4069#ifdef CONFIG_CIFS_DFS_UPCALL
3771/* 4070/*
@@ -3774,10 +4073,11 @@ cifs_cleanup_volume_info(struct smb_vol *volume_info)
3774 */ 4073 */
3775static char * 4074static char *
3776build_unc_path_to_root(const struct smb_vol *vol, 4075build_unc_path_to_root(const struct smb_vol *vol,
3777 const struct cifs_sb_info *cifs_sb) 4076 const struct cifs_sb_info *cifs_sb, bool useppath)
3778{ 4077{
3779 char *full_path, *pos; 4078 char *full_path, *pos;
3780 unsigned int pplen = vol->prepath ? strlen(vol->prepath) + 1 : 0; 4079 unsigned int pplen = useppath && vol->prepath ?
4080 strlen(vol->prepath) + 1 : 0;
3781 unsigned int unc_len = strnlen(vol->UNC, MAX_TREE_SIZE + 1); 4081 unsigned int unc_len = strnlen(vol->UNC, MAX_TREE_SIZE + 1);
3782 4082
3783 full_path = kmalloc(unc_len + pplen + 1, GFP_KERNEL); 4083 full_path = kmalloc(unc_len + pplen + 1, GFP_KERNEL);
@@ -3799,8 +4099,9 @@ build_unc_path_to_root(const struct smb_vol *vol,
3799 return full_path; 4099 return full_path;
3800} 4100}
3801 4101
3802/* 4102/**
3803 * Perform a dfs referral query for a share and (optionally) prefix 4103 * expand_dfs_referral - Perform a dfs referral query and update the cifs_sb
4104 *
3804 * 4105 *
3805 * If a referral is found, cifs_sb->mountdata will be (re-)allocated 4106 * If a referral is found, cifs_sb->mountdata will be (re-)allocated
3806 * to a string containing updated options for the submount. Otherwise it 4107 * to a string containing updated options for the submount. Otherwise it
@@ -3815,39 +4116,36 @@ expand_dfs_referral(const unsigned int xid, struct cifs_ses *ses,
3815 int check_prefix) 4116 int check_prefix)
3816{ 4117{
3817 int rc; 4118 int rc;
3818 unsigned int num_referrals = 0; 4119 struct dfs_info3_param referral = {0};
3819 struct dfs_info3_param *referrals = NULL;
3820 char *full_path = NULL, *ref_path = NULL, *mdata = NULL; 4120 char *full_path = NULL, *ref_path = NULL, *mdata = NULL;
3821 4121
3822 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS) 4122 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS)
3823 return -EREMOTE; 4123 return -EREMOTE;
3824 4124
3825 full_path = build_unc_path_to_root(volume_info, cifs_sb); 4125 full_path = build_unc_path_to_root(volume_info, cifs_sb, true);
3826 if (IS_ERR(full_path)) 4126 if (IS_ERR(full_path))
3827 return PTR_ERR(full_path); 4127 return PTR_ERR(full_path);
3828 4128
3829 /* For DFS paths, skip the first '\' of the UNC */ 4129 /* For DFS paths, skip the first '\' of the UNC */
3830 ref_path = check_prefix ? full_path + 1 : volume_info->UNC + 1; 4130 ref_path = check_prefix ? full_path + 1 : volume_info->UNC + 1;
3831 4131
3832 rc = get_dfs_path(xid, ses, ref_path, cifs_sb->local_nls, 4132 rc = dfs_cache_find(xid, ses, cifs_sb->local_nls, cifs_remap(cifs_sb),
3833 &num_referrals, &referrals, cifs_remap(cifs_sb)); 4133 ref_path, &referral, NULL);
3834 4134 if (!rc) {
3835 if (!rc && num_referrals > 0) {
3836 char *fake_devname = NULL; 4135 char *fake_devname = NULL;
3837 4136
3838 mdata = cifs_compose_mount_options(cifs_sb->mountdata, 4137 mdata = cifs_compose_mount_options(cifs_sb->mountdata,
3839 full_path + 1, referrals, 4138 full_path + 1, &referral,
3840 &fake_devname); 4139 &fake_devname);
3841 4140 free_dfs_info_param(&referral);
3842 free_dfs_info_array(referrals, num_referrals);
3843 4141
3844 if (IS_ERR(mdata)) { 4142 if (IS_ERR(mdata)) {
3845 rc = PTR_ERR(mdata); 4143 rc = PTR_ERR(mdata);
3846 mdata = NULL; 4144 mdata = NULL;
3847 } else { 4145 } else {
3848 cleanup_volume_info_contents(volume_info); 4146 cifs_cleanup_volume_info_contents(volume_info);
3849 rc = cifs_setup_volume_info(volume_info, mdata, 4147 rc = cifs_setup_volume_info(volume_info, mdata,
3850 fake_devname, false); 4148 fake_devname, false);
3851 } 4149 }
3852 kfree(fake_devname); 4150 kfree(fake_devname);
3853 kfree(cifs_sb->mountdata); 4151 kfree(cifs_sb->mountdata);
@@ -3856,6 +4154,143 @@ expand_dfs_referral(const unsigned int xid, struct cifs_ses *ses,
3856 kfree(full_path); 4154 kfree(full_path);
3857 return rc; 4155 return rc;
3858} 4156}
4157
4158static inline int get_next_dfs_tgt(const char *path,
4159 struct dfs_cache_tgt_list *tgt_list,
4160 struct dfs_cache_tgt_iterator **tgt_it)
4161{
4162 if (!*tgt_it)
4163 *tgt_it = dfs_cache_get_tgt_iterator(tgt_list);
4164 else
4165 *tgt_it = dfs_cache_get_next_tgt(tgt_list, *tgt_it);
4166 return !*tgt_it ? -EHOSTDOWN : 0;
4167}
4168
4169static int update_vol_info(const struct dfs_cache_tgt_iterator *tgt_it,
4170 struct smb_vol *fake_vol, struct smb_vol *vol)
4171{
4172 const char *tgt = dfs_cache_get_tgt_name(tgt_it);
4173 int len = strlen(tgt) + 2;
4174 char *new_unc;
4175
4176 new_unc = kmalloc(len, GFP_KERNEL);
4177 if (!new_unc)
4178 return -ENOMEM;
4179 snprintf(new_unc, len, "\\%s", tgt);
4180
4181 kfree(vol->UNC);
4182 vol->UNC = new_unc;
4183
4184 if (fake_vol->prepath) {
4185 kfree(vol->prepath);
4186 vol->prepath = fake_vol->prepath;
4187 fake_vol->prepath = NULL;
4188 }
4189 memcpy(&vol->dstaddr, &fake_vol->dstaddr, sizeof(vol->dstaddr));
4190
4191 return 0;
4192}
4193
4194static int setup_dfs_tgt_conn(const char *path,
4195 const struct dfs_cache_tgt_iterator *tgt_it,
4196 struct cifs_sb_info *cifs_sb,
4197 struct smb_vol *vol,
4198 unsigned int *xid,
4199 struct TCP_Server_Info **server,
4200 struct cifs_ses **ses,
4201 struct cifs_tcon **tcon)
4202{
4203 int rc;
4204 struct dfs_info3_param ref = {0};
4205 char *mdata = NULL, *fake_devname = NULL;
4206 struct smb_vol fake_vol = {0};
4207
4208 cifs_dbg(FYI, "%s: dfs path: %s\n", __func__, path);
4209
4210 rc = dfs_cache_get_tgt_referral(path, tgt_it, &ref);
4211 if (rc)
4212 return rc;
4213
4214 mdata = cifs_compose_mount_options(cifs_sb->mountdata, path, &ref,
4215 &fake_devname);
4216 free_dfs_info_param(&ref);
4217
4218 if (IS_ERR(mdata)) {
4219 rc = PTR_ERR(mdata);
4220 mdata = NULL;
4221 } else {
4222 cifs_dbg(FYI, "%s: fake_devname: %s\n", __func__, fake_devname);
4223 rc = cifs_setup_volume_info(&fake_vol, mdata, fake_devname,
4224 false);
4225 }
4226 kfree(mdata);
4227 kfree(fake_devname);
4228
4229 if (!rc) {
4230 /*
4231 * We use a 'fake_vol' here because we need pass it down to the
4232 * mount_{get,put} functions to test connection against new DFS
4233 * targets.
4234 */
4235 mount_put_conns(cifs_sb, *xid, *server, *ses, *tcon);
4236 rc = mount_get_conns(&fake_vol, cifs_sb, xid, server, ses,
4237 tcon);
4238 if (!rc) {
4239 /*
4240 * We were able to connect to new target server.
4241 * Update current volume info with new target server.
4242 */
4243 rc = update_vol_info(tgt_it, &fake_vol, vol);
4244 }
4245 }
4246 cifs_cleanup_volume_info_contents(&fake_vol);
4247 return rc;
4248}
4249
4250static int mount_do_dfs_failover(const char *path,
4251 struct cifs_sb_info *cifs_sb,
4252 struct smb_vol *vol,
4253 struct cifs_ses *root_ses,
4254 unsigned int *xid,
4255 struct TCP_Server_Info **server,
4256 struct cifs_ses **ses,
4257 struct cifs_tcon **tcon)
4258{
4259 int rc;
4260 struct dfs_cache_tgt_list tgt_list;
4261 struct dfs_cache_tgt_iterator *tgt_it = NULL;
4262
4263 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS)
4264 return -EOPNOTSUPP;
4265
4266 rc = dfs_cache_noreq_find(path, NULL, &tgt_list);
4267 if (rc)
4268 return rc;
4269
4270 for (;;) {
4271 /* Get next DFS target server - if any */
4272 rc = get_next_dfs_tgt(path, &tgt_list, &tgt_it);
4273 if (rc)
4274 break;
4275 /* Connect to next DFS target */
4276 rc = setup_dfs_tgt_conn(path, tgt_it, cifs_sb, vol, xid, server,
4277 ses, tcon);
4278 if (!rc || rc == -EACCES || rc == -EOPNOTSUPP)
4279 break;
4280 }
4281 if (!rc) {
4282 /*
4283 * Update DFS target hint in DFS referral cache with the target
4284 * server we successfully reconnected to.
4285 */
4286 rc = dfs_cache_update_tgthint(*xid, root_ses ? root_ses : *ses,
4287 cifs_sb->local_nls,
4288 cifs_remap(cifs_sb), path,
4289 tgt_it);
4290 }
4291 dfs_cache_free_tgts(&tgt_list);
4292 return rc;
4293}
3859#endif 4294#endif
3860 4295
3861static int 4296static int
@@ -3954,107 +4389,108 @@ cifs_are_all_path_components_accessible(struct TCP_Server_Info *server,
3954 return rc; 4389 return rc;
3955} 4390}
3956 4391
3957int 4392/*
3958cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *volume_info) 4393 * Check if path is remote (e.g. a DFS share). Return -EREMOTE if it is,
4394 * otherwise 0.
4395 */
4396static int is_path_remote(struct cifs_sb_info *cifs_sb, struct smb_vol *vol,
4397 const unsigned int xid,
4398 struct TCP_Server_Info *server,
4399 struct cifs_tcon *tcon)
3959{ 4400{
3960 int rc; 4401 int rc;
3961 unsigned int xid; 4402 char *full_path;
3962 struct cifs_ses *ses;
3963 struct cifs_tcon *tcon;
3964 struct TCP_Server_Info *server;
3965 char *full_path;
3966 struct tcon_link *tlink;
3967#ifdef CONFIG_CIFS_DFS_UPCALL
3968 int referral_walks_count = 0;
3969#endif
3970 4403
3971#ifdef CONFIG_CIFS_DFS_UPCALL 4404 if (!server->ops->is_path_accessible)
3972try_mount_again: 4405 return -EOPNOTSUPP;
3973 /* cleanup activities if we're chasing a referral */
3974 if (referral_walks_count) {
3975 if (tcon)
3976 cifs_put_tcon(tcon);
3977 else if (ses)
3978 cifs_put_smb_ses(ses);
3979 4406
3980 cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_POSIX_PATHS; 4407 /*
3981 4408 * cifs_build_path_to_root works only when we have a valid tcon
3982 free_xid(xid); 4409 */
3983 } 4410 full_path = cifs_build_path_to_root(vol, cifs_sb, tcon,
3984#endif 4411 tcon->Flags & SMB_SHARE_IS_IN_DFS);
3985 rc = 0; 4412 if (full_path == NULL)
3986 tcon = NULL; 4413 return -ENOMEM;
3987 ses = NULL;
3988 server = NULL;
3989 full_path = NULL;
3990 tlink = NULL;
3991 4414
3992 xid = get_xid(); 4415 cifs_dbg(FYI, "%s: full_path: %s\n", __func__, full_path);
3993 4416
3994 /* get a reference to a tcp session */ 4417 rc = server->ops->is_path_accessible(xid, tcon, cifs_sb,
3995 server = cifs_get_tcp_session(volume_info); 4418 full_path);
3996 if (IS_ERR(server)) { 4419 if (rc != 0 && rc != -EREMOTE) {
3997 rc = PTR_ERR(server); 4420 kfree(full_path);
3998 goto out; 4421 return rc;
3999 }
4000 if ((volume_info->max_credits < 20) ||
4001 (volume_info->max_credits > 60000))
4002 server->max_credits = SMB2_MAX_CREDITS_AVAILABLE;
4003 else
4004 server->max_credits = volume_info->max_credits;
4005 /* get a reference to a SMB session */
4006 ses = cifs_get_smb_ses(server, volume_info);
4007 if (IS_ERR(ses)) {
4008 rc = PTR_ERR(ses);
4009 ses = NULL;
4010 goto mount_fail_check;
4011 } 4422 }
4012 4423
4013 if ((volume_info->persistent == true) && ((ses->server->capabilities & 4424 if (rc != -EREMOTE) {
4014 SMB2_GLOBAL_CAP_PERSISTENT_HANDLES) == 0)) { 4425 rc = cifs_are_all_path_components_accessible(server, xid, tcon,
4015 cifs_dbg(VFS, "persistent handles not supported by server\n"); 4426 cifs_sb,
4016 rc = -EOPNOTSUPP; 4427 full_path);
4017 goto mount_fail_check; 4428 if (rc != 0) {
4429 cifs_dbg(VFS, "cannot query dirs between root and final path, "
4430 "enabling CIFS_MOUNT_USE_PREFIX_PATH\n");
4431 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH;
4432 rc = 0;
4433 }
4018 } 4434 }
4019 4435
4020 /* search for existing tcon to this server share */ 4436 kfree(full_path);
4021 tcon = cifs_get_tcon(ses, volume_info); 4437 return rc;
4022 if (IS_ERR(tcon)) { 4438}
4023 rc = PTR_ERR(tcon);
4024 tcon = NULL;
4025 if (rc == -EACCES)
4026 goto mount_fail_check;
4027
4028 goto remote_path_check;
4029 }
4030 4439
4031 /* if new SMB3.11 POSIX extensions are supported do not remap / and \ */ 4440#ifdef CONFIG_CIFS_DFS_UPCALL
4032 if (tcon->posix_extensions) 4441int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *vol)
4033 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_POSIX_PATHS; 4442{
4443 int rc = 0;
4444 unsigned int xid;
4445 struct cifs_ses *ses;
4446 struct cifs_tcon *root_tcon = NULL;
4447 struct cifs_tcon *tcon = NULL;
4448 struct TCP_Server_Info *server;
4449 char *root_path = NULL, *full_path = NULL;
4450 char *old_mountdata;
4451 int count;
4034 4452
4035 /* tell server which Unix caps we support */ 4453 rc = mount_get_conns(vol, cifs_sb, &xid, &server, &ses, &tcon);
4036 if (cap_unix(tcon->ses)) { 4454 if (!rc && tcon) {
4037 /* reset of caps checks mount to see if unix extensions 4455 /* If not a standalone DFS root, then check if path is remote */
4038 disabled for just this mount */ 4456 rc = dfs_cache_find(xid, ses, cifs_sb->local_nls,
4039 reset_cifs_unix_caps(xid, tcon, cifs_sb, volume_info); 4457 cifs_remap(cifs_sb), vol->UNC + 1, NULL,
4040 if ((tcon->ses->server->tcpStatus == CifsNeedReconnect) && 4458 NULL);
4041 (le64_to_cpu(tcon->fsUnixInfo.Capability) & 4459 if (rc) {
4042 CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP)) { 4460 rc = is_path_remote(cifs_sb, vol, xid, server, tcon);
4043 rc = -EACCES; 4461 if (!rc)
4044 goto mount_fail_check; 4462 goto out;
4463 if (rc != -EREMOTE)
4464 goto error;
4045 } 4465 }
4046 } else 4466 }
4047 tcon->unix_ext = 0; /* server does not support them */ 4467 /*
4048 4468 * If first DFS target server went offline and we failed to connect it,
4049 /* do not care if a following call succeed - informational */ 4469 * server and ses pointers are NULL at this point, though we still have
4050 if (!tcon->pipe && server->ops->qfs_tcon) 4470 * chance to get a cached DFS referral in expand_dfs_referral() and
4051 server->ops->qfs_tcon(xid, tcon); 4471 * retry next target available in it.
4052 4472 *
4053 cifs_sb->wsize = server->ops->negotiate_wsize(tcon, volume_info); 4473 * If a NULL ses ptr is passed to dfs_cache_find(), a lookup will be
4054 cifs_sb->rsize = server->ops->negotiate_rsize(tcon, volume_info); 4474 * performed against DFS path and *no* requests will be sent to server
4475 * for any new DFS referrals. Hence it's safe to skip checking whether
4476 * server or ses ptr is NULL.
4477 */
4478 if (rc == -EACCES || rc == -EOPNOTSUPP)
4479 goto error;
4480
4481 root_path = build_unc_path_to_root(vol, cifs_sb, false);
4482 if (IS_ERR(root_path)) {
4483 rc = PTR_ERR(root_path);
4484 root_path = NULL;
4485 goto error;
4486 }
4055 4487
4056remote_path_check: 4488 full_path = build_unc_path_to_root(vol, cifs_sb, true);
4057#ifdef CONFIG_CIFS_DFS_UPCALL 4489 if (IS_ERR(full_path)) {
4490 rc = PTR_ERR(full_path);
4491 full_path = NULL;
4492 goto error;
4493 }
4058 /* 4494 /*
4059 * Perform an unconditional check for whether there are DFS 4495 * Perform an unconditional check for whether there are DFS
4060 * referrals for this path without prefix, to provide support 4496 * referrals for this path without prefix, to provide support
@@ -4062,119 +4498,173 @@ remote_path_check:
4062 * with PATH_NOT_COVERED to requests that include the prefix. 4498 * with PATH_NOT_COVERED to requests that include the prefix.
4063 * Chase the referral if found, otherwise continue normally. 4499 * Chase the referral if found, otherwise continue normally.
4064 */ 4500 */
4065 if (referral_walks_count == 0) { 4501 old_mountdata = cifs_sb->mountdata;
4066 int refrc = expand_dfs_referral(xid, ses, volume_info, cifs_sb, 4502 (void)expand_dfs_referral(xid, ses, vol, cifs_sb, false);
4067 false); 4503
4068 if (!refrc) { 4504 if (cifs_sb->mountdata == NULL) {
4069 referral_walks_count++; 4505 rc = -ENOENT;
4070 goto try_mount_again; 4506 goto error;
4071 }
4072 } 4507 }
4073#endif
4074 4508
4075 /* check if a whole path is not remote */ 4509 if (cifs_sb->mountdata != old_mountdata) {
4076 if (!rc && tcon) { 4510 /* If we were redirected, reconnect to new target server */
4077 if (!server->ops->is_path_accessible) { 4511 mount_put_conns(cifs_sb, xid, server, ses, tcon);
4078 rc = -ENOSYS; 4512 rc = mount_get_conns(vol, cifs_sb, &xid, &server, &ses, &tcon);
4079 goto mount_fail_check; 4513 }
4514 if (rc) {
4515 if (rc == -EACCES || rc == -EOPNOTSUPP)
4516 goto error;
4517 /* Perform DFS failover to any other DFS targets */
4518 rc = mount_do_dfs_failover(root_path + 1, cifs_sb, vol, NULL,
4519 &xid, &server, &ses, &tcon);
4520 if (rc)
4521 goto error;
4522 }
4523
4524 kfree(root_path);
4525 root_path = build_unc_path_to_root(vol, cifs_sb, false);
4526 if (IS_ERR(root_path)) {
4527 rc = PTR_ERR(root_path);
4528 root_path = NULL;
4529 goto error;
4530 }
4531 /* Cache out resolved root server */
4532 (void)dfs_cache_find(xid, ses, cifs_sb->local_nls, cifs_remap(cifs_sb),
4533 root_path + 1, NULL, NULL);
4534 /*
4535 * Save root tcon for additional DFS requests to update or create a new
4536 * DFS cache entry, or even perform DFS failover.
4537 */
4538 spin_lock(&cifs_tcp_ses_lock);
4539 tcon->tc_count++;
4540 tcon->dfs_path = root_path;
4541 root_path = NULL;
4542 tcon->remap = cifs_remap(cifs_sb);
4543 spin_unlock(&cifs_tcp_ses_lock);
4544
4545 root_tcon = tcon;
4546
4547 for (count = 1; ;) {
4548 if (!rc && tcon) {
4549 rc = is_path_remote(cifs_sb, vol, xid, server, tcon);
4550 if (!rc || rc != -EREMOTE)
4551 break;
4080 } 4552 }
4081 /* 4553 /*
4082 * cifs_build_path_to_root works only when we have a valid tcon 4554 * BB: when we implement proper loop detection,
4555 * we will remove this check. But now we need it
4556 * to prevent an indefinite loop if 'DFS tree' is
4557 * misconfigured (i.e. has loops).
4083 */ 4558 */
4084 full_path = cifs_build_path_to_root(volume_info, cifs_sb, tcon, 4559 if (count++ > MAX_NESTED_LINKS) {
4085 tcon->Flags & SMB_SHARE_IS_IN_DFS); 4560 rc = -ELOOP;
4086 if (full_path == NULL) { 4561 break;
4087 rc = -ENOMEM;
4088 goto mount_fail_check;
4089 }
4090 rc = server->ops->is_path_accessible(xid, tcon, cifs_sb,
4091 full_path);
4092 if (rc != 0 && rc != -EREMOTE) {
4093 kfree(full_path);
4094 goto mount_fail_check;
4095 } 4562 }
4096 4563
4097 if (rc != -EREMOTE) {
4098 rc = cifs_are_all_path_components_accessible(server,
4099 xid, tcon, cifs_sb,
4100 full_path);
4101 if (rc != 0) {
4102 cifs_dbg(VFS, "cannot query dirs between root and final path, "
4103 "enabling CIFS_MOUNT_USE_PREFIX_PATH\n");
4104 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH;
4105 rc = 0;
4106 }
4107 }
4108 kfree(full_path); 4564 kfree(full_path);
4109 } 4565 full_path = build_unc_path_to_root(vol, cifs_sb, true);
4110 4566 if (IS_ERR(full_path)) {
4111 /* get referral if needed */ 4567 rc = PTR_ERR(full_path);
4112 if (rc == -EREMOTE) { 4568 full_path = NULL;
4113#ifdef CONFIG_CIFS_DFS_UPCALL 4569 break;
4114 if (referral_walks_count > MAX_NESTED_LINKS) {
4115 /*
4116 * BB: when we implement proper loop detection,
4117 * we will remove this check. But now we need it
4118 * to prevent an indefinite loop if 'DFS tree' is
4119 * misconfigured (i.e. has loops).
4120 */
4121 rc = -ELOOP;
4122 goto mount_fail_check;
4123 } 4570 }
4124 4571
4125 rc = expand_dfs_referral(xid, ses, volume_info, cifs_sb, true); 4572 old_mountdata = cifs_sb->mountdata;
4573 rc = expand_dfs_referral(xid, root_tcon->ses, vol, cifs_sb,
4574 true);
4575 if (rc)
4576 break;
4126 4577
4127 if (!rc) { 4578 if (cifs_sb->mountdata != old_mountdata) {
4128 referral_walks_count++; 4579 mount_put_conns(cifs_sb, xid, server, ses, tcon);
4129 goto try_mount_again; 4580 rc = mount_get_conns(vol, cifs_sb, &xid, &server, &ses,
4581 &tcon);
4582 }
4583 if (rc) {
4584 if (rc == -EACCES || rc == -EOPNOTSUPP)
4585 break;
4586 /* Perform DFS failover to any other DFS targets */
4587 rc = mount_do_dfs_failover(full_path + 1, cifs_sb, vol,
4588 root_tcon->ses, &xid,
4589 &server, &ses, &tcon);
4590 if (rc == -EACCES || rc == -EOPNOTSUPP || !server ||
4591 !ses)
4592 goto error;
4130 } 4593 }
4131 goto mount_fail_check;
4132#else /* No DFS support, return error on mount */
4133 rc = -EOPNOTSUPP;
4134#endif
4135 } 4594 }
4595 cifs_put_tcon(root_tcon);
4136 4596
4137 if (rc) 4597 if (rc)
4138 goto mount_fail_check; 4598 goto error;
4139 4599
4140 /* now, hang the tcon off of the superblock */ 4600 spin_lock(&cifs_tcp_ses_lock);
4141 tlink = kzalloc(sizeof *tlink, GFP_KERNEL); 4601 if (!tcon->dfs_path) {
4142 if (tlink == NULL) { 4602 /* Save full path in new tcon to do failover when reconnecting tcons */
4603 tcon->dfs_path = full_path;
4604 full_path = NULL;
4605 tcon->remap = cifs_remap(cifs_sb);
4606 }
4607 cifs_sb->origin_fullpath = kstrndup(tcon->dfs_path,
4608 strlen(tcon->dfs_path),
4609 GFP_ATOMIC);
4610 if (!cifs_sb->origin_fullpath) {
4611 spin_unlock(&cifs_tcp_ses_lock);
4143 rc = -ENOMEM; 4612 rc = -ENOMEM;
4144 goto mount_fail_check; 4613 goto error;
4145 } 4614 }
4615 spin_unlock(&cifs_tcp_ses_lock);
4146 4616
4147 tlink->tl_uid = ses->linux_uid; 4617 rc = dfs_cache_add_vol(vol, cifs_sb->origin_fullpath);
4148 tlink->tl_tcon = tcon; 4618 if (rc) {
4149 tlink->tl_time = jiffies; 4619 kfree(cifs_sb->origin_fullpath);
4150 set_bit(TCON_LINK_MASTER, &tlink->tl_flags); 4620 goto error;
4151 set_bit(TCON_LINK_IN_TREE, &tlink->tl_flags); 4621 }
4622 /*
4623 * After reconnecting to a different server, unique ids won't
4624 * match anymore, so we disable serverino. This prevents
4625 * dentry revalidation to think the dentry are stale (ESTALE).
4626 */
4627 cifs_autodisable_serverino(cifs_sb);
4628out:
4629 free_xid(xid);
4630 return mount_setup_tlink(cifs_sb, ses, tcon);
4152 4631
4153 cifs_sb->master_tlink = tlink; 4632error:
4154 spin_lock(&cifs_sb->tlink_tree_lock); 4633 kfree(full_path);
4155 tlink_rb_insert(&cifs_sb->tlink_tree, tlink); 4634 kfree(root_path);
4156 spin_unlock(&cifs_sb->tlink_tree_lock); 4635 mount_put_conns(cifs_sb, xid, server, ses, tcon);
4636 return rc;
4637}
4638#else
4639int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *vol)
4640{
4641 int rc = 0;
4642 unsigned int xid;
4643 struct cifs_ses *ses;
4644 struct cifs_tcon *tcon;
4645 struct TCP_Server_Info *server;
4157 4646
4158 queue_delayed_work(cifsiod_wq, &cifs_sb->prune_tlinks, 4647 rc = mount_get_conns(vol, cifs_sb, &xid, &server, &ses, &tcon);
4159 TLINK_IDLE_EXPIRE); 4648 if (rc)
4649 goto error;
4160 4650
4161mount_fail_check: 4651 if (tcon) {
4162 /* on error free sesinfo and tcon struct if needed */ 4652 rc = is_path_remote(cifs_sb, vol, xid, server, tcon);
4163 if (rc) { 4653 if (rc == -EREMOTE)
4164 /* If find_unc succeeded then rc == 0 so we can not end */ 4654 rc = -EOPNOTSUPP;
4165 /* up accidentally freeing someone elses tcon struct */ 4655 if (rc)
4166 if (tcon) 4656 goto error;
4167 cifs_put_tcon(tcon);
4168 else if (ses)
4169 cifs_put_smb_ses(ses);
4170 else
4171 cifs_put_tcp_session(server, 0);
4172 } 4657 }
4173 4658
4174out:
4175 free_xid(xid); 4659 free_xid(xid);
4660
4661 return mount_setup_tlink(cifs_sb, ses, tcon);
4662
4663error:
4664 mount_put_conns(cifs_sb, xid, server, ses, tcon);
4176 return rc; 4665 return rc;
4177} 4666}
4667#endif
4178 4668
4179/* 4669/*
4180 * Issue a TREE_CONNECT request. 4670 * Issue a TREE_CONNECT request.
@@ -4370,6 +4860,10 @@ cifs_umount(struct cifs_sb_info *cifs_sb)
4370 4860
4371 kfree(cifs_sb->mountdata); 4861 kfree(cifs_sb->mountdata);
4372 kfree(cifs_sb->prepath); 4862 kfree(cifs_sb->prepath);
4863#ifdef CONFIG_CIFS_DFS_UPCALL
4864 dfs_cache_del_vol(cifs_sb->origin_fullpath);
4865 kfree(cifs_sb->origin_fullpath);
4866#endif
4373 call_rcu(&cifs_sb->rcu, delayed_free); 4867 call_rcu(&cifs_sb->rcu, delayed_free);
4374} 4868}
4375 4869
diff --git a/fs/cifs/dfs_cache.c b/fs/cifs/dfs_cache.c
new file mode 100644
index 000000000000..cd63c4a70875
--- /dev/null
+++ b/fs/cifs/dfs_cache.c
@@ -0,0 +1,1367 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * DFS referral cache routines
4 *
5 * Copyright (c) 2018 Paulo Alcantara <palcantara@suse.de>
6 */
7
8#include <linux/rcupdate.h>
9#include <linux/rculist.h>
10#include <linux/jhash.h>
11#include <linux/ktime.h>
12#include <linux/slab.h>
13#include <linux/nls.h>
14#include <linux/workqueue.h>
15#include "cifsglob.h"
16#include "smb2pdu.h"
17#include "smb2proto.h"
18#include "cifsproto.h"
19#include "cifs_debug.h"
20#include "cifs_unicode.h"
21#include "smb2glob.h"
22
23#include "dfs_cache.h"
24
25#define DFS_CACHE_HTABLE_SIZE 32
26#define DFS_CACHE_MAX_ENTRIES 64
27
28#define IS_INTERLINK_SET(v) ((v) & (DFSREF_REFERRAL_SERVER | \
29 DFSREF_STORAGE_SERVER))
30
31struct dfs_cache_tgt {
32 char *t_name;
33 struct list_head t_list;
34};
35
36struct dfs_cache_entry {
37 struct hlist_node ce_hlist;
38 const char *ce_path;
39 int ce_ttl;
40 int ce_srvtype;
41 int ce_flags;
42 struct timespec64 ce_etime;
43 int ce_path_consumed;
44 int ce_numtgts;
45 struct list_head ce_tlist;
46 struct dfs_cache_tgt *ce_tgthint;
47 struct rcu_head ce_rcu;
48};
49
50static struct kmem_cache *dfs_cache_slab __read_mostly;
51
52struct dfs_cache_vol_info {
53 char *vi_fullpath;
54 struct smb_vol vi_vol;
55 struct list_head vi_list;
56};
57
58struct dfs_cache {
59 struct mutex dc_lock;
60 struct nls_table *dc_nlsc;
61 struct list_head dc_vol_list;
62 int dc_ttl;
63 struct delayed_work dc_refresh;
64};
65
66static struct dfs_cache dfs_cache;
67
68/*
69 * Number of entries in the cache
70 */
71static size_t dfs_cache_count;
72
73static DEFINE_MUTEX(dfs_cache_list_lock);
74static struct hlist_head dfs_cache_htable[DFS_CACHE_HTABLE_SIZE];
75
76static void refresh_cache_worker(struct work_struct *work);
77
78static inline bool is_path_valid(const char *path)
79{
80 return path && (strchr(path + 1, '\\') || strchr(path + 1, '/'));
81}
82
83static inline int get_normalized_path(const char *path, char **npath)
84{
85 if (*path == '\\') {
86 *npath = (char *)path;
87 } else {
88 *npath = kstrndup(path, strlen(path), GFP_KERNEL);
89 if (!*npath)
90 return -ENOMEM;
91 convert_delimiter(*npath, '\\');
92 }
93 return 0;
94}
95
96static inline void free_normalized_path(const char *path, char *npath)
97{
98 if (path != npath)
99 kfree(npath);
100}
101
102static inline bool cache_entry_expired(const struct dfs_cache_entry *ce)
103{
104 struct timespec64 ts;
105
106 ktime_get_coarse_real_ts64(&ts);
107 return timespec64_compare(&ts, &ce->ce_etime) >= 0;
108}
109
110static inline void free_tgts(struct dfs_cache_entry *ce)
111{
112 struct dfs_cache_tgt *t, *n;
113
114 list_for_each_entry_safe(t, n, &ce->ce_tlist, t_list) {
115 list_del(&t->t_list);
116 kfree(t->t_name);
117 kfree(t);
118 }
119}
120
121static void free_cache_entry(struct rcu_head *rcu)
122{
123 struct dfs_cache_entry *ce = container_of(rcu, struct dfs_cache_entry,
124 ce_rcu);
125 kmem_cache_free(dfs_cache_slab, ce);
126}
127
128static inline void flush_cache_ent(struct dfs_cache_entry *ce)
129{
130 if (hlist_unhashed(&ce->ce_hlist))
131 return;
132
133 hlist_del_init_rcu(&ce->ce_hlist);
134 kfree(ce->ce_path);
135 free_tgts(ce);
136 dfs_cache_count--;
137 call_rcu(&ce->ce_rcu, free_cache_entry);
138}
139
140static void flush_cache_ents(void)
141{
142 int i;
143
144 rcu_read_lock();
145 for (i = 0; i < DFS_CACHE_HTABLE_SIZE; i++) {
146 struct hlist_head *l = &dfs_cache_htable[i];
147 struct dfs_cache_entry *ce;
148
149 hlist_for_each_entry_rcu(ce, l, ce_hlist)
150 flush_cache_ent(ce);
151 }
152 rcu_read_unlock();
153}
154
155/*
156 * dfs cache /proc file
157 */
158static int dfscache_proc_show(struct seq_file *m, void *v)
159{
160 int bucket;
161 struct dfs_cache_entry *ce;
162 struct dfs_cache_tgt *t;
163
164 seq_puts(m, "DFS cache\n---------\n");
165
166 mutex_lock(&dfs_cache_list_lock);
167
168 rcu_read_lock();
169 hash_for_each_rcu(dfs_cache_htable, bucket, ce, ce_hlist) {
170 seq_printf(m,
171 "cache entry: path=%s,type=%s,ttl=%d,etime=%ld,"
172 "interlink=%s,path_consumed=%d,expired=%s\n",
173 ce->ce_path,
174 ce->ce_srvtype == DFS_TYPE_ROOT ? "root" : "link",
175 ce->ce_ttl, ce->ce_etime.tv_nsec,
176 IS_INTERLINK_SET(ce->ce_flags) ? "yes" : "no",
177 ce->ce_path_consumed,
178 cache_entry_expired(ce) ? "yes" : "no");
179
180 list_for_each_entry(t, &ce->ce_tlist, t_list) {
181 seq_printf(m, " %s%s\n",
182 t->t_name,
183 ce->ce_tgthint == t ? " (target hint)" : "");
184 }
185
186 }
187 rcu_read_unlock();
188
189 mutex_unlock(&dfs_cache_list_lock);
190 return 0;
191}
192
193static ssize_t dfscache_proc_write(struct file *file, const char __user *buffer,
194 size_t count, loff_t *ppos)
195{
196 char c;
197 int rc;
198
199 rc = get_user(c, buffer);
200 if (rc)
201 return rc;
202
203 if (c != '0')
204 return -EINVAL;
205
206 cifs_dbg(FYI, "clearing dfs cache");
207 mutex_lock(&dfs_cache_list_lock);
208 flush_cache_ents();
209 mutex_unlock(&dfs_cache_list_lock);
210
211 return count;
212}
213
214static int dfscache_proc_open(struct inode *inode, struct file *file)
215{
216 return single_open(file, dfscache_proc_show, NULL);
217}
218
219const struct file_operations dfscache_proc_fops = {
220 .open = dfscache_proc_open,
221 .read = seq_read,
222 .llseek = seq_lseek,
223 .release = single_release,
224 .write = dfscache_proc_write,
225};
226
227#ifdef CONFIG_CIFS_DEBUG2
228static inline void dump_tgts(const struct dfs_cache_entry *ce)
229{
230 struct dfs_cache_tgt *t;
231
232 cifs_dbg(FYI, "target list:\n");
233 list_for_each_entry(t, &ce->ce_tlist, t_list) {
234 cifs_dbg(FYI, " %s%s\n", t->t_name,
235 ce->ce_tgthint == t ? " (target hint)" : "");
236 }
237}
238
239static inline void dump_ce(const struct dfs_cache_entry *ce)
240{
241 cifs_dbg(FYI, "cache entry: path=%s,type=%s,ttl=%d,etime=%ld,"
242 "interlink=%s,path_consumed=%d,expired=%s\n", ce->ce_path,
243 ce->ce_srvtype == DFS_TYPE_ROOT ? "root" : "link", ce->ce_ttl,
244 ce->ce_etime.tv_nsec,
245 IS_INTERLINK_SET(ce->ce_flags) ? "yes" : "no",
246 ce->ce_path_consumed,
247 cache_entry_expired(ce) ? "yes" : "no");
248 dump_tgts(ce);
249}
250
251static inline void dump_refs(const struct dfs_info3_param *refs, int numrefs)
252{
253 int i;
254
255 cifs_dbg(FYI, "DFS referrals returned by the server:\n");
256 for (i = 0; i < numrefs; i++) {
257 const struct dfs_info3_param *ref = &refs[i];
258
259 cifs_dbg(FYI,
260 "\n"
261 "flags: 0x%x\n"
262 "path_consumed: %d\n"
263 "server_type: 0x%x\n"
264 "ref_flag: 0x%x\n"
265 "path_name: %s\n"
266 "node_name: %s\n"
267 "ttl: %d (%dm)\n",
268 ref->flags, ref->path_consumed, ref->server_type,
269 ref->ref_flag, ref->path_name, ref->node_name,
270 ref->ttl, ref->ttl / 60);
271 }
272}
273#else
274#define dump_tgts(e)
275#define dump_ce(e)
276#define dump_refs(r, n)
277#endif
278
279/**
280 * dfs_cache_init - Initialize DFS referral cache.
281 *
282 * Return zero if initialized successfully, otherwise non-zero.
283 */
284int dfs_cache_init(void)
285{
286 int i;
287
288 dfs_cache_slab = kmem_cache_create("cifs_dfs_cache",
289 sizeof(struct dfs_cache_entry), 0,
290 SLAB_HWCACHE_ALIGN, NULL);
291 if (!dfs_cache_slab)
292 return -ENOMEM;
293
294 for (i = 0; i < DFS_CACHE_HTABLE_SIZE; i++)
295 INIT_HLIST_HEAD(&dfs_cache_htable[i]);
296
297 INIT_LIST_HEAD(&dfs_cache.dc_vol_list);
298 mutex_init(&dfs_cache.dc_lock);
299 INIT_DELAYED_WORK(&dfs_cache.dc_refresh, refresh_cache_worker);
300 dfs_cache.dc_ttl = -1;
301 dfs_cache.dc_nlsc = load_nls_default();
302
303 cifs_dbg(FYI, "%s: initialized DFS referral cache\n", __func__);
304 return 0;
305}
306
307static inline unsigned int cache_entry_hash(const void *data, int size)
308{
309 unsigned int h;
310
311 h = jhash(data, size, 0);
312 return h & (DFS_CACHE_HTABLE_SIZE - 1);
313}
314
315/* Check whether second path component of @path is SYSVOL or NETLOGON */
316static inline bool is_sysvol_or_netlogon(const char *path)
317{
318 const char *s;
319 char sep = path[0];
320
321 s = strchr(path + 1, sep) + 1;
322 return !strncasecmp(s, "sysvol", strlen("sysvol")) ||
323 !strncasecmp(s, "netlogon", strlen("netlogon"));
324}
325
326/* Return target hint of a DFS cache entry */
327static inline char *get_tgt_name(const struct dfs_cache_entry *ce)
328{
329 struct dfs_cache_tgt *t = ce->ce_tgthint;
330
331 return t ? t->t_name : ERR_PTR(-ENOENT);
332}
333
334/* Return expire time out of a new entry's TTL */
335static inline struct timespec64 get_expire_time(int ttl)
336{
337 struct timespec64 ts = {
338 .tv_sec = ttl,
339 .tv_nsec = 0,
340 };
341 struct timespec64 now;
342
343 ktime_get_coarse_real_ts64(&now);
344 return timespec64_add(now, ts);
345}
346
347/* Allocate a new DFS target */
348static inline struct dfs_cache_tgt *alloc_tgt(const char *name)
349{
350 struct dfs_cache_tgt *t;
351
352 t = kmalloc(sizeof(*t), GFP_KERNEL);
353 if (!t)
354 return ERR_PTR(-ENOMEM);
355 t->t_name = kstrndup(name, strlen(name), GFP_KERNEL);
356 if (!t->t_name) {
357 kfree(t);
358 return ERR_PTR(-ENOMEM);
359 }
360 INIT_LIST_HEAD(&t->t_list);
361 return t;
362}
363
364/*
365 * Copy DFS referral information to a cache entry and conditionally update
366 * target hint.
367 */
368static int copy_ref_data(const struct dfs_info3_param *refs, int numrefs,
369 struct dfs_cache_entry *ce, const char *tgthint)
370{
371 int i;
372
373 ce->ce_ttl = refs[0].ttl;
374 ce->ce_etime = get_expire_time(ce->ce_ttl);
375 ce->ce_srvtype = refs[0].server_type;
376 ce->ce_flags = refs[0].ref_flag;
377 ce->ce_path_consumed = refs[0].path_consumed;
378
379 for (i = 0; i < numrefs; i++) {
380 struct dfs_cache_tgt *t;
381
382 t = alloc_tgt(refs[i].node_name);
383 if (IS_ERR(t)) {
384 free_tgts(ce);
385 return PTR_ERR(t);
386 }
387 if (tgthint && !strcasecmp(t->t_name, tgthint)) {
388 list_add(&t->t_list, &ce->ce_tlist);
389 tgthint = NULL;
390 } else {
391 list_add_tail(&t->t_list, &ce->ce_tlist);
392 }
393 ce->ce_numtgts++;
394 }
395
396 ce->ce_tgthint = list_first_entry_or_null(&ce->ce_tlist,
397 struct dfs_cache_tgt, t_list);
398
399 return 0;
400}
401
402/* Allocate a new cache entry */
403static struct dfs_cache_entry *
404alloc_cache_entry(const char *path, const struct dfs_info3_param *refs,
405 int numrefs)
406{
407 struct dfs_cache_entry *ce;
408 int rc;
409
410 ce = kmem_cache_zalloc(dfs_cache_slab, GFP_KERNEL);
411 if (!ce)
412 return ERR_PTR(-ENOMEM);
413
414 ce->ce_path = kstrdup_const(path, GFP_KERNEL);
415 if (!ce->ce_path) {
416 kmem_cache_free(dfs_cache_slab, ce);
417 return ERR_PTR(-ENOMEM);
418 }
419 INIT_HLIST_NODE(&ce->ce_hlist);
420 INIT_LIST_HEAD(&ce->ce_tlist);
421
422 rc = copy_ref_data(refs, numrefs, ce, NULL);
423 if (rc) {
424 kfree(ce->ce_path);
425 kmem_cache_free(dfs_cache_slab, ce);
426 ce = ERR_PTR(rc);
427 }
428 return ce;
429}
430
431static void remove_oldest_entry(void)
432{
433 int bucket;
434 struct dfs_cache_entry *ce;
435 struct dfs_cache_entry *to_del = NULL;
436
437 rcu_read_lock();
438 hash_for_each_rcu(dfs_cache_htable, bucket, ce, ce_hlist) {
439 if (!to_del || timespec64_compare(&ce->ce_etime,
440 &to_del->ce_etime) < 0)
441 to_del = ce;
442 }
443 if (!to_del) {
444 cifs_dbg(FYI, "%s: no entry to remove", __func__);
445 goto out;
446 }
447 cifs_dbg(FYI, "%s: removing entry", __func__);
448 dump_ce(to_del);
449 flush_cache_ent(to_del);
450out:
451 rcu_read_unlock();
452}
453
454/* Add a new DFS cache entry */
455static inline struct dfs_cache_entry *
456add_cache_entry(unsigned int hash, const char *path,
457 const struct dfs_info3_param *refs, int numrefs)
458{
459 struct dfs_cache_entry *ce;
460
461 ce = alloc_cache_entry(path, refs, numrefs);
462 if (IS_ERR(ce))
463 return ce;
464
465 hlist_add_head_rcu(&ce->ce_hlist, &dfs_cache_htable[hash]);
466
467 mutex_lock(&dfs_cache.dc_lock);
468 if (dfs_cache.dc_ttl < 0) {
469 dfs_cache.dc_ttl = ce->ce_ttl;
470 queue_delayed_work(cifsiod_wq, &dfs_cache.dc_refresh,
471 dfs_cache.dc_ttl * HZ);
472 } else {
473 dfs_cache.dc_ttl = min_t(int, dfs_cache.dc_ttl, ce->ce_ttl);
474 mod_delayed_work(cifsiod_wq, &dfs_cache.dc_refresh,
475 dfs_cache.dc_ttl * HZ);
476 }
477 mutex_unlock(&dfs_cache.dc_lock);
478
479 return ce;
480}
481
482static struct dfs_cache_entry *__find_cache_entry(unsigned int hash,
483 const char *path)
484{
485 struct dfs_cache_entry *ce;
486 bool found = false;
487
488 rcu_read_lock();
489 hlist_for_each_entry_rcu(ce, &dfs_cache_htable[hash], ce_hlist) {
490 if (!strcasecmp(path, ce->ce_path)) {
491#ifdef CONFIG_CIFS_DEBUG2
492 char *name = get_tgt_name(ce);
493
494 if (unlikely(IS_ERR(name))) {
495 rcu_read_unlock();
496 return ERR_CAST(name);
497 }
498 cifs_dbg(FYI, "%s: cache hit\n", __func__);
499 cifs_dbg(FYI, "%s: target hint: %s\n", __func__, name);
500#endif
501 found = true;
502 break;
503 }
504 }
505 rcu_read_unlock();
506 return found ? ce : ERR_PTR(-ENOENT);
507}
508
509/*
510 * Find a DFS cache entry in hash table and optionally check prefix path against
511 * @path.
512 * Use whole path components in the match.
513 * Return ERR_PTR(-ENOENT) if the entry is not found.
514 */
515static inline struct dfs_cache_entry *find_cache_entry(const char *path,
516 unsigned int *hash)
517{
518 *hash = cache_entry_hash(path, strlen(path));
519 return __find_cache_entry(*hash, path);
520}
521
522static inline void destroy_slab_cache(void)
523{
524 rcu_barrier();
525 kmem_cache_destroy(dfs_cache_slab);
526}
527
528static inline void free_vol(struct dfs_cache_vol_info *vi)
529{
530 list_del(&vi->vi_list);
531 kfree(vi->vi_fullpath);
532 cifs_cleanup_volume_info_contents(&vi->vi_vol);
533 kfree(vi);
534}
535
536static inline void free_vol_list(void)
537{
538 struct dfs_cache_vol_info *vi, *nvi;
539
540 list_for_each_entry_safe(vi, nvi, &dfs_cache.dc_vol_list, vi_list)
541 free_vol(vi);
542}
543
544/**
545 * dfs_cache_destroy - destroy DFS referral cache
546 */
547void dfs_cache_destroy(void)
548{
549 cancel_delayed_work_sync(&dfs_cache.dc_refresh);
550 unload_nls(dfs_cache.dc_nlsc);
551 free_vol_list();
552 mutex_destroy(&dfs_cache.dc_lock);
553
554 flush_cache_ents();
555 destroy_slab_cache();
556 mutex_destroy(&dfs_cache_list_lock);
557
558 cifs_dbg(FYI, "%s: destroyed DFS referral cache\n", __func__);
559}
560
561static inline struct dfs_cache_entry *
562__update_cache_entry(const char *path, const struct dfs_info3_param *refs,
563 int numrefs)
564{
565 int rc;
566 unsigned int h;
567 struct dfs_cache_entry *ce;
568 char *s, *th = NULL;
569
570 ce = find_cache_entry(path, &h);
571 if (IS_ERR(ce))
572 return ce;
573
574 if (ce->ce_tgthint) {
575 s = ce->ce_tgthint->t_name;
576 th = kstrndup(s, strlen(s), GFP_KERNEL);
577 if (!th)
578 return ERR_PTR(-ENOMEM);
579 }
580
581 free_tgts(ce);
582 ce->ce_numtgts = 0;
583
584 rc = copy_ref_data(refs, numrefs, ce, th);
585 kfree(th);
586
587 if (rc)
588 ce = ERR_PTR(rc);
589
590 return ce;
591}
592
593/* Update an expired cache entry by getting a new DFS referral from server */
594static struct dfs_cache_entry *
595update_cache_entry(const unsigned int xid, struct cifs_ses *ses,
596 const struct nls_table *nls_codepage, int remap,
597 const char *path, struct dfs_cache_entry *ce)
598{
599 int rc;
600 struct dfs_info3_param *refs = NULL;
601 int numrefs = 0;
602
603 cifs_dbg(FYI, "%s: update expired cache entry\n", __func__);
604 /*
605 * Check if caller provided enough parameters to update an expired
606 * entry.
607 */
608 if (!ses || !ses->server || !ses->server->ops->get_dfs_refer)
609 return ERR_PTR(-ETIME);
610 if (unlikely(!nls_codepage))
611 return ERR_PTR(-ETIME);
612
613 cifs_dbg(FYI, "%s: DFS referral request for %s\n", __func__, path);
614
615 rc = ses->server->ops->get_dfs_refer(xid, ses, path, &refs, &numrefs,
616 nls_codepage, remap);
617 if (rc)
618 ce = ERR_PTR(rc);
619 else
620 ce = __update_cache_entry(path, refs, numrefs);
621
622 dump_refs(refs, numrefs);
623 free_dfs_info_array(refs, numrefs);
624
625 return ce;
626}
627
628/*
629 * Find, create or update a DFS cache entry.
630 *
631 * If the entry wasn't found, it will create a new one. Or if it was found but
632 * expired, then it will update the entry accordingly.
633 *
634 * For interlinks, __cifs_dfs_mount() and expand_dfs_referral() are supposed to
635 * handle them properly.
636 */
637static struct dfs_cache_entry *
638do_dfs_cache_find(const unsigned int xid, struct cifs_ses *ses,
639 const struct nls_table *nls_codepage, int remap,
640 const char *path, bool noreq)
641{
642 int rc;
643 unsigned int h;
644 struct dfs_cache_entry *ce;
645 struct dfs_info3_param *nrefs;
646 int numnrefs;
647
648 cifs_dbg(FYI, "%s: search path: %s\n", __func__, path);
649
650 ce = find_cache_entry(path, &h);
651 if (IS_ERR(ce)) {
652 cifs_dbg(FYI, "%s: cache miss\n", __func__);
653 /*
654 * If @noreq is set, no requests will be sent to the server for
655 * either updating or getting a new DFS referral.
656 */
657 if (noreq)
658 return ce;
659 /*
660 * No cache entry was found, so check for valid parameters that
661 * will be required to get a new DFS referral and then create a
662 * new cache entry.
663 */
664 if (!ses || !ses->server || !ses->server->ops->get_dfs_refer) {
665 ce = ERR_PTR(-EOPNOTSUPP);
666 return ce;
667 }
668 if (unlikely(!nls_codepage)) {
669 ce = ERR_PTR(-EINVAL);
670 return ce;
671 }
672
673 nrefs = NULL;
674 numnrefs = 0;
675
676 cifs_dbg(FYI, "%s: DFS referral request for %s\n", __func__,
677 path);
678
679 rc = ses->server->ops->get_dfs_refer(xid, ses, path, &nrefs,
680 &numnrefs, nls_codepage,
681 remap);
682 if (rc) {
683 ce = ERR_PTR(rc);
684 return ce;
685 }
686
687 dump_refs(nrefs, numnrefs);
688
689 cifs_dbg(FYI, "%s: new cache entry\n", __func__);
690
691 if (dfs_cache_count >= DFS_CACHE_MAX_ENTRIES) {
692 cifs_dbg(FYI, "%s: reached max cache size (%d)",
693 __func__, DFS_CACHE_MAX_ENTRIES);
694 remove_oldest_entry();
695 }
696 ce = add_cache_entry(h, path, nrefs, numnrefs);
697 free_dfs_info_array(nrefs, numnrefs);
698
699 if (IS_ERR(ce))
700 return ce;
701
702 dfs_cache_count++;
703 }
704
705 dump_ce(ce);
706
707 /* Just return the found cache entry in case @noreq is set */
708 if (noreq)
709 return ce;
710
711 if (cache_entry_expired(ce)) {
712 cifs_dbg(FYI, "%s: expired cache entry\n", __func__);
713 ce = update_cache_entry(xid, ses, nls_codepage, remap, path,
714 ce);
715 if (IS_ERR(ce)) {
716 cifs_dbg(FYI, "%s: failed to update expired entry\n",
717 __func__);
718 }
719 }
720 return ce;
721}
722
723/* Set up a new DFS referral from a given cache entry */
724static int setup_ref(const char *path, const struct dfs_cache_entry *ce,
725 struct dfs_info3_param *ref, const char *tgt)
726{
727 int rc;
728
729 cifs_dbg(FYI, "%s: set up new ref\n", __func__);
730
731 memset(ref, 0, sizeof(*ref));
732
733 ref->path_name = kstrndup(path, strlen(path), GFP_KERNEL);
734 if (!ref->path_name)
735 return -ENOMEM;
736
737 ref->path_consumed = ce->ce_path_consumed;
738
739 ref->node_name = kstrndup(tgt, strlen(tgt), GFP_KERNEL);
740 if (!ref->node_name) {
741 rc = -ENOMEM;
742 goto err_free_path;
743 }
744
745 ref->ttl = ce->ce_ttl;
746 ref->server_type = ce->ce_srvtype;
747 ref->ref_flag = ce->ce_flags;
748
749 return 0;
750
751err_free_path:
752 kfree(ref->path_name);
753 ref->path_name = NULL;
754 return rc;
755}
756
757/* Return target list of a DFS cache entry */
758static int get_tgt_list(const struct dfs_cache_entry *ce,
759 struct dfs_cache_tgt_list *tl)
760{
761 int rc;
762 struct list_head *head = &tl->tl_list;
763 struct dfs_cache_tgt *t;
764 struct dfs_cache_tgt_iterator *it, *nit;
765
766 memset(tl, 0, sizeof(*tl));
767 INIT_LIST_HEAD(head);
768
769 list_for_each_entry(t, &ce->ce_tlist, t_list) {
770 it = kzalloc(sizeof(*it), GFP_KERNEL);
771 if (!it) {
772 rc = -ENOMEM;
773 goto err_free_it;
774 }
775
776 it->it_name = kstrndup(t->t_name, strlen(t->t_name),
777 GFP_KERNEL);
778 if (!it->it_name) {
779 rc = -ENOMEM;
780 goto err_free_it;
781 }
782
783 if (ce->ce_tgthint == t)
784 list_add(&it->it_list, head);
785 else
786 list_add_tail(&it->it_list, head);
787 }
788 tl->tl_numtgts = ce->ce_numtgts;
789
790 return 0;
791
792err_free_it:
793 list_for_each_entry_safe(it, nit, head, it_list) {
794 kfree(it->it_name);
795 kfree(it);
796 }
797 return rc;
798}
799
800/**
801 * dfs_cache_find - find a DFS cache entry
802 *
803 * If it doesn't find the cache entry, then it will get a DFS referral
804 * for @path and create a new entry.
805 *
806 * In case the cache entry exists but expired, it will get a DFS referral
807 * for @path and then update the respective cache entry.
808 *
809 * These parameters are passed down to the get_dfs_refer() call if it
810 * needs to be issued:
811 * @xid: syscall xid
812 * @ses: smb session to issue the request on
813 * @nls_codepage: charset conversion
814 * @remap: path character remapping type
815 * @path: path to lookup in DFS referral cache.
816 *
817 * @ref: when non-NULL, store single DFS referral result in it.
818 * @tgt_list: when non-NULL, store complete DFS target list in it.
819 *
820 * Return zero if the target was found, otherwise non-zero.
821 */
822int dfs_cache_find(const unsigned int xid, struct cifs_ses *ses,
823 const struct nls_table *nls_codepage, int remap,
824 const char *path, struct dfs_info3_param *ref,
825 struct dfs_cache_tgt_list *tgt_list)
826{
827 int rc;
828 char *npath;
829 struct dfs_cache_entry *ce;
830
831 if (unlikely(!is_path_valid(path)))
832 return -EINVAL;
833
834 rc = get_normalized_path(path, &npath);
835 if (rc)
836 return rc;
837
838 mutex_lock(&dfs_cache_list_lock);
839 ce = do_dfs_cache_find(xid, ses, nls_codepage, remap, npath, false);
840 if (!IS_ERR(ce)) {
841 if (ref)
842 rc = setup_ref(path, ce, ref, get_tgt_name(ce));
843 else
844 rc = 0;
845 if (!rc && tgt_list)
846 rc = get_tgt_list(ce, tgt_list);
847 } else {
848 rc = PTR_ERR(ce);
849 }
850 mutex_unlock(&dfs_cache_list_lock);
851 free_normalized_path(path, npath);
852 return rc;
853}
854
855/**
856 * dfs_cache_noreq_find - find a DFS cache entry without sending any requests to
857 * the currently connected server.
858 *
859 * NOTE: This function will neither update a cache entry in case it was
860 * expired, nor create a new cache entry if @path hasn't been found. It heavily
861 * relies on an existing cache entry.
862 *
863 * @path: path to lookup in the DFS referral cache.
864 * @ref: when non-NULL, store single DFS referral result in it.
865 * @tgt_list: when non-NULL, store complete DFS target list in it.
866 *
867 * Return 0 if successful.
868 * Return -ENOENT if the entry was not found.
869 * Return non-zero for other errors.
870 */
871int dfs_cache_noreq_find(const char *path, struct dfs_info3_param *ref,
872 struct dfs_cache_tgt_list *tgt_list)
873{
874 int rc;
875 char *npath;
876 struct dfs_cache_entry *ce;
877
878 if (unlikely(!is_path_valid(path)))
879 return -EINVAL;
880
881 rc = get_normalized_path(path, &npath);
882 if (rc)
883 return rc;
884
885 mutex_lock(&dfs_cache_list_lock);
886 ce = do_dfs_cache_find(0, NULL, NULL, 0, npath, true);
887 if (IS_ERR(ce)) {
888 rc = PTR_ERR(ce);
889 goto out;
890 }
891
892 if (ref)
893 rc = setup_ref(path, ce, ref, get_tgt_name(ce));
894 else
895 rc = 0;
896 if (!rc && tgt_list)
897 rc = get_tgt_list(ce, tgt_list);
898out:
899 mutex_unlock(&dfs_cache_list_lock);
900 free_normalized_path(path, npath);
901 return rc;
902}
903
904/**
905 * dfs_cache_update_tgthint - update target hint of a DFS cache entry
906 *
907 * If it doesn't find the cache entry, then it will get a DFS referral for @path
908 * and create a new entry.
909 *
910 * In case the cache entry exists but expired, it will get a DFS referral
911 * for @path and then update the respective cache entry.
912 *
913 * @xid: syscall id
914 * @ses: smb session
915 * @nls_codepage: charset conversion
916 * @remap: type of character remapping for paths
917 * @path: path to lookup in DFS referral cache.
918 * @it: DFS target iterator
919 *
920 * Return zero if the target hint was updated successfully, otherwise non-zero.
921 */
922int dfs_cache_update_tgthint(const unsigned int xid, struct cifs_ses *ses,
923 const struct nls_table *nls_codepage, int remap,
924 const char *path,
925 const struct dfs_cache_tgt_iterator *it)
926{
927 int rc;
928 char *npath;
929 struct dfs_cache_entry *ce;
930 struct dfs_cache_tgt *t;
931
932 if (unlikely(!is_path_valid(path)))
933 return -EINVAL;
934
935 rc = get_normalized_path(path, &npath);
936 if (rc)
937 return rc;
938
939 cifs_dbg(FYI, "%s: path: %s\n", __func__, npath);
940
941 mutex_lock(&dfs_cache_list_lock);
942 ce = do_dfs_cache_find(xid, ses, nls_codepage, remap, npath, false);
943 if (IS_ERR(ce)) {
944 rc = PTR_ERR(ce);
945 goto out;
946 }
947
948 rc = 0;
949
950 t = ce->ce_tgthint;
951
952 if (likely(!strcasecmp(it->it_name, t->t_name)))
953 goto out;
954
955 list_for_each_entry(t, &ce->ce_tlist, t_list) {
956 if (!strcasecmp(t->t_name, it->it_name)) {
957 ce->ce_tgthint = t;
958 cifs_dbg(FYI, "%s: new target hint: %s\n", __func__,
959 it->it_name);
960 break;
961 }
962 }
963
964out:
965 mutex_unlock(&dfs_cache_list_lock);
966 free_normalized_path(path, npath);
967 return rc;
968}
969
970/**
971 * dfs_cache_noreq_update_tgthint - update target hint of a DFS cache entry
972 * without sending any requests to the currently connected server.
973 *
974 * NOTE: This function will neither update a cache entry in case it was
975 * expired, nor create a new cache entry if @path hasn't been found. It heavily
976 * relies on an existing cache entry.
977 *
978 * @path: path to lookup in DFS referral cache.
979 * @it: target iterator which contains the target hint to update the cache
980 * entry with.
981 *
982 * Return zero if the target hint was updated successfully, otherwise non-zero.
983 */
984int dfs_cache_noreq_update_tgthint(const char *path,
985 const struct dfs_cache_tgt_iterator *it)
986{
987 int rc;
988 char *npath;
989 struct dfs_cache_entry *ce;
990 struct dfs_cache_tgt *t;
991
992 if (unlikely(!is_path_valid(path)) || !it)
993 return -EINVAL;
994
995 rc = get_normalized_path(path, &npath);
996 if (rc)
997 return rc;
998
999 cifs_dbg(FYI, "%s: path: %s\n", __func__, npath);
1000
1001 mutex_lock(&dfs_cache_list_lock);
1002
1003 ce = do_dfs_cache_find(0, NULL, NULL, 0, npath, true);
1004 if (IS_ERR(ce)) {
1005 rc = PTR_ERR(ce);
1006 goto out;
1007 }
1008
1009 rc = 0;
1010
1011 t = ce->ce_tgthint;
1012
1013 if (unlikely(!strcasecmp(it->it_name, t->t_name)))
1014 goto out;
1015
1016 list_for_each_entry(t, &ce->ce_tlist, t_list) {
1017 if (!strcasecmp(t->t_name, it->it_name)) {
1018 ce->ce_tgthint = t;
1019 cifs_dbg(FYI, "%s: new target hint: %s\n", __func__,
1020 it->it_name);
1021 break;
1022 }
1023 }
1024
1025out:
1026 mutex_unlock(&dfs_cache_list_lock);
1027 free_normalized_path(path, npath);
1028 return rc;
1029}
1030
1031/**
1032 * dfs_cache_get_tgt_referral - returns a DFS referral (@ref) from a given
1033 * target iterator (@it).
1034 *
1035 * @path: path to lookup in DFS referral cache.
1036 * @it: DFS target iterator.
1037 * @ref: DFS referral pointer to set up the gathered information.
1038 *
1039 * Return zero if the DFS referral was set up correctly, otherwise non-zero.
1040 */
1041int dfs_cache_get_tgt_referral(const char *path,
1042 const struct dfs_cache_tgt_iterator *it,
1043 struct dfs_info3_param *ref)
1044{
1045 int rc;
1046 char *npath;
1047 struct dfs_cache_entry *ce;
1048 unsigned int h;
1049
1050 if (!it || !ref)
1051 return -EINVAL;
1052 if (unlikely(!is_path_valid(path)))
1053 return -EINVAL;
1054
1055 rc = get_normalized_path(path, &npath);
1056 if (rc)
1057 return rc;
1058
1059 cifs_dbg(FYI, "%s: path: %s\n", __func__, npath);
1060
1061 mutex_lock(&dfs_cache_list_lock);
1062
1063 ce = find_cache_entry(npath, &h);
1064 if (IS_ERR(ce)) {
1065 rc = PTR_ERR(ce);
1066 goto out;
1067 }
1068
1069 cifs_dbg(FYI, "%s: target name: %s\n", __func__, it->it_name);
1070
1071 rc = setup_ref(path, ce, ref, it->it_name);
1072
1073out:
1074 mutex_unlock(&dfs_cache_list_lock);
1075 free_normalized_path(path, npath);
1076 return rc;
1077}
1078
1079static int dup_vol(struct smb_vol *vol, struct smb_vol *new)
1080{
1081 memcpy(new, vol, sizeof(*new));
1082
1083 if (vol->username) {
1084 new->username = kstrndup(vol->username, strlen(vol->username),
1085 GFP_KERNEL);
1086 if (!new->username)
1087 return -ENOMEM;
1088 }
1089 if (vol->password) {
1090 new->password = kstrndup(vol->password, strlen(vol->password),
1091 GFP_KERNEL);
1092 if (!new->password)
1093 goto err_free_username;
1094 }
1095 if (vol->UNC) {
1096 cifs_dbg(FYI, "%s: vol->UNC: %s\n", __func__, vol->UNC);
1097 new->UNC = kstrndup(vol->UNC, strlen(vol->UNC), GFP_KERNEL);
1098 if (!new->UNC)
1099 goto err_free_password;
1100 }
1101 if (vol->domainname) {
1102 new->domainname = kstrndup(vol->domainname,
1103 strlen(vol->domainname), GFP_KERNEL);
1104 if (!new->domainname)
1105 goto err_free_unc;
1106 }
1107 if (vol->iocharset) {
1108 new->iocharset = kstrndup(vol->iocharset,
1109 strlen(vol->iocharset), GFP_KERNEL);
1110 if (!new->iocharset)
1111 goto err_free_domainname;
1112 }
1113 if (vol->prepath) {
1114 cifs_dbg(FYI, "%s: vol->prepath: %s\n", __func__, vol->prepath);
1115 new->prepath = kstrndup(vol->prepath, strlen(vol->prepath),
1116 GFP_KERNEL);
1117 if (!new->prepath)
1118 goto err_free_iocharset;
1119 }
1120
1121 return 0;
1122
1123err_free_iocharset:
1124 kfree(new->iocharset);
1125err_free_domainname:
1126 kfree(new->domainname);
1127err_free_unc:
1128 kfree(new->UNC);
1129err_free_password:
1130 kzfree(new->password);
1131err_free_username:
1132 kfree(new->username);
1133 kfree(new);
1134 return -ENOMEM;
1135}
1136
1137/**
1138 * dfs_cache_add_vol - add a cifs volume during mount() that will be handled by
1139 * DFS cache refresh worker.
1140 *
1141 * @vol: cifs volume.
1142 * @fullpath: origin full path.
1143 *
1144 * Return zero if volume was set up correctly, otherwise non-zero.
1145 */
1146int dfs_cache_add_vol(struct smb_vol *vol, const char *fullpath)
1147{
1148 int rc;
1149 struct dfs_cache_vol_info *vi;
1150
1151 if (!vol || !fullpath)
1152 return -EINVAL;
1153
1154 cifs_dbg(FYI, "%s: fullpath: %s\n", __func__, fullpath);
1155
1156 vi = kzalloc(sizeof(*vi), GFP_KERNEL);
1157 if (!vi)
1158 return -ENOMEM;
1159
1160 vi->vi_fullpath = kstrndup(fullpath, strlen(fullpath), GFP_KERNEL);
1161 if (!vi->vi_fullpath) {
1162 rc = -ENOMEM;
1163 goto err_free_vi;
1164 }
1165
1166 rc = dup_vol(vol, &vi->vi_vol);
1167 if (rc)
1168 goto err_free_fullpath;
1169
1170 mutex_lock(&dfs_cache.dc_lock);
1171 list_add_tail(&vi->vi_list, &dfs_cache.dc_vol_list);
1172 mutex_unlock(&dfs_cache.dc_lock);
1173 return 0;
1174
1175err_free_fullpath:
1176 kfree(vi->vi_fullpath);
1177err_free_vi:
1178 kfree(vi);
1179 return rc;
1180}
1181
1182static inline struct dfs_cache_vol_info *find_vol(const char *fullpath)
1183{
1184 struct dfs_cache_vol_info *vi;
1185
1186 list_for_each_entry(vi, &dfs_cache.dc_vol_list, vi_list) {
1187 cifs_dbg(FYI, "%s: vi->vi_fullpath: %s\n", __func__,
1188 vi->vi_fullpath);
1189 if (!strcasecmp(vi->vi_fullpath, fullpath))
1190 return vi;
1191 }
1192 return ERR_PTR(-ENOENT);
1193}
1194
1195/**
1196 * dfs_cache_update_vol - update vol info in DFS cache after failover
1197 *
1198 * @fullpath: fullpath to look up in volume list.
1199 * @server: TCP ses pointer.
1200 *
1201 * Return zero if volume was updated, otherwise non-zero.
1202 */
1203int dfs_cache_update_vol(const char *fullpath, struct TCP_Server_Info *server)
1204{
1205 int rc;
1206 struct dfs_cache_vol_info *vi;
1207
1208 if (!fullpath || !server)
1209 return -EINVAL;
1210
1211 cifs_dbg(FYI, "%s: fullpath: %s\n", __func__, fullpath);
1212
1213 mutex_lock(&dfs_cache.dc_lock);
1214
1215 vi = find_vol(fullpath);
1216 if (IS_ERR(vi)) {
1217 rc = PTR_ERR(vi);
1218 goto out;
1219 }
1220
1221 cifs_dbg(FYI, "%s: updating volume info\n", __func__);
1222 memcpy(&vi->vi_vol.dstaddr, &server->dstaddr,
1223 sizeof(vi->vi_vol.dstaddr));
1224 rc = 0;
1225
1226out:
1227 mutex_unlock(&dfs_cache.dc_lock);
1228 return rc;
1229}
1230
1231/**
1232 * dfs_cache_del_vol - remove volume info in DFS cache during umount()
1233 *
1234 * @fullpath: fullpath to look up in volume list.
1235 */
1236void dfs_cache_del_vol(const char *fullpath)
1237{
1238 struct dfs_cache_vol_info *vi;
1239
1240 if (!fullpath || !*fullpath)
1241 return;
1242
1243 cifs_dbg(FYI, "%s: fullpath: %s\n", __func__, fullpath);
1244
1245 mutex_lock(&dfs_cache.dc_lock);
1246 vi = find_vol(fullpath);
1247 if (!IS_ERR(vi))
1248 free_vol(vi);
1249 mutex_unlock(&dfs_cache.dc_lock);
1250}
1251
1252/* Get all tcons that are within a DFS namespace and can be refreshed */
1253static void get_tcons(struct TCP_Server_Info *server, struct list_head *head)
1254{
1255 struct cifs_ses *ses;
1256 struct cifs_tcon *tcon;
1257
1258 INIT_LIST_HEAD(head);
1259
1260 spin_lock(&cifs_tcp_ses_lock);
1261 list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
1262 list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
1263 if (!tcon->need_reconnect && !tcon->need_reopen_files &&
1264 tcon->dfs_path) {
1265 tcon->tc_count++;
1266 list_add_tail(&tcon->ulist, head);
1267 }
1268 }
1269 if (ses->tcon_ipc && !ses->tcon_ipc->need_reconnect &&
1270 ses->tcon_ipc->dfs_path) {
1271 list_add_tail(&ses->tcon_ipc->ulist, head);
1272 }
1273 }
1274 spin_unlock(&cifs_tcp_ses_lock);
1275}
1276
1277/* Refresh DFS cache entry from a given tcon */
1278static void do_refresh_tcon(struct dfs_cache *dc, struct cifs_tcon *tcon)
1279{
1280 int rc = 0;
1281 unsigned int xid;
1282 char *path, *npath;
1283 unsigned int h;
1284 struct dfs_cache_entry *ce;
1285 struct dfs_info3_param *refs = NULL;
1286 int numrefs = 0;
1287
1288 xid = get_xid();
1289
1290 path = tcon->dfs_path + 1;
1291
1292 rc = get_normalized_path(path, &npath);
1293 if (rc)
1294 goto out;
1295
1296 mutex_lock(&dfs_cache_list_lock);
1297 ce = find_cache_entry(npath, &h);
1298 mutex_unlock(&dfs_cache_list_lock);
1299
1300 if (IS_ERR(ce)) {
1301 rc = PTR_ERR(ce);
1302 goto out;
1303 }
1304
1305 if (!cache_entry_expired(ce))
1306 goto out;
1307
1308 if (unlikely(!tcon->ses->server->ops->get_dfs_refer)) {
1309 rc = -EOPNOTSUPP;
1310 } else {
1311 rc = tcon->ses->server->ops->get_dfs_refer(xid, tcon->ses, path,
1312 &refs, &numrefs,
1313 dc->dc_nlsc,
1314 tcon->remap);
1315 if (!rc) {
1316 mutex_lock(&dfs_cache_list_lock);
1317 ce = __update_cache_entry(npath, refs, numrefs);
1318 mutex_unlock(&dfs_cache_list_lock);
1319 dump_refs(refs, numrefs);
1320 free_dfs_info_array(refs, numrefs);
1321 if (IS_ERR(ce))
1322 rc = PTR_ERR(ce);
1323 }
1324 }
1325 if (rc)
1326 cifs_dbg(FYI, "%s: failed to update expired entry\n", __func__);
1327out:
1328 free_xid(xid);
1329 free_normalized_path(path, npath);
1330}
1331
1332/*
1333 * Worker that will refresh DFS cache based on lowest TTL value from a DFS
1334 * referral.
1335 *
1336 * FIXME: ensure that all requests are sent to DFS root for refreshing the
1337 * cache.
1338 */
1339static void refresh_cache_worker(struct work_struct *work)
1340{
1341 struct dfs_cache *dc = container_of(work, struct dfs_cache,
1342 dc_refresh.work);
1343 struct dfs_cache_vol_info *vi;
1344 struct TCP_Server_Info *server;
1345 LIST_HEAD(list);
1346 struct cifs_tcon *tcon, *ntcon;
1347
1348 mutex_lock(&dc->dc_lock);
1349
1350 list_for_each_entry(vi, &dc->dc_vol_list, vi_list) {
1351 server = cifs_find_tcp_session(&vi->vi_vol);
1352 if (IS_ERR_OR_NULL(server))
1353 continue;
1354 if (server->tcpStatus != CifsGood)
1355 goto next;
1356 get_tcons(server, &list);
1357 list_for_each_entry_safe(tcon, ntcon, &list, ulist) {
1358 do_refresh_tcon(dc, tcon);
1359 list_del_init(&tcon->ulist);
1360 cifs_put_tcon(tcon);
1361 }
1362next:
1363 cifs_put_tcp_session(server, 0);
1364 }
1365 queue_delayed_work(cifsiod_wq, &dc->dc_refresh, dc->dc_ttl * HZ);
1366 mutex_unlock(&dc->dc_lock);
1367}
diff --git a/fs/cifs/dfs_cache.h b/fs/cifs/dfs_cache.h
new file mode 100644
index 000000000000..22f366514f3a
--- /dev/null
+++ b/fs/cifs/dfs_cache.h
@@ -0,0 +1,97 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * DFS referral cache routines
4 *
5 * Copyright (c) 2018 Paulo Alcantara <palcantara@suse.de>
6 */
7
8#ifndef _CIFS_DFS_CACHE_H
9#define _CIFS_DFS_CACHE_H
10
11#include <linux/nls.h>
12#include <linux/list.h>
13#include "cifsglob.h"
14
15struct dfs_cache_tgt_list {
16 int tl_numtgts;
17 struct list_head tl_list;
18};
19
20struct dfs_cache_tgt_iterator {
21 char *it_name;
22 struct list_head it_list;
23};
24
25extern int dfs_cache_init(void);
26extern void dfs_cache_destroy(void);
27extern const struct file_operations dfscache_proc_fops;
28
29extern int dfs_cache_find(const unsigned int xid, struct cifs_ses *ses,
30 const struct nls_table *nls_codepage, int remap,
31 const char *path, struct dfs_info3_param *ref,
32 struct dfs_cache_tgt_list *tgt_list);
33extern int dfs_cache_noreq_find(const char *path, struct dfs_info3_param *ref,
34 struct dfs_cache_tgt_list *tgt_list);
35extern int dfs_cache_update_tgthint(const unsigned int xid,
36 struct cifs_ses *ses,
37 const struct nls_table *nls_codepage,
38 int remap, const char *path,
39 const struct dfs_cache_tgt_iterator *it);
40extern int
41dfs_cache_noreq_update_tgthint(const char *path,
42 const struct dfs_cache_tgt_iterator *it);
43extern int dfs_cache_get_tgt_referral(const char *path,
44 const struct dfs_cache_tgt_iterator *it,
45 struct dfs_info3_param *ref);
46extern int dfs_cache_add_vol(struct smb_vol *vol, const char *fullpath);
47extern int dfs_cache_update_vol(const char *fullpath,
48 struct TCP_Server_Info *server);
49extern void dfs_cache_del_vol(const char *fullpath);
50
51static inline struct dfs_cache_tgt_iterator *
52dfs_cache_get_next_tgt(struct dfs_cache_tgt_list *tl,
53 struct dfs_cache_tgt_iterator *it)
54{
55 if (!tl || list_empty(&tl->tl_list) || !it ||
56 list_is_last(&it->it_list, &tl->tl_list))
57 return NULL;
58 return list_next_entry(it, it_list);
59}
60
61static inline struct dfs_cache_tgt_iterator *
62dfs_cache_get_tgt_iterator(struct dfs_cache_tgt_list *tl)
63{
64 if (!tl)
65 return NULL;
66 return list_first_entry_or_null(&tl->tl_list,
67 struct dfs_cache_tgt_iterator,
68 it_list);
69}
70
71static inline void dfs_cache_free_tgts(struct dfs_cache_tgt_list *tl)
72{
73 struct dfs_cache_tgt_iterator *it, *nit;
74
75 if (!tl || list_empty(&tl->tl_list))
76 return;
77 list_for_each_entry_safe(it, nit, &tl->tl_list, it_list) {
78 list_del(&it->it_list);
79 kfree(it->it_name);
80 kfree(it);
81 }
82 tl->tl_numtgts = 0;
83}
84
85static inline const char *
86dfs_cache_get_tgt_name(const struct dfs_cache_tgt_iterator *it)
87{
88 return it ? it->it_name : NULL;
89}
90
91static inline int
92dfs_cache_get_nr_tgts(const struct dfs_cache_tgt_list *tl)
93{
94 return tl ? tl->tl_numtgts : 0;
95}
96
97#endif /* _CIFS_DFS_CACHE_H */
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 6706328ce03f..5e405164394a 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -2617,11 +2617,13 @@ cifs_write_from_iter(loff_t offset, size_t len, struct iov_iter *from,
2617 if (rc) 2617 if (rc)
2618 break; 2618 break;
2619 2619
2620 cur_len = min_t(const size_t, len, wsize);
2621
2620 if (ctx->direct_io) { 2622 if (ctx->direct_io) {
2621 ssize_t result; 2623 ssize_t result;
2622 2624
2623 result = iov_iter_get_pages_alloc( 2625 result = iov_iter_get_pages_alloc(
2624 from, &pagevec, wsize, &start); 2626 from, &pagevec, cur_len, &start);
2625 if (result < 0) { 2627 if (result < 0) {
2626 cifs_dbg(VFS, 2628 cifs_dbg(VFS,
2627 "direct_writev couldn't get user pages " 2629 "direct_writev couldn't get user pages "
@@ -2630,6 +2632,9 @@ cifs_write_from_iter(loff_t offset, size_t len, struct iov_iter *from,
2630 result, from->type, 2632 result, from->type,
2631 from->iov_offset, from->count); 2633 from->iov_offset, from->count);
2632 dump_stack(); 2634 dump_stack();
2635
2636 rc = result;
2637 add_credits_and_wake_if(server, credits, 0);
2633 break; 2638 break;
2634 } 2639 }
2635 cur_len = (size_t)result; 2640 cur_len = (size_t)result;
@@ -3313,13 +3318,16 @@ cifs_send_async_read(loff_t offset, size_t len, struct cifsFileInfo *open_file,
3313 cur_len, &start); 3318 cur_len, &start);
3314 if (result < 0) { 3319 if (result < 0) {
3315 cifs_dbg(VFS, 3320 cifs_dbg(VFS,
3316 "couldn't get user pages (cur_len=%zd)" 3321 "couldn't get user pages (rc=%zd)"
3317 " iter type %d" 3322 " iter type %d"
3318 " iov_offset %zd count %zd\n", 3323 " iov_offset %zd count %zd\n",
3319 result, direct_iov.type, 3324 result, direct_iov.type,
3320 direct_iov.iov_offset, 3325 direct_iov.iov_offset,
3321 direct_iov.count); 3326 direct_iov.count);
3322 dump_stack(); 3327 dump_stack();
3328
3329 rc = result;
3330 add_credits_and_wake_if(server, credits, 0);
3323 break; 3331 break;
3324 } 3332 }
3325 cur_len = (size_t)result; 3333 cur_len = (size_t)result;
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index a81a9df997c1..13fb59aadebc 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -333,7 +333,7 @@ cifs_create_dfs_fattr(struct cifs_fattr *fattr, struct super_block *sb)
333 fattr->cf_mtime = timespec64_trunc(fattr->cf_mtime, sb->s_time_gran); 333 fattr->cf_mtime = timespec64_trunc(fattr->cf_mtime, sb->s_time_gran);
334 fattr->cf_atime = fattr->cf_ctime = fattr->cf_mtime; 334 fattr->cf_atime = fattr->cf_ctime = fattr->cf_mtime;
335 fattr->cf_nlink = 2; 335 fattr->cf_nlink = 2;
336 fattr->cf_flags |= CIFS_FATTR_DFS_REFERRAL; 336 fattr->cf_flags = CIFS_FATTR_DFS_REFERRAL;
337} 337}
338 338
339static int 339static int
@@ -730,7 +730,6 @@ cifs_get_inode_info(struct inode **inode, const char *full_path,
730 FILE_ALL_INFO *data, struct super_block *sb, int xid, 730 FILE_ALL_INFO *data, struct super_block *sb, int xid,
731 const struct cifs_fid *fid) 731 const struct cifs_fid *fid)
732{ 732{
733 bool validinum = false;
734 __u16 srchflgs; 733 __u16 srchflgs;
735 int rc = 0, tmprc = ENOSYS; 734 int rc = 0, tmprc = ENOSYS;
736 struct cifs_tcon *tcon; 735 struct cifs_tcon *tcon;
@@ -821,7 +820,6 @@ cifs_get_inode_info(struct inode **inode, const char *full_path,
821 (FILE_DIRECTORY_INFO *)data, cifs_sb); 820 (FILE_DIRECTORY_INFO *)data, cifs_sb);
822 fattr.cf_uniqueid = le64_to_cpu( 821 fattr.cf_uniqueid = le64_to_cpu(
823 ((SEARCH_ID_FULL_DIR_INFO *)data)->UniqueId); 822 ((SEARCH_ID_FULL_DIR_INFO *)data)->UniqueId);
824 validinum = true;
825 823
826 cifs_buf_release(srchinf->ntwrk_buf_start); 824 cifs_buf_release(srchinf->ntwrk_buf_start);
827 } 825 }
@@ -840,31 +838,29 @@ cifs_get_inode_info(struct inode **inode, const char *full_path,
840 */ 838 */
841 if (*inode == NULL) { 839 if (*inode == NULL) {
842 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { 840 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
843 if (validinum == false) { 841 if (server->ops->get_srv_inum)
844 if (server->ops->get_srv_inum) 842 tmprc = server->ops->get_srv_inum(xid,
845 tmprc = server->ops->get_srv_inum(xid, 843 tcon, cifs_sb, full_path,
846 tcon, cifs_sb, full_path, 844 &fattr.cf_uniqueid, data);
847 &fattr.cf_uniqueid, data); 845 if (tmprc) {
848 if (tmprc) { 846 cifs_dbg(FYI, "GetSrvInodeNum rc %d\n",
849 cifs_dbg(FYI, "GetSrvInodeNum rc %d\n", 847 tmprc);
850 tmprc); 848 fattr.cf_uniqueid = iunique(sb, ROOT_I);
851 fattr.cf_uniqueid = iunique(sb, ROOT_I); 849 cifs_autodisable_serverino(cifs_sb);
852 cifs_autodisable_serverino(cifs_sb); 850 } else if ((fattr.cf_uniqueid == 0) &&
853 } else if ((fattr.cf_uniqueid == 0) && 851 strlen(full_path) == 0) {
854 strlen(full_path) == 0) { 852 /* some servers ret bad root ino ie 0 */
855 /* some servers ret bad root ino ie 0 */ 853 cifs_dbg(FYI, "Invalid (0) inodenum\n");
856 cifs_dbg(FYI, "Invalid (0) inodenum\n"); 854 fattr.cf_flags |=
857 fattr.cf_flags |= 855 CIFS_FATTR_FAKE_ROOT_INO;
858 CIFS_FATTR_FAKE_ROOT_INO; 856 fattr.cf_uniqueid =
859 fattr.cf_uniqueid = 857 simple_hashstr(tcon->treeName);
860 simple_hashstr(tcon->treeName);
861 }
862 } 858 }
863 } else 859 } else
864 fattr.cf_uniqueid = iunique(sb, ROOT_I); 860 fattr.cf_uniqueid = iunique(sb, ROOT_I);
865 } else { 861 } else {
866 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) && 862 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
867 validinum == false && server->ops->get_srv_inum) { 863 && server->ops->get_srv_inum) {
868 /* 864 /*
869 * Pass a NULL tcon to ensure we don't make a round 865 * Pass a NULL tcon to ensure we don't make a round
870 * trip to the server. This only works for SMB2+. 866 * trip to the server. This only works for SMB2+.
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index 8a41f4eba726..bee203055b30 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -111,21 +111,27 @@ struct cifs_tcon *
111tconInfoAlloc(void) 111tconInfoAlloc(void)
112{ 112{
113 struct cifs_tcon *ret_buf; 113 struct cifs_tcon *ret_buf;
114 ret_buf = kzalloc(sizeof(struct cifs_tcon), GFP_KERNEL); 114
115 if (ret_buf) { 115 ret_buf = kzalloc(sizeof(*ret_buf), GFP_KERNEL);
116 atomic_inc(&tconInfoAllocCount); 116 if (!ret_buf)
117 ret_buf->tidStatus = CifsNew; 117 return NULL;
118 ++ret_buf->tc_count; 118 ret_buf->crfid.fid = kzalloc(sizeof(*ret_buf->crfid.fid), GFP_KERNEL);
119 INIT_LIST_HEAD(&ret_buf->openFileList); 119 if (!ret_buf->crfid.fid) {
120 INIT_LIST_HEAD(&ret_buf->tcon_list); 120 kfree(ret_buf);
121 spin_lock_init(&ret_buf->open_file_lock); 121 return NULL;
122 mutex_init(&ret_buf->crfid.fid_mutex);
123 ret_buf->crfid.fid = kzalloc(sizeof(struct cifs_fid),
124 GFP_KERNEL);
125 spin_lock_init(&ret_buf->stat_lock);
126 atomic_set(&ret_buf->num_local_opens, 0);
127 atomic_set(&ret_buf->num_remote_opens, 0);
128 } 122 }
123
124 atomic_inc(&tconInfoAllocCount);
125 ret_buf->tidStatus = CifsNew;
126 ++ret_buf->tc_count;
127 INIT_LIST_HEAD(&ret_buf->openFileList);
128 INIT_LIST_HEAD(&ret_buf->tcon_list);
129 spin_lock_init(&ret_buf->open_file_lock);
130 mutex_init(&ret_buf->crfid.fid_mutex);
131 spin_lock_init(&ret_buf->stat_lock);
132 atomic_set(&ret_buf->num_local_opens, 0);
133 atomic_set(&ret_buf->num_remote_opens, 0);
134
129 return ret_buf; 135 return ret_buf;
130} 136}
131 137
@@ -140,6 +146,9 @@ tconInfoFree(struct cifs_tcon *buf_to_free)
140 kfree(buf_to_free->nativeFileSystem); 146 kfree(buf_to_free->nativeFileSystem);
141 kzfree(buf_to_free->password); 147 kzfree(buf_to_free->password);
142 kfree(buf_to_free->crfid.fid); 148 kfree(buf_to_free->crfid.fid);
149#ifdef CONFIG_CIFS_DFS_UPCALL
150 kfree(buf_to_free->dfs_path);
151#endif
143 kfree(buf_to_free); 152 kfree(buf_to_free);
144} 153}
145 154
@@ -525,9 +534,17 @@ void
525cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb) 534cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb)
526{ 535{
527 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { 536 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
537 struct cifs_tcon *tcon = NULL;
538
539 if (cifs_sb->master_tlink)
540 tcon = cifs_sb_master_tcon(cifs_sb);
541
528 cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM; 542 cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM;
529 cifs_dbg(VFS, "Autodisabling the use of server inode numbers on %s. This server doesn't seem to support them properly. Hardlinks will not be recognized on this mount. Consider mounting with the \"noserverino\" option to silence this message.\n", 543 cifs_dbg(VFS, "Autodisabling the use of server inode numbers on %s.\n",
530 cifs_sb_master_tcon(cifs_sb)->treeName); 544 tcon ? tcon->treeName : "new server");
545 cifs_dbg(VFS, "The server doesn't seem to support them properly or the files might be on different servers (DFS).\n");
546 cifs_dbg(VFS, "Hardlinks will not be recognized on this mount. Consider mounting with the \"noserverino\" option to silence this message.\n");
547
531 } 548 }
532} 549}
533 550
@@ -732,6 +749,8 @@ parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size,
732 goto parse_DFS_referrals_exit; 749 goto parse_DFS_referrals_exit;
733 } 750 }
734 751
752 node->ttl = le32_to_cpu(ref->TimeToLive);
753
735 ref++; 754 ref++;
736 } 755 }
737 756
@@ -933,3 +952,20 @@ void rqst_page_get_length(struct smb_rqst *rqst, unsigned int page,
933 else if (page == 0) 952 else if (page == 0)
934 *len = rqst->rq_pagesz - rqst->rq_offset; 953 *len = rqst->rq_pagesz - rqst->rq_offset;
935} 954}
955
956void extract_unc_hostname(const char *unc, const char **h, size_t *len)
957{
958 const char *end;
959
960 /* skip initial slashes */
961 while (*unc && (*unc == '\\' || *unc == '/'))
962 unc++;
963
964 end = unc;
965
966 while (*end && !(*end == '\\' || *end == '/'))
967 end++;
968
969 *h = unc;
970 *len = end - unc;
971}
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index e169e1a5fd35..3925a7bfc74d 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -655,7 +655,14 @@ find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon, loff_t pos,
655 /* scan and find it */ 655 /* scan and find it */
656 int i; 656 int i;
657 char *cur_ent; 657 char *cur_ent;
658 char *end_of_smb = cfile->srch_inf.ntwrk_buf_start + 658 char *end_of_smb;
659
660 if (cfile->srch_inf.ntwrk_buf_start == NULL) {
661 cifs_dbg(VFS, "ntwrk_buf_start is NULL during readdir\n");
662 return -EIO;
663 }
664
665 end_of_smb = cfile->srch_inf.ntwrk_buf_start +
659 server->ops->calc_smb_size( 666 server->ops->calc_smb_size(
660 cfile->srch_inf.ntwrk_buf_start, 667 cfile->srch_inf.ntwrk_buf_start,
661 server); 668 server);
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
index aa23c00367ec..dcd49ad60c83 100644
--- a/fs/cifs/sess.c
+++ b/fs/cifs/sess.c
@@ -534,9 +534,9 @@ cifs_select_sectype(struct TCP_Server_Info *server, enum securityEnum requested)
534 if (global_secflags & CIFSSEC_MAY_NTLM) 534 if (global_secflags & CIFSSEC_MAY_NTLM)
535 return NTLM; 535 return NTLM;
536 default: 536 default:
537 /* Fallthrough to attempt LANMAN authentication next */
538 break; 537 break;
539 } 538 }
539 /* Fallthrough - to attempt LANMAN authentication next */
540 case CIFS_NEGFLAVOR_LANMAN: 540 case CIFS_NEGFLAVOR_LANMAN:
541 switch (requested) { 541 switch (requested) {
542 case LANMAN: 542 case LANMAN:
@@ -1154,14 +1154,12 @@ out:
1154static int 1154static int
1155_sess_auth_rawntlmssp_assemble_req(struct sess_data *sess_data) 1155_sess_auth_rawntlmssp_assemble_req(struct sess_data *sess_data)
1156{ 1156{
1157 struct smb_hdr *smb_buf;
1158 SESSION_SETUP_ANDX *pSMB; 1157 SESSION_SETUP_ANDX *pSMB;
1159 struct cifs_ses *ses = sess_data->ses; 1158 struct cifs_ses *ses = sess_data->ses;
1160 __u32 capabilities; 1159 __u32 capabilities;
1161 char *bcc_ptr; 1160 char *bcc_ptr;
1162 1161
1163 pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base; 1162 pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
1164 smb_buf = (struct smb_hdr *)pSMB;
1165 1163
1166 capabilities = cifs_ssetup_hdr(ses, pSMB); 1164 capabilities = cifs_ssetup_hdr(ses, pSMB);
1167 if ((pSMB->req.hdr.Flags2 & SMBFLG2_UNICODE) == 0) { 1165 if ((pSMB->req.hdr.Flags2 & SMBFLG2_UNICODE) == 0) {
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index 378151e09e91..32a6c020478f 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -929,19 +929,18 @@ cifs_unix_dfs_readlink(const unsigned int xid, struct cifs_tcon *tcon,
929{ 929{
930#ifdef CONFIG_CIFS_DFS_UPCALL 930#ifdef CONFIG_CIFS_DFS_UPCALL
931 int rc; 931 int rc;
932 unsigned int num_referrals = 0; 932 struct dfs_info3_param referral = {0};
933 struct dfs_info3_param *referrals = NULL;
934 933
935 rc = get_dfs_path(xid, tcon->ses, searchName, nls_codepage, 934 rc = get_dfs_path(xid, tcon->ses, searchName, nls_codepage, &referral,
936 &num_referrals, &referrals, 0); 935 0);
937 936
938 if (!rc && num_referrals > 0) { 937 if (!rc) {
939 *symlinkinfo = kstrndup(referrals->node_name, 938 *symlinkinfo = kstrndup(referral.node_name,
940 strlen(referrals->node_name), 939 strlen(referral.node_name),
941 GFP_KERNEL); 940 GFP_KERNEL);
941 free_dfs_info_param(&referral);
942 if (!*symlinkinfo) 942 if (!*symlinkinfo)
943 rc = -ENOMEM; 943 rc = -ENOMEM;
944 free_dfs_info_array(referrals, num_referrals);
945 } 944 }
946 return rc; 945 return rc;
947#else /* No DFS support */ 946#else /* No DFS support */
diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c
index a8999f930b22..f14533da3a93 100644
--- a/fs/cifs/smb2inode.c
+++ b/fs/cifs/smb2inode.c
@@ -49,7 +49,6 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
49 struct cifs_open_parms oparms; 49 struct cifs_open_parms oparms;
50 struct cifs_fid fid; 50 struct cifs_fid fid;
51 struct cifs_ses *ses = tcon->ses; 51 struct cifs_ses *ses = tcon->ses;
52 struct TCP_Server_Info *server = ses->server;
53 int num_rqst = 0; 52 int num_rqst = 0;
54 struct smb_rqst rqst[3]; 53 struct smb_rqst rqst[3];
55 int resp_buftype[3]; 54 int resp_buftype[3];
@@ -97,7 +96,7 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
97 if (rc) 96 if (rc)
98 goto finished; 97 goto finished;
99 98
100 smb2_set_next_command(server, &rqst[num_rqst++], 0); 99 smb2_set_next_command(tcon, &rqst[num_rqst++]);
101 100
102 /* Operation */ 101 /* Operation */
103 switch (command) { 102 switch (command) {
@@ -111,7 +110,7 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
111 SMB2_O_INFO_FILE, 0, 110 SMB2_O_INFO_FILE, 0,
112 sizeof(struct smb2_file_all_info) + 111 sizeof(struct smb2_file_all_info) +
113 PATH_MAX * 2, 0, NULL); 112 PATH_MAX * 2, 0, NULL);
114 smb2_set_next_command(server, &rqst[num_rqst], 0); 113 smb2_set_next_command(tcon, &rqst[num_rqst]);
115 smb2_set_related(&rqst[num_rqst++]); 114 smb2_set_related(&rqst[num_rqst++]);
116 break; 115 break;
117 case SMB2_OP_DELETE: 116 case SMB2_OP_DELETE:
@@ -134,7 +133,7 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
134 COMPOUND_FID, current->tgid, 133 COMPOUND_FID, current->tgid,
135 FILE_DISPOSITION_INFORMATION, 134 FILE_DISPOSITION_INFORMATION,
136 SMB2_O_INFO_FILE, 0, data, size); 135 SMB2_O_INFO_FILE, 0, data, size);
137 smb2_set_next_command(server, &rqst[num_rqst], 1); 136 smb2_set_next_command(tcon, &rqst[num_rqst]);
138 smb2_set_related(&rqst[num_rqst++]); 137 smb2_set_related(&rqst[num_rqst++]);
139 break; 138 break;
140 case SMB2_OP_SET_EOF: 139 case SMB2_OP_SET_EOF:
@@ -149,7 +148,7 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
149 COMPOUND_FID, current->tgid, 148 COMPOUND_FID, current->tgid,
150 FILE_END_OF_FILE_INFORMATION, 149 FILE_END_OF_FILE_INFORMATION,
151 SMB2_O_INFO_FILE, 0, data, size); 150 SMB2_O_INFO_FILE, 0, data, size);
152 smb2_set_next_command(server, &rqst[num_rqst], 0); 151 smb2_set_next_command(tcon, &rqst[num_rqst]);
153 smb2_set_related(&rqst[num_rqst++]); 152 smb2_set_related(&rqst[num_rqst++]);
154 break; 153 break;
155 case SMB2_OP_SET_INFO: 154 case SMB2_OP_SET_INFO:
@@ -165,7 +164,7 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
165 COMPOUND_FID, current->tgid, 164 COMPOUND_FID, current->tgid,
166 FILE_BASIC_INFORMATION, 165 FILE_BASIC_INFORMATION,
167 SMB2_O_INFO_FILE, 0, data, size); 166 SMB2_O_INFO_FILE, 0, data, size);
168 smb2_set_next_command(server, &rqst[num_rqst], 0); 167 smb2_set_next_command(tcon, &rqst[num_rqst]);
169 smb2_set_related(&rqst[num_rqst++]); 168 smb2_set_related(&rqst[num_rqst++]);
170 break; 169 break;
171 case SMB2_OP_RENAME: 170 case SMB2_OP_RENAME:
@@ -189,7 +188,7 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
189 COMPOUND_FID, current->tgid, 188 COMPOUND_FID, current->tgid,
190 FILE_RENAME_INFORMATION, 189 FILE_RENAME_INFORMATION,
191 SMB2_O_INFO_FILE, 0, data, size); 190 SMB2_O_INFO_FILE, 0, data, size);
192 smb2_set_next_command(server, &rqst[num_rqst], 0); 191 smb2_set_next_command(tcon, &rqst[num_rqst]);
193 smb2_set_related(&rqst[num_rqst++]); 192 smb2_set_related(&rqst[num_rqst++]);
194 break; 193 break;
195 case SMB2_OP_HARDLINK: 194 case SMB2_OP_HARDLINK:
@@ -213,7 +212,7 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
213 COMPOUND_FID, current->tgid, 212 COMPOUND_FID, current->tgid,
214 FILE_LINK_INFORMATION, 213 FILE_LINK_INFORMATION,
215 SMB2_O_INFO_FILE, 0, data, size); 214 SMB2_O_INFO_FILE, 0, data, size);
216 smb2_set_next_command(server, &rqst[num_rqst], 0); 215 smb2_set_next_command(tcon, &rqst[num_rqst]);
217 smb2_set_related(&rqst[num_rqst++]); 216 smb2_set_related(&rqst[num_rqst++]);
218 break; 217 break;
219 default: 218 default:
@@ -388,7 +387,6 @@ smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon,
388 rc = -ENOMEM; 387 rc = -ENOMEM;
389 goto smb2_rename_path; 388 goto smb2_rename_path;
390 } 389 }
391
392 rc = smb2_compound_op(xid, tcon, cifs_sb, from_name, access, 390 rc = smb2_compound_op(xid, tcon, cifs_sb, from_name, access,
393 FILE_OPEN, 0, smb2_to_name, command); 391 FILE_OPEN, 0, smb2_to_name, command);
394smb2_rename_path: 392smb2_rename_path:
diff --git a/fs/cifs/smb2maperror.c b/fs/cifs/smb2maperror.c
index d47b7f5dfa6c..924269cec135 100644
--- a/fs/cifs/smb2maperror.c
+++ b/fs/cifs/smb2maperror.c
@@ -379,8 +379,8 @@ static const struct status_to_posix_error smb2_error_map_table[] = {
379 {STATUS_NONEXISTENT_EA_ENTRY, -EIO, "STATUS_NONEXISTENT_EA_ENTRY"}, 379 {STATUS_NONEXISTENT_EA_ENTRY, -EIO, "STATUS_NONEXISTENT_EA_ENTRY"},
380 {STATUS_NO_EAS_ON_FILE, -ENODATA, "STATUS_NO_EAS_ON_FILE"}, 380 {STATUS_NO_EAS_ON_FILE, -ENODATA, "STATUS_NO_EAS_ON_FILE"},
381 {STATUS_EA_CORRUPT_ERROR, -EIO, "STATUS_EA_CORRUPT_ERROR"}, 381 {STATUS_EA_CORRUPT_ERROR, -EIO, "STATUS_EA_CORRUPT_ERROR"},
382 {STATUS_FILE_LOCK_CONFLICT, -EIO, "STATUS_FILE_LOCK_CONFLICT"}, 382 {STATUS_FILE_LOCK_CONFLICT, -EACCES, "STATUS_FILE_LOCK_CONFLICT"},
383 {STATUS_LOCK_NOT_GRANTED, -EIO, "STATUS_LOCK_NOT_GRANTED"}, 383 {STATUS_LOCK_NOT_GRANTED, -EACCES, "STATUS_LOCK_NOT_GRANTED"},
384 {STATUS_DELETE_PENDING, -ENOENT, "STATUS_DELETE_PENDING"}, 384 {STATUS_DELETE_PENDING, -ENOENT, "STATUS_DELETE_PENDING"},
385 {STATUS_CTL_FILE_NOT_SUPPORTED, -ENOSYS, 385 {STATUS_CTL_FILE_NOT_SUPPORTED, -ENOSYS,
386 "STATUS_CTL_FILE_NOT_SUPPORTED"}, 386 "STATUS_CTL_FILE_NOT_SUPPORTED"},
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index e25c7aade98a..33100ef74d7f 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -831,72 +831,48 @@ smb2_query_eas(const unsigned int xid, struct cifs_tcon *tcon,
831{ 831{
832 int rc; 832 int rc;
833 __le16 *utf16_path; 833 __le16 *utf16_path;
834 __u8 oplock = SMB2_OPLOCK_LEVEL_NONE; 834 struct kvec rsp_iov = {NULL, 0};
835 struct cifs_open_parms oparms; 835 int buftype = CIFS_NO_BUFFER;
836 struct cifs_fid fid; 836 struct smb2_query_info_rsp *rsp;
837 struct smb2_file_full_ea_info *smb2_data; 837 struct smb2_file_full_ea_info *info = NULL;
838 int ea_buf_size = SMB2_MIN_EA_BUF;
839 838
840 utf16_path = cifs_convert_path_to_utf16(path, cifs_sb); 839 utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
841 if (!utf16_path) 840 if (!utf16_path)
842 return -ENOMEM; 841 return -ENOMEM;
843 842
844 oparms.tcon = tcon; 843 rc = smb2_query_info_compound(xid, tcon, utf16_path,
845 oparms.desired_access = FILE_READ_EA; 844 FILE_READ_EA,
846 oparms.disposition = FILE_OPEN; 845 FILE_FULL_EA_INFORMATION,
847 if (backup_cred(cifs_sb)) 846 SMB2_O_INFO_FILE,
848 oparms.create_options = CREATE_OPEN_BACKUP_INTENT; 847 SMB2_MAX_EA_BUF,
849 else 848 &rsp_iov, &buftype, cifs_sb);
850 oparms.create_options = 0;
851 oparms.fid = &fid;
852 oparms.reconnect = false;
853
854 rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL, NULL);
855 kfree(utf16_path);
856 if (rc) { 849 if (rc) {
857 cifs_dbg(FYI, "open failed rc=%d\n", rc); 850 /*
858 return rc; 851 * If ea_name is NULL (listxattr) and there are no EAs,
859 } 852 * return 0 as it's not an error. Otherwise, the specified
860 853 * ea_name was not found.
861 while (1) { 854 */
862 smb2_data = kzalloc(ea_buf_size, GFP_KERNEL); 855 if (!ea_name && rc == -ENODATA)
863 if (smb2_data == NULL) { 856 rc = 0;
864 SMB2_close(xid, tcon, fid.persistent_fid, 857 goto qeas_exit;
865 fid.volatile_fid);
866 return -ENOMEM;
867 }
868
869 rc = SMB2_query_eas(xid, tcon, fid.persistent_fid,
870 fid.volatile_fid,
871 ea_buf_size, smb2_data);
872
873 if (rc != -E2BIG)
874 break;
875
876 kfree(smb2_data);
877 ea_buf_size <<= 1;
878
879 if (ea_buf_size > SMB2_MAX_EA_BUF) {
880 cifs_dbg(VFS, "EA size is too large\n");
881 SMB2_close(xid, tcon, fid.persistent_fid,
882 fid.volatile_fid);
883 return -ENOMEM;
884 }
885 } 858 }
886 859
887 SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid); 860 rsp = (struct smb2_query_info_rsp *)rsp_iov.iov_base;
861 rc = smb2_validate_iov(le16_to_cpu(rsp->OutputBufferOffset),
862 le32_to_cpu(rsp->OutputBufferLength),
863 &rsp_iov,
864 sizeof(struct smb2_file_full_ea_info));
865 if (rc)
866 goto qeas_exit;
888 867
889 /* 868 info = (struct smb2_file_full_ea_info *)(
890 * If ea_name is NULL (listxattr) and there are no EAs, return 0 as it's 869 le16_to_cpu(rsp->OutputBufferOffset) + (char *)rsp);
891 * not an error. Otherwise, the specified ea_name was not found. 870 rc = move_smb2_ea_to_cifs(ea_data, buf_size, info,
892 */ 871 le32_to_cpu(rsp->OutputBufferLength), ea_name);
893 if (!rc)
894 rc = move_smb2_ea_to_cifs(ea_data, buf_size, smb2_data,
895 SMB2_MAX_EA_BUF, ea_name);
896 else if (!ea_name && rc == -ENODATA)
897 rc = 0;
898 872
899 kfree(smb2_data); 873 qeas_exit:
874 kfree(utf16_path);
875 free_rsp_buf(buftype, rsp_iov.iov_base);
900 return rc; 876 return rc;
901} 877}
902 878
@@ -907,14 +883,27 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
907 const __u16 ea_value_len, const struct nls_table *nls_codepage, 883 const __u16 ea_value_len, const struct nls_table *nls_codepage,
908 struct cifs_sb_info *cifs_sb) 884 struct cifs_sb_info *cifs_sb)
909{ 885{
910 int rc; 886 struct cifs_ses *ses = tcon->ses;
911 __le16 *utf16_path; 887 __le16 *utf16_path = NULL;
912 __u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
913 struct cifs_open_parms oparms;
914 struct cifs_fid fid;
915 struct smb2_file_full_ea_info *ea;
916 int ea_name_len = strlen(ea_name); 888 int ea_name_len = strlen(ea_name);
889 int flags = 0;
917 int len; 890 int len;
891 struct smb_rqst rqst[3];
892 int resp_buftype[3];
893 struct kvec rsp_iov[3];
894 struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
895 struct cifs_open_parms oparms;
896 __u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
897 struct cifs_fid fid;
898 struct kvec si_iov[SMB2_SET_INFO_IOV_SIZE];
899 unsigned int size[1];
900 void *data[1];
901 struct smb2_file_full_ea_info *ea = NULL;
902 struct kvec close_iov[1];
903 int rc;
904
905 if (smb3_encryption_required(tcon))
906 flags |= CIFS_TRANSFORM_REQ;
918 907
919 if (ea_name_len > 255) 908 if (ea_name_len > 255)
920 return -EINVAL; 909 return -EINVAL;
@@ -923,6 +912,16 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
923 if (!utf16_path) 912 if (!utf16_path)
924 return -ENOMEM; 913 return -ENOMEM;
925 914
915 memset(rqst, 0, sizeof(rqst));
916 resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
917 memset(rsp_iov, 0, sizeof(rsp_iov));
918
919 /* Open */
920 memset(&open_iov, 0, sizeof(open_iov));
921 rqst[0].rq_iov = open_iov;
922 rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE;
923
924 memset(&oparms, 0, sizeof(oparms));
926 oparms.tcon = tcon; 925 oparms.tcon = tcon;
927 oparms.desired_access = FILE_WRITE_EA; 926 oparms.desired_access = FILE_WRITE_EA;
928 oparms.disposition = FILE_OPEN; 927 oparms.disposition = FILE_OPEN;
@@ -933,18 +932,22 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
933 oparms.fid = &fid; 932 oparms.fid = &fid;
934 oparms.reconnect = false; 933 oparms.reconnect = false;
935 934
936 rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL, NULL); 935 rc = SMB2_open_init(tcon, &rqst[0], &oplock, &oparms, utf16_path);
937 kfree(utf16_path); 936 if (rc)
938 if (rc) { 937 goto sea_exit;
939 cifs_dbg(FYI, "open failed rc=%d\n", rc); 938 smb2_set_next_command(tcon, &rqst[0]);
940 return rc; 939
941 } 940
941 /* Set Info */
942 memset(&si_iov, 0, sizeof(si_iov));
943 rqst[1].rq_iov = si_iov;
944 rqst[1].rq_nvec = 1;
942 945
943 len = sizeof(ea) + ea_name_len + ea_value_len + 1; 946 len = sizeof(ea) + ea_name_len + ea_value_len + 1;
944 ea = kzalloc(len, GFP_KERNEL); 947 ea = kzalloc(len, GFP_KERNEL);
945 if (ea == NULL) { 948 if (ea == NULL) {
946 SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid); 949 rc = -ENOMEM;
947 return -ENOMEM; 950 goto sea_exit;
948 } 951 }
949 952
950 ea->ea_name_length = ea_name_len; 953 ea->ea_name_length = ea_name_len;
@@ -952,12 +955,36 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
952 memcpy(ea->ea_data, ea_name, ea_name_len + 1); 955 memcpy(ea->ea_data, ea_name, ea_name_len + 1);
953 memcpy(ea->ea_data + ea_name_len + 1, ea_value, ea_value_len); 956 memcpy(ea->ea_data + ea_name_len + 1, ea_value, ea_value_len);
954 957
955 rc = SMB2_set_ea(xid, tcon, fid.persistent_fid, fid.volatile_fid, ea, 958 size[0] = len;
956 len); 959 data[0] = ea;
957 kfree(ea); 960
961 rc = SMB2_set_info_init(tcon, &rqst[1], COMPOUND_FID,
962 COMPOUND_FID, current->tgid,
963 FILE_FULL_EA_INFORMATION,
964 SMB2_O_INFO_FILE, 0, data, size);
965 smb2_set_next_command(tcon, &rqst[1]);
966 smb2_set_related(&rqst[1]);
958 967
959 SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
960 968
969 /* Close */
970 memset(&close_iov, 0, sizeof(close_iov));
971 rqst[2].rq_iov = close_iov;
972 rqst[2].rq_nvec = 1;
973 rc = SMB2_close_init(tcon, &rqst[2], COMPOUND_FID, COMPOUND_FID);
974 smb2_set_related(&rqst[2]);
975
976 rc = compound_send_recv(xid, ses, flags, 3, rqst,
977 resp_buftype, rsp_iov);
978
979 sea_exit:
980 kfree(ea);
981 kfree(utf16_path);
982 SMB2_open_free(&rqst[0]);
983 SMB2_set_info_free(&rqst[1]);
984 SMB2_close_free(&rqst[2]);
985 free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
986 free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
987 free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base);
961 return rc; 988 return rc;
962} 989}
963#endif 990#endif
@@ -1194,7 +1221,7 @@ smb2_ioctl_query_info(const unsigned int xid,
1194 rc = SMB2_open_init(tcon, &rqst[0], &oplock, &oparms, path); 1221 rc = SMB2_open_init(tcon, &rqst[0], &oplock, &oparms, path);
1195 if (rc) 1222 if (rc)
1196 goto iqinf_exit; 1223 goto iqinf_exit;
1197 smb2_set_next_command(ses->server, &rqst[0], 0); 1224 smb2_set_next_command(tcon, &rqst[0]);
1198 1225
1199 /* Query */ 1226 /* Query */
1200 memset(&qi_iov, 0, sizeof(qi_iov)); 1227 memset(&qi_iov, 0, sizeof(qi_iov));
@@ -1208,7 +1235,7 @@ smb2_ioctl_query_info(const unsigned int xid,
1208 qi.output_buffer_length, buffer); 1235 qi.output_buffer_length, buffer);
1209 if (rc) 1236 if (rc)
1210 goto iqinf_exit; 1237 goto iqinf_exit;
1211 smb2_set_next_command(ses->server, &rqst[1], 0); 1238 smb2_set_next_command(tcon, &rqst[1]);
1212 smb2_set_related(&rqst[1]); 1239 smb2_set_related(&rqst[1]);
1213 1240
1214 /* Close */ 1241 /* Close */
@@ -1761,49 +1788,79 @@ smb2_set_related(struct smb_rqst *rqst)
1761char smb2_padding[7] = {0, 0, 0, 0, 0, 0, 0}; 1788char smb2_padding[7] = {0, 0, 0, 0, 0, 0, 0};
1762 1789
1763void 1790void
1764smb2_set_next_command(struct TCP_Server_Info *server, struct smb_rqst *rqst, 1791smb2_set_next_command(struct cifs_tcon *tcon, struct smb_rqst *rqst)
1765 bool has_space_for_padding)
1766{ 1792{
1767 struct smb2_sync_hdr *shdr; 1793 struct smb2_sync_hdr *shdr;
1794 struct cifs_ses *ses = tcon->ses;
1795 struct TCP_Server_Info *server = ses->server;
1768 unsigned long len = smb_rqst_len(server, rqst); 1796 unsigned long len = smb_rqst_len(server, rqst);
1797 int i, num_padding;
1769 1798
1770 /* SMB headers in a compound are 8 byte aligned. */ 1799 /* SMB headers in a compound are 8 byte aligned. */
1771 if (len & 7) { 1800
1772 if (has_space_for_padding) { 1801 /* No padding needed */
1773 len = rqst->rq_iov[rqst->rq_nvec - 1].iov_len; 1802 if (!(len & 7))
1774 rqst->rq_iov[rqst->rq_nvec - 1].iov_len = 1803 goto finished;
1775 (len + 7) & ~7; 1804
1776 } else { 1805 num_padding = 8 - (len & 7);
1777 rqst->rq_iov[rqst->rq_nvec].iov_base = smb2_padding; 1806 if (!smb3_encryption_required(tcon)) {
1778 rqst->rq_iov[rqst->rq_nvec].iov_len = 8 - (len & 7); 1807 /*
1779 rqst->rq_nvec++; 1808 * If we do not have encryption then we can just add an extra
1809 * iov for the padding.
1810 */
1811 rqst->rq_iov[rqst->rq_nvec].iov_base = smb2_padding;
1812 rqst->rq_iov[rqst->rq_nvec].iov_len = num_padding;
1813 rqst->rq_nvec++;
1814 len += num_padding;
1815 } else {
1816 /*
1817 * We can not add a small padding iov for the encryption case
1818 * because the encryption framework can not handle the padding
1819 * iovs.
1820 * We have to flatten this into a single buffer and add
1821 * the padding to it.
1822 */
1823 for (i = 1; i < rqst->rq_nvec; i++) {
1824 memcpy(rqst->rq_iov[0].iov_base +
1825 rqst->rq_iov[0].iov_len,
1826 rqst->rq_iov[i].iov_base,
1827 rqst->rq_iov[i].iov_len);
1828 rqst->rq_iov[0].iov_len += rqst->rq_iov[i].iov_len;
1780 } 1829 }
1781 len = smb_rqst_len(server, rqst); 1830 memset(rqst->rq_iov[0].iov_base + rqst->rq_iov[0].iov_len,
1831 0, num_padding);
1832 rqst->rq_iov[0].iov_len += num_padding;
1833 len += num_padding;
1834 rqst->rq_nvec = 1;
1782 } 1835 }
1783 1836
1837 finished:
1784 shdr = (struct smb2_sync_hdr *)(rqst->rq_iov[0].iov_base); 1838 shdr = (struct smb2_sync_hdr *)(rqst->rq_iov[0].iov_base);
1785 shdr->NextCommand = cpu_to_le32(len); 1839 shdr->NextCommand = cpu_to_le32(len);
1786} 1840}
1787 1841
1788static int 1842/*
1789smb2_queryfs(const unsigned int xid, struct cifs_tcon *tcon, 1843 * Passes the query info response back to the caller on success.
1790 struct kstatfs *buf) 1844 * Caller need to free this with free_rsp_buf().
1845 */
1846int
1847smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
1848 __le16 *utf16_path, u32 desired_access,
1849 u32 class, u32 type, u32 output_len,
1850 struct kvec *rsp, int *buftype,
1851 struct cifs_sb_info *cifs_sb)
1791{ 1852{
1792 struct smb2_query_info_rsp *rsp; 1853 struct cifs_ses *ses = tcon->ses;
1793 struct smb2_fs_full_size_info *info = NULL; 1854 int flags = 0;
1794 struct smb_rqst rqst[3]; 1855 struct smb_rqst rqst[3];
1795 int resp_buftype[3]; 1856 int resp_buftype[3];
1796 struct kvec rsp_iov[3]; 1857 struct kvec rsp_iov[3];
1797 struct kvec open_iov[SMB2_CREATE_IOV_SIZE]; 1858 struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
1798 struct kvec qi_iov[1]; 1859 struct kvec qi_iov[1];
1799 struct kvec close_iov[1]; 1860 struct kvec close_iov[1];
1800 struct cifs_ses *ses = tcon->ses;
1801 struct TCP_Server_Info *server = ses->server;
1802 __le16 srch_path = 0; /* Null - open root of share */
1803 u8 oplock = SMB2_OPLOCK_LEVEL_NONE; 1861 u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
1804 struct cifs_open_parms oparms; 1862 struct cifs_open_parms oparms;
1805 struct cifs_fid fid; 1863 struct cifs_fid fid;
1806 int flags = 0;
1807 int rc; 1864 int rc;
1808 1865
1809 if (smb3_encryption_required(tcon)) 1866 if (smb3_encryption_required(tcon))
@@ -1818,29 +1875,31 @@ smb2_queryfs(const unsigned int xid, struct cifs_tcon *tcon,
1818 rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE; 1875 rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE;
1819 1876
1820 oparms.tcon = tcon; 1877 oparms.tcon = tcon;
1821 oparms.desired_access = FILE_READ_ATTRIBUTES; 1878 oparms.desired_access = desired_access;
1822 oparms.disposition = FILE_OPEN; 1879 oparms.disposition = FILE_OPEN;
1823 oparms.create_options = 0; 1880 if (cifs_sb && backup_cred(cifs_sb))
1881 oparms.create_options = CREATE_OPEN_BACKUP_INTENT;
1882 else
1883 oparms.create_options = 0;
1824 oparms.fid = &fid; 1884 oparms.fid = &fid;
1825 oparms.reconnect = false; 1885 oparms.reconnect = false;
1826 1886
1827 rc = SMB2_open_init(tcon, &rqst[0], &oplock, &oparms, &srch_path); 1887 rc = SMB2_open_init(tcon, &rqst[0], &oplock, &oparms, utf16_path);
1828 if (rc) 1888 if (rc)
1829 goto qfs_exit; 1889 goto qic_exit;
1830 smb2_set_next_command(server, &rqst[0], 0); 1890 smb2_set_next_command(tcon, &rqst[0]);
1831 1891
1832 memset(&qi_iov, 0, sizeof(qi_iov)); 1892 memset(&qi_iov, 0, sizeof(qi_iov));
1833 rqst[1].rq_iov = qi_iov; 1893 rqst[1].rq_iov = qi_iov;
1834 rqst[1].rq_nvec = 1; 1894 rqst[1].rq_nvec = 1;
1835 1895
1836 rc = SMB2_query_info_init(tcon, &rqst[1], COMPOUND_FID, COMPOUND_FID, 1896 rc = SMB2_query_info_init(tcon, &rqst[1], COMPOUND_FID, COMPOUND_FID,
1837 FS_FULL_SIZE_INFORMATION, 1897 class, type, 0,
1838 SMB2_O_INFO_FILESYSTEM, 0, 1898 output_len, 0,
1839 sizeof(struct smb2_fs_full_size_info), 0,
1840 NULL); 1899 NULL);
1841 if (rc) 1900 if (rc)
1842 goto qfs_exit; 1901 goto qic_exit;
1843 smb2_set_next_command(server, &rqst[1], 0); 1902 smb2_set_next_command(tcon, &rqst[1]);
1844 smb2_set_related(&rqst[1]); 1903 smb2_set_related(&rqst[1]);
1845 1904
1846 memset(&close_iov, 0, sizeof(close_iov)); 1905 memset(&close_iov, 0, sizeof(close_iov));
@@ -1849,32 +1908,61 @@ smb2_queryfs(const unsigned int xid, struct cifs_tcon *tcon,
1849 1908
1850 rc = SMB2_close_init(tcon, &rqst[2], COMPOUND_FID, COMPOUND_FID); 1909 rc = SMB2_close_init(tcon, &rqst[2], COMPOUND_FID, COMPOUND_FID);
1851 if (rc) 1910 if (rc)
1852 goto qfs_exit; 1911 goto qic_exit;
1853 smb2_set_related(&rqst[2]); 1912 smb2_set_related(&rqst[2]);
1854 1913
1855 rc = compound_send_recv(xid, ses, flags, 3, rqst, 1914 rc = compound_send_recv(xid, ses, flags, 3, rqst,
1856 resp_buftype, rsp_iov); 1915 resp_buftype, rsp_iov);
1916 if (rc) {
1917 free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
1918 goto qic_exit;
1919 }
1920 *rsp = rsp_iov[1];
1921 *buftype = resp_buftype[1];
1922
1923 qic_exit:
1924 SMB2_open_free(&rqst[0]);
1925 SMB2_query_info_free(&rqst[1]);
1926 SMB2_close_free(&rqst[2]);
1927 free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
1928 free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base);
1929 return rc;
1930}
1931
1932static int
1933smb2_queryfs(const unsigned int xid, struct cifs_tcon *tcon,
1934 struct kstatfs *buf)
1935{
1936 struct smb2_query_info_rsp *rsp;
1937 struct smb2_fs_full_size_info *info = NULL;
1938 __le16 utf16_path = 0; /* Null - open root of share */
1939 struct kvec rsp_iov = {NULL, 0};
1940 int buftype = CIFS_NO_BUFFER;
1941 int rc;
1942
1943
1944 rc = smb2_query_info_compound(xid, tcon, &utf16_path,
1945 FILE_READ_ATTRIBUTES,
1946 FS_FULL_SIZE_INFORMATION,
1947 SMB2_O_INFO_FILESYSTEM,
1948 sizeof(struct smb2_fs_full_size_info),
1949 &rsp_iov, &buftype, NULL);
1857 if (rc) 1950 if (rc)
1858 goto qfs_exit; 1951 goto qfs_exit;
1859 1952
1860 rsp = (struct smb2_query_info_rsp *)rsp_iov[1].iov_base; 1953 rsp = (struct smb2_query_info_rsp *)rsp_iov.iov_base;
1861 buf->f_type = SMB2_MAGIC_NUMBER; 1954 buf->f_type = SMB2_MAGIC_NUMBER;
1862 info = (struct smb2_fs_full_size_info *)( 1955 info = (struct smb2_fs_full_size_info *)(
1863 le16_to_cpu(rsp->OutputBufferOffset) + (char *)rsp); 1956 le16_to_cpu(rsp->OutputBufferOffset) + (char *)rsp);
1864 rc = smb2_validate_iov(le16_to_cpu(rsp->OutputBufferOffset), 1957 rc = smb2_validate_iov(le16_to_cpu(rsp->OutputBufferOffset),
1865 le32_to_cpu(rsp->OutputBufferLength), 1958 le32_to_cpu(rsp->OutputBufferLength),
1866 &rsp_iov[1], 1959 &rsp_iov,
1867 sizeof(struct smb2_fs_full_size_info)); 1960 sizeof(struct smb2_fs_full_size_info));
1868 if (!rc) 1961 if (!rc)
1869 smb2_copy_fs_info_to_kstatfs(info, buf); 1962 smb2_copy_fs_info_to_kstatfs(info, buf);
1870 1963
1871qfs_exit: 1964qfs_exit:
1872 SMB2_open_free(&rqst[0]); 1965 free_rsp_buf(buftype, rsp_iov.iov_base);
1873 SMB2_query_info_free(&rqst[1]);
1874 SMB2_close_free(&rqst[2]);
1875 free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
1876 free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
1877 free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base);
1878 return rc; 1966 return rc;
1879} 1967}
1880 1968
@@ -2743,7 +2831,7 @@ init_sg(int num_rqst, struct smb_rqst *rqst, u8 *sign)
2743 smb2_sg_set_buf(&sg[idx++], 2831 smb2_sg_set_buf(&sg[idx++],
2744 rqst[i].rq_iov[j].iov_base + skip, 2832 rqst[i].rq_iov[j].iov_base + skip,
2745 rqst[i].rq_iov[j].iov_len - skip); 2833 rqst[i].rq_iov[j].iov_len - skip);
2746 } 2834 }
2747 2835
2748 for (j = 0; j < rqst[i].rq_npages; j++) { 2836 for (j = 0; j < rqst[i].rq_npages; j++) {
2749 unsigned int len, offset; 2837 unsigned int len, offset;
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 27f86537a5d1..e283590955cd 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -50,6 +50,9 @@
50#include "cifs_spnego.h" 50#include "cifs_spnego.h"
51#include "smbdirect.h" 51#include "smbdirect.h"
52#include "trace.h" 52#include "trace.h"
53#ifdef CONFIG_CIFS_DFS_UPCALL
54#include "dfs_cache.h"
55#endif
53 56
54/* 57/*
55 * The following table defines the expected "StructureSize" of SMB2 requests 58 * The following table defines the expected "StructureSize" of SMB2 requests
@@ -152,6 +155,77 @@ out:
152 return; 155 return;
153} 156}
154 157
158#ifdef CONFIG_CIFS_DFS_UPCALL
159static int __smb2_reconnect(const struct nls_table *nlsc,
160 struct cifs_tcon *tcon)
161{
162 int rc;
163 struct dfs_cache_tgt_list tl;
164 struct dfs_cache_tgt_iterator *it = NULL;
165 char tree[MAX_TREE_SIZE + 1];
166 const char *tcp_host;
167 size_t tcp_host_len;
168 const char *dfs_host;
169 size_t dfs_host_len;
170
171 if (tcon->ipc) {
172 snprintf(tree, sizeof(tree), "\\\\%s\\IPC$",
173 tcon->ses->server->hostname);
174 return SMB2_tcon(0, tcon->ses, tree, tcon, nlsc);
175 }
176
177 if (!tcon->dfs_path)
178 return SMB2_tcon(0, tcon->ses, tcon->treeName, tcon, nlsc);
179
180 rc = dfs_cache_noreq_find(tcon->dfs_path + 1, NULL, &tl);
181 if (rc)
182 return rc;
183
184 extract_unc_hostname(tcon->ses->server->hostname, &tcp_host,
185 &tcp_host_len);
186
187 for (it = dfs_cache_get_tgt_iterator(&tl); it;
188 it = dfs_cache_get_next_tgt(&tl, it)) {
189 const char *tgt = dfs_cache_get_tgt_name(it);
190
191 extract_unc_hostname(tgt, &dfs_host, &dfs_host_len);
192
193 if (dfs_host_len != tcp_host_len
194 || strncasecmp(dfs_host, tcp_host, dfs_host_len) != 0) {
195 cifs_dbg(FYI, "%s: skipping %.*s, doesn't match %.*s",
196 __func__,
197 (int)dfs_host_len, dfs_host,
198 (int)tcp_host_len, tcp_host);
199 continue;
200 }
201
202 snprintf(tree, sizeof(tree), "\\%s", tgt);
203
204 rc = SMB2_tcon(0, tcon->ses, tree, tcon, nlsc);
205 if (!rc)
206 break;
207 if (rc == -EREMOTE)
208 break;
209 }
210
211 if (!rc) {
212 if (it)
213 rc = dfs_cache_noreq_update_tgthint(tcon->dfs_path + 1,
214 it);
215 else
216 rc = -ENOENT;
217 }
218 dfs_cache_free_tgts(&tl);
219 return rc;
220}
221#else
222static inline int __smb2_reconnect(const struct nls_table *nlsc,
223 struct cifs_tcon *tcon)
224{
225 return SMB2_tcon(0, tcon->ses, tcon->treeName, tcon, nlsc);
226}
227#endif
228
155static int 229static int
156smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon) 230smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon)
157{ 231{
@@ -159,6 +233,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon)
159 struct nls_table *nls_codepage; 233 struct nls_table *nls_codepage;
160 struct cifs_ses *ses; 234 struct cifs_ses *ses;
161 struct TCP_Server_Info *server; 235 struct TCP_Server_Info *server;
236 int retries;
162 237
163 /* 238 /*
164 * SMB2s NegProt, SessSetup, Logoff do not have tcon yet so 239 * SMB2s NegProt, SessSetup, Logoff do not have tcon yet so
@@ -192,9 +267,12 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon)
192 ses = tcon->ses; 267 ses = tcon->ses;
193 server = ses->server; 268 server = ses->server;
194 269
270 retries = server->nr_targets;
271
195 /* 272 /*
196 * Give demultiplex thread up to 10 seconds to reconnect, should be 273 * Give demultiplex thread up to 10 seconds to each target available for
197 * greater than cifs socket timeout which is 7 seconds 274 * reconnect -- should be greater than cifs socket timeout which is 7
275 * seconds.
198 */ 276 */
199 while (server->tcpStatus == CifsNeedReconnect) { 277 while (server->tcpStatus == CifsNeedReconnect) {
200 /* 278 /*
@@ -225,6 +303,9 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon)
225 if (server->tcpStatus != CifsNeedReconnect) 303 if (server->tcpStatus != CifsNeedReconnect)
226 break; 304 break;
227 305
306 if (--retries)
307 continue;
308
228 /* 309 /*
229 * on "soft" mounts we wait once. Hard mounts keep 310 * on "soft" mounts we wait once. Hard mounts keep
230 * retrying until process is killed or server comes 311 * retrying until process is killed or server comes
@@ -234,6 +315,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon)
234 cifs_dbg(FYI, "gave up waiting on reconnect in smb_init\n"); 315 cifs_dbg(FYI, "gave up waiting on reconnect in smb_init\n");
235 return -EHOSTDOWN; 316 return -EHOSTDOWN;
236 } 317 }
318 retries = server->nr_targets;
237 } 319 }
238 320
239 if (!tcon->ses->need_reconnect && !tcon->need_reconnect) 321 if (!tcon->ses->need_reconnect && !tcon->need_reconnect)
@@ -271,7 +353,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon)
271 if (tcon->use_persistent) 353 if (tcon->use_persistent)
272 tcon->need_reopen_files = true; 354 tcon->need_reopen_files = true;
273 355
274 rc = SMB2_tcon(0, tcon->ses, tcon->treeName, tcon, nls_codepage); 356 rc = __smb2_reconnect(nls_codepage, tcon);
275 mutex_unlock(&tcon->ses->session_mutex); 357 mutex_unlock(&tcon->ses->session_mutex);
276 358
277 cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc); 359 cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc);
@@ -1955,7 +2037,6 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
1955 struct smb_rqst rqst; 2037 struct smb_rqst rqst;
1956 struct smb2_create_req *req; 2038 struct smb2_create_req *req;
1957 struct smb2_create_rsp *rsp = NULL; 2039 struct smb2_create_rsp *rsp = NULL;
1958 struct TCP_Server_Info *server;
1959 struct cifs_ses *ses = tcon->ses; 2040 struct cifs_ses *ses = tcon->ses;
1960 struct kvec iov[3]; /* make sure at least one for each open context */ 2041 struct kvec iov[3]; /* make sure at least one for each open context */
1961 struct kvec rsp_iov = {NULL, 0}; 2042 struct kvec rsp_iov = {NULL, 0};
@@ -1978,9 +2059,7 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
1978 if (!utf16_path) 2059 if (!utf16_path)
1979 return -ENOMEM; 2060 return -ENOMEM;
1980 2061
1981 if (ses && (ses->server)) 2062 if (!ses || !(ses->server)) {
1982 server = ses->server;
1983 else {
1984 rc = -EIO; 2063 rc = -EIO;
1985 goto err_free_path; 2064 goto err_free_path;
1986 } 2065 }
@@ -2768,18 +2847,6 @@ qinf_exit:
2768 return rc; 2847 return rc;
2769} 2848}
2770 2849
2771int SMB2_query_eas(const unsigned int xid, struct cifs_tcon *tcon,
2772 u64 persistent_fid, u64 volatile_fid,
2773 int ea_buf_size, struct smb2_file_full_ea_info *data)
2774{
2775 return query_info(xid, tcon, persistent_fid, volatile_fid,
2776 FILE_FULL_EA_INFORMATION, SMB2_O_INFO_FILE, 0,
2777 ea_buf_size,
2778 sizeof(struct smb2_file_full_ea_info),
2779 (void **)&data,
2780 NULL);
2781}
2782
2783int SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon, 2850int SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
2784 u64 persistent_fid, u64 volatile_fid, struct smb2_file_all_info *data) 2851 u64 persistent_fid, u64 volatile_fid, struct smb2_file_all_info *data)
2785{ 2852{
@@ -3994,7 +4061,6 @@ static int
3994build_qfs_info_req(struct kvec *iov, struct cifs_tcon *tcon, int level, 4061build_qfs_info_req(struct kvec *iov, struct cifs_tcon *tcon, int level,
3995 int outbuf_len, u64 persistent_fid, u64 volatile_fid) 4062 int outbuf_len, u64 persistent_fid, u64 volatile_fid)
3996{ 4063{
3997 struct TCP_Server_Info *server;
3998 int rc; 4064 int rc;
3999 struct smb2_query_info_req *req; 4065 struct smb2_query_info_req *req;
4000 unsigned int total_len; 4066 unsigned int total_len;
@@ -4004,8 +4070,6 @@ build_qfs_info_req(struct kvec *iov, struct cifs_tcon *tcon, int level,
4004 if ((tcon->ses == NULL) || (tcon->ses->server == NULL)) 4070 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
4005 return -EIO; 4071 return -EIO;
4006 4072
4007 server = tcon->ses->server;
4008
4009 rc = smb2_plain_req_init(SMB2_QUERY_INFO, tcon, (void **) &req, 4073 rc = smb2_plain_req_init(SMB2_QUERY_INFO, tcon, (void **) &req,
4010 &total_len); 4074 &total_len);
4011 if (rc) 4075 if (rc)
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index 5671d5ee7f58..05dea6750c33 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -1398,7 +1398,6 @@ struct smb2_file_link_info { /* encoding of request for level 11 */
1398 char FileName[0]; /* Name to be assigned to new link */ 1398 char FileName[0]; /* Name to be assigned to new link */
1399} __packed; /* level 11 Set */ 1399} __packed; /* level 11 Set */
1400 1400
1401#define SMB2_MIN_EA_BUF 2048
1402#define SMB2_MAX_EA_BUF 65536 1401#define SMB2_MAX_EA_BUF 65536
1403 1402
1404struct smb2_file_full_ea_info { /* encoding of response for level 15 */ 1403struct smb2_file_full_ea_info { /* encoding of response for level 15 */
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 2fe78acd7d0c..87733b27a65f 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -116,9 +116,8 @@ extern void smb2_reconnect_server(struct work_struct *work);
116extern int smb3_crypto_aead_allocate(struct TCP_Server_Info *server); 116extern int smb3_crypto_aead_allocate(struct TCP_Server_Info *server);
117extern unsigned long smb_rqst_len(struct TCP_Server_Info *server, 117extern unsigned long smb_rqst_len(struct TCP_Server_Info *server,
118 struct smb_rqst *rqst); 118 struct smb_rqst *rqst);
119extern void smb2_set_next_command(struct TCP_Server_Info *server, 119extern void smb2_set_next_command(struct cifs_tcon *tcon,
120 struct smb_rqst *rqst, 120 struct smb_rqst *rqst);
121 bool has_space_for_padding);
122extern void smb2_set_related(struct smb_rqst *rqst); 121extern void smb2_set_related(struct smb_rqst *rqst);
123 122
124/* 123/*
@@ -154,10 +153,6 @@ extern int SMB2_close_init(struct cifs_tcon *tcon, struct smb_rqst *rqst,
154extern void SMB2_close_free(struct smb_rqst *rqst); 153extern void SMB2_close_free(struct smb_rqst *rqst);
155extern int SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, 154extern int SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon,
156 u64 persistent_file_id, u64 volatile_file_id); 155 u64 persistent_file_id, u64 volatile_file_id);
157extern int SMB2_query_eas(const unsigned int xid, struct cifs_tcon *tcon,
158 u64 persistent_file_id, u64 volatile_file_id,
159 int ea_buf_size,
160 struct smb2_file_full_ea_info *data);
161extern int SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon, 156extern int SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
162 u64 persistent_file_id, u64 volatile_file_id, 157 u64 persistent_file_id, u64 volatile_file_id,
163 struct smb2_file_all_info *data); 158 struct smb2_file_all_info *data);
@@ -241,4 +236,10 @@ extern void smb2_copy_fs_info_to_kstatfs(
241extern int smb311_crypto_shash_allocate(struct TCP_Server_Info *server); 236extern int smb311_crypto_shash_allocate(struct TCP_Server_Info *server);
242extern int smb311_update_preauth_hash(struct cifs_ses *ses, 237extern int smb311_update_preauth_hash(struct cifs_ses *ses,
243 struct kvec *iov, int nvec); 238 struct kvec *iov, int nvec);
239extern int smb2_query_info_compound(const unsigned int xid,
240 struct cifs_tcon *tcon,
241 __le16 *utf16_path, u32 desired_access,
242 u32 class, u32 type, u32 output_len,
243 struct kvec *rsp, int *buftype,
244 struct cifs_sb_info *cifs_sb);
244#endif /* _SMB2PROTO_H */ 245#endif /* _SMB2PROTO_H */
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 83ff0c25710d..5be7302853b6 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -126,9 +126,11 @@ DeleteMidQEntry(struct mid_q_entry *midEntry)
126 if ((slow_rsp_threshold != 0) && 126 if ((slow_rsp_threshold != 0) &&
127 time_after(now, midEntry->when_alloc + (slow_rsp_threshold * HZ)) && 127 time_after(now, midEntry->when_alloc + (slow_rsp_threshold * HZ)) &&
128 (midEntry->command != command)) { 128 (midEntry->command != command)) {
129 /* smb2slowcmd[NUMBER_OF_SMB2_COMMANDS] counts by command */ 129 /*
130 if ((le16_to_cpu(midEntry->command) < NUMBER_OF_SMB2_COMMANDS) && 130 * smb2slowcmd[NUMBER_OF_SMB2_COMMANDS] counts by command
131 (le16_to_cpu(midEntry->command) >= 0)) 131 * NB: le16_to_cpu returns unsigned so can not be negative below
132 */
133 if (le16_to_cpu(midEntry->command) < NUMBER_OF_SMB2_COMMANDS)
132 cifs_stats_inc(&midEntry->server->smb2slowcmd[le16_to_cpu(midEntry->command)]); 134 cifs_stats_inc(&midEntry->server->smb2slowcmd[le16_to_cpu(midEntry->command)]);
133 135
134 trace_smb3_slow_rsp(le16_to_cpu(midEntry->command), 136 trace_smb3_slow_rsp(le16_to_cpu(midEntry->command),