Commit cacf02df authored by Linus Torvalds's avatar Linus Torvalds

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
  ...
parents 74673fc5 fea17080
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 ...@@ -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 ...@@ -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 ...@@ -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. ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 @@ ...@@ -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) ...@@ -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) ...@@ -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 @@ ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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 @@ char *cifs_compose_mount_options(const char *sb_mountdata, ...@@ -234,8 +239,7 @@ char *cifs_compose_mount_options(const char *sb_mountdata,
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, ...@@ -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) ...@@ -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) ...@@ -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;
tcon = cifs_sb_master_tcon(cifs_sb);
if (!tcon) {
cifs_dbg(FYI, "%s: master tcon is NULL\n", __func__);
goto free_full_path;
}
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);
ses = tcon->ses;
xid = get_xid(); 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); /*
* If DFS root has been expired, then unconditionally fetch it again to
mnt = ERR_PTR(-ENOENT); * refresh DFS referral cache.
for (i = 0; i < num_referrals; i++) { */
int len; rc = dfs_cache_find(xid, ses, cifs_sb->local_nls, cifs_remap(cifs_sb),
dump_referral(referrals + i); root_path + 1, NULL, NULL);
/* connect to a node */ if (!rc) {
len = strlen(referrals[i].node_name); rc = dfs_cache_find(xid, ses, cifs_sb->local_nls,
if (len < 2) { cifs_remap(cifs_sb), full_path + 1,
cifs_dbg(VFS, "%s: Net Address path too short: %s\n", &referral, NULL);
__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 free_xid(xid);
* preference */
if (rc != 0) if (rc) {
mnt = ERR_PTR(rc); mnt = ERR_PTR(rc);
goto free_root_path;
}
dump_referral(&referral);
success: len = strlen(referral.node_name);
free_dfs_info_array(referrals, num_referrals); 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 { ...@@ -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, ...@@ -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) ...@@ -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 @@ ...@@ -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) ...@@ -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 @@ init_cifs(void) ...@@ -1525,6 +1533,10 @@ init_cifs(void)
#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) ...@@ -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); ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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) ...@@ -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; ...@@ -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 @@ ...@@ -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 *); ...@@ -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, ...@@ -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, ...@@ -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); ...@@ -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 @@ ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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);
......
This diff is collapsed.
This diff is collapsed.
/* 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, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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 * ...@@ -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) ...@@ -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 ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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 @@ sess_auth_kerberos(struct sess_data *sess_data) ...@@ -1154,14 +1154,12 @@ sess_auth_kerberos(struct sess_data *sess_data)
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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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[] = { ...@@ -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"},
......
This diff is collapsed.
...@@ -50,6 +50,9 @@ ...@@ -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 @@ smb2_hdr_assemble(struct smb2_sync_hdr *shdr, __le16 smb2_cmd, ...@@ -152,6 +155,77 @@ smb2_hdr_assemble(struct smb2_sync_hdr *shdr, __le16 smb2_cmd,
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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -2768,18 +2847,6 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
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 ...@@ -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, ...@@ -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 */ ...@@ -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); ...@@ -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, ...@@ -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( ...@@ -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) ...@@ -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),
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment