mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-06 05:02:31 +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
@ -1,4 +1,4 @@
|
||||
Version 2.11 September 13, 2017
|
||||
Version 2.14 December 21, 2018
|
||||
|
||||
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
|
||||
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
|
||||
- directory leases (improved metadata caching), started (root dir only)
|
||||
- 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
|
||||
to make it to network filesystems or deviceless filesystems)
|
||||
|
||||
e) Compounding (in progress) to reduce number of roundtrips, and also
|
||||
better optimize open to reduce redundant opens (using reference counts more).
|
||||
e) Additional use cases where we use "compoounding" (e.g. open/query/close
|
||||
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
|
||||
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
|
||||
(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
|
||||
|
||||
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
|
||||
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
|
||||
so far).
|
||||
|
||||
w) Add support for additional strong encryption types, and additional spnego
|
||||
authentication mechanisms (see MS-SMB2)
|
||||
|
||||
KNOWN BUGS
|
||||
====================================
|
||||
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.
|
||||
|
||||
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
|
||||
an upcall mechanism for CIFS which contacts userspace helper
|
||||
utilities to provide server name resolution (host names to
|
||||
IP addresses) which is needed for implicit mounts of DFS junction
|
||||
points. If unsure, say Y.
|
||||
IP addresses) which is needed in order to reconnect to
|
||||
servers if their addresses change or for implicit mounts of
|
||||
DFS junction points. If unsure, say Y.
|
||||
|
||||
config CIFS_NFSD_EXPORT
|
||||
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_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
|
||||
|
||||
|
@ -30,6 +30,9 @@
|
||||
#include "cifsproto.h"
|
||||
#include "cifs_debug.h"
|
||||
#include "cifsfs.h"
|
||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
#include "dfs_cache.h"
|
||||
#endif
|
||||
#ifdef CONFIG_CIFS_SMB_DIRECT
|
||||
#include "smbdirect.h"
|
||||
#endif
|
||||
@ -629,6 +632,11 @@ cifs_proc_init(void)
|
||||
&cifs_security_flags_proc_fops);
|
||||
proc_create("LookupCacheEnabled", 0644, proc_fs_cifs,
|
||||
&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
|
||||
proc_create("rdma_readwrite_threshold", 0644, proc_fs_cifs,
|
||||
&cifs_rdma_readwrite_threshold_proc_fops);
|
||||
@ -663,6 +671,10 @@ cifs_proc_clean(void)
|
||||
remove_proc_entry("SecurityFlags", proc_fs_cifs);
|
||||
remove_proc_entry("LinuxExtensionsEnabled", 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
|
||||
remove_proc_entry("rdma_readwrite_threshold", proc_fs_cifs);
|
||||
remove_proc_entry("smbd_max_frmr_depth", proc_fs_cifs);
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "dns_resolve.h"
|
||||
#include "cifs_debug.h"
|
||||
#include "cifs_unicode.h"
|
||||
#include "dfs_cache.h"
|
||||
|
||||
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)
|
||||
* @fullpath: full path in UNC format
|
||||
* @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
|
||||
* 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)
|
||||
{
|
||||
int rc;
|
||||
char *name;
|
||||
char *mountdata = NULL;
|
||||
const char *prepath = NULL;
|
||||
int md_len;
|
||||
@ -158,17 +160,17 @@ char *cifs_compose_mount_options(const char *sb_mountdata,
|
||||
prepath++;
|
||||
}
|
||||
|
||||
*devname = cifs_build_devname(ref->node_name, prepath);
|
||||
if (IS_ERR(*devname)) {
|
||||
rc = PTR_ERR(*devname);
|
||||
*devname = NULL;
|
||||
name = cifs_build_devname(ref->node_name, prepath);
|
||||
if (IS_ERR(name)) {
|
||||
rc = PTR_ERR(name);
|
||||
name = NULL;
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -224,6 +226,9 @@ char *cifs_compose_mount_options(const char *sb_mountdata,
|
||||
strcat(mountdata, "ip=");
|
||||
strcat(mountdata, srvIP);
|
||||
|
||||
if (devname)
|
||||
*devname = name;
|
||||
|
||||
/*cifs_dbg(FYI, "%s: parent mountdata: %s\n", __func__, sb_mountdata);*/
|
||||
/*cifs_dbg(FYI, "%s: submount mountdata: %s\n", __func__, mountdata );*/
|
||||
|
||||
@ -234,8 +239,7 @@ char *cifs_compose_mount_options(const char *sb_mountdata,
|
||||
compose_mount_options_err:
|
||||
kfree(mountdata);
|
||||
mountdata = ERR_PTR(rc);
|
||||
kfree(*devname);
|
||||
*devname = NULL;
|
||||
kfree(name);
|
||||
goto compose_mount_options_out;
|
||||
}
|
||||
|
||||
@ -251,20 +255,30 @@ static struct vfsmount *cifs_dfs_do_refmount(struct dentry *mntpt,
|
||||
{
|
||||
struct vfsmount *mnt;
|
||||
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 */
|
||||
mountdata = cifs_compose_mount_options(cifs_sb->mountdata,
|
||||
fullpath + 1, ref, &devname);
|
||||
|
||||
if (IS_ERR(mountdata))
|
||||
fullpath + 1, ref, NULL);
|
||||
if (IS_ERR(mountdata)) {
|
||||
kfree(devname);
|
||||
return (struct vfsmount *)mountdata;
|
||||
}
|
||||
|
||||
mnt = vfs_submount(mntpt, &cifs_fs_type, devname, mountdata);
|
||||
kfree(mountdata);
|
||||
kfree(devname);
|
||||
return mnt;
|
||||
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct dfs_info3_param *referrals = NULL;
|
||||
unsigned int num_referrals = 0;
|
||||
struct dfs_info3_param referral = {0};
|
||||
struct cifs_sb_info *cifs_sb;
|
||||
struct cifs_ses *ses;
|
||||
char *full_path;
|
||||
struct cifs_tcon *tcon;
|
||||
char *full_path, *root_path;
|
||||
unsigned int xid;
|
||||
int i;
|
||||
int len;
|
||||
int rc;
|
||||
struct vfsmount *mnt;
|
||||
struct tcon_link *tlink;
|
||||
|
||||
cifs_dbg(FYI, "in %s\n", __func__);
|
||||
BUG_ON(IS_ROOT(mntpt));
|
||||
@ -315,48 +328,69 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
|
||||
if (full_path == NULL)
|
||||
goto cdda_exit;
|
||||
|
||||
tlink = cifs_sb_tlink(cifs_sb);
|
||||
if (IS_ERR(tlink)) {
|
||||
mnt = ERR_CAST(tlink);
|
||||
cifs_dbg(FYI, "%s: full_path: %s\n", __func__, full_path);
|
||||
|
||||
if (!cifs_sb_master_tlink(cifs_sb)) {
|
||||
cifs_dbg(FYI, "%s: master tlink is NULL\n", __func__);
|
||||
goto free_full_path;
|
||||
}
|
||||
ses = tlink_tcon(tlink)->ses;
|
||||
|
||||
xid = get_xid();
|
||||
rc = get_dfs_path(xid, ses, full_path + 1, cifs_sb->local_nls,
|
||||
&num_referrals, &referrals,
|
||||
cifs_remap(cifs_sb));
|
||||
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;
|
||||
tcon = cifs_sb_master_tcon(cifs_sb);
|
||||
if (!tcon) {
|
||||
cifs_dbg(FYI, "%s: master tcon is NULL\n", __func__);
|
||||
goto free_full_path;
|
||||
}
|
||||
|
||||
/* no valid submounts were found; return error from get_dfs_path() by
|
||||
* preference */
|
||||
if (rc != 0)
|
||||
mnt = ERR_PTR(rc);
|
||||
root_path = kstrdup(tcon->treeName, GFP_KERNEL);
|
||||
if (!root_path) {
|
||||
mnt = ERR_PTR(-ENOMEM);
|
||||
goto free_full_path;
|
||||
}
|
||||
cifs_dbg(FYI, "%s: root path: %s\n", __func__, root_path);
|
||||
|
||||
success:
|
||||
free_dfs_info_array(referrals, num_referrals);
|
||||
ses = tcon->ses;
|
||||
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:
|
||||
kfree(full_path);
|
||||
cdda_exit:
|
||||
|
@ -72,6 +72,15 @@ struct cifs_sb_info {
|
||||
char *mountdata; /* options received at mount time or via DFS refs */
|
||||
struct delayed_work prune_tlinks;
|
||||
struct rcu_head rcu;
|
||||
|
||||
/* only used when CIFS_MOUNT_USE_PREFIX_PATH is set */
|
||||
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 */
|
||||
|
@ -224,7 +224,7 @@ int cifs_verify_signature(struct smb_rqst *rqst,
|
||||
if (cifs_pdu->Command == SMB_COM_LOCKING_ANDX) {
|
||||
struct smb_com_lock_req *pSMB =
|
||||
(struct smb_com_lock_req *)cifs_pdu;
|
||||
if (pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE)
|
||||
if (pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE)
|
||||
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,
|
||||
char *lnm_session_key)
|
||||
{
|
||||
int i;
|
||||
int i, len;
|
||||
int rc;
|
||||
char password_with_pad[CIFS_ENCPWD_SIZE] = {0};
|
||||
|
||||
if (password)
|
||||
strncpy(password_with_pad, password, CIFS_ENCPWD_SIZE);
|
||||
if (password) {
|
||||
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) {
|
||||
memcpy(lnm_session_key, password_with_pad,
|
||||
|
@ -52,6 +52,9 @@
|
||||
#include "cifs_spnego.h"
|
||||
#include "fscache.h"
|
||||
#include "smb2pdu.h"
|
||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
#include "dfs_cache.h"
|
||||
#endif
|
||||
|
||||
int cifsFYI = 0;
|
||||
bool traceSMB;
|
||||
@ -1494,10 +1497,15 @@ init_cifs(void)
|
||||
if (rc)
|
||||
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
|
||||
rc = init_cifs_spnego();
|
||||
if (rc)
|
||||
goto out_destroy_request_bufs;
|
||||
goto out_destroy_dfs_cache;
|
||||
#endif /* CONFIG_CIFS_UPCALL */
|
||||
|
||||
#ifdef CONFIG_CIFS_ACL
|
||||
@ -1525,6 +1533,10 @@ init_cifs(void)
|
||||
#endif
|
||||
#ifdef CONFIG_CIFS_UPCALL
|
||||
exit_cifs_spnego();
|
||||
out_destroy_dfs_cache:
|
||||
#endif
|
||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
dfs_cache_destroy();
|
||||
out_destroy_request_bufs:
|
||||
#endif
|
||||
cifs_destroy_request_bufs();
|
||||
@ -1555,6 +1567,9 @@ exit_cifs(void)
|
||||
#endif
|
||||
#ifdef CONFIG_CIFS_UPCALL
|
||||
exit_cifs_spnego();
|
||||
#endif
|
||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
dfs_cache_destroy();
|
||||
#endif
|
||||
cifs_destroy_request_bufs();
|
||||
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;
|
||||
#endif /* CONFIG_CIFS_NFSD_EXPORT */
|
||||
|
||||
#define CIFS_VERSION "2.14"
|
||||
#define CIFS_VERSION "2.15"
|
||||
#endif /* _CIFSFS_H */
|
||||
|
@ -701,6 +701,13 @@ struct TCP_Server_Info {
|
||||
struct delayed_work reconnect; /* reconnect workqueue job */
|
||||
struct mutex reconnect_mutex; /* prevent simultaneous reconnects */
|
||||
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
|
||||
@ -1014,6 +1021,11 @@ struct cifs_tcon {
|
||||
struct list_head pending_opens; /* list of incomplete opens */
|
||||
struct cached_fid crfid; /* Cached root fid */
|
||||
/* 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;
|
||||
char *path_name;
|
||||
char *node_name;
|
||||
int ttl;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -1545,7 +1558,6 @@ static inline void free_dfs_info_param(struct dfs_info3_param *param)
|
||||
if (param) {
|
||||
kfree(param->path_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_values smb30_values;
|
||||
#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_values smb302_values;
|
||||
#define SMB311_VERSION_STRING "3.1.1"
|
||||
|
@ -22,6 +22,9 @@
|
||||
#define _CIFSPROTO_H
|
||||
#include <linux/nls.h>
|
||||
#include "trace.h"
|
||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
#include "dfs_cache.h"
|
||||
#endif
|
||||
|
||||
struct statfs;
|
||||
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 struct smb_vol *cifs_get_volume_info(char *mount_data,
|
||||
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_mark_open_files_invalid(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,
|
||||
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,
|
||||
unsigned int *num_of_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);
|
||||
extern int SMBencrypt(unsigned char *passwd, const unsigned char *c8,
|
||||
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);
|
||||
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,
|
||||
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 */
|
||||
|
@ -44,6 +44,9 @@
|
||||
#include "cifs_debug.h"
|
||||
#include "fscache.h"
|
||||
#include "smbdirect.h"
|
||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
#include "dfs_cache.h"
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CIFS_POSIX
|
||||
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 */
|
||||
static int
|
||||
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 TCP_Server_Info *server;
|
||||
struct nls_table *nls_codepage;
|
||||
int retries;
|
||||
|
||||
/*
|
||||
* 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
|
||||
* greater than cifs socket timeout which is 7 seconds
|
||||
* Give demultiplex thread up to 10 seconds to each target available for
|
||||
* reconnect -- should be greater than cifs socket timeout which is 7
|
||||
* seconds.
|
||||
*/
|
||||
while (server->tcpStatus == CifsNeedReconnect) {
|
||||
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)
|
||||
break;
|
||||
|
||||
if (--retries)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* on "soft" mounts we wait once. Hard mounts keep
|
||||
* 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");
|
||||
return -EHOSTDOWN;
|
||||
}
|
||||
retries = server->nr_targets;
|
||||
}
|
||||
|
||||
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);
|
||||
rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
|
||||
rc = __cifs_reconnect_tcon(nls_codepage, tcon);
|
||||
mutex_unlock(&ses->session_mutex);
|
||||
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)
|
||||
break;
|
||||
|
||||
cur_len = min_t(const size_t, len, wsize);
|
||||
|
||||
if (ctx->direct_io) {
|
||||
ssize_t result;
|
||||
|
||||
result = iov_iter_get_pages_alloc(
|
||||
from, &pagevec, wsize, &start);
|
||||
from, &pagevec, cur_len, &start);
|
||||
if (result < 0) {
|
||||
cifs_dbg(VFS,
|
||||
"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,
|
||||
from->iov_offset, from->count);
|
||||
dump_stack();
|
||||
|
||||
rc = result;
|
||||
add_credits_and_wake_if(server, credits, 0);
|
||||
break;
|
||||
}
|
||||
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);
|
||||
if (result < 0) {
|
||||
cifs_dbg(VFS,
|
||||
"couldn't get user pages (cur_len=%zd)"
|
||||
"couldn't get user pages (rc=%zd)"
|
||||
" iter type %d"
|
||||
" iov_offset %zd count %zd\n",
|
||||
result, direct_iov.type,
|
||||
direct_iov.iov_offset,
|
||||
direct_iov.count);
|
||||
dump_stack();
|
||||
|
||||
rc = result;
|
||||
add_credits_and_wake_if(server, credits, 0);
|
||||
break;
|
||||
}
|
||||
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_atime = fattr->cf_ctime = fattr->cf_mtime;
|
||||
fattr->cf_nlink = 2;
|
||||
fattr->cf_flags |= CIFS_FATTR_DFS_REFERRAL;
|
||||
fattr->cf_flags = CIFS_FATTR_DFS_REFERRAL;
|
||||
}
|
||||
|
||||
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,
|
||||
const struct cifs_fid *fid)
|
||||
{
|
||||
bool validinum = false;
|
||||
__u16 srchflgs;
|
||||
int rc = 0, tmprc = ENOSYS;
|
||||
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);
|
||||
fattr.cf_uniqueid = le64_to_cpu(
|
||||
((SEARCH_ID_FULL_DIR_INFO *)data)->UniqueId);
|
||||
validinum = true;
|
||||
|
||||
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 (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
|
||||
if (validinum == false) {
|
||||
if (server->ops->get_srv_inum)
|
||||
tmprc = server->ops->get_srv_inum(xid,
|
||||
tcon, cifs_sb, full_path,
|
||||
&fattr.cf_uniqueid, data);
|
||||
if (tmprc) {
|
||||
cifs_dbg(FYI, "GetSrvInodeNum rc %d\n",
|
||||
tmprc);
|
||||
fattr.cf_uniqueid = iunique(sb, ROOT_I);
|
||||
cifs_autodisable_serverino(cifs_sb);
|
||||
} else if ((fattr.cf_uniqueid == 0) &&
|
||||
strlen(full_path) == 0) {
|
||||
/* some servers ret bad root ino ie 0 */
|
||||
cifs_dbg(FYI, "Invalid (0) inodenum\n");
|
||||
fattr.cf_flags |=
|
||||
CIFS_FATTR_FAKE_ROOT_INO;
|
||||
fattr.cf_uniqueid =
|
||||
simple_hashstr(tcon->treeName);
|
||||
}
|
||||
if (server->ops->get_srv_inum)
|
||||
tmprc = server->ops->get_srv_inum(xid,
|
||||
tcon, cifs_sb, full_path,
|
||||
&fattr.cf_uniqueid, data);
|
||||
if (tmprc) {
|
||||
cifs_dbg(FYI, "GetSrvInodeNum rc %d\n",
|
||||
tmprc);
|
||||
fattr.cf_uniqueid = iunique(sb, ROOT_I);
|
||||
cifs_autodisable_serverino(cifs_sb);
|
||||
} else if ((fattr.cf_uniqueid == 0) &&
|
||||
strlen(full_path) == 0) {
|
||||
/* some servers ret bad root ino ie 0 */
|
||||
cifs_dbg(FYI, "Invalid (0) inodenum\n");
|
||||
fattr.cf_flags |=
|
||||
CIFS_FATTR_FAKE_ROOT_INO;
|
||||
fattr.cf_uniqueid =
|
||||
simple_hashstr(tcon->treeName);
|
||||
}
|
||||
} else
|
||||
fattr.cf_uniqueid = iunique(sb, ROOT_I);
|
||||
} else {
|
||||
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) &&
|
||||
validinum == false && server->ops->get_srv_inum) {
|
||||
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
|
||||
&& server->ops->get_srv_inum) {
|
||||
/*
|
||||
* Pass a NULL tcon to ensure we don't make a round
|
||||
* trip to the server. This only works for SMB2+.
|
||||
|
@ -111,21 +111,27 @@ struct cifs_tcon *
|
||||
tconInfoAlloc(void)
|
||||
{
|
||||
struct cifs_tcon *ret_buf;
|
||||
ret_buf = kzalloc(sizeof(struct cifs_tcon), GFP_KERNEL);
|
||||
if (ret_buf) {
|
||||
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);
|
||||
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);
|
||||
|
||||
ret_buf = kzalloc(sizeof(*ret_buf), GFP_KERNEL);
|
||||
if (!ret_buf)
|
||||
return NULL;
|
||||
ret_buf->crfid.fid = kzalloc(sizeof(*ret_buf->crfid.fid), GFP_KERNEL);
|
||||
if (!ret_buf->crfid.fid) {
|
||||
kfree(ret_buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -140,6 +146,9 @@ tconInfoFree(struct cifs_tcon *buf_to_free)
|
||||
kfree(buf_to_free->nativeFileSystem);
|
||||
kzfree(buf_to_free->password);
|
||||
kfree(buf_to_free->crfid.fid);
|
||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
kfree(buf_to_free->dfs_path);
|
||||
#endif
|
||||
kfree(buf_to_free);
|
||||
}
|
||||
|
||||
@ -525,9 +534,17 @@ void
|
||||
cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb)
|
||||
{
|
||||
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_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_sb_master_tcon(cifs_sb)->treeName);
|
||||
cifs_dbg(VFS, "Autodisabling the use of server inode numbers on %s.\n",
|
||||
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;
|
||||
}
|
||||
|
||||
node->ttl = le32_to_cpu(ref->TimeToLive);
|
||||
|
||||
ref++;
|
||||
}
|
||||
|
||||
@ -933,3 +952,20 @@ void rqst_page_get_length(struct smb_rqst *rqst, unsigned int page,
|
||||
else if (page == 0)
|
||||
*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 */
|
||||
int i;
|
||||
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(
|
||||
cfile->srch_inf.ntwrk_buf_start,
|
||||
server);
|
||||
|
@ -534,9 +534,9 @@ cifs_select_sectype(struct TCP_Server_Info *server, enum securityEnum requested)
|
||||
if (global_secflags & CIFSSEC_MAY_NTLM)
|
||||
return NTLM;
|
||||
default:
|
||||
/* Fallthrough to attempt LANMAN authentication next */
|
||||
break;
|
||||
}
|
||||
/* Fallthrough - to attempt LANMAN authentication next */
|
||||
case CIFS_NEGFLAVOR_LANMAN:
|
||||
switch (requested) {
|
||||
case LANMAN:
|
||||
@ -1154,14 +1154,12 @@ sess_auth_kerberos(struct sess_data *sess_data)
|
||||
static int
|
||||
_sess_auth_rawntlmssp_assemble_req(struct sess_data *sess_data)
|
||||
{
|
||||
struct smb_hdr *smb_buf;
|
||||
SESSION_SETUP_ANDX *pSMB;
|
||||
struct cifs_ses *ses = sess_data->ses;
|
||||
__u32 capabilities;
|
||||
char *bcc_ptr;
|
||||
|
||||
pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
|
||||
smb_buf = (struct smb_hdr *)pSMB;
|
||||
|
||||
capabilities = cifs_ssetup_hdr(ses, pSMB);
|
||||
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
|
||||
int rc;
|
||||
unsigned int num_referrals = 0;
|
||||
struct dfs_info3_param *referrals = NULL;
|
||||
struct dfs_info3_param referral = {0};
|
||||
|
||||
rc = get_dfs_path(xid, tcon->ses, searchName, nls_codepage,
|
||||
&num_referrals, &referrals, 0);
|
||||
rc = get_dfs_path(xid, tcon->ses, searchName, nls_codepage, &referral,
|
||||
0);
|
||||
|
||||
if (!rc && num_referrals > 0) {
|
||||
*symlinkinfo = kstrndup(referrals->node_name,
|
||||
strlen(referrals->node_name),
|
||||
if (!rc) {
|
||||
*symlinkinfo = kstrndup(referral.node_name,
|
||||
strlen(referral.node_name),
|
||||
GFP_KERNEL);
|
||||
free_dfs_info_param(&referral);
|
||||
if (!*symlinkinfo)
|
||||
rc = -ENOMEM;
|
||||
free_dfs_info_array(referrals, num_referrals);
|
||||
}
|
||||
return rc;
|
||||
#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_fid fid;
|
||||
struct cifs_ses *ses = tcon->ses;
|
||||
struct TCP_Server_Info *server = ses->server;
|
||||
int num_rqst = 0;
|
||||
struct smb_rqst rqst[3];
|
||||
int resp_buftype[3];
|
||||
@ -97,7 +96,7 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
if (rc)
|
||||
goto finished;
|
||||
|
||||
smb2_set_next_command(server, &rqst[num_rqst++], 0);
|
||||
smb2_set_next_command(tcon, &rqst[num_rqst++]);
|
||||
|
||||
/* Operation */
|
||||
switch (command) {
|
||||
@ -111,7 +110,7 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
SMB2_O_INFO_FILE, 0,
|
||||
sizeof(struct smb2_file_all_info) +
|
||||
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++]);
|
||||
break;
|
||||
case SMB2_OP_DELETE:
|
||||
@ -134,7 +133,7 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
COMPOUND_FID, current->tgid,
|
||||
FILE_DISPOSITION_INFORMATION,
|
||||
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++]);
|
||||
break;
|
||||
case SMB2_OP_SET_EOF:
|
||||
@ -149,7 +148,7 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
COMPOUND_FID, current->tgid,
|
||||
FILE_END_OF_FILE_INFORMATION,
|
||||
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++]);
|
||||
break;
|
||||
case SMB2_OP_SET_INFO:
|
||||
@ -165,7 +164,7 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
COMPOUND_FID, current->tgid,
|
||||
FILE_BASIC_INFORMATION,
|
||||
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++]);
|
||||
break;
|
||||
case SMB2_OP_RENAME:
|
||||
@ -189,7 +188,7 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
COMPOUND_FID, current->tgid,
|
||||
FILE_RENAME_INFORMATION,
|
||||
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++]);
|
||||
break;
|
||||
case SMB2_OP_HARDLINK:
|
||||
@ -213,7 +212,7 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
COMPOUND_FID, current->tgid,
|
||||
FILE_LINK_INFORMATION,
|
||||
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++]);
|
||||
break;
|
||||
default:
|
||||
@ -388,7 +387,6 @@ smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
rc = -ENOMEM;
|
||||
goto smb2_rename_path;
|
||||
}
|
||||
|
||||
rc = smb2_compound_op(xid, tcon, cifs_sb, from_name, access,
|
||||
FILE_OPEN, 0, smb2_to_name, command);
|
||||
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_NO_EAS_ON_FILE, -ENODATA, "STATUS_NO_EAS_ON_FILE"},
|
||||
{STATUS_EA_CORRUPT_ERROR, -EIO, "STATUS_EA_CORRUPT_ERROR"},
|
||||
{STATUS_FILE_LOCK_CONFLICT, -EIO, "STATUS_FILE_LOCK_CONFLICT"},
|
||||
{STATUS_LOCK_NOT_GRANTED, -EIO, "STATUS_LOCK_NOT_GRANTED"},
|
||||
{STATUS_FILE_LOCK_CONFLICT, -EACCES, "STATUS_FILE_LOCK_CONFLICT"},
|
||||
{STATUS_LOCK_NOT_GRANTED, -EACCES, "STATUS_LOCK_NOT_GRANTED"},
|
||||
{STATUS_DELETE_PENDING, -ENOENT, "STATUS_DELETE_PENDING"},
|
||||
{STATUS_CTL_FILE_NOT_SUPPORTED, -ENOSYS,
|
||||
"STATUS_CTL_FILE_NOT_SUPPORTED"},
|
||||
|
@ -831,72 +831,48 @@ smb2_query_eas(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
{
|
||||
int rc;
|
||||
__le16 *utf16_path;
|
||||
__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
|
||||
struct cifs_open_parms oparms;
|
||||
struct cifs_fid fid;
|
||||
struct smb2_file_full_ea_info *smb2_data;
|
||||
int ea_buf_size = SMB2_MIN_EA_BUF;
|
||||
struct kvec rsp_iov = {NULL, 0};
|
||||
int buftype = CIFS_NO_BUFFER;
|
||||
struct smb2_query_info_rsp *rsp;
|
||||
struct smb2_file_full_ea_info *info = NULL;
|
||||
|
||||
utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
|
||||
if (!utf16_path)
|
||||
return -ENOMEM;
|
||||
|
||||
oparms.tcon = tcon;
|
||||
oparms.desired_access = FILE_READ_EA;
|
||||
oparms.disposition = FILE_OPEN;
|
||||
if (backup_cred(cifs_sb))
|
||||
oparms.create_options = CREATE_OPEN_BACKUP_INTENT;
|
||||
else
|
||||
oparms.create_options = 0;
|
||||
oparms.fid = &fid;
|
||||
oparms.reconnect = false;
|
||||
|
||||
rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL, NULL);
|
||||
kfree(utf16_path);
|
||||
rc = smb2_query_info_compound(xid, tcon, utf16_path,
|
||||
FILE_READ_EA,
|
||||
FILE_FULL_EA_INFORMATION,
|
||||
SMB2_O_INFO_FILE,
|
||||
SMB2_MAX_EA_BUF,
|
||||
&rsp_iov, &buftype, cifs_sb);
|
||||
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) {
|
||||
smb2_data = kzalloc(ea_buf_size, GFP_KERNEL);
|
||||
if (smb2_data == NULL) {
|
||||
SMB2_close(xid, tcon, fid.persistent_fid,
|
||||
fid.volatile_fid);
|
||||
return -ENOMEM;
|
||||
}
|
||||
rsp = (struct smb2_query_info_rsp *)rsp_iov.iov_base;
|
||||
rc = smb2_validate_iov(le16_to_cpu(rsp->OutputBufferOffset),
|
||||
le32_to_cpu(rsp->OutputBufferLength),
|
||||
&rsp_iov,
|
||||
sizeof(struct smb2_file_full_ea_info));
|
||||
if (rc)
|
||||
goto qeas_exit;
|
||||
|
||||
rc = SMB2_query_eas(xid, tcon, fid.persistent_fid,
|
||||
fid.volatile_fid,
|
||||
ea_buf_size, smb2_data);
|
||||
info = (struct smb2_file_full_ea_info *)(
|
||||
le16_to_cpu(rsp->OutputBufferOffset) + (char *)rsp);
|
||||
rc = move_smb2_ea_to_cifs(ea_data, buf_size, info,
|
||||
le32_to_cpu(rsp->OutputBufferLength), ea_name);
|
||||
|
||||
if (rc != -E2BIG)
|
||||
break;
|
||||
|
||||
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);
|
||||
qeas_exit:
|
||||
kfree(utf16_path);
|
||||
free_rsp_buf(buftype, rsp_iov.iov_base);
|
||||
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,
|
||||
struct cifs_sb_info *cifs_sb)
|
||||
{
|
||||
int rc;
|
||||
__le16 *utf16_path;
|
||||
__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
|
||||
struct cifs_open_parms oparms;
|
||||
struct cifs_fid fid;
|
||||
struct smb2_file_full_ea_info *ea;
|
||||
struct cifs_ses *ses = tcon->ses;
|
||||
__le16 *utf16_path = NULL;
|
||||
int ea_name_len = strlen(ea_name);
|
||||
int flags = 0;
|
||||
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)
|
||||
return -EINVAL;
|
||||
@ -923,6 +912,16 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
if (!utf16_path)
|
||||
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.desired_access = FILE_WRITE_EA;
|
||||
oparms.disposition = FILE_OPEN;
|
||||
@ -933,18 +932,22 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
oparms.fid = &fid;
|
||||
oparms.reconnect = false;
|
||||
|
||||
rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL, NULL);
|
||||
kfree(utf16_path);
|
||||
if (rc) {
|
||||
cifs_dbg(FYI, "open failed rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
rc = SMB2_open_init(tcon, &rqst[0], &oplock, &oparms, utf16_path);
|
||||
if (rc)
|
||||
goto sea_exit;
|
||||
smb2_set_next_command(tcon, &rqst[0]);
|
||||
|
||||
|
||||
/* 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;
|
||||
ea = kzalloc(len, GFP_KERNEL);
|
||||
if (ea == NULL) {
|
||||
SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
|
||||
return -ENOMEM;
|
||||
rc = -ENOMEM;
|
||||
goto sea_exit;
|
||||
}
|
||||
|
||||
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_len + 1, ea_value, ea_value_len);
|
||||
|
||||
rc = SMB2_set_ea(xid, tcon, fid.persistent_fid, fid.volatile_fid, ea,
|
||||
len);
|
||||
size[0] = 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);
|
||||
|
||||
SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
|
||||
|
||||
kfree(utf16_path);
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
@ -1194,7 +1221,7 @@ smb2_ioctl_query_info(const unsigned int xid,
|
||||
rc = SMB2_open_init(tcon, &rqst[0], &oplock, &oparms, path);
|
||||
if (rc)
|
||||
goto iqinf_exit;
|
||||
smb2_set_next_command(ses->server, &rqst[0], 0);
|
||||
smb2_set_next_command(tcon, &rqst[0]);
|
||||
|
||||
/* Query */
|
||||
memset(&qi_iov, 0, sizeof(qi_iov));
|
||||
@ -1208,7 +1235,7 @@ smb2_ioctl_query_info(const unsigned int xid,
|
||||
qi.output_buffer_length, buffer);
|
||||
if (rc)
|
||||
goto iqinf_exit;
|
||||
smb2_set_next_command(ses->server, &rqst[1], 0);
|
||||
smb2_set_next_command(tcon, &rqst[1]);
|
||||
smb2_set_related(&rqst[1]);
|
||||
|
||||
/* Close */
|
||||
@ -1761,49 +1788,79 @@ smb2_set_related(struct smb_rqst *rqst)
|
||||
char smb2_padding[7] = {0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
void
|
||||
smb2_set_next_command(struct TCP_Server_Info *server, struct smb_rqst *rqst,
|
||||
bool has_space_for_padding)
|
||||
smb2_set_next_command(struct cifs_tcon *tcon, struct smb_rqst *rqst)
|
||||
{
|
||||
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);
|
||||
int i, num_padding;
|
||||
|
||||
/* SMB headers in a compound are 8 byte aligned. */
|
||||
if (len & 7) {
|
||||
if (has_space_for_padding) {
|
||||
len = rqst->rq_iov[rqst->rq_nvec - 1].iov_len;
|
||||
rqst->rq_iov[rqst->rq_nvec - 1].iov_len =
|
||||
(len + 7) & ~7;
|
||||
} else {
|
||||
rqst->rq_iov[rqst->rq_nvec].iov_base = smb2_padding;
|
||||
rqst->rq_iov[rqst->rq_nvec].iov_len = 8 - (len & 7);
|
||||
rqst->rq_nvec++;
|
||||
|
||||
/* No padding needed */
|
||||
if (!(len & 7))
|
||||
goto finished;
|
||||
|
||||
num_padding = 8 - (len & 7);
|
||||
if (!smb3_encryption_required(tcon)) {
|
||||
/*
|
||||
* 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->NextCommand = cpu_to_le32(len);
|
||||
}
|
||||
|
||||
static int
|
||||
smb2_queryfs(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
struct kstatfs *buf)
|
||||
/*
|
||||
* Passes the query info response back to the caller on success.
|
||||
* 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 smb2_fs_full_size_info *info = NULL;
|
||||
struct cifs_ses *ses = tcon->ses;
|
||||
int flags = 0;
|
||||
struct smb_rqst rqst[3];
|
||||
int resp_buftype[3];
|
||||
struct kvec rsp_iov[3];
|
||||
struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
|
||||
struct kvec qi_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;
|
||||
struct cifs_open_parms oparms;
|
||||
struct cifs_fid fid;
|
||||
int flags = 0;
|
||||
int rc;
|
||||
|
||||
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;
|
||||
|
||||
oparms.tcon = tcon;
|
||||
oparms.desired_access = FILE_READ_ATTRIBUTES;
|
||||
oparms.desired_access = desired_access;
|
||||
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.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)
|
||||
goto qfs_exit;
|
||||
smb2_set_next_command(server, &rqst[0], 0);
|
||||
goto qic_exit;
|
||||
smb2_set_next_command(tcon, &rqst[0]);
|
||||
|
||||
memset(&qi_iov, 0, sizeof(qi_iov));
|
||||
rqst[1].rq_iov = qi_iov;
|
||||
rqst[1].rq_nvec = 1;
|
||||
|
||||
rc = SMB2_query_info_init(tcon, &rqst[1], COMPOUND_FID, COMPOUND_FID,
|
||||
FS_FULL_SIZE_INFORMATION,
|
||||
SMB2_O_INFO_FILESYSTEM, 0,
|
||||
sizeof(struct smb2_fs_full_size_info), 0,
|
||||
class, type, 0,
|
||||
output_len, 0,
|
||||
NULL);
|
||||
if (rc)
|
||||
goto qfs_exit;
|
||||
smb2_set_next_command(server, &rqst[1], 0);
|
||||
goto qic_exit;
|
||||
smb2_set_next_command(tcon, &rqst[1]);
|
||||
smb2_set_related(&rqst[1]);
|
||||
|
||||
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);
|
||||
if (rc)
|
||||
goto qfs_exit;
|
||||
goto qic_exit;
|
||||
smb2_set_related(&rqst[2]);
|
||||
|
||||
rc = compound_send_recv(xid, ses, flags, 3, rqst,
|
||||
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)
|
||||
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;
|
||||
info = (struct smb2_fs_full_size_info *)(
|
||||
le16_to_cpu(rsp->OutputBufferOffset) + (char *)rsp);
|
||||
rc = smb2_validate_iov(le16_to_cpu(rsp->OutputBufferOffset),
|
||||
le32_to_cpu(rsp->OutputBufferLength),
|
||||
&rsp_iov[1],
|
||||
&rsp_iov,
|
||||
sizeof(struct smb2_fs_full_size_info));
|
||||
if (!rc)
|
||||
smb2_copy_fs_info_to_kstatfs(info, buf);
|
||||
|
||||
qfs_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[1], rsp_iov[1].iov_base);
|
||||
free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base);
|
||||
free_rsp_buf(buftype, rsp_iov.iov_base);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -2743,7 +2831,7 @@ init_sg(int num_rqst, struct smb_rqst *rqst, u8 *sign)
|
||||
smb2_sg_set_buf(&sg[idx++],
|
||||
rqst[i].rq_iov[j].iov_base + skip,
|
||||
rqst[i].rq_iov[j].iov_len - skip);
|
||||
}
|
||||
}
|
||||
|
||||
for (j = 0; j < rqst[i].rq_npages; j++) {
|
||||
unsigned int len, offset;
|
||||
|
@ -50,6 +50,9 @@
|
||||
#include "cifs_spnego.h"
|
||||
#include "smbdirect.h"
|
||||
#include "trace.h"
|
||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
#include "dfs_cache.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The following table defines the expected "StructureSize" of SMB2 requests
|
||||
@ -152,6 +155,77 @@ smb2_hdr_assemble(struct smb2_sync_hdr *shdr, __le16 smb2_cmd,
|
||||
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
|
||||
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 cifs_ses *ses;
|
||||
struct TCP_Server_Info *server;
|
||||
int retries;
|
||||
|
||||
/*
|
||||
* 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;
|
||||
server = ses->server;
|
||||
|
||||
retries = server->nr_targets;
|
||||
|
||||
/*
|
||||
* Give demultiplex thread up to 10 seconds to reconnect, should be
|
||||
* greater than cifs socket timeout which is 7 seconds
|
||||
* Give demultiplex thread up to 10 seconds to each target available for
|
||||
* reconnect -- should be greater than cifs socket timeout which is 7
|
||||
* seconds.
|
||||
*/
|
||||
while (server->tcpStatus == CifsNeedReconnect) {
|
||||
/*
|
||||
@ -225,6 +303,9 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon)
|
||||
if (server->tcpStatus != CifsNeedReconnect)
|
||||
break;
|
||||
|
||||
if (--retries)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* on "soft" mounts we wait once. Hard mounts keep
|
||||
* 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");
|
||||
return -EHOSTDOWN;
|
||||
}
|
||||
retries = server->nr_targets;
|
||||
}
|
||||
|
||||
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)
|
||||
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);
|
||||
|
||||
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 smb2_create_req *req;
|
||||
struct smb2_create_rsp *rsp = NULL;
|
||||
struct TCP_Server_Info *server;
|
||||
struct cifs_ses *ses = tcon->ses;
|
||||
struct kvec iov[3]; /* make sure at least one for each open context */
|
||||
struct kvec rsp_iov = {NULL, 0};
|
||||
@ -1978,9 +2059,7 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
|
||||
if (!utf16_path)
|
||||
return -ENOMEM;
|
||||
|
||||
if (ses && (ses->server))
|
||||
server = ses->server;
|
||||
else {
|
||||
if (!ses || !(ses->server)) {
|
||||
rc = -EIO;
|
||||
goto err_free_path;
|
||||
}
|
||||
@ -2768,18 +2847,6 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
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,
|
||||
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,
|
||||
int outbuf_len, u64 persistent_fid, u64 volatile_fid)
|
||||
{
|
||||
struct TCP_Server_Info *server;
|
||||
int rc;
|
||||
struct smb2_query_info_req *req;
|
||||
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))
|
||||
return -EIO;
|
||||
|
||||
server = tcon->ses->server;
|
||||
|
||||
rc = smb2_plain_req_init(SMB2_QUERY_INFO, tcon, (void **) &req,
|
||||
&total_len);
|
||||
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 */
|
||||
} __packed; /* level 11 Set */
|
||||
|
||||
#define SMB2_MIN_EA_BUF 2048
|
||||
#define SMB2_MAX_EA_BUF 65536
|
||||
|
||||
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 unsigned long smb_rqst_len(struct TCP_Server_Info *server,
|
||||
struct smb_rqst *rqst);
|
||||
extern void smb2_set_next_command(struct TCP_Server_Info *server,
|
||||
struct smb_rqst *rqst,
|
||||
bool has_space_for_padding);
|
||||
extern void smb2_set_next_command(struct cifs_tcon *tcon,
|
||||
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 int SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
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,
|
||||
u64 persistent_file_id, u64 volatile_file_id,
|
||||
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_update_preauth_hash(struct cifs_ses *ses,
|
||||
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 */
|
||||
|
@ -126,9 +126,11 @@ DeleteMidQEntry(struct mid_q_entry *midEntry)
|
||||
if ((slow_rsp_threshold != 0) &&
|
||||
time_after(now, midEntry->when_alloc + (slow_rsp_threshold * HZ)) &&
|
||||
(midEntry->command != command)) {
|
||||
/* smb2slowcmd[NUMBER_OF_SMB2_COMMANDS] counts by command */
|
||||
if ((le16_to_cpu(midEntry->command) < NUMBER_OF_SMB2_COMMANDS) &&
|
||||
(le16_to_cpu(midEntry->command) >= 0))
|
||||
/*
|
||||
* smb2slowcmd[NUMBER_OF_SMB2_COMMANDS] counts by command
|
||||
* 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)]);
|
||||
|
||||
trace_smb3_slow_rsp(le16_to_cpu(midEntry->command),
|
||||
|
Loading…
Reference in New Issue
Block a user