mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-07-23 07:12:09 +00:00
4 fixes for stable, improvements to DFS including allowing failover to alternate targets, and some small performance improvements
-----BEGIN PGP SIGNATURE----- iQGzBAABCgAdFiEE6fsu8pdIjtWE/DpLiiy9cAdyT1EFAlwqtf4ACgkQiiy9cAdy T1GLwAv+I4MaCe5oq/IHDZnr09Mb/sIRLqLXnMWJciRHedHFIa/x2egb+584M+bf Lrb3UjDyS4aXV8cjrm4XO8zzzvQkTRLtaJrlxo/b1oDZJ8JkH2M6EeNr5gAB6qso dbmUX59YMX8KSpmQMhigcv+ilOQdokDWVdxqZ2ezbEMeVMotkQOnhrcSiJPx05QS CRktWjSn7JKD87cj8i0dTX+txBPX9iIpYQJGWdbJa2n6V8mQkx9JPgyQCC/FwKF2 TzCXl7wfn1gTnFSxCa/sq7lnYAr6xCngbFi+pgVU+O/Aw0dyW3AoKfF7hBOo+gAH ZJALnvhb8pJmKolXFt7OKQKuOoJSq8MInsjKSKgSe0Xt1yHEtm7IJPy6Kbj3zKVy TuDq1KXstB5m3uwO3QBmzGxZ7rCB4B1w1cGjn8MFcpK4+tOxtmSvIeYuzEj9Vxet 5JFZzMICFyzedyuBaRxyEX8SKH7CxOXCiDajxLsp7GI8KN1i0skzjgpbmZ/tdRbB kHaPnRdU =rYS/ -----END PGP SIGNATURE----- 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 ...
This commit is contained in:
commit
cacf02df4b
28 changed files with 2877 additions and 522 deletions
|
@ -1,4 +1,4 @@
|
||||||
Version 2.11 September 13, 2017
|
Version 2.14 December 21, 2018
|
||||||
|
|
||||||
A Partial List of Missing Features
|
A Partial List of Missing Features
|
||||||
==================================
|
==================================
|
||||||
|
@ -7,7 +7,7 @@ Contributions are welcome. There are plenty of opportunities
|
||||||
for visible, important contributions to this module. Here
|
for visible, important contributions to this module. Here
|
||||||
is a partial list of the known problems and missing features:
|
is a partial list of the known problems and missing features:
|
||||||
|
|
||||||
a) SMB3 (and SMB3.02) missing optional features:
|
a) SMB3 (and SMB3.1.1) missing optional features:
|
||||||
- multichannel (started), integration with RDMA
|
- multichannel (started), integration with RDMA
|
||||||
- directory leases (improved metadata caching), started (root dir only)
|
- directory leases (improved metadata caching), started (root dir only)
|
||||||
- T10 copy offload ie "ODX" (copy chunk, and "Duplicate Extents" ioctl
|
- 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
|
||||||
d) quota support (needs minor kernel change since quota calls
|
d) quota support (needs minor kernel change since quota calls
|
||||||
to make it to network filesystems or deviceless filesystems)
|
to make it to network filesystems or deviceless filesystems)
|
||||||
|
|
||||||
e) Compounding (in progress) to reduce number of roundtrips, and also
|
e) Additional use cases where we use "compoounding" (e.g. open/query/close
|
||||||
better optimize open to reduce redundant opens (using reference counts more).
|
and open/setinfo/close) to reduce the number of roundtrips, and also
|
||||||
|
open to reduce redundant opens (using deferred close and reference counts more).
|
||||||
|
|
||||||
f) Finish inotify support so kde and gnome file list windows
|
f) Finish inotify support so kde and gnome file list windows
|
||||||
will autorefresh (partially complete by Asser). Needs minor kernel
|
will autorefresh (partially complete by Asser). Needs minor kernel
|
||||||
|
@ -43,11 +44,13 @@ exists. Also better integration with winbind for resolving SID owners
|
||||||
|
|
||||||
k) Add tools to take advantage of more smb3 specific ioctls and features
|
k) Add tools to take advantage of more smb3 specific ioctls and features
|
||||||
(passthrough ioctl/fsctl for sending various SMB3 fsctls to the server
|
(passthrough ioctl/fsctl for sending various SMB3 fsctls to the server
|
||||||
is in progress)
|
is in progress, and a passthrough query_info call is already implemented
|
||||||
|
in cifs.ko to allow smb3 info levels queries to be sent from userspace)
|
||||||
|
|
||||||
l) encrypted file support
|
l) encrypted file support
|
||||||
|
|
||||||
m) improved stats gathering, tools (perhaps integration with nfsometer?)
|
m) improved stats gathering tools (perhaps integration with nfsometer?)
|
||||||
|
to extend and make easier to use what is currently in /proc/fs/cifs/Stats
|
||||||
|
|
||||||
n) allow setting more NTFS/SMB3 file attributes remotely (currently limited to compressed
|
n) allow setting more NTFS/SMB3 file attributes remotely (currently limited to compressed
|
||||||
file attribute via chflags) and improve user space tools for managing and
|
file attribute via chflags) and improve user space tools for managing and
|
||||||
|
@ -76,6 +79,9 @@ and simplify the code.
|
||||||
v) POSIX Extensions for SMB3.1.1 (started, create and mkdir support added
|
v) POSIX Extensions for SMB3.1.1 (started, create and mkdir support added
|
||||||
so far).
|
so far).
|
||||||
|
|
||||||
|
w) Add support for additional strong encryption types, and additional spnego
|
||||||
|
authentication mechanisms (see MS-SMB2)
|
||||||
|
|
||||||
KNOWN BUGS
|
KNOWN BUGS
|
||||||
====================================
|
====================================
|
||||||
See http://bugzilla.samba.org - search on product "CifsVFS" for
|
See 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
|
||||||
negotiated size) and send larger write sizes to modern servers.
|
negotiated size) and send larger write sizes to modern servers.
|
||||||
|
|
||||||
4) More exhaustively test against less common servers
|
4) More exhaustively test against less common servers
|
||||||
|
|
||||||
|
5) Continue to extend the smb3 "buildbot" which does automated xfstesting
|
||||||
|
against Windows, Samba and Azure currently - to add additional tests and
|
||||||
|
to allow the buildbot to execute the tests faster.
|
||||||
|
|
||||||
|
6) Address various coverity warnings (most are not bugs per-se, but
|
||||||
|
the more warnings are addressed, the easier it is to spot real
|
||||||
|
problems that static analyzers will point out in the future).
|
||||||
|
|
|
@ -190,8 +190,9 @@ config CIFS_DFS_UPCALL
|
||||||
moves to a different server. This feature also enables
|
moves to a different server. This feature also enables
|
||||||
an upcall mechanism for CIFS which contacts userspace helper
|
an upcall mechanism for CIFS which contacts userspace helper
|
||||||
utilities to provide server name resolution (host names to
|
utilities to provide server name resolution (host names to
|
||||||
IP addresses) which is needed for implicit mounts of DFS junction
|
IP addresses) which is needed in order to reconnect to
|
||||||
points. If unsure, say Y.
|
servers if their addresses change or for implicit mounts of
|
||||||
|
DFS junction points. If unsure, say Y.
|
||||||
|
|
||||||
config CIFS_NFSD_EXPORT
|
config CIFS_NFSD_EXPORT
|
||||||
bool "Allow nfsd to export CIFS file system"
|
bool "Allow nfsd to export CIFS file system"
|
||||||
|
|
|
@ -17,7 +17,7 @@ cifs-$(CONFIG_CIFS_ACL) += cifsacl.o
|
||||||
|
|
||||||
cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o
|
cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o
|
||||||
|
|
||||||
cifs-$(CONFIG_CIFS_DFS_UPCALL) += dns_resolve.o cifs_dfs_ref.o
|
cifs-$(CONFIG_CIFS_DFS_UPCALL) += dns_resolve.o cifs_dfs_ref.o dfs_cache.o
|
||||||
|
|
||||||
cifs-$(CONFIG_CIFS_FSCACHE) += fscache.o cache.o
|
cifs-$(CONFIG_CIFS_FSCACHE) += fscache.o cache.o
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,9 @@
|
||||||
#include "cifsproto.h"
|
#include "cifsproto.h"
|
||||||
#include "cifs_debug.h"
|
#include "cifs_debug.h"
|
||||||
#include "cifsfs.h"
|
#include "cifsfs.h"
|
||||||
|
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||||
|
#include "dfs_cache.h"
|
||||||
|
#endif
|
||||||
#ifdef CONFIG_CIFS_SMB_DIRECT
|
#ifdef CONFIG_CIFS_SMB_DIRECT
|
||||||
#include "smbdirect.h"
|
#include "smbdirect.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -629,6 +632,11 @@ cifs_proc_init(void)
|
||||||
&cifs_security_flags_proc_fops);
|
&cifs_security_flags_proc_fops);
|
||||||
proc_create("LookupCacheEnabled", 0644, proc_fs_cifs,
|
proc_create("LookupCacheEnabled", 0644, proc_fs_cifs,
|
||||||
&cifs_lookup_cache_proc_fops);
|
&cifs_lookup_cache_proc_fops);
|
||||||
|
|
||||||
|
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||||
|
proc_create("dfscache", 0644, proc_fs_cifs, &dfscache_proc_fops);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_CIFS_SMB_DIRECT
|
#ifdef CONFIG_CIFS_SMB_DIRECT
|
||||||
proc_create("rdma_readwrite_threshold", 0644, proc_fs_cifs,
|
proc_create("rdma_readwrite_threshold", 0644, proc_fs_cifs,
|
||||||
&cifs_rdma_readwrite_threshold_proc_fops);
|
&cifs_rdma_readwrite_threshold_proc_fops);
|
||||||
|
@ -663,6 +671,10 @@ cifs_proc_clean(void)
|
||||||
remove_proc_entry("SecurityFlags", proc_fs_cifs);
|
remove_proc_entry("SecurityFlags", proc_fs_cifs);
|
||||||
remove_proc_entry("LinuxExtensionsEnabled", proc_fs_cifs);
|
remove_proc_entry("LinuxExtensionsEnabled", proc_fs_cifs);
|
||||||
remove_proc_entry("LookupCacheEnabled", proc_fs_cifs);
|
remove_proc_entry("LookupCacheEnabled", proc_fs_cifs);
|
||||||
|
|
||||||
|
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||||
|
remove_proc_entry("dfscache", proc_fs_cifs);
|
||||||
|
#endif
|
||||||
#ifdef CONFIG_CIFS_SMB_DIRECT
|
#ifdef CONFIG_CIFS_SMB_DIRECT
|
||||||
remove_proc_entry("rdma_readwrite_threshold", proc_fs_cifs);
|
remove_proc_entry("rdma_readwrite_threshold", proc_fs_cifs);
|
||||||
remove_proc_entry("smbd_max_frmr_depth", proc_fs_cifs);
|
remove_proc_entry("smbd_max_frmr_depth", proc_fs_cifs);
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "dns_resolve.h"
|
#include "dns_resolve.h"
|
||||||
#include "cifs_debug.h"
|
#include "cifs_debug.h"
|
||||||
#include "cifs_unicode.h"
|
#include "cifs_unicode.h"
|
||||||
|
#include "dfs_cache.h"
|
||||||
|
|
||||||
static LIST_HEAD(cifs_dfs_automount_list);
|
static LIST_HEAD(cifs_dfs_automount_list);
|
||||||
|
|
||||||
|
@ -126,7 +127,7 @@ cifs_build_devname(char *nodename, const char *prepath)
|
||||||
* @sb_mountdata: parent/root DFS mount options (template)
|
* @sb_mountdata: parent/root DFS mount options (template)
|
||||||
* @fullpath: full path in UNC format
|
* @fullpath: full path in UNC format
|
||||||
* @ref: server's referral
|
* @ref: server's referral
|
||||||
* @devname: pointer for saving device name
|
* @devname: optional pointer for saving device name
|
||||||
*
|
*
|
||||||
* creates mount options for submount based on template options sb_mountdata
|
* creates mount options for submount based on template options sb_mountdata
|
||||||
* and replacing unc,ip,prefixpath options with ones we've got form ref_unc.
|
* 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,
|
||||||
char **devname)
|
char **devname)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
char *name;
|
||||||
char *mountdata = NULL;
|
char *mountdata = NULL;
|
||||||
const char *prepath = NULL;
|
const char *prepath = NULL;
|
||||||
int md_len;
|
int md_len;
|
||||||
|
@ -158,17 +160,17 @@ char *cifs_compose_mount_options(const char *sb_mountdata,
|
||||||
prepath++;
|
prepath++;
|
||||||
}
|
}
|
||||||
|
|
||||||
*devname = cifs_build_devname(ref->node_name, prepath);
|
name = cifs_build_devname(ref->node_name, prepath);
|
||||||
if (IS_ERR(*devname)) {
|
if (IS_ERR(name)) {
|
||||||
rc = PTR_ERR(*devname);
|
rc = PTR_ERR(name);
|
||||||
*devname = NULL;
|
name = NULL;
|
||||||
goto compose_mount_options_err;
|
goto compose_mount_options_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = dns_resolve_server_name_to_ip(*devname, &srvIP);
|
rc = dns_resolve_server_name_to_ip(name, &srvIP);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
cifs_dbg(FYI, "%s: Failed to resolve server part of %s to IP: %d\n",
|
cifs_dbg(FYI, "%s: Failed to resolve server part of %s to IP: %d\n",
|
||||||
__func__, *devname, rc);
|
__func__, name, rc);
|
||||||
goto compose_mount_options_err;
|
goto compose_mount_options_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,6 +226,9 @@ char *cifs_compose_mount_options(const char *sb_mountdata,
|
||||||
strcat(mountdata, "ip=");
|
strcat(mountdata, "ip=");
|
||||||
strcat(mountdata, srvIP);
|
strcat(mountdata, srvIP);
|
||||||
|
|
||||||
|
if (devname)
|
||||||
|
*devname = name;
|
||||||
|
|
||||||
/*cifs_dbg(FYI, "%s: parent mountdata: %s\n", __func__, sb_mountdata);*/
|
/*cifs_dbg(FYI, "%s: parent mountdata: %s\n", __func__, sb_mountdata);*/
|
||||||
/*cifs_dbg(FYI, "%s: submount mountdata: %s\n", __func__, mountdata );*/
|
/*cifs_dbg(FYI, "%s: submount mountdata: %s\n", __func__, mountdata );*/
|
||||||
|
|
||||||
|
@ -234,8 +239,7 @@ compose_mount_options_out:
|
||||||
compose_mount_options_err:
|
compose_mount_options_err:
|
||||||
kfree(mountdata);
|
kfree(mountdata);
|
||||||
mountdata = ERR_PTR(rc);
|
mountdata = ERR_PTR(rc);
|
||||||
kfree(*devname);
|
kfree(name);
|
||||||
*devname = NULL;
|
|
||||||
goto compose_mount_options_out;
|
goto compose_mount_options_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,20 +255,30 @@ static struct vfsmount *cifs_dfs_do_refmount(struct dentry *mntpt,
|
||||||
{
|
{
|
||||||
struct vfsmount *mnt;
|
struct vfsmount *mnt;
|
||||||
char *mountdata;
|
char *mountdata;
|
||||||
char *devname = NULL;
|
char *devname;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Always pass down the DFS full path to smb3_do_mount() so we
|
||||||
|
* can use it later for failover.
|
||||||
|
*/
|
||||||
|
devname = kstrndup(fullpath, strlen(fullpath), GFP_KERNEL);
|
||||||
|
if (!devname)
|
||||||
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
|
convert_delimiter(devname, '/');
|
||||||
|
|
||||||
/* strip first '\' from fullpath */
|
/* strip first '\' from fullpath */
|
||||||
mountdata = cifs_compose_mount_options(cifs_sb->mountdata,
|
mountdata = cifs_compose_mount_options(cifs_sb->mountdata,
|
||||||
fullpath + 1, ref, &devname);
|
fullpath + 1, ref, NULL);
|
||||||
|
if (IS_ERR(mountdata)) {
|
||||||
if (IS_ERR(mountdata))
|
kfree(devname);
|
||||||
return (struct vfsmount *)mountdata;
|
return (struct vfsmount *)mountdata;
|
||||||
|
}
|
||||||
|
|
||||||
mnt = vfs_submount(mntpt, &cifs_fs_type, devname, mountdata);
|
mnt = vfs_submount(mntpt, &cifs_fs_type, devname, mountdata);
|
||||||
kfree(mountdata);
|
kfree(mountdata);
|
||||||
kfree(devname);
|
kfree(devname);
|
||||||
return mnt;
|
return mnt;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dump_referral(const struct dfs_info3_param *ref)
|
static void dump_referral(const struct dfs_info3_param *ref)
|
||||||
|
@ -282,16 +296,15 @@ static void dump_referral(const struct dfs_info3_param *ref)
|
||||||
*/
|
*/
|
||||||
static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
|
static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
|
||||||
{
|
{
|
||||||
struct dfs_info3_param *referrals = NULL;
|
struct dfs_info3_param referral = {0};
|
||||||
unsigned int num_referrals = 0;
|
|
||||||
struct cifs_sb_info *cifs_sb;
|
struct cifs_sb_info *cifs_sb;
|
||||||
struct cifs_ses *ses;
|
struct cifs_ses *ses;
|
||||||
char *full_path;
|
struct cifs_tcon *tcon;
|
||||||
|
char *full_path, *root_path;
|
||||||
unsigned int xid;
|
unsigned int xid;
|
||||||
int i;
|
int len;
|
||||||
int rc;
|
int rc;
|
||||||
struct vfsmount *mnt;
|
struct vfsmount *mnt;
|
||||||
struct tcon_link *tlink;
|
|
||||||
|
|
||||||
cifs_dbg(FYI, "in %s\n", __func__);
|
cifs_dbg(FYI, "in %s\n", __func__);
|
||||||
BUG_ON(IS_ROOT(mntpt));
|
BUG_ON(IS_ROOT(mntpt));
|
||||||
|
@ -315,48 +328,69 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
|
||||||
if (full_path == NULL)
|
if (full_path == NULL)
|
||||||
goto cdda_exit;
|
goto cdda_exit;
|
||||||
|
|
||||||
tlink = cifs_sb_tlink(cifs_sb);
|
cifs_dbg(FYI, "%s: full_path: %s\n", __func__, full_path);
|
||||||
if (IS_ERR(tlink)) {
|
|
||||||
mnt = ERR_CAST(tlink);
|
if (!cifs_sb_master_tlink(cifs_sb)) {
|
||||||
|
cifs_dbg(FYI, "%s: master tlink is NULL\n", __func__);
|
||||||
goto free_full_path;
|
goto free_full_path;
|
||||||
}
|
}
|
||||||
ses = tlink_tcon(tlink)->ses;
|
|
||||||
|
|
||||||
xid = get_xid();
|
tcon = cifs_sb_master_tcon(cifs_sb);
|
||||||
rc = get_dfs_path(xid, ses, full_path + 1, cifs_sb->local_nls,
|
if (!tcon) {
|
||||||
&num_referrals, &referrals,
|
cifs_dbg(FYI, "%s: master tcon is NULL\n", __func__);
|
||||||
cifs_remap(cifs_sb));
|
goto free_full_path;
|
||||||
free_xid(xid);
|
|
||||||
|
|
||||||
cifs_put_tlink(tlink);
|
|
||||||
|
|
||||||
mnt = ERR_PTR(-ENOENT);
|
|
||||||
for (i = 0; i < num_referrals; i++) {
|
|
||||||
int len;
|
|
||||||
dump_referral(referrals + i);
|
|
||||||
/* connect to a node */
|
|
||||||
len = strlen(referrals[i].node_name);
|
|
||||||
if (len < 2) {
|
|
||||||
cifs_dbg(VFS, "%s: Net Address path too short: %s\n",
|
|
||||||
__func__, referrals[i].node_name);
|
|
||||||
mnt = ERR_PTR(-EINVAL);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
mnt = cifs_dfs_do_refmount(mntpt, cifs_sb,
|
|
||||||
full_path, referrals + i);
|
|
||||||
cifs_dbg(FYI, "%s: cifs_dfs_do_refmount:%s , mnt:%p\n",
|
|
||||||
__func__, referrals[i].node_name, mnt);
|
|
||||||
if (!IS_ERR(mnt))
|
|
||||||
goto success;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* no valid submounts were found; return error from get_dfs_path() by
|
root_path = kstrdup(tcon->treeName, GFP_KERNEL);
|
||||||
* preference */
|
if (!root_path) {
|
||||||
if (rc != 0)
|
mnt = ERR_PTR(-ENOMEM);
|
||||||
mnt = ERR_PTR(rc);
|
goto free_full_path;
|
||||||
|
}
|
||||||
|
cifs_dbg(FYI, "%s: root path: %s\n", __func__, root_path);
|
||||||
|
|
||||||
success:
|
ses = tcon->ses;
|
||||||
free_dfs_info_array(referrals, num_referrals);
|
xid = get_xid();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If DFS root has been expired, then unconditionally fetch it again to
|
||||||
|
* refresh DFS referral cache.
|
||||||
|
*/
|
||||||
|
rc = dfs_cache_find(xid, ses, cifs_sb->local_nls, cifs_remap(cifs_sb),
|
||||||
|
root_path + 1, NULL, NULL);
|
||||||
|
if (!rc) {
|
||||||
|
rc = dfs_cache_find(xid, ses, cifs_sb->local_nls,
|
||||||
|
cifs_remap(cifs_sb), full_path + 1,
|
||||||
|
&referral, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
free_xid(xid);
|
||||||
|
|
||||||
|
if (rc) {
|
||||||
|
mnt = ERR_PTR(rc);
|
||||||
|
goto free_root_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
dump_referral(&referral);
|
||||||
|
|
||||||
|
len = strlen(referral.node_name);
|
||||||
|
if (len < 2) {
|
||||||
|
cifs_dbg(VFS, "%s: Net Address path too short: %s\n",
|
||||||
|
__func__, referral.node_name);
|
||||||
|
mnt = ERR_PTR(-EINVAL);
|
||||||
|
goto free_dfs_ref;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* cifs_mount() will retry every available node server in case
|
||||||
|
* of failures.
|
||||||
|
*/
|
||||||
|
mnt = cifs_dfs_do_refmount(mntpt, cifs_sb, full_path, &referral);
|
||||||
|
cifs_dbg(FYI, "%s: cifs_dfs_do_refmount:%s , mnt:%p\n", __func__,
|
||||||
|
referral.node_name, mnt);
|
||||||
|
|
||||||
|
free_dfs_ref:
|
||||||
|
free_dfs_info_param(&referral);
|
||||||
|
free_root_path:
|
||||||
|
kfree(root_path);
|
||||||
free_full_path:
|
free_full_path:
|
||||||
kfree(full_path);
|
kfree(full_path);
|
||||||
cdda_exit:
|
cdda_exit:
|
||||||
|
|
|
@ -72,6 +72,15 @@ struct cifs_sb_info {
|
||||||
char *mountdata; /* options received at mount time or via DFS refs */
|
char *mountdata; /* options received at mount time or via DFS refs */
|
||||||
struct delayed_work prune_tlinks;
|
struct delayed_work prune_tlinks;
|
||||||
struct rcu_head rcu;
|
struct rcu_head rcu;
|
||||||
|
|
||||||
|
/* only used when CIFS_MOUNT_USE_PREFIX_PATH is set */
|
||||||
char *prepath;
|
char *prepath;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Path initially provided by the mount call. We might connect
|
||||||
|
* to something different via DFS but we want to keep it to do
|
||||||
|
* failover properly.
|
||||||
|
*/
|
||||||
|
char *origin_fullpath; /* \\HOST\SHARE\[OPTIONAL PATH] */
|
||||||
};
|
};
|
||||||
#endif /* _CIFS_FS_SB_H */
|
#endif /* _CIFS_FS_SB_H */
|
||||||
|
|
|
@ -224,7 +224,7 @@ int cifs_verify_signature(struct smb_rqst *rqst,
|
||||||
if (cifs_pdu->Command == SMB_COM_LOCKING_ANDX) {
|
if (cifs_pdu->Command == SMB_COM_LOCKING_ANDX) {
|
||||||
struct smb_com_lock_req *pSMB =
|
struct smb_com_lock_req *pSMB =
|
||||||
(struct smb_com_lock_req *)cifs_pdu;
|
(struct smb_com_lock_req *)cifs_pdu;
|
||||||
if (pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE)
|
if (pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,12 +304,17 @@ int setup_ntlm_response(struct cifs_ses *ses, const struct nls_table *nls_cp)
|
||||||
int calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt,
|
int calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt,
|
||||||
char *lnm_session_key)
|
char *lnm_session_key)
|
||||||
{
|
{
|
||||||
int i;
|
int i, len;
|
||||||
int rc;
|
int rc;
|
||||||
char password_with_pad[CIFS_ENCPWD_SIZE] = {0};
|
char password_with_pad[CIFS_ENCPWD_SIZE] = {0};
|
||||||
|
|
||||||
if (password)
|
if (password) {
|
||||||
strncpy(password_with_pad, password, CIFS_ENCPWD_SIZE);
|
for (len = 0; len < CIFS_ENCPWD_SIZE; len++)
|
||||||
|
if (!password[len])
|
||||||
|
break;
|
||||||
|
|
||||||
|
memcpy(password_with_pad, password, len);
|
||||||
|
}
|
||||||
|
|
||||||
if (!encrypt && global_secflags & CIFSSEC_MAY_PLNTXT) {
|
if (!encrypt && global_secflags & CIFSSEC_MAY_PLNTXT) {
|
||||||
memcpy(lnm_session_key, password_with_pad,
|
memcpy(lnm_session_key, password_with_pad,
|
||||||
|
|
|
@ -52,6 +52,9 @@
|
||||||
#include "cifs_spnego.h"
|
#include "cifs_spnego.h"
|
||||||
#include "fscache.h"
|
#include "fscache.h"
|
||||||
#include "smb2pdu.h"
|
#include "smb2pdu.h"
|
||||||
|
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||||
|
#include "dfs_cache.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
int cifsFYI = 0;
|
int cifsFYI = 0;
|
||||||
bool traceSMB;
|
bool traceSMB;
|
||||||
|
@ -1494,10 +1497,15 @@ init_cifs(void)
|
||||||
if (rc)
|
if (rc)
|
||||||
goto out_destroy_mids;
|
goto out_destroy_mids;
|
||||||
|
|
||||||
|
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||||
|
rc = dfs_cache_init();
|
||||||
|
if (rc)
|
||||||
|
goto out_destroy_request_bufs;
|
||||||
|
#endif /* CONFIG_CIFS_DFS_UPCALL */
|
||||||
#ifdef CONFIG_CIFS_UPCALL
|
#ifdef CONFIG_CIFS_UPCALL
|
||||||
rc = init_cifs_spnego();
|
rc = init_cifs_spnego();
|
||||||
if (rc)
|
if (rc)
|
||||||
goto out_destroy_request_bufs;
|
goto out_destroy_dfs_cache;
|
||||||
#endif /* CONFIG_CIFS_UPCALL */
|
#endif /* CONFIG_CIFS_UPCALL */
|
||||||
|
|
||||||
#ifdef CONFIG_CIFS_ACL
|
#ifdef CONFIG_CIFS_ACL
|
||||||
|
@ -1525,6 +1533,10 @@ out_register_key_type:
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_CIFS_UPCALL
|
#ifdef CONFIG_CIFS_UPCALL
|
||||||
exit_cifs_spnego();
|
exit_cifs_spnego();
|
||||||
|
out_destroy_dfs_cache:
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||||
|
dfs_cache_destroy();
|
||||||
out_destroy_request_bufs:
|
out_destroy_request_bufs:
|
||||||
#endif
|
#endif
|
||||||
cifs_destroy_request_bufs();
|
cifs_destroy_request_bufs();
|
||||||
|
@ -1555,6 +1567,9 @@ exit_cifs(void)
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_CIFS_UPCALL
|
#ifdef CONFIG_CIFS_UPCALL
|
||||||
exit_cifs_spnego();
|
exit_cifs_spnego();
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||||
|
dfs_cache_destroy();
|
||||||
#endif
|
#endif
|
||||||
cifs_destroy_request_bufs();
|
cifs_destroy_request_bufs();
|
||||||
cifs_destroy_mids();
|
cifs_destroy_mids();
|
||||||
|
|
|
@ -150,5 +150,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
|
||||||
extern const struct export_operations cifs_export_ops;
|
extern const struct export_operations cifs_export_ops;
|
||||||
#endif /* CONFIG_CIFS_NFSD_EXPORT */
|
#endif /* CONFIG_CIFS_NFSD_EXPORT */
|
||||||
|
|
||||||
#define CIFS_VERSION "2.14"
|
#define CIFS_VERSION "2.15"
|
||||||
#endif /* _CIFSFS_H */
|
#endif /* _CIFSFS_H */
|
||||||
|
|
|
@ -701,6 +701,13 @@ struct TCP_Server_Info {
|
||||||
struct delayed_work reconnect; /* reconnect workqueue job */
|
struct delayed_work reconnect; /* reconnect workqueue job */
|
||||||
struct mutex reconnect_mutex; /* prevent simultaneous reconnects */
|
struct mutex reconnect_mutex; /* prevent simultaneous reconnects */
|
||||||
unsigned long echo_interval;
|
unsigned long echo_interval;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Number of targets available for reconnect. The more targets
|
||||||
|
* the more tasks have to wait to let the demultiplex thread
|
||||||
|
* reconnect.
|
||||||
|
*/
|
||||||
|
int nr_targets;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline unsigned int
|
static inline unsigned int
|
||||||
|
@ -1014,6 +1021,11 @@ struct cifs_tcon {
|
||||||
struct list_head pending_opens; /* list of incomplete opens */
|
struct list_head pending_opens; /* list of incomplete opens */
|
||||||
struct cached_fid crfid; /* Cached root fid */
|
struct cached_fid crfid; /* Cached root fid */
|
||||||
/* BB add field for back pointer to sb struct(s)? */
|
/* BB add field for back pointer to sb struct(s)? */
|
||||||
|
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||||
|
char *dfs_path;
|
||||||
|
int remap:2;
|
||||||
|
struct list_head ulist; /* cache update list */
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1508,6 +1520,7 @@ struct dfs_info3_param {
|
||||||
int ref_flag;
|
int ref_flag;
|
||||||
char *path_name;
|
char *path_name;
|
||||||
char *node_name;
|
char *node_name;
|
||||||
|
int ttl;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1545,7 +1558,6 @@ static inline void free_dfs_info_param(struct dfs_info3_param *param)
|
||||||
if (param) {
|
if (param) {
|
||||||
kfree(param->path_name);
|
kfree(param->path_name);
|
||||||
kfree(param->node_name);
|
kfree(param->node_name);
|
||||||
kfree(param);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1790,6 +1802,7 @@ extern struct smb_version_values smb3any_values;
|
||||||
extern struct smb_version_operations smb30_operations;
|
extern struct smb_version_operations smb30_operations;
|
||||||
extern struct smb_version_values smb30_values;
|
extern struct smb_version_values smb30_values;
|
||||||
#define SMB302_VERSION_STRING "3.02"
|
#define SMB302_VERSION_STRING "3.02"
|
||||||
|
#define ALT_SMB302_VERSION_STRING "3.0.2"
|
||||||
/*extern struct smb_version_operations smb302_operations;*/ /* not needed yet */
|
/*extern struct smb_version_operations smb302_operations;*/ /* not needed yet */
|
||||||
extern struct smb_version_values smb302_values;
|
extern struct smb_version_values smb302_values;
|
||||||
#define SMB311_VERSION_STRING "3.1.1"
|
#define SMB311_VERSION_STRING "3.1.1"
|
||||||
|
|
|
@ -22,6 +22,9 @@
|
||||||
#define _CIFSPROTO_H
|
#define _CIFSPROTO_H
|
||||||
#include <linux/nls.h>
|
#include <linux/nls.h>
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
|
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||||
|
#include "dfs_cache.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
struct statfs;
|
struct statfs;
|
||||||
struct smb_vol;
|
struct smb_vol;
|
||||||
|
@ -213,7 +216,7 @@ extern int cifs_match_super(struct super_block *, void *);
|
||||||
extern void cifs_cleanup_volume_info(struct smb_vol *pvolume_info);
|
extern void cifs_cleanup_volume_info(struct smb_vol *pvolume_info);
|
||||||
extern struct smb_vol *cifs_get_volume_info(char *mount_data,
|
extern struct smb_vol *cifs_get_volume_info(char *mount_data,
|
||||||
const char *devname, bool is_smb3);
|
const char *devname, bool is_smb3);
|
||||||
extern int cifs_mount(struct cifs_sb_info *, struct smb_vol *);
|
extern int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *vol);
|
||||||
extern void cifs_umount(struct cifs_sb_info *);
|
extern void cifs_umount(struct cifs_sb_info *);
|
||||||
extern void cifs_mark_open_files_invalid(struct cifs_tcon *tcon);
|
extern void cifs_mark_open_files_invalid(struct cifs_tcon *tcon);
|
||||||
extern void cifs_reopen_persistent_handles(struct cifs_tcon *tcon);
|
extern void cifs_reopen_persistent_handles(struct cifs_tcon *tcon);
|
||||||
|
@ -294,11 +297,6 @@ extern int CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
|
||||||
unsigned int *num_of_nodes,
|
unsigned int *num_of_nodes,
|
||||||
const struct nls_table *nls_codepage, int remap);
|
const struct nls_table *nls_codepage, int remap);
|
||||||
|
|
||||||
extern int get_dfs_path(const unsigned int xid, struct cifs_ses *ses,
|
|
||||||
const char *old_path,
|
|
||||||
const struct nls_table *nls_codepage,
|
|
||||||
unsigned int *num_referrals,
|
|
||||||
struct dfs_info3_param **referrals, int remap);
|
|
||||||
extern int parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size,
|
extern int parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size,
|
||||||
unsigned int *num_of_nodes,
|
unsigned int *num_of_nodes,
|
||||||
struct dfs_info3_param **target_nodes,
|
struct dfs_info3_param **target_nodes,
|
||||||
|
@ -524,6 +522,11 @@ extern int E_md4hash(const unsigned char *passwd, unsigned char *p16,
|
||||||
const struct nls_table *codepage);
|
const struct nls_table *codepage);
|
||||||
extern int SMBencrypt(unsigned char *passwd, const unsigned char *c8,
|
extern int SMBencrypt(unsigned char *passwd, const unsigned char *c8,
|
||||||
unsigned char *p24);
|
unsigned char *p24);
|
||||||
|
extern void
|
||||||
|
cifs_cleanup_volume_info_contents(struct smb_vol *volume_info);
|
||||||
|
|
||||||
|
extern struct TCP_Server_Info *
|
||||||
|
cifs_find_tcp_session(struct smb_vol *vol);
|
||||||
|
|
||||||
void cifs_readdata_release(struct kref *refcount);
|
void cifs_readdata_release(struct kref *refcount);
|
||||||
int cifs_async_readv(struct cifs_readdata *rdata);
|
int cifs_async_readv(struct cifs_readdata *rdata);
|
||||||
|
@ -562,4 +565,17 @@ void cifs_free_hash(struct crypto_shash **shash, struct sdesc **sdesc);
|
||||||
extern void rqst_page_get_length(struct smb_rqst *rqst, unsigned int page,
|
extern void rqst_page_get_length(struct smb_rqst *rqst, unsigned int page,
|
||||||
unsigned int *len, unsigned int *offset);
|
unsigned int *len, unsigned int *offset);
|
||||||
|
|
||||||
|
void extract_unc_hostname(const char *unc, const char **h, size_t *len);
|
||||||
|
|
||||||
|
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||||
|
static inline int get_dfs_path(const unsigned int xid, struct cifs_ses *ses,
|
||||||
|
const char *old_path,
|
||||||
|
const struct nls_table *nls_codepage,
|
||||||
|
struct dfs_info3_param *referral, int remap)
|
||||||
|
{
|
||||||
|
return dfs_cache_find(xid, ses, nls_codepage, remap, old_path,
|
||||||
|
referral, NULL);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* _CIFSPROTO_H */
|
#endif /* _CIFSPROTO_H */
|
||||||
|
|
|
@ -44,6 +44,9 @@
|
||||||
#include "cifs_debug.h"
|
#include "cifs_debug.h"
|
||||||
#include "fscache.h"
|
#include "fscache.h"
|
||||||
#include "smbdirect.h"
|
#include "smbdirect.h"
|
||||||
|
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||||
|
#include "dfs_cache.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_CIFS_POSIX
|
#ifdef CONFIG_CIFS_POSIX
|
||||||
static struct {
|
static struct {
|
||||||
|
@ -118,6 +121,77 @@ cifs_mark_open_files_invalid(struct cifs_tcon *tcon)
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||||
|
static int __cifs_reconnect_tcon(const struct nls_table *nlsc,
|
||||||
|
struct cifs_tcon *tcon)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
struct dfs_cache_tgt_list tl;
|
||||||
|
struct dfs_cache_tgt_iterator *it = NULL;
|
||||||
|
char tree[MAX_TREE_SIZE + 1];
|
||||||
|
const char *tcp_host;
|
||||||
|
size_t tcp_host_len;
|
||||||
|
const char *dfs_host;
|
||||||
|
size_t dfs_host_len;
|
||||||
|
|
||||||
|
if (tcon->ipc) {
|
||||||
|
snprintf(tree, sizeof(tree), "\\\\%s\\IPC$",
|
||||||
|
tcon->ses->server->hostname);
|
||||||
|
return CIFSTCon(0, tcon->ses, tree, tcon, nlsc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tcon->dfs_path)
|
||||||
|
return CIFSTCon(0, tcon->ses, tcon->treeName, tcon, nlsc);
|
||||||
|
|
||||||
|
rc = dfs_cache_noreq_find(tcon->dfs_path + 1, NULL, &tl);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
extract_unc_hostname(tcon->ses->server->hostname, &tcp_host,
|
||||||
|
&tcp_host_len);
|
||||||
|
|
||||||
|
for (it = dfs_cache_get_tgt_iterator(&tl); it;
|
||||||
|
it = dfs_cache_get_next_tgt(&tl, it)) {
|
||||||
|
const char *tgt = dfs_cache_get_tgt_name(it);
|
||||||
|
|
||||||
|
extract_unc_hostname(tgt, &dfs_host, &dfs_host_len);
|
||||||
|
|
||||||
|
if (dfs_host_len != tcp_host_len
|
||||||
|
|| strncasecmp(dfs_host, tcp_host, dfs_host_len) != 0) {
|
||||||
|
cifs_dbg(FYI, "%s: skipping %.*s, doesn't match %.*s",
|
||||||
|
__func__,
|
||||||
|
(int)dfs_host_len, dfs_host,
|
||||||
|
(int)tcp_host_len, tcp_host);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(tree, sizeof(tree), "\\%s", tgt);
|
||||||
|
|
||||||
|
rc = CIFSTCon(0, tcon->ses, tree, tcon, nlsc);
|
||||||
|
if (!rc)
|
||||||
|
break;
|
||||||
|
if (rc == -EREMOTE)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!rc) {
|
||||||
|
if (it)
|
||||||
|
rc = dfs_cache_noreq_update_tgthint(tcon->dfs_path + 1,
|
||||||
|
it);
|
||||||
|
else
|
||||||
|
rc = -ENOENT;
|
||||||
|
}
|
||||||
|
dfs_cache_free_tgts(&tl);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static inline int __cifs_reconnect_tcon(const struct nls_table *nlsc,
|
||||||
|
struct cifs_tcon *tcon)
|
||||||
|
{
|
||||||
|
return CIFSTCon(0, tcon->ses, tcon->treeName, tcon, nlsc);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* reconnect the socket, tcon, and smb session if needed */
|
/* reconnect the socket, tcon, and smb session if needed */
|
||||||
static int
|
static int
|
||||||
cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
|
cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
|
||||||
|
@ -126,6 +200,7 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
|
||||||
struct cifs_ses *ses;
|
struct cifs_ses *ses;
|
||||||
struct TCP_Server_Info *server;
|
struct TCP_Server_Info *server;
|
||||||
struct nls_table *nls_codepage;
|
struct nls_table *nls_codepage;
|
||||||
|
int retries;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
|
* 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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
retries = server->nr_targets;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Give demultiplex thread up to 10 seconds to reconnect, should be
|
* Give demultiplex thread up to 10 seconds to each target available for
|
||||||
* greater than cifs socket timeout which is 7 seconds
|
* reconnect -- should be greater than cifs socket timeout which is 7
|
||||||
|
* seconds.
|
||||||
*/
|
*/
|
||||||
while (server->tcpStatus == CifsNeedReconnect) {
|
while (server->tcpStatus == CifsNeedReconnect) {
|
||||||
rc = wait_event_interruptible_timeout(server->response_q,
|
rc = wait_event_interruptible_timeout(server->response_q,
|
||||||
|
@ -170,6 +248,9 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
|
||||||
if (server->tcpStatus != CifsNeedReconnect)
|
if (server->tcpStatus != CifsNeedReconnect)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
if (--retries)
|
||||||
|
continue;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* on "soft" mounts we wait once. Hard mounts keep
|
* on "soft" mounts we wait once. Hard mounts keep
|
||||||
* retrying until process is killed or server comes
|
* retrying until process is killed or server comes
|
||||||
|
@ -179,6 +260,7 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
|
||||||
cifs_dbg(FYI, "gave up waiting on reconnect in smb_init\n");
|
cifs_dbg(FYI, "gave up waiting on reconnect in smb_init\n");
|
||||||
return -EHOSTDOWN;
|
return -EHOSTDOWN;
|
||||||
}
|
}
|
||||||
|
retries = server->nr_targets;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ses->need_reconnect && !tcon->need_reconnect)
|
if (!ses->need_reconnect && !tcon->need_reconnect)
|
||||||
|
@ -214,7 +296,7 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
|
||||||
}
|
}
|
||||||
|
|
||||||
cifs_mark_open_files_invalid(tcon);
|
cifs_mark_open_files_invalid(tcon);
|
||||||
rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
|
rc = __cifs_reconnect_tcon(nls_codepage, tcon);
|
||||||
mutex_unlock(&ses->session_mutex);
|
mutex_unlock(&ses->session_mutex);
|
||||||
cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc);
|
cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc);
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
1367
fs/cifs/dfs_cache.c
Normal file
1367
fs/cifs/dfs_cache.c
Normal file
File diff suppressed because it is too large
Load diff
97
fs/cifs/dfs_cache.h
Normal file
97
fs/cifs/dfs_cache.h
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
/*
|
||||||
|
* DFS referral cache routines
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Paulo Alcantara <palcantara@suse.de>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _CIFS_DFS_CACHE_H
|
||||||
|
#define _CIFS_DFS_CACHE_H
|
||||||
|
|
||||||
|
#include <linux/nls.h>
|
||||||
|
#include <linux/list.h>
|
||||||
|
#include "cifsglob.h"
|
||||||
|
|
||||||
|
struct dfs_cache_tgt_list {
|
||||||
|
int tl_numtgts;
|
||||||
|
struct list_head tl_list;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dfs_cache_tgt_iterator {
|
||||||
|
char *it_name;
|
||||||
|
struct list_head it_list;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern int dfs_cache_init(void);
|
||||||
|
extern void dfs_cache_destroy(void);
|
||||||
|
extern const struct file_operations dfscache_proc_fops;
|
||||||
|
|
||||||
|
extern int dfs_cache_find(const unsigned int xid, struct cifs_ses *ses,
|
||||||
|
const struct nls_table *nls_codepage, int remap,
|
||||||
|
const char *path, struct dfs_info3_param *ref,
|
||||||
|
struct dfs_cache_tgt_list *tgt_list);
|
||||||
|
extern int dfs_cache_noreq_find(const char *path, struct dfs_info3_param *ref,
|
||||||
|
struct dfs_cache_tgt_list *tgt_list);
|
||||||
|
extern int dfs_cache_update_tgthint(const unsigned int xid,
|
||||||
|
struct cifs_ses *ses,
|
||||||
|
const struct nls_table *nls_codepage,
|
||||||
|
int remap, const char *path,
|
||||||
|
const struct dfs_cache_tgt_iterator *it);
|
||||||
|
extern int
|
||||||
|
dfs_cache_noreq_update_tgthint(const char *path,
|
||||||
|
const struct dfs_cache_tgt_iterator *it);
|
||||||
|
extern int dfs_cache_get_tgt_referral(const char *path,
|
||||||
|
const struct dfs_cache_tgt_iterator *it,
|
||||||
|
struct dfs_info3_param *ref);
|
||||||
|
extern int dfs_cache_add_vol(struct smb_vol *vol, const char *fullpath);
|
||||||
|
extern int dfs_cache_update_vol(const char *fullpath,
|
||||||
|
struct TCP_Server_Info *server);
|
||||||
|
extern void dfs_cache_del_vol(const char *fullpath);
|
||||||
|
|
||||||
|
static inline struct dfs_cache_tgt_iterator *
|
||||||
|
dfs_cache_get_next_tgt(struct dfs_cache_tgt_list *tl,
|
||||||
|
struct dfs_cache_tgt_iterator *it)
|
||||||
|
{
|
||||||
|
if (!tl || list_empty(&tl->tl_list) || !it ||
|
||||||
|
list_is_last(&it->it_list, &tl->tl_list))
|
||||||
|
return NULL;
|
||||||
|
return list_next_entry(it, it_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct dfs_cache_tgt_iterator *
|
||||||
|
dfs_cache_get_tgt_iterator(struct dfs_cache_tgt_list *tl)
|
||||||
|
{
|
||||||
|
if (!tl)
|
||||||
|
return NULL;
|
||||||
|
return list_first_entry_or_null(&tl->tl_list,
|
||||||
|
struct dfs_cache_tgt_iterator,
|
||||||
|
it_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void dfs_cache_free_tgts(struct dfs_cache_tgt_list *tl)
|
||||||
|
{
|
||||||
|
struct dfs_cache_tgt_iterator *it, *nit;
|
||||||
|
|
||||||
|
if (!tl || list_empty(&tl->tl_list))
|
||||||
|
return;
|
||||||
|
list_for_each_entry_safe(it, nit, &tl->tl_list, it_list) {
|
||||||
|
list_del(&it->it_list);
|
||||||
|
kfree(it->it_name);
|
||||||
|
kfree(it);
|
||||||
|
}
|
||||||
|
tl->tl_numtgts = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline const char *
|
||||||
|
dfs_cache_get_tgt_name(const struct dfs_cache_tgt_iterator *it)
|
||||||
|
{
|
||||||
|
return it ? it->it_name : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
dfs_cache_get_nr_tgts(const struct dfs_cache_tgt_list *tl)
|
||||||
|
{
|
||||||
|
return tl ? tl->tl_numtgts : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _CIFS_DFS_CACHE_H */
|
|
@ -2617,11 +2617,13 @@ cifs_write_from_iter(loff_t offset, size_t len, struct iov_iter *from,
|
||||||
if (rc)
|
if (rc)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
cur_len = min_t(const size_t, len, wsize);
|
||||||
|
|
||||||
if (ctx->direct_io) {
|
if (ctx->direct_io) {
|
||||||
ssize_t result;
|
ssize_t result;
|
||||||
|
|
||||||
result = iov_iter_get_pages_alloc(
|
result = iov_iter_get_pages_alloc(
|
||||||
from, &pagevec, wsize, &start);
|
from, &pagevec, cur_len, &start);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
cifs_dbg(VFS,
|
cifs_dbg(VFS,
|
||||||
"direct_writev couldn't get user pages "
|
"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,
|
||||||
result, from->type,
|
result, from->type,
|
||||||
from->iov_offset, from->count);
|
from->iov_offset, from->count);
|
||||||
dump_stack();
|
dump_stack();
|
||||||
|
|
||||||
|
rc = result;
|
||||||
|
add_credits_and_wake_if(server, credits, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
cur_len = (size_t)result;
|
cur_len = (size_t)result;
|
||||||
|
@ -3313,13 +3318,16 @@ cifs_send_async_read(loff_t offset, size_t len, struct cifsFileInfo *open_file,
|
||||||
cur_len, &start);
|
cur_len, &start);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
cifs_dbg(VFS,
|
cifs_dbg(VFS,
|
||||||
"couldn't get user pages (cur_len=%zd)"
|
"couldn't get user pages (rc=%zd)"
|
||||||
" iter type %d"
|
" iter type %d"
|
||||||
" iov_offset %zd count %zd\n",
|
" iov_offset %zd count %zd\n",
|
||||||
result, direct_iov.type,
|
result, direct_iov.type,
|
||||||
direct_iov.iov_offset,
|
direct_iov.iov_offset,
|
||||||
direct_iov.count);
|
direct_iov.count);
|
||||||
dump_stack();
|
dump_stack();
|
||||||
|
|
||||||
|
rc = result;
|
||||||
|
add_credits_and_wake_if(server, credits, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
cur_len = (size_t)result;
|
cur_len = (size_t)result;
|
||||||
|
|
|
@ -333,7 +333,7 @@ cifs_create_dfs_fattr(struct cifs_fattr *fattr, struct super_block *sb)
|
||||||
fattr->cf_mtime = timespec64_trunc(fattr->cf_mtime, sb->s_time_gran);
|
fattr->cf_mtime = timespec64_trunc(fattr->cf_mtime, sb->s_time_gran);
|
||||||
fattr->cf_atime = fattr->cf_ctime = fattr->cf_mtime;
|
fattr->cf_atime = fattr->cf_ctime = fattr->cf_mtime;
|
||||||
fattr->cf_nlink = 2;
|
fattr->cf_nlink = 2;
|
||||||
fattr->cf_flags |= CIFS_FATTR_DFS_REFERRAL;
|
fattr->cf_flags = CIFS_FATTR_DFS_REFERRAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -730,7 +730,6 @@ cifs_get_inode_info(struct inode **inode, const char *full_path,
|
||||||
FILE_ALL_INFO *data, struct super_block *sb, int xid,
|
FILE_ALL_INFO *data, struct super_block *sb, int xid,
|
||||||
const struct cifs_fid *fid)
|
const struct cifs_fid *fid)
|
||||||
{
|
{
|
||||||
bool validinum = false;
|
|
||||||
__u16 srchflgs;
|
__u16 srchflgs;
|
||||||
int rc = 0, tmprc = ENOSYS;
|
int rc = 0, tmprc = ENOSYS;
|
||||||
struct cifs_tcon *tcon;
|
struct cifs_tcon *tcon;
|
||||||
|
@ -821,7 +820,6 @@ cifs_get_inode_info(struct inode **inode, const char *full_path,
|
||||||
(FILE_DIRECTORY_INFO *)data, cifs_sb);
|
(FILE_DIRECTORY_INFO *)data, cifs_sb);
|
||||||
fattr.cf_uniqueid = le64_to_cpu(
|
fattr.cf_uniqueid = le64_to_cpu(
|
||||||
((SEARCH_ID_FULL_DIR_INFO *)data)->UniqueId);
|
((SEARCH_ID_FULL_DIR_INFO *)data)->UniqueId);
|
||||||
validinum = true;
|
|
||||||
|
|
||||||
cifs_buf_release(srchinf->ntwrk_buf_start);
|
cifs_buf_release(srchinf->ntwrk_buf_start);
|
||||||
}
|
}
|
||||||
|
@ -840,31 +838,29 @@ cifs_get_inode_info(struct inode **inode, const char *full_path,
|
||||||
*/
|
*/
|
||||||
if (*inode == NULL) {
|
if (*inode == NULL) {
|
||||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
|
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
|
||||||
if (validinum == false) {
|
if (server->ops->get_srv_inum)
|
||||||
if (server->ops->get_srv_inum)
|
tmprc = server->ops->get_srv_inum(xid,
|
||||||
tmprc = server->ops->get_srv_inum(xid,
|
tcon, cifs_sb, full_path,
|
||||||
tcon, cifs_sb, full_path,
|
&fattr.cf_uniqueid, data);
|
||||||
&fattr.cf_uniqueid, data);
|
if (tmprc) {
|
||||||
if (tmprc) {
|
cifs_dbg(FYI, "GetSrvInodeNum rc %d\n",
|
||||||
cifs_dbg(FYI, "GetSrvInodeNum rc %d\n",
|
tmprc);
|
||||||
tmprc);
|
fattr.cf_uniqueid = iunique(sb, ROOT_I);
|
||||||
fattr.cf_uniqueid = iunique(sb, ROOT_I);
|
cifs_autodisable_serverino(cifs_sb);
|
||||||
cifs_autodisable_serverino(cifs_sb);
|
} else if ((fattr.cf_uniqueid == 0) &&
|
||||||
} else if ((fattr.cf_uniqueid == 0) &&
|
strlen(full_path) == 0) {
|
||||||
strlen(full_path) == 0) {
|
/* some servers ret bad root ino ie 0 */
|
||||||
/* some servers ret bad root ino ie 0 */
|
cifs_dbg(FYI, "Invalid (0) inodenum\n");
|
||||||
cifs_dbg(FYI, "Invalid (0) inodenum\n");
|
fattr.cf_flags |=
|
||||||
fattr.cf_flags |=
|
CIFS_FATTR_FAKE_ROOT_INO;
|
||||||
CIFS_FATTR_FAKE_ROOT_INO;
|
fattr.cf_uniqueid =
|
||||||
fattr.cf_uniqueid =
|
simple_hashstr(tcon->treeName);
|
||||||
simple_hashstr(tcon->treeName);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
fattr.cf_uniqueid = iunique(sb, ROOT_I);
|
fattr.cf_uniqueid = iunique(sb, ROOT_I);
|
||||||
} else {
|
} else {
|
||||||
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) &&
|
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
|
||||||
validinum == false && server->ops->get_srv_inum) {
|
&& server->ops->get_srv_inum) {
|
||||||
/*
|
/*
|
||||||
* Pass a NULL tcon to ensure we don't make a round
|
* Pass a NULL tcon to ensure we don't make a round
|
||||||
* trip to the server. This only works for SMB2+.
|
* trip to the server. This only works for SMB2+.
|
||||||
|
|
|
@ -111,21 +111,27 @@ struct cifs_tcon *
|
||||||
tconInfoAlloc(void)
|
tconInfoAlloc(void)
|
||||||
{
|
{
|
||||||
struct cifs_tcon *ret_buf;
|
struct cifs_tcon *ret_buf;
|
||||||
ret_buf = kzalloc(sizeof(struct cifs_tcon), GFP_KERNEL);
|
|
||||||
if (ret_buf) {
|
ret_buf = kzalloc(sizeof(*ret_buf), GFP_KERNEL);
|
||||||
atomic_inc(&tconInfoAllocCount);
|
if (!ret_buf)
|
||||||
ret_buf->tidStatus = CifsNew;
|
return NULL;
|
||||||
++ret_buf->tc_count;
|
ret_buf->crfid.fid = kzalloc(sizeof(*ret_buf->crfid.fid), GFP_KERNEL);
|
||||||
INIT_LIST_HEAD(&ret_buf->openFileList);
|
if (!ret_buf->crfid.fid) {
|
||||||
INIT_LIST_HEAD(&ret_buf->tcon_list);
|
kfree(ret_buf);
|
||||||
spin_lock_init(&ret_buf->open_file_lock);
|
return NULL;
|
||||||
mutex_init(&ret_buf->crfid.fid_mutex);
|
|
||||||
ret_buf->crfid.fid = kzalloc(sizeof(struct cifs_fid),
|
|
||||||
GFP_KERNEL);
|
|
||||||
spin_lock_init(&ret_buf->stat_lock);
|
|
||||||
atomic_set(&ret_buf->num_local_opens, 0);
|
|
||||||
atomic_set(&ret_buf->num_remote_opens, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
atomic_inc(&tconInfoAllocCount);
|
||||||
|
ret_buf->tidStatus = CifsNew;
|
||||||
|
++ret_buf->tc_count;
|
||||||
|
INIT_LIST_HEAD(&ret_buf->openFileList);
|
||||||
|
INIT_LIST_HEAD(&ret_buf->tcon_list);
|
||||||
|
spin_lock_init(&ret_buf->open_file_lock);
|
||||||
|
mutex_init(&ret_buf->crfid.fid_mutex);
|
||||||
|
spin_lock_init(&ret_buf->stat_lock);
|
||||||
|
atomic_set(&ret_buf->num_local_opens, 0);
|
||||||
|
atomic_set(&ret_buf->num_remote_opens, 0);
|
||||||
|
|
||||||
return ret_buf;
|
return ret_buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,6 +146,9 @@ tconInfoFree(struct cifs_tcon *buf_to_free)
|
||||||
kfree(buf_to_free->nativeFileSystem);
|
kfree(buf_to_free->nativeFileSystem);
|
||||||
kzfree(buf_to_free->password);
|
kzfree(buf_to_free->password);
|
||||||
kfree(buf_to_free->crfid.fid);
|
kfree(buf_to_free->crfid.fid);
|
||||||
|
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||||
|
kfree(buf_to_free->dfs_path);
|
||||||
|
#endif
|
||||||
kfree(buf_to_free);
|
kfree(buf_to_free);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -525,9 +534,17 @@ void
|
||||||
cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb)
|
cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb)
|
||||||
{
|
{
|
||||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
|
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
|
||||||
|
struct cifs_tcon *tcon = NULL;
|
||||||
|
|
||||||
|
if (cifs_sb->master_tlink)
|
||||||
|
tcon = cifs_sb_master_tcon(cifs_sb);
|
||||||
|
|
||||||
cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM;
|
cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM;
|
||||||
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",
|
cifs_dbg(VFS, "Autodisabling the use of server inode numbers on %s.\n",
|
||||||
cifs_sb_master_tcon(cifs_sb)->treeName);
|
tcon ? tcon->treeName : "new server");
|
||||||
|
cifs_dbg(VFS, "The server doesn't seem to support them properly or the files might be on different servers (DFS).\n");
|
||||||
|
cifs_dbg(VFS, "Hardlinks will not be recognized on this mount. Consider mounting with the \"noserverino\" option to silence this message.\n");
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -732,6 +749,8 @@ parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size,
|
||||||
goto parse_DFS_referrals_exit;
|
goto parse_DFS_referrals_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
node->ttl = le32_to_cpu(ref->TimeToLive);
|
||||||
|
|
||||||
ref++;
|
ref++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -933,3 +952,20 @@ void rqst_page_get_length(struct smb_rqst *rqst, unsigned int page,
|
||||||
else if (page == 0)
|
else if (page == 0)
|
||||||
*len = rqst->rq_pagesz - rqst->rq_offset;
|
*len = rqst->rq_pagesz - rqst->rq_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void extract_unc_hostname(const char *unc, const char **h, size_t *len)
|
||||||
|
{
|
||||||
|
const char *end;
|
||||||
|
|
||||||
|
/* skip initial slashes */
|
||||||
|
while (*unc && (*unc == '\\' || *unc == '/'))
|
||||||
|
unc++;
|
||||||
|
|
||||||
|
end = unc;
|
||||||
|
|
||||||
|
while (*end && !(*end == '\\' || *end == '/'))
|
||||||
|
end++;
|
||||||
|
|
||||||
|
*h = unc;
|
||||||
|
*len = end - unc;
|
||||||
|
}
|
||||||
|
|
|
@ -655,7 +655,14 @@ find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon, loff_t pos,
|
||||||
/* scan and find it */
|
/* scan and find it */
|
||||||
int i;
|
int i;
|
||||||
char *cur_ent;
|
char *cur_ent;
|
||||||
char *end_of_smb = cfile->srch_inf.ntwrk_buf_start +
|
char *end_of_smb;
|
||||||
|
|
||||||
|
if (cfile->srch_inf.ntwrk_buf_start == NULL) {
|
||||||
|
cifs_dbg(VFS, "ntwrk_buf_start is NULL during readdir\n");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
end_of_smb = cfile->srch_inf.ntwrk_buf_start +
|
||||||
server->ops->calc_smb_size(
|
server->ops->calc_smb_size(
|
||||||
cfile->srch_inf.ntwrk_buf_start,
|
cfile->srch_inf.ntwrk_buf_start,
|
||||||
server);
|
server);
|
||||||
|
|
|
@ -534,9 +534,9 @@ cifs_select_sectype(struct TCP_Server_Info *server, enum securityEnum requested)
|
||||||
if (global_secflags & CIFSSEC_MAY_NTLM)
|
if (global_secflags & CIFSSEC_MAY_NTLM)
|
||||||
return NTLM;
|
return NTLM;
|
||||||
default:
|
default:
|
||||||
/* Fallthrough to attempt LANMAN authentication next */
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
/* Fallthrough - to attempt LANMAN authentication next */
|
||||||
case CIFS_NEGFLAVOR_LANMAN:
|
case CIFS_NEGFLAVOR_LANMAN:
|
||||||
switch (requested) {
|
switch (requested) {
|
||||||
case LANMAN:
|
case LANMAN:
|
||||||
|
@ -1154,14 +1154,12 @@ out:
|
||||||
static int
|
static int
|
||||||
_sess_auth_rawntlmssp_assemble_req(struct sess_data *sess_data)
|
_sess_auth_rawntlmssp_assemble_req(struct sess_data *sess_data)
|
||||||
{
|
{
|
||||||
struct smb_hdr *smb_buf;
|
|
||||||
SESSION_SETUP_ANDX *pSMB;
|
SESSION_SETUP_ANDX *pSMB;
|
||||||
struct cifs_ses *ses = sess_data->ses;
|
struct cifs_ses *ses = sess_data->ses;
|
||||||
__u32 capabilities;
|
__u32 capabilities;
|
||||||
char *bcc_ptr;
|
char *bcc_ptr;
|
||||||
|
|
||||||
pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
|
pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
|
||||||
smb_buf = (struct smb_hdr *)pSMB;
|
|
||||||
|
|
||||||
capabilities = cifs_ssetup_hdr(ses, pSMB);
|
capabilities = cifs_ssetup_hdr(ses, pSMB);
|
||||||
if ((pSMB->req.hdr.Flags2 & SMBFLG2_UNICODE) == 0) {
|
if ((pSMB->req.hdr.Flags2 & SMBFLG2_UNICODE) == 0) {
|
||||||
|
|
|
@ -929,19 +929,18 @@ cifs_unix_dfs_readlink(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||||
int rc;
|
int rc;
|
||||||
unsigned int num_referrals = 0;
|
struct dfs_info3_param referral = {0};
|
||||||
struct dfs_info3_param *referrals = NULL;
|
|
||||||
|
|
||||||
rc = get_dfs_path(xid, tcon->ses, searchName, nls_codepage,
|
rc = get_dfs_path(xid, tcon->ses, searchName, nls_codepage, &referral,
|
||||||
&num_referrals, &referrals, 0);
|
0);
|
||||||
|
|
||||||
if (!rc && num_referrals > 0) {
|
if (!rc) {
|
||||||
*symlinkinfo = kstrndup(referrals->node_name,
|
*symlinkinfo = kstrndup(referral.node_name,
|
||||||
strlen(referrals->node_name),
|
strlen(referral.node_name),
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
|
free_dfs_info_param(&referral);
|
||||||
if (!*symlinkinfo)
|
if (!*symlinkinfo)
|
||||||
rc = -ENOMEM;
|
rc = -ENOMEM;
|
||||||
free_dfs_info_array(referrals, num_referrals);
|
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
#else /* No DFS support */
|
#else /* No DFS support */
|
||||||
|
|
|
@ -49,7 +49,6 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
struct cifs_open_parms oparms;
|
struct cifs_open_parms oparms;
|
||||||
struct cifs_fid fid;
|
struct cifs_fid fid;
|
||||||
struct cifs_ses *ses = tcon->ses;
|
struct cifs_ses *ses = tcon->ses;
|
||||||
struct TCP_Server_Info *server = ses->server;
|
|
||||||
int num_rqst = 0;
|
int num_rqst = 0;
|
||||||
struct smb_rqst rqst[3];
|
struct smb_rqst rqst[3];
|
||||||
int resp_buftype[3];
|
int resp_buftype[3];
|
||||||
|
@ -97,7 +96,7 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
if (rc)
|
if (rc)
|
||||||
goto finished;
|
goto finished;
|
||||||
|
|
||||||
smb2_set_next_command(server, &rqst[num_rqst++], 0);
|
smb2_set_next_command(tcon, &rqst[num_rqst++]);
|
||||||
|
|
||||||
/* Operation */
|
/* Operation */
|
||||||
switch (command) {
|
switch (command) {
|
||||||
|
@ -111,7 +110,7 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
SMB2_O_INFO_FILE, 0,
|
SMB2_O_INFO_FILE, 0,
|
||||||
sizeof(struct smb2_file_all_info) +
|
sizeof(struct smb2_file_all_info) +
|
||||||
PATH_MAX * 2, 0, NULL);
|
PATH_MAX * 2, 0, NULL);
|
||||||
smb2_set_next_command(server, &rqst[num_rqst], 0);
|
smb2_set_next_command(tcon, &rqst[num_rqst]);
|
||||||
smb2_set_related(&rqst[num_rqst++]);
|
smb2_set_related(&rqst[num_rqst++]);
|
||||||
break;
|
break;
|
||||||
case SMB2_OP_DELETE:
|
case SMB2_OP_DELETE:
|
||||||
|
@ -134,7 +133,7 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
COMPOUND_FID, current->tgid,
|
COMPOUND_FID, current->tgid,
|
||||||
FILE_DISPOSITION_INFORMATION,
|
FILE_DISPOSITION_INFORMATION,
|
||||||
SMB2_O_INFO_FILE, 0, data, size);
|
SMB2_O_INFO_FILE, 0, data, size);
|
||||||
smb2_set_next_command(server, &rqst[num_rqst], 1);
|
smb2_set_next_command(tcon, &rqst[num_rqst]);
|
||||||
smb2_set_related(&rqst[num_rqst++]);
|
smb2_set_related(&rqst[num_rqst++]);
|
||||||
break;
|
break;
|
||||||
case SMB2_OP_SET_EOF:
|
case SMB2_OP_SET_EOF:
|
||||||
|
@ -149,7 +148,7 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
COMPOUND_FID, current->tgid,
|
COMPOUND_FID, current->tgid,
|
||||||
FILE_END_OF_FILE_INFORMATION,
|
FILE_END_OF_FILE_INFORMATION,
|
||||||
SMB2_O_INFO_FILE, 0, data, size);
|
SMB2_O_INFO_FILE, 0, data, size);
|
||||||
smb2_set_next_command(server, &rqst[num_rqst], 0);
|
smb2_set_next_command(tcon, &rqst[num_rqst]);
|
||||||
smb2_set_related(&rqst[num_rqst++]);
|
smb2_set_related(&rqst[num_rqst++]);
|
||||||
break;
|
break;
|
||||||
case SMB2_OP_SET_INFO:
|
case SMB2_OP_SET_INFO:
|
||||||
|
@ -165,7 +164,7 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
COMPOUND_FID, current->tgid,
|
COMPOUND_FID, current->tgid,
|
||||||
FILE_BASIC_INFORMATION,
|
FILE_BASIC_INFORMATION,
|
||||||
SMB2_O_INFO_FILE, 0, data, size);
|
SMB2_O_INFO_FILE, 0, data, size);
|
||||||
smb2_set_next_command(server, &rqst[num_rqst], 0);
|
smb2_set_next_command(tcon, &rqst[num_rqst]);
|
||||||
smb2_set_related(&rqst[num_rqst++]);
|
smb2_set_related(&rqst[num_rqst++]);
|
||||||
break;
|
break;
|
||||||
case SMB2_OP_RENAME:
|
case SMB2_OP_RENAME:
|
||||||
|
@ -189,7 +188,7 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
COMPOUND_FID, current->tgid,
|
COMPOUND_FID, current->tgid,
|
||||||
FILE_RENAME_INFORMATION,
|
FILE_RENAME_INFORMATION,
|
||||||
SMB2_O_INFO_FILE, 0, data, size);
|
SMB2_O_INFO_FILE, 0, data, size);
|
||||||
smb2_set_next_command(server, &rqst[num_rqst], 0);
|
smb2_set_next_command(tcon, &rqst[num_rqst]);
|
||||||
smb2_set_related(&rqst[num_rqst++]);
|
smb2_set_related(&rqst[num_rqst++]);
|
||||||
break;
|
break;
|
||||||
case SMB2_OP_HARDLINK:
|
case SMB2_OP_HARDLINK:
|
||||||
|
@ -213,7 +212,7 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
COMPOUND_FID, current->tgid,
|
COMPOUND_FID, current->tgid,
|
||||||
FILE_LINK_INFORMATION,
|
FILE_LINK_INFORMATION,
|
||||||
SMB2_O_INFO_FILE, 0, data, size);
|
SMB2_O_INFO_FILE, 0, data, size);
|
||||||
smb2_set_next_command(server, &rqst[num_rqst], 0);
|
smb2_set_next_command(tcon, &rqst[num_rqst]);
|
||||||
smb2_set_related(&rqst[num_rqst++]);
|
smb2_set_related(&rqst[num_rqst++]);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -388,7 +387,6 @@ smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
rc = -ENOMEM;
|
rc = -ENOMEM;
|
||||||
goto smb2_rename_path;
|
goto smb2_rename_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = smb2_compound_op(xid, tcon, cifs_sb, from_name, access,
|
rc = smb2_compound_op(xid, tcon, cifs_sb, from_name, access,
|
||||||
FILE_OPEN, 0, smb2_to_name, command);
|
FILE_OPEN, 0, smb2_to_name, command);
|
||||||
smb2_rename_path:
|
smb2_rename_path:
|
||||||
|
|
|
@ -379,8 +379,8 @@ static const struct status_to_posix_error smb2_error_map_table[] = {
|
||||||
{STATUS_NONEXISTENT_EA_ENTRY, -EIO, "STATUS_NONEXISTENT_EA_ENTRY"},
|
{STATUS_NONEXISTENT_EA_ENTRY, -EIO, "STATUS_NONEXISTENT_EA_ENTRY"},
|
||||||
{STATUS_NO_EAS_ON_FILE, -ENODATA, "STATUS_NO_EAS_ON_FILE"},
|
{STATUS_NO_EAS_ON_FILE, -ENODATA, "STATUS_NO_EAS_ON_FILE"},
|
||||||
{STATUS_EA_CORRUPT_ERROR, -EIO, "STATUS_EA_CORRUPT_ERROR"},
|
{STATUS_EA_CORRUPT_ERROR, -EIO, "STATUS_EA_CORRUPT_ERROR"},
|
||||||
{STATUS_FILE_LOCK_CONFLICT, -EIO, "STATUS_FILE_LOCK_CONFLICT"},
|
{STATUS_FILE_LOCK_CONFLICT, -EACCES, "STATUS_FILE_LOCK_CONFLICT"},
|
||||||
{STATUS_LOCK_NOT_GRANTED, -EIO, "STATUS_LOCK_NOT_GRANTED"},
|
{STATUS_LOCK_NOT_GRANTED, -EACCES, "STATUS_LOCK_NOT_GRANTED"},
|
||||||
{STATUS_DELETE_PENDING, -ENOENT, "STATUS_DELETE_PENDING"},
|
{STATUS_DELETE_PENDING, -ENOENT, "STATUS_DELETE_PENDING"},
|
||||||
{STATUS_CTL_FILE_NOT_SUPPORTED, -ENOSYS,
|
{STATUS_CTL_FILE_NOT_SUPPORTED, -ENOSYS,
|
||||||
"STATUS_CTL_FILE_NOT_SUPPORTED"},
|
"STATUS_CTL_FILE_NOT_SUPPORTED"},
|
||||||
|
|
|
@ -831,72 +831,48 @@ smb2_query_eas(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
__le16 *utf16_path;
|
__le16 *utf16_path;
|
||||||
__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
|
struct kvec rsp_iov = {NULL, 0};
|
||||||
struct cifs_open_parms oparms;
|
int buftype = CIFS_NO_BUFFER;
|
||||||
struct cifs_fid fid;
|
struct smb2_query_info_rsp *rsp;
|
||||||
struct smb2_file_full_ea_info *smb2_data;
|
struct smb2_file_full_ea_info *info = NULL;
|
||||||
int ea_buf_size = SMB2_MIN_EA_BUF;
|
|
||||||
|
|
||||||
utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
|
utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
|
||||||
if (!utf16_path)
|
if (!utf16_path)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
oparms.tcon = tcon;
|
rc = smb2_query_info_compound(xid, tcon, utf16_path,
|
||||||
oparms.desired_access = FILE_READ_EA;
|
FILE_READ_EA,
|
||||||
oparms.disposition = FILE_OPEN;
|
FILE_FULL_EA_INFORMATION,
|
||||||
if (backup_cred(cifs_sb))
|
SMB2_O_INFO_FILE,
|
||||||
oparms.create_options = CREATE_OPEN_BACKUP_INTENT;
|
SMB2_MAX_EA_BUF,
|
||||||
else
|
&rsp_iov, &buftype, cifs_sb);
|
||||||
oparms.create_options = 0;
|
|
||||||
oparms.fid = &fid;
|
|
||||||
oparms.reconnect = false;
|
|
||||||
|
|
||||||
rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL, NULL);
|
|
||||||
kfree(utf16_path);
|
|
||||||
if (rc) {
|
if (rc) {
|
||||||
cifs_dbg(FYI, "open failed rc=%d\n", rc);
|
/*
|
||||||
return rc;
|
* If ea_name is NULL (listxattr) and there are no EAs,
|
||||||
|
* return 0 as it's not an error. Otherwise, the specified
|
||||||
|
* ea_name was not found.
|
||||||
|
*/
|
||||||
|
if (!ea_name && rc == -ENODATA)
|
||||||
|
rc = 0;
|
||||||
|
goto qeas_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (1) {
|
rsp = (struct smb2_query_info_rsp *)rsp_iov.iov_base;
|
||||||
smb2_data = kzalloc(ea_buf_size, GFP_KERNEL);
|
rc = smb2_validate_iov(le16_to_cpu(rsp->OutputBufferOffset),
|
||||||
if (smb2_data == NULL) {
|
le32_to_cpu(rsp->OutputBufferLength),
|
||||||
SMB2_close(xid, tcon, fid.persistent_fid,
|
&rsp_iov,
|
||||||
fid.volatile_fid);
|
sizeof(struct smb2_file_full_ea_info));
|
||||||
return -ENOMEM;
|
if (rc)
|
||||||
}
|
goto qeas_exit;
|
||||||
|
|
||||||
rc = SMB2_query_eas(xid, tcon, fid.persistent_fid,
|
info = (struct smb2_file_full_ea_info *)(
|
||||||
fid.volatile_fid,
|
le16_to_cpu(rsp->OutputBufferOffset) + (char *)rsp);
|
||||||
ea_buf_size, smb2_data);
|
rc = move_smb2_ea_to_cifs(ea_data, buf_size, info,
|
||||||
|
le32_to_cpu(rsp->OutputBufferLength), ea_name);
|
||||||
|
|
||||||
if (rc != -E2BIG)
|
qeas_exit:
|
||||||
break;
|
kfree(utf16_path);
|
||||||
|
free_rsp_buf(buftype, rsp_iov.iov_base);
|
||||||
kfree(smb2_data);
|
|
||||||
ea_buf_size <<= 1;
|
|
||||||
|
|
||||||
if (ea_buf_size > SMB2_MAX_EA_BUF) {
|
|
||||||
cifs_dbg(VFS, "EA size is too large\n");
|
|
||||||
SMB2_close(xid, tcon, fid.persistent_fid,
|
|
||||||
fid.volatile_fid);
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If ea_name is NULL (listxattr) and there are no EAs, return 0 as it's
|
|
||||||
* not an error. Otherwise, the specified ea_name was not found.
|
|
||||||
*/
|
|
||||||
if (!rc)
|
|
||||||
rc = move_smb2_ea_to_cifs(ea_data, buf_size, smb2_data,
|
|
||||||
SMB2_MAX_EA_BUF, ea_name);
|
|
||||||
else if (!ea_name && rc == -ENODATA)
|
|
||||||
rc = 0;
|
|
||||||
|
|
||||||
kfree(smb2_data);
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -907,14 +883,27 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
const __u16 ea_value_len, const struct nls_table *nls_codepage,
|
const __u16 ea_value_len, const struct nls_table *nls_codepage,
|
||||||
struct cifs_sb_info *cifs_sb)
|
struct cifs_sb_info *cifs_sb)
|
||||||
{
|
{
|
||||||
int rc;
|
struct cifs_ses *ses = tcon->ses;
|
||||||
__le16 *utf16_path;
|
__le16 *utf16_path = NULL;
|
||||||
__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
|
|
||||||
struct cifs_open_parms oparms;
|
|
||||||
struct cifs_fid fid;
|
|
||||||
struct smb2_file_full_ea_info *ea;
|
|
||||||
int ea_name_len = strlen(ea_name);
|
int ea_name_len = strlen(ea_name);
|
||||||
|
int flags = 0;
|
||||||
int len;
|
int len;
|
||||||
|
struct smb_rqst rqst[3];
|
||||||
|
int resp_buftype[3];
|
||||||
|
struct kvec rsp_iov[3];
|
||||||
|
struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
|
||||||
|
struct cifs_open_parms oparms;
|
||||||
|
__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
|
||||||
|
struct cifs_fid fid;
|
||||||
|
struct kvec si_iov[SMB2_SET_INFO_IOV_SIZE];
|
||||||
|
unsigned int size[1];
|
||||||
|
void *data[1];
|
||||||
|
struct smb2_file_full_ea_info *ea = NULL;
|
||||||
|
struct kvec close_iov[1];
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (smb3_encryption_required(tcon))
|
||||||
|
flags |= CIFS_TRANSFORM_REQ;
|
||||||
|
|
||||||
if (ea_name_len > 255)
|
if (ea_name_len > 255)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -923,6 +912,16 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
if (!utf16_path)
|
if (!utf16_path)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
memset(rqst, 0, sizeof(rqst));
|
||||||
|
resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
|
||||||
|
memset(rsp_iov, 0, sizeof(rsp_iov));
|
||||||
|
|
||||||
|
/* Open */
|
||||||
|
memset(&open_iov, 0, sizeof(open_iov));
|
||||||
|
rqst[0].rq_iov = open_iov;
|
||||||
|
rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE;
|
||||||
|
|
||||||
|
memset(&oparms, 0, sizeof(oparms));
|
||||||
oparms.tcon = tcon;
|
oparms.tcon = tcon;
|
||||||
oparms.desired_access = FILE_WRITE_EA;
|
oparms.desired_access = FILE_WRITE_EA;
|
||||||
oparms.disposition = FILE_OPEN;
|
oparms.disposition = FILE_OPEN;
|
||||||
|
@ -933,18 +932,22 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
oparms.fid = &fid;
|
oparms.fid = &fid;
|
||||||
oparms.reconnect = false;
|
oparms.reconnect = false;
|
||||||
|
|
||||||
rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL, NULL);
|
rc = SMB2_open_init(tcon, &rqst[0], &oplock, &oparms, utf16_path);
|
||||||
kfree(utf16_path);
|
if (rc)
|
||||||
if (rc) {
|
goto sea_exit;
|
||||||
cifs_dbg(FYI, "open failed rc=%d\n", rc);
|
smb2_set_next_command(tcon, &rqst[0]);
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
/* Set Info */
|
||||||
|
memset(&si_iov, 0, sizeof(si_iov));
|
||||||
|
rqst[1].rq_iov = si_iov;
|
||||||
|
rqst[1].rq_nvec = 1;
|
||||||
|
|
||||||
len = sizeof(ea) + ea_name_len + ea_value_len + 1;
|
len = sizeof(ea) + ea_name_len + ea_value_len + 1;
|
||||||
ea = kzalloc(len, GFP_KERNEL);
|
ea = kzalloc(len, GFP_KERNEL);
|
||||||
if (ea == NULL) {
|
if (ea == NULL) {
|
||||||
SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
|
rc = -ENOMEM;
|
||||||
return -ENOMEM;
|
goto sea_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
ea->ea_name_length = ea_name_len;
|
ea->ea_name_length = ea_name_len;
|
||||||
|
@ -952,12 +955,36 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
memcpy(ea->ea_data, ea_name, ea_name_len + 1);
|
memcpy(ea->ea_data, ea_name, ea_name_len + 1);
|
||||||
memcpy(ea->ea_data + ea_name_len + 1, ea_value, ea_value_len);
|
memcpy(ea->ea_data + ea_name_len + 1, ea_value, ea_value_len);
|
||||||
|
|
||||||
rc = SMB2_set_ea(xid, tcon, fid.persistent_fid, fid.volatile_fid, ea,
|
size[0] = len;
|
||||||
len);
|
data[0] = ea;
|
||||||
|
|
||||||
|
rc = SMB2_set_info_init(tcon, &rqst[1], COMPOUND_FID,
|
||||||
|
COMPOUND_FID, current->tgid,
|
||||||
|
FILE_FULL_EA_INFORMATION,
|
||||||
|
SMB2_O_INFO_FILE, 0, data, size);
|
||||||
|
smb2_set_next_command(tcon, &rqst[1]);
|
||||||
|
smb2_set_related(&rqst[1]);
|
||||||
|
|
||||||
|
|
||||||
|
/* Close */
|
||||||
|
memset(&close_iov, 0, sizeof(close_iov));
|
||||||
|
rqst[2].rq_iov = close_iov;
|
||||||
|
rqst[2].rq_nvec = 1;
|
||||||
|
rc = SMB2_close_init(tcon, &rqst[2], COMPOUND_FID, COMPOUND_FID);
|
||||||
|
smb2_set_related(&rqst[2]);
|
||||||
|
|
||||||
|
rc = compound_send_recv(xid, ses, flags, 3, rqst,
|
||||||
|
resp_buftype, rsp_iov);
|
||||||
|
|
||||||
|
sea_exit:
|
||||||
kfree(ea);
|
kfree(ea);
|
||||||
|
kfree(utf16_path);
|
||||||
SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
|
SMB2_open_free(&rqst[0]);
|
||||||
|
SMB2_set_info_free(&rqst[1]);
|
||||||
|
SMB2_close_free(&rqst[2]);
|
||||||
|
free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
|
||||||
|
free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
|
||||||
|
free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -1194,7 +1221,7 @@ smb2_ioctl_query_info(const unsigned int xid,
|
||||||
rc = SMB2_open_init(tcon, &rqst[0], &oplock, &oparms, path);
|
rc = SMB2_open_init(tcon, &rqst[0], &oplock, &oparms, path);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto iqinf_exit;
|
goto iqinf_exit;
|
||||||
smb2_set_next_command(ses->server, &rqst[0], 0);
|
smb2_set_next_command(tcon, &rqst[0]);
|
||||||
|
|
||||||
/* Query */
|
/* Query */
|
||||||
memset(&qi_iov, 0, sizeof(qi_iov));
|
memset(&qi_iov, 0, sizeof(qi_iov));
|
||||||
|
@ -1208,7 +1235,7 @@ smb2_ioctl_query_info(const unsigned int xid,
|
||||||
qi.output_buffer_length, buffer);
|
qi.output_buffer_length, buffer);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto iqinf_exit;
|
goto iqinf_exit;
|
||||||
smb2_set_next_command(ses->server, &rqst[1], 0);
|
smb2_set_next_command(tcon, &rqst[1]);
|
||||||
smb2_set_related(&rqst[1]);
|
smb2_set_related(&rqst[1]);
|
||||||
|
|
||||||
/* Close */
|
/* Close */
|
||||||
|
@ -1761,49 +1788,79 @@ smb2_set_related(struct smb_rqst *rqst)
|
||||||
char smb2_padding[7] = {0, 0, 0, 0, 0, 0, 0};
|
char smb2_padding[7] = {0, 0, 0, 0, 0, 0, 0};
|
||||||
|
|
||||||
void
|
void
|
||||||
smb2_set_next_command(struct TCP_Server_Info *server, struct smb_rqst *rqst,
|
smb2_set_next_command(struct cifs_tcon *tcon, struct smb_rqst *rqst)
|
||||||
bool has_space_for_padding)
|
|
||||||
{
|
{
|
||||||
struct smb2_sync_hdr *shdr;
|
struct smb2_sync_hdr *shdr;
|
||||||
|
struct cifs_ses *ses = tcon->ses;
|
||||||
|
struct TCP_Server_Info *server = ses->server;
|
||||||
unsigned long len = smb_rqst_len(server, rqst);
|
unsigned long len = smb_rqst_len(server, rqst);
|
||||||
|
int i, num_padding;
|
||||||
|
|
||||||
/* SMB headers in a compound are 8 byte aligned. */
|
/* SMB headers in a compound are 8 byte aligned. */
|
||||||
if (len & 7) {
|
|
||||||
if (has_space_for_padding) {
|
/* No padding needed */
|
||||||
len = rqst->rq_iov[rqst->rq_nvec - 1].iov_len;
|
if (!(len & 7))
|
||||||
rqst->rq_iov[rqst->rq_nvec - 1].iov_len =
|
goto finished;
|
||||||
(len + 7) & ~7;
|
|
||||||
} else {
|
num_padding = 8 - (len & 7);
|
||||||
rqst->rq_iov[rqst->rq_nvec].iov_base = smb2_padding;
|
if (!smb3_encryption_required(tcon)) {
|
||||||
rqst->rq_iov[rqst->rq_nvec].iov_len = 8 - (len & 7);
|
/*
|
||||||
rqst->rq_nvec++;
|
* If we do not have encryption then we can just add an extra
|
||||||
|
* iov for the padding.
|
||||||
|
*/
|
||||||
|
rqst->rq_iov[rqst->rq_nvec].iov_base = smb2_padding;
|
||||||
|
rqst->rq_iov[rqst->rq_nvec].iov_len = num_padding;
|
||||||
|
rqst->rq_nvec++;
|
||||||
|
len += num_padding;
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* We can not add a small padding iov for the encryption case
|
||||||
|
* because the encryption framework can not handle the padding
|
||||||
|
* iovs.
|
||||||
|
* We have to flatten this into a single buffer and add
|
||||||
|
* the padding to it.
|
||||||
|
*/
|
||||||
|
for (i = 1; i < rqst->rq_nvec; i++) {
|
||||||
|
memcpy(rqst->rq_iov[0].iov_base +
|
||||||
|
rqst->rq_iov[0].iov_len,
|
||||||
|
rqst->rq_iov[i].iov_base,
|
||||||
|
rqst->rq_iov[i].iov_len);
|
||||||
|
rqst->rq_iov[0].iov_len += rqst->rq_iov[i].iov_len;
|
||||||
}
|
}
|
||||||
len = smb_rqst_len(server, rqst);
|
memset(rqst->rq_iov[0].iov_base + rqst->rq_iov[0].iov_len,
|
||||||
|
0, num_padding);
|
||||||
|
rqst->rq_iov[0].iov_len += num_padding;
|
||||||
|
len += num_padding;
|
||||||
|
rqst->rq_nvec = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
finished:
|
||||||
shdr = (struct smb2_sync_hdr *)(rqst->rq_iov[0].iov_base);
|
shdr = (struct smb2_sync_hdr *)(rqst->rq_iov[0].iov_base);
|
||||||
shdr->NextCommand = cpu_to_le32(len);
|
shdr->NextCommand = cpu_to_le32(len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
/*
|
||||||
smb2_queryfs(const unsigned int xid, struct cifs_tcon *tcon,
|
* Passes the query info response back to the caller on success.
|
||||||
struct kstatfs *buf)
|
* Caller need to free this with free_rsp_buf().
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
|
__le16 *utf16_path, u32 desired_access,
|
||||||
|
u32 class, u32 type, u32 output_len,
|
||||||
|
struct kvec *rsp, int *buftype,
|
||||||
|
struct cifs_sb_info *cifs_sb)
|
||||||
{
|
{
|
||||||
struct smb2_query_info_rsp *rsp;
|
struct cifs_ses *ses = tcon->ses;
|
||||||
struct smb2_fs_full_size_info *info = NULL;
|
int flags = 0;
|
||||||
struct smb_rqst rqst[3];
|
struct smb_rqst rqst[3];
|
||||||
int resp_buftype[3];
|
int resp_buftype[3];
|
||||||
struct kvec rsp_iov[3];
|
struct kvec rsp_iov[3];
|
||||||
struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
|
struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
|
||||||
struct kvec qi_iov[1];
|
struct kvec qi_iov[1];
|
||||||
struct kvec close_iov[1];
|
struct kvec close_iov[1];
|
||||||
struct cifs_ses *ses = tcon->ses;
|
|
||||||
struct TCP_Server_Info *server = ses->server;
|
|
||||||
__le16 srch_path = 0; /* Null - open root of share */
|
|
||||||
u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
|
u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
|
||||||
struct cifs_open_parms oparms;
|
struct cifs_open_parms oparms;
|
||||||
struct cifs_fid fid;
|
struct cifs_fid fid;
|
||||||
int flags = 0;
|
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (smb3_encryption_required(tcon))
|
if (smb3_encryption_required(tcon))
|
||||||
|
@ -1818,29 +1875,31 @@ smb2_queryfs(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE;
|
rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE;
|
||||||
|
|
||||||
oparms.tcon = tcon;
|
oparms.tcon = tcon;
|
||||||
oparms.desired_access = FILE_READ_ATTRIBUTES;
|
oparms.desired_access = desired_access;
|
||||||
oparms.disposition = FILE_OPEN;
|
oparms.disposition = FILE_OPEN;
|
||||||
oparms.create_options = 0;
|
if (cifs_sb && backup_cred(cifs_sb))
|
||||||
|
oparms.create_options = CREATE_OPEN_BACKUP_INTENT;
|
||||||
|
else
|
||||||
|
oparms.create_options = 0;
|
||||||
oparms.fid = &fid;
|
oparms.fid = &fid;
|
||||||
oparms.reconnect = false;
|
oparms.reconnect = false;
|
||||||
|
|
||||||
rc = SMB2_open_init(tcon, &rqst[0], &oplock, &oparms, &srch_path);
|
rc = SMB2_open_init(tcon, &rqst[0], &oplock, &oparms, utf16_path);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto qfs_exit;
|
goto qic_exit;
|
||||||
smb2_set_next_command(server, &rqst[0], 0);
|
smb2_set_next_command(tcon, &rqst[0]);
|
||||||
|
|
||||||
memset(&qi_iov, 0, sizeof(qi_iov));
|
memset(&qi_iov, 0, sizeof(qi_iov));
|
||||||
rqst[1].rq_iov = qi_iov;
|
rqst[1].rq_iov = qi_iov;
|
||||||
rqst[1].rq_nvec = 1;
|
rqst[1].rq_nvec = 1;
|
||||||
|
|
||||||
rc = SMB2_query_info_init(tcon, &rqst[1], COMPOUND_FID, COMPOUND_FID,
|
rc = SMB2_query_info_init(tcon, &rqst[1], COMPOUND_FID, COMPOUND_FID,
|
||||||
FS_FULL_SIZE_INFORMATION,
|
class, type, 0,
|
||||||
SMB2_O_INFO_FILESYSTEM, 0,
|
output_len, 0,
|
||||||
sizeof(struct smb2_fs_full_size_info), 0,
|
|
||||||
NULL);
|
NULL);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto qfs_exit;
|
goto qic_exit;
|
||||||
smb2_set_next_command(server, &rqst[1], 0);
|
smb2_set_next_command(tcon, &rqst[1]);
|
||||||
smb2_set_related(&rqst[1]);
|
smb2_set_related(&rqst[1]);
|
||||||
|
|
||||||
memset(&close_iov, 0, sizeof(close_iov));
|
memset(&close_iov, 0, sizeof(close_iov));
|
||||||
|
@ -1849,32 +1908,61 @@ smb2_queryfs(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
|
|
||||||
rc = SMB2_close_init(tcon, &rqst[2], COMPOUND_FID, COMPOUND_FID);
|
rc = SMB2_close_init(tcon, &rqst[2], COMPOUND_FID, COMPOUND_FID);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto qfs_exit;
|
goto qic_exit;
|
||||||
smb2_set_related(&rqst[2]);
|
smb2_set_related(&rqst[2]);
|
||||||
|
|
||||||
rc = compound_send_recv(xid, ses, flags, 3, rqst,
|
rc = compound_send_recv(xid, ses, flags, 3, rqst,
|
||||||
resp_buftype, rsp_iov);
|
resp_buftype, rsp_iov);
|
||||||
|
if (rc) {
|
||||||
|
free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
|
||||||
|
goto qic_exit;
|
||||||
|
}
|
||||||
|
*rsp = rsp_iov[1];
|
||||||
|
*buftype = resp_buftype[1];
|
||||||
|
|
||||||
|
qic_exit:
|
||||||
|
SMB2_open_free(&rqst[0]);
|
||||||
|
SMB2_query_info_free(&rqst[1]);
|
||||||
|
SMB2_close_free(&rqst[2]);
|
||||||
|
free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
|
||||||
|
free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
smb2_queryfs(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
|
struct kstatfs *buf)
|
||||||
|
{
|
||||||
|
struct smb2_query_info_rsp *rsp;
|
||||||
|
struct smb2_fs_full_size_info *info = NULL;
|
||||||
|
__le16 utf16_path = 0; /* Null - open root of share */
|
||||||
|
struct kvec rsp_iov = {NULL, 0};
|
||||||
|
int buftype = CIFS_NO_BUFFER;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
|
||||||
|
rc = smb2_query_info_compound(xid, tcon, &utf16_path,
|
||||||
|
FILE_READ_ATTRIBUTES,
|
||||||
|
FS_FULL_SIZE_INFORMATION,
|
||||||
|
SMB2_O_INFO_FILESYSTEM,
|
||||||
|
sizeof(struct smb2_fs_full_size_info),
|
||||||
|
&rsp_iov, &buftype, NULL);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto qfs_exit;
|
goto qfs_exit;
|
||||||
|
|
||||||
rsp = (struct smb2_query_info_rsp *)rsp_iov[1].iov_base;
|
rsp = (struct smb2_query_info_rsp *)rsp_iov.iov_base;
|
||||||
buf->f_type = SMB2_MAGIC_NUMBER;
|
buf->f_type = SMB2_MAGIC_NUMBER;
|
||||||
info = (struct smb2_fs_full_size_info *)(
|
info = (struct smb2_fs_full_size_info *)(
|
||||||
le16_to_cpu(rsp->OutputBufferOffset) + (char *)rsp);
|
le16_to_cpu(rsp->OutputBufferOffset) + (char *)rsp);
|
||||||
rc = smb2_validate_iov(le16_to_cpu(rsp->OutputBufferOffset),
|
rc = smb2_validate_iov(le16_to_cpu(rsp->OutputBufferOffset),
|
||||||
le32_to_cpu(rsp->OutputBufferLength),
|
le32_to_cpu(rsp->OutputBufferLength),
|
||||||
&rsp_iov[1],
|
&rsp_iov,
|
||||||
sizeof(struct smb2_fs_full_size_info));
|
sizeof(struct smb2_fs_full_size_info));
|
||||||
if (!rc)
|
if (!rc)
|
||||||
smb2_copy_fs_info_to_kstatfs(info, buf);
|
smb2_copy_fs_info_to_kstatfs(info, buf);
|
||||||
|
|
||||||
qfs_exit:
|
qfs_exit:
|
||||||
SMB2_open_free(&rqst[0]);
|
free_rsp_buf(buftype, rsp_iov.iov_base);
|
||||||
SMB2_query_info_free(&rqst[1]);
|
|
||||||
SMB2_close_free(&rqst[2]);
|
|
||||||
free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
|
|
||||||
free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
|
|
||||||
free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base);
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2743,7 +2831,7 @@ init_sg(int num_rqst, struct smb_rqst *rqst, u8 *sign)
|
||||||
smb2_sg_set_buf(&sg[idx++],
|
smb2_sg_set_buf(&sg[idx++],
|
||||||
rqst[i].rq_iov[j].iov_base + skip,
|
rqst[i].rq_iov[j].iov_base + skip,
|
||||||
rqst[i].rq_iov[j].iov_len - skip);
|
rqst[i].rq_iov[j].iov_len - skip);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (j = 0; j < rqst[i].rq_npages; j++) {
|
for (j = 0; j < rqst[i].rq_npages; j++) {
|
||||||
unsigned int len, offset;
|
unsigned int len, offset;
|
||||||
|
|
|
@ -50,6 +50,9 @@
|
||||||
#include "cifs_spnego.h"
|
#include "cifs_spnego.h"
|
||||||
#include "smbdirect.h"
|
#include "smbdirect.h"
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
|
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||||
|
#include "dfs_cache.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The following table defines the expected "StructureSize" of SMB2 requests
|
* The following table defines the expected "StructureSize" of SMB2 requests
|
||||||
|
@ -152,6 +155,77 @@ out:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||||
|
static int __smb2_reconnect(const struct nls_table *nlsc,
|
||||||
|
struct cifs_tcon *tcon)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
struct dfs_cache_tgt_list tl;
|
||||||
|
struct dfs_cache_tgt_iterator *it = NULL;
|
||||||
|
char tree[MAX_TREE_SIZE + 1];
|
||||||
|
const char *tcp_host;
|
||||||
|
size_t tcp_host_len;
|
||||||
|
const char *dfs_host;
|
||||||
|
size_t dfs_host_len;
|
||||||
|
|
||||||
|
if (tcon->ipc) {
|
||||||
|
snprintf(tree, sizeof(tree), "\\\\%s\\IPC$",
|
||||||
|
tcon->ses->server->hostname);
|
||||||
|
return SMB2_tcon(0, tcon->ses, tree, tcon, nlsc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tcon->dfs_path)
|
||||||
|
return SMB2_tcon(0, tcon->ses, tcon->treeName, tcon, nlsc);
|
||||||
|
|
||||||
|
rc = dfs_cache_noreq_find(tcon->dfs_path + 1, NULL, &tl);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
extract_unc_hostname(tcon->ses->server->hostname, &tcp_host,
|
||||||
|
&tcp_host_len);
|
||||||
|
|
||||||
|
for (it = dfs_cache_get_tgt_iterator(&tl); it;
|
||||||
|
it = dfs_cache_get_next_tgt(&tl, it)) {
|
||||||
|
const char *tgt = dfs_cache_get_tgt_name(it);
|
||||||
|
|
||||||
|
extract_unc_hostname(tgt, &dfs_host, &dfs_host_len);
|
||||||
|
|
||||||
|
if (dfs_host_len != tcp_host_len
|
||||||
|
|| strncasecmp(dfs_host, tcp_host, dfs_host_len) != 0) {
|
||||||
|
cifs_dbg(FYI, "%s: skipping %.*s, doesn't match %.*s",
|
||||||
|
__func__,
|
||||||
|
(int)dfs_host_len, dfs_host,
|
||||||
|
(int)tcp_host_len, tcp_host);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(tree, sizeof(tree), "\\%s", tgt);
|
||||||
|
|
||||||
|
rc = SMB2_tcon(0, tcon->ses, tree, tcon, nlsc);
|
||||||
|
if (!rc)
|
||||||
|
break;
|
||||||
|
if (rc == -EREMOTE)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!rc) {
|
||||||
|
if (it)
|
||||||
|
rc = dfs_cache_noreq_update_tgthint(tcon->dfs_path + 1,
|
||||||
|
it);
|
||||||
|
else
|
||||||
|
rc = -ENOENT;
|
||||||
|
}
|
||||||
|
dfs_cache_free_tgts(&tl);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static inline int __smb2_reconnect(const struct nls_table *nlsc,
|
||||||
|
struct cifs_tcon *tcon)
|
||||||
|
{
|
||||||
|
return SMB2_tcon(0, tcon->ses, tcon->treeName, tcon, nlsc);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static int
|
static int
|
||||||
smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon)
|
smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon)
|
||||||
{
|
{
|
||||||
|
@ -159,6 +233,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon)
|
||||||
struct nls_table *nls_codepage;
|
struct nls_table *nls_codepage;
|
||||||
struct cifs_ses *ses;
|
struct cifs_ses *ses;
|
||||||
struct TCP_Server_Info *server;
|
struct TCP_Server_Info *server;
|
||||||
|
int retries;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SMB2s NegProt, SessSetup, Logoff do not have tcon yet so
|
* SMB2s NegProt, SessSetup, Logoff do not have tcon yet so
|
||||||
|
@ -192,9 +267,12 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon)
|
||||||
ses = tcon->ses;
|
ses = tcon->ses;
|
||||||
server = ses->server;
|
server = ses->server;
|
||||||
|
|
||||||
|
retries = server->nr_targets;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Give demultiplex thread up to 10 seconds to reconnect, should be
|
* Give demultiplex thread up to 10 seconds to each target available for
|
||||||
* greater than cifs socket timeout which is 7 seconds
|
* reconnect -- should be greater than cifs socket timeout which is 7
|
||||||
|
* seconds.
|
||||||
*/
|
*/
|
||||||
while (server->tcpStatus == CifsNeedReconnect) {
|
while (server->tcpStatus == CifsNeedReconnect) {
|
||||||
/*
|
/*
|
||||||
|
@ -225,6 +303,9 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon)
|
||||||
if (server->tcpStatus != CifsNeedReconnect)
|
if (server->tcpStatus != CifsNeedReconnect)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
if (--retries)
|
||||||
|
continue;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* on "soft" mounts we wait once. Hard mounts keep
|
* on "soft" mounts we wait once. Hard mounts keep
|
||||||
* retrying until process is killed or server comes
|
* retrying until process is killed or server comes
|
||||||
|
@ -234,6 +315,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon)
|
||||||
cifs_dbg(FYI, "gave up waiting on reconnect in smb_init\n");
|
cifs_dbg(FYI, "gave up waiting on reconnect in smb_init\n");
|
||||||
return -EHOSTDOWN;
|
return -EHOSTDOWN;
|
||||||
}
|
}
|
||||||
|
retries = server->nr_targets;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tcon->ses->need_reconnect && !tcon->need_reconnect)
|
if (!tcon->ses->need_reconnect && !tcon->need_reconnect)
|
||||||
|
@ -271,7 +353,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon)
|
||||||
if (tcon->use_persistent)
|
if (tcon->use_persistent)
|
||||||
tcon->need_reopen_files = true;
|
tcon->need_reopen_files = true;
|
||||||
|
|
||||||
rc = SMB2_tcon(0, tcon->ses, tcon->treeName, tcon, nls_codepage);
|
rc = __smb2_reconnect(nls_codepage, tcon);
|
||||||
mutex_unlock(&tcon->ses->session_mutex);
|
mutex_unlock(&tcon->ses->session_mutex);
|
||||||
|
|
||||||
cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc);
|
cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc);
|
||||||
|
@ -1955,7 +2037,6 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
|
||||||
struct smb_rqst rqst;
|
struct smb_rqst rqst;
|
||||||
struct smb2_create_req *req;
|
struct smb2_create_req *req;
|
||||||
struct smb2_create_rsp *rsp = NULL;
|
struct smb2_create_rsp *rsp = NULL;
|
||||||
struct TCP_Server_Info *server;
|
|
||||||
struct cifs_ses *ses = tcon->ses;
|
struct cifs_ses *ses = tcon->ses;
|
||||||
struct kvec iov[3]; /* make sure at least one for each open context */
|
struct kvec iov[3]; /* make sure at least one for each open context */
|
||||||
struct kvec rsp_iov = {NULL, 0};
|
struct kvec rsp_iov = {NULL, 0};
|
||||||
|
@ -1978,9 +2059,7 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
|
||||||
if (!utf16_path)
|
if (!utf16_path)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
if (ses && (ses->server))
|
if (!ses || !(ses->server)) {
|
||||||
server = ses->server;
|
|
||||||
else {
|
|
||||||
rc = -EIO;
|
rc = -EIO;
|
||||||
goto err_free_path;
|
goto err_free_path;
|
||||||
}
|
}
|
||||||
|
@ -2768,18 +2847,6 @@ qinf_exit:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SMB2_query_eas(const unsigned int xid, struct cifs_tcon *tcon,
|
|
||||||
u64 persistent_fid, u64 volatile_fid,
|
|
||||||
int ea_buf_size, struct smb2_file_full_ea_info *data)
|
|
||||||
{
|
|
||||||
return query_info(xid, tcon, persistent_fid, volatile_fid,
|
|
||||||
FILE_FULL_EA_INFORMATION, SMB2_O_INFO_FILE, 0,
|
|
||||||
ea_buf_size,
|
|
||||||
sizeof(struct smb2_file_full_ea_info),
|
|
||||||
(void **)&data,
|
|
||||||
NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
int SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
|
int SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
u64 persistent_fid, u64 volatile_fid, struct smb2_file_all_info *data)
|
u64 persistent_fid, u64 volatile_fid, struct smb2_file_all_info *data)
|
||||||
{
|
{
|
||||||
|
@ -3994,7 +4061,6 @@ static int
|
||||||
build_qfs_info_req(struct kvec *iov, struct cifs_tcon *tcon, int level,
|
build_qfs_info_req(struct kvec *iov, struct cifs_tcon *tcon, int level,
|
||||||
int outbuf_len, u64 persistent_fid, u64 volatile_fid)
|
int outbuf_len, u64 persistent_fid, u64 volatile_fid)
|
||||||
{
|
{
|
||||||
struct TCP_Server_Info *server;
|
|
||||||
int rc;
|
int rc;
|
||||||
struct smb2_query_info_req *req;
|
struct smb2_query_info_req *req;
|
||||||
unsigned int total_len;
|
unsigned int total_len;
|
||||||
|
@ -4004,8 +4070,6 @@ build_qfs_info_req(struct kvec *iov, struct cifs_tcon *tcon, int level,
|
||||||
if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
|
if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
server = tcon->ses->server;
|
|
||||||
|
|
||||||
rc = smb2_plain_req_init(SMB2_QUERY_INFO, tcon, (void **) &req,
|
rc = smb2_plain_req_init(SMB2_QUERY_INFO, tcon, (void **) &req,
|
||||||
&total_len);
|
&total_len);
|
||||||
if (rc)
|
if (rc)
|
||||||
|
|
|
@ -1398,7 +1398,6 @@ struct smb2_file_link_info { /* encoding of request for level 11 */
|
||||||
char FileName[0]; /* Name to be assigned to new link */
|
char FileName[0]; /* Name to be assigned to new link */
|
||||||
} __packed; /* level 11 Set */
|
} __packed; /* level 11 Set */
|
||||||
|
|
||||||
#define SMB2_MIN_EA_BUF 2048
|
|
||||||
#define SMB2_MAX_EA_BUF 65536
|
#define SMB2_MAX_EA_BUF 65536
|
||||||
|
|
||||||
struct smb2_file_full_ea_info { /* encoding of response for level 15 */
|
struct smb2_file_full_ea_info { /* encoding of response for level 15 */
|
||||||
|
|
|
@ -116,9 +116,8 @@ extern void smb2_reconnect_server(struct work_struct *work);
|
||||||
extern int smb3_crypto_aead_allocate(struct TCP_Server_Info *server);
|
extern int smb3_crypto_aead_allocate(struct TCP_Server_Info *server);
|
||||||
extern unsigned long smb_rqst_len(struct TCP_Server_Info *server,
|
extern unsigned long smb_rqst_len(struct TCP_Server_Info *server,
|
||||||
struct smb_rqst *rqst);
|
struct smb_rqst *rqst);
|
||||||
extern void smb2_set_next_command(struct TCP_Server_Info *server,
|
extern void smb2_set_next_command(struct cifs_tcon *tcon,
|
||||||
struct smb_rqst *rqst,
|
struct smb_rqst *rqst);
|
||||||
bool has_space_for_padding);
|
|
||||||
extern void smb2_set_related(struct smb_rqst *rqst);
|
extern void smb2_set_related(struct smb_rqst *rqst);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -154,10 +153,6 @@ extern int SMB2_close_init(struct cifs_tcon *tcon, struct smb_rqst *rqst,
|
||||||
extern void SMB2_close_free(struct smb_rqst *rqst);
|
extern void SMB2_close_free(struct smb_rqst *rqst);
|
||||||
extern int SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon,
|
extern int SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
u64 persistent_file_id, u64 volatile_file_id);
|
u64 persistent_file_id, u64 volatile_file_id);
|
||||||
extern int SMB2_query_eas(const unsigned int xid, struct cifs_tcon *tcon,
|
|
||||||
u64 persistent_file_id, u64 volatile_file_id,
|
|
||||||
int ea_buf_size,
|
|
||||||
struct smb2_file_full_ea_info *data);
|
|
||||||
extern int SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
|
extern int SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
u64 persistent_file_id, u64 volatile_file_id,
|
u64 persistent_file_id, u64 volatile_file_id,
|
||||||
struct smb2_file_all_info *data);
|
struct smb2_file_all_info *data);
|
||||||
|
@ -241,4 +236,10 @@ extern void smb2_copy_fs_info_to_kstatfs(
|
||||||
extern int smb311_crypto_shash_allocate(struct TCP_Server_Info *server);
|
extern int smb311_crypto_shash_allocate(struct TCP_Server_Info *server);
|
||||||
extern int smb311_update_preauth_hash(struct cifs_ses *ses,
|
extern int smb311_update_preauth_hash(struct cifs_ses *ses,
|
||||||
struct kvec *iov, int nvec);
|
struct kvec *iov, int nvec);
|
||||||
|
extern int smb2_query_info_compound(const unsigned int xid,
|
||||||
|
struct cifs_tcon *tcon,
|
||||||
|
__le16 *utf16_path, u32 desired_access,
|
||||||
|
u32 class, u32 type, u32 output_len,
|
||||||
|
struct kvec *rsp, int *buftype,
|
||||||
|
struct cifs_sb_info *cifs_sb);
|
||||||
#endif /* _SMB2PROTO_H */
|
#endif /* _SMB2PROTO_H */
|
||||||
|
|
|
@ -126,9 +126,11 @@ DeleteMidQEntry(struct mid_q_entry *midEntry)
|
||||||
if ((slow_rsp_threshold != 0) &&
|
if ((slow_rsp_threshold != 0) &&
|
||||||
time_after(now, midEntry->when_alloc + (slow_rsp_threshold * HZ)) &&
|
time_after(now, midEntry->when_alloc + (slow_rsp_threshold * HZ)) &&
|
||||||
(midEntry->command != command)) {
|
(midEntry->command != command)) {
|
||||||
/* smb2slowcmd[NUMBER_OF_SMB2_COMMANDS] counts by command */
|
/*
|
||||||
if ((le16_to_cpu(midEntry->command) < NUMBER_OF_SMB2_COMMANDS) &&
|
* smb2slowcmd[NUMBER_OF_SMB2_COMMANDS] counts by command
|
||||||
(le16_to_cpu(midEntry->command) >= 0))
|
* NB: le16_to_cpu returns unsigned so can not be negative below
|
||||||
|
*/
|
||||||
|
if (le16_to_cpu(midEntry->command) < NUMBER_OF_SMB2_COMMANDS)
|
||||||
cifs_stats_inc(&midEntry->server->smb2slowcmd[le16_to_cpu(midEntry->command)]);
|
cifs_stats_inc(&midEntry->server->smb2slowcmd[le16_to_cpu(midEntry->command)]);
|
||||||
|
|
||||||
trace_smb3_slow_rsp(le16_to_cpu(midEntry->command),
|
trace_smb3_slow_rsp(le16_to_cpu(midEntry->command),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue