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:
Linus Torvalds
2019-01-02 12:08:29 -08:00
28 changed files with 2876 additions and 521 deletions
+20 -6
View File
@@ -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).
+3 -2
View File
@@ -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"
+1 -1
View File
@@ -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
+12
View File
@@ -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);
+89 -55
View File
@@ -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 @@ compose_mount_options_out:
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:
+9
View File
@@ -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 */
+9 -4
View File
@@ -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,
+16 -1
View File
@@ -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 @@ out_register_key_type:
#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();
+1 -1
View File
@@ -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 */
+14 -1
View File
@@ -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
View File
@@ -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 */
+85 -3
View File
@@ -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);
+719 -225
View File
File diff suppressed because it is too large Load Diff
+1367
View File
File diff suppressed because it is too large Load Diff
+97
View 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 */
+10 -2
View File
@@ -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;
+20 -24
View File
@@ -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+.
+52 -16
View File
@@ -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;
}
+8 -1
View File
@@ -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);
+1 -3
View File
@@ -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 @@ out:
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) {

Some files were not shown because too many files have changed in this diff Show More