Commit 1dd5c6b1 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-next' of git://git.samba.org/sfrench/cifs-2.6

Pull cifs fixes from Steve French:
 "This ncludes various cifs/smb3 bug fixes, mostly for stable as well.

  In the next week I expect that Germano will have some reconnection
  fixes, and also I expect to have the remaining pieces of the snapshot
  enablement and SMB3 ACLs, but wanted to get this set of bug fixes in"

* 'for-next' of git://git.samba.org/sfrench/cifs-2.6:
  cifs_get_root shouldn't use path with tree name
  Fix default behaviour for empty domains and add domainauto option
  cifs: use %16phN for formatting md5 sum
  cifs: Fix smbencrypt() to stop pointing a scatterlist at the stack
  CIFS: Fix a possible double locking of mutex during reconnect
  CIFS: Fix a possible memory corruption during reconnect
  CIFS: Fix a possible memory corruption in push locks
  CIFS: Fix missing nls unload in smb2_reconnect()
  CIFS: Decrease verbosity of ioctl call
  SMB3: parsing for new snapshot timestamp mount parm
parents 3a77fa85 374402a2
...@@ -699,11 +699,15 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp) ...@@ -699,11 +699,15 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
if (ses->server->negflavor == CIFS_NEGFLAVOR_EXTENDED) { if (ses->server->negflavor == CIFS_NEGFLAVOR_EXTENDED) {
if (!ses->domainName) { if (!ses->domainName) {
rc = find_domain_name(ses, nls_cp); if (ses->domainAuto) {
if (rc) { rc = find_domain_name(ses, nls_cp);
cifs_dbg(VFS, "error %d finding domain name\n", if (rc) {
rc); cifs_dbg(VFS, "error %d finding domain name\n",
goto setup_ntlmv2_rsp_ret; rc);
goto setup_ntlmv2_rsp_ret;
}
} else {
ses->domainName = kstrdup("", GFP_KERNEL);
} }
} }
} else { } else {
......
...@@ -615,7 +615,7 @@ cifs_get_root(struct smb_vol *vol, struct super_block *sb) ...@@ -615,7 +615,7 @@ cifs_get_root(struct smb_vol *vol, struct super_block *sb)
return dget(sb->s_root); return dget(sb->s_root);
full_path = cifs_build_path_to_root(vol, cifs_sb, full_path = cifs_build_path_to_root(vol, cifs_sb,
cifs_sb_master_tcon(cifs_sb)); cifs_sb_master_tcon(cifs_sb), 0);
if (full_path == NULL) if (full_path == NULL)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
......
...@@ -514,6 +514,7 @@ struct smb_vol { ...@@ -514,6 +514,7 @@ struct smb_vol {
bool persistent:1; bool persistent:1;
bool nopersistent:1; bool nopersistent:1;
bool resilient:1; /* noresilient not required since not fored for CA */ bool resilient:1; /* noresilient not required since not fored for CA */
bool domainauto:1;
unsigned int rsize; unsigned int rsize;
unsigned int wsize; unsigned int wsize;
bool sockopt_tcp_nodelay:1; bool sockopt_tcp_nodelay:1;
...@@ -525,6 +526,7 @@ struct smb_vol { ...@@ -525,6 +526,7 @@ struct smb_vol {
struct sockaddr_storage srcaddr; /* allow binding to a local IP */ struct sockaddr_storage srcaddr; /* allow binding to a local IP */
struct nls_table *local_nls; struct nls_table *local_nls;
unsigned int echo_interval; /* echo interval in secs */ unsigned int echo_interval; /* echo interval in secs */
__u64 snapshot_time; /* needed for timewarp tokens */
unsigned int max_credits; /* smb3 max_credits 10 < credits < 60000 */ unsigned int max_credits; /* smb3 max_credits 10 < credits < 60000 */
}; };
...@@ -646,6 +648,8 @@ struct TCP_Server_Info { ...@@ -646,6 +648,8 @@ struct TCP_Server_Info {
unsigned int max_read; unsigned int max_read;
unsigned int max_write; unsigned int max_write;
__u8 preauth_hash[512]; __u8 preauth_hash[512];
struct delayed_work reconnect; /* reconnect workqueue job */
struct mutex reconnect_mutex; /* prevent simultaneous reconnects */
#endif /* CONFIG_CIFS_SMB2 */ #endif /* CONFIG_CIFS_SMB2 */
unsigned long echo_interval; unsigned long echo_interval;
}; };
...@@ -827,6 +831,7 @@ struct cifs_ses { ...@@ -827,6 +831,7 @@ struct cifs_ses {
enum securityEnum sectype; /* what security flavor was specified? */ enum securityEnum sectype; /* what security flavor was specified? */
bool sign; /* is signing required? */ bool sign; /* is signing required? */
bool need_reconnect:1; /* connection reset, uid now invalid */ bool need_reconnect:1; /* connection reset, uid now invalid */
bool domainAuto:1;
#ifdef CONFIG_CIFS_SMB2 #ifdef CONFIG_CIFS_SMB2
__u16 session_flags; __u16 session_flags;
__u8 smb3signingkey[SMB3_SIGN_KEY_SIZE]; __u8 smb3signingkey[SMB3_SIGN_KEY_SIZE];
...@@ -849,6 +854,7 @@ cap_unix(struct cifs_ses *ses) ...@@ -849,6 +854,7 @@ cap_unix(struct cifs_ses *ses)
struct cifs_tcon { struct cifs_tcon {
struct list_head tcon_list; struct list_head tcon_list;
int tc_count; int tc_count;
struct list_head rlist; /* reconnect list */
struct list_head openFileList; struct list_head openFileList;
spinlock_t open_file_lock; /* protects list above */ spinlock_t open_file_lock; /* protects list above */
struct cifs_ses *ses; /* pointer to session associated with */ struct cifs_ses *ses; /* pointer to session associated with */
...@@ -922,6 +928,7 @@ struct cifs_tcon { ...@@ -922,6 +928,7 @@ struct cifs_tcon {
bool broken_posix_open; /* e.g. Samba server versions < 3.3.2, 3.2.9 */ bool broken_posix_open; /* e.g. Samba server versions < 3.3.2, 3.2.9 */
bool broken_sparse_sup; /* if server or share does not support sparse */ bool broken_sparse_sup; /* if server or share does not support sparse */
bool need_reconnect:1; /* connection reset, tid now invalid */ bool need_reconnect:1; /* connection reset, tid now invalid */
bool need_reopen_files:1; /* need to reopen tcon file handles */
bool use_resilient:1; /* use resilient instead of durable handles */ bool use_resilient:1; /* use resilient instead of durable handles */
bool use_persistent:1; /* use persistent instead of durable handles */ bool use_persistent:1; /* use persistent instead of durable handles */
#ifdef CONFIG_CIFS_SMB2 #ifdef CONFIG_CIFS_SMB2
...@@ -932,6 +939,7 @@ struct cifs_tcon { ...@@ -932,6 +939,7 @@ struct cifs_tcon {
__u32 maximal_access; __u32 maximal_access;
__u32 vol_serial_number; __u32 vol_serial_number;
__le64 vol_create_time; __le64 vol_create_time;
__u64 snapshot_time; /* for timewarp tokens - timestamp of snapshot */
__u32 ss_flags; /* sector size flags */ __u32 ss_flags; /* sector size flags */
__u32 perf_sector_size; /* best sector size for perf */ __u32 perf_sector_size; /* best sector size for perf */
__u32 max_chunks; __u32 max_chunks;
......
...@@ -63,7 +63,8 @@ extern void exit_cifs_spnego(void); ...@@ -63,7 +63,8 @@ extern void exit_cifs_spnego(void);
extern char *build_path_from_dentry(struct dentry *); extern char *build_path_from_dentry(struct dentry *);
extern char *cifs_build_path_to_root(struct smb_vol *vol, extern char *cifs_build_path_to_root(struct smb_vol *vol,
struct cifs_sb_info *cifs_sb, struct cifs_sb_info *cifs_sb,
struct cifs_tcon *tcon); struct cifs_tcon *tcon,
int add_treename);
extern char *build_wildcard_path_from_dentry(struct dentry *direntry); extern char *build_wildcard_path_from_dentry(struct dentry *direntry);
extern char *cifs_compose_mount_options(const char *sb_mountdata, extern char *cifs_compose_mount_options(const char *sb_mountdata,
const char *fullpath, const struct dfs_info3_param *ref, const char *fullpath, const struct dfs_info3_param *ref,
...@@ -206,6 +207,9 @@ extern void cifs_add_pending_open_locked(struct cifs_fid *fid, ...@@ -206,6 +207,9 @@ extern void cifs_add_pending_open_locked(struct cifs_fid *fid,
struct tcon_link *tlink, struct tcon_link *tlink,
struct cifs_pending_open *open); struct cifs_pending_open *open);
extern void cifs_del_pending_open(struct cifs_pending_open *open); extern void cifs_del_pending_open(struct cifs_pending_open *open);
extern void cifs_put_tcp_session(struct TCP_Server_Info *server,
int from_reconnect);
extern void cifs_put_tcon(struct cifs_tcon *tcon);
#if IS_ENABLED(CONFIG_CIFS_DFS_UPCALL) #if IS_ENABLED(CONFIG_CIFS_DFS_UPCALL)
extern void cifs_dfs_release_automount_timer(void); extern void cifs_dfs_release_automount_timer(void);
......
...@@ -53,6 +53,9 @@ ...@@ -53,6 +53,9 @@
#include "nterr.h" #include "nterr.h"
#include "rfc1002pdu.h" #include "rfc1002pdu.h"
#include "fscache.h" #include "fscache.h"
#ifdef CONFIG_CIFS_SMB2
#include "smb2proto.h"
#endif
#define CIFS_PORT 445 #define CIFS_PORT 445
#define RFC1001_PORT 139 #define RFC1001_PORT 139
...@@ -89,6 +92,7 @@ enum { ...@@ -89,6 +92,7 @@ enum {
Opt_multiuser, Opt_sloppy, Opt_nosharesock, Opt_multiuser, Opt_sloppy, Opt_nosharesock,
Opt_persistent, Opt_nopersistent, Opt_persistent, Opt_nopersistent,
Opt_resilient, Opt_noresilient, Opt_resilient, Opt_noresilient,
Opt_domainauto,
/* Mount options which take numeric value */ /* Mount options which take numeric value */
Opt_backupuid, Opt_backupgid, Opt_uid, Opt_backupuid, Opt_backupgid, Opt_uid,
...@@ -96,6 +100,7 @@ enum { ...@@ -96,6 +100,7 @@ enum {
Opt_dirmode, Opt_port, Opt_dirmode, Opt_port,
Opt_rsize, Opt_wsize, Opt_actimeo, Opt_rsize, Opt_wsize, Opt_actimeo,
Opt_echo_interval, Opt_max_credits, Opt_echo_interval, Opt_max_credits,
Opt_snapshot,
/* Mount options which take string value */ /* Mount options which take string value */
Opt_user, Opt_pass, Opt_ip, Opt_user, Opt_pass, Opt_ip,
...@@ -177,6 +182,7 @@ static const match_table_t cifs_mount_option_tokens = { ...@@ -177,6 +182,7 @@ static const match_table_t cifs_mount_option_tokens = {
{ Opt_nopersistent, "nopersistenthandles"}, { Opt_nopersistent, "nopersistenthandles"},
{ Opt_resilient, "resilienthandles"}, { Opt_resilient, "resilienthandles"},
{ Opt_noresilient, "noresilienthandles"}, { Opt_noresilient, "noresilienthandles"},
{ Opt_domainauto, "domainauto"},
{ Opt_backupuid, "backupuid=%s" }, { Opt_backupuid, "backupuid=%s" },
{ Opt_backupgid, "backupgid=%s" }, { Opt_backupgid, "backupgid=%s" },
...@@ -192,6 +198,7 @@ static const match_table_t cifs_mount_option_tokens = { ...@@ -192,6 +198,7 @@ static const match_table_t cifs_mount_option_tokens = {
{ Opt_actimeo, "actimeo=%s" }, { Opt_actimeo, "actimeo=%s" },
{ Opt_echo_interval, "echo_interval=%s" }, { Opt_echo_interval, "echo_interval=%s" },
{ Opt_max_credits, "max_credits=%s" }, { Opt_max_credits, "max_credits=%s" },
{ Opt_snapshot, "snapshot=%s" },
{ Opt_blank_user, "user=" }, { Opt_blank_user, "user=" },
{ Opt_blank_user, "username=" }, { Opt_blank_user, "username=" },
...@@ -1500,6 +1507,9 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, ...@@ -1500,6 +1507,9 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
case Opt_noresilient: case Opt_noresilient:
vol->resilient = false; /* already the default */ vol->resilient = false; /* already the default */
break; break;
case Opt_domainauto:
vol->domainauto = true;
break;
/* Numeric Values */ /* Numeric Values */
case Opt_backupuid: case Opt_backupuid:
...@@ -1602,6 +1612,14 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, ...@@ -1602,6 +1612,14 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
} }
vol->echo_interval = option; vol->echo_interval = option;
break; break;
case Opt_snapshot:
if (get_option_ul(args, &option)) {
cifs_dbg(VFS, "%s: Invalid snapshot time\n",
__func__);
goto cifs_parse_mount_err;
}
vol->snapshot_time = option;
break;
case Opt_max_credits: case Opt_max_credits:
if (get_option_ul(args, &option) || (option < 20) || if (get_option_ul(args, &option) || (option < 20) ||
(option > 60000)) { (option > 60000)) {
...@@ -2101,8 +2119,8 @@ cifs_find_tcp_session(struct smb_vol *vol) ...@@ -2101,8 +2119,8 @@ cifs_find_tcp_session(struct smb_vol *vol)
return NULL; return NULL;
} }
static void void
cifs_put_tcp_session(struct TCP_Server_Info *server) cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect)
{ {
struct task_struct *task; struct task_struct *task;
...@@ -2119,6 +2137,19 @@ cifs_put_tcp_session(struct TCP_Server_Info *server) ...@@ -2119,6 +2137,19 @@ cifs_put_tcp_session(struct TCP_Server_Info *server)
cancel_delayed_work_sync(&server->echo); cancel_delayed_work_sync(&server->echo);
#ifdef CONFIG_CIFS_SMB2
if (from_reconnect)
/*
* Avoid deadlock here: reconnect work calls
* cifs_put_tcp_session() at its end. Need to be sure
* that reconnect work does nothing with server pointer after
* that step.
*/
cancel_delayed_work(&server->reconnect);
else
cancel_delayed_work_sync(&server->reconnect);
#endif
spin_lock(&GlobalMid_Lock); spin_lock(&GlobalMid_Lock);
server->tcpStatus = CifsExiting; server->tcpStatus = CifsExiting;
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
...@@ -2183,6 +2214,10 @@ cifs_get_tcp_session(struct smb_vol *volume_info) ...@@ -2183,6 +2214,10 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
INIT_LIST_HEAD(&tcp_ses->tcp_ses_list); INIT_LIST_HEAD(&tcp_ses->tcp_ses_list);
INIT_LIST_HEAD(&tcp_ses->smb_ses_list); INIT_LIST_HEAD(&tcp_ses->smb_ses_list);
INIT_DELAYED_WORK(&tcp_ses->echo, cifs_echo_request); INIT_DELAYED_WORK(&tcp_ses->echo, cifs_echo_request);
#ifdef CONFIG_CIFS_SMB2
INIT_DELAYED_WORK(&tcp_ses->reconnect, smb2_reconnect_server);
mutex_init(&tcp_ses->reconnect_mutex);
#endif
memcpy(&tcp_ses->srcaddr, &volume_info->srcaddr, memcpy(&tcp_ses->srcaddr, &volume_info->srcaddr,
sizeof(tcp_ses->srcaddr)); sizeof(tcp_ses->srcaddr));
memcpy(&tcp_ses->dstaddr, &volume_info->dstaddr, memcpy(&tcp_ses->dstaddr, &volume_info->dstaddr,
...@@ -2341,7 +2376,7 @@ cifs_put_smb_ses(struct cifs_ses *ses) ...@@ -2341,7 +2376,7 @@ cifs_put_smb_ses(struct cifs_ses *ses)
spin_unlock(&cifs_tcp_ses_lock); spin_unlock(&cifs_tcp_ses_lock);
sesInfoFree(ses); sesInfoFree(ses);
cifs_put_tcp_session(server); cifs_put_tcp_session(server, 0);
} }
#ifdef CONFIG_KEYS #ifdef CONFIG_KEYS
...@@ -2515,7 +2550,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) ...@@ -2515,7 +2550,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
mutex_unlock(&ses->session_mutex); mutex_unlock(&ses->session_mutex);
/* existing SMB ses has a server reference already */ /* existing SMB ses has a server reference already */
cifs_put_tcp_session(server); cifs_put_tcp_session(server, 0);
free_xid(xid); free_xid(xid);
return ses; return ses;
} }
...@@ -2549,6 +2584,8 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) ...@@ -2549,6 +2584,8 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
if (!ses->domainName) if (!ses->domainName)
goto get_ses_fail; goto get_ses_fail;
} }
if (volume_info->domainauto)
ses->domainAuto = volume_info->domainauto;
ses->cred_uid = volume_info->cred_uid; ses->cred_uid = volume_info->cred_uid;
ses->linux_uid = volume_info->linux_uid; ses->linux_uid = volume_info->linux_uid;
...@@ -2587,7 +2624,7 @@ static int match_tcon(struct cifs_tcon *tcon, const char *unc) ...@@ -2587,7 +2624,7 @@ static int match_tcon(struct cifs_tcon *tcon, const char *unc)
} }
static struct cifs_tcon * static struct cifs_tcon *
cifs_find_tcon(struct cifs_ses *ses, const char *unc) cifs_find_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
{ {
struct list_head *tmp; struct list_head *tmp;
struct cifs_tcon *tcon; struct cifs_tcon *tcon;
...@@ -2595,8 +2632,14 @@ cifs_find_tcon(struct cifs_ses *ses, const char *unc) ...@@ -2595,8 +2632,14 @@ cifs_find_tcon(struct cifs_ses *ses, const char *unc)
spin_lock(&cifs_tcp_ses_lock); spin_lock(&cifs_tcp_ses_lock);
list_for_each(tmp, &ses->tcon_list) { list_for_each(tmp, &ses->tcon_list) {
tcon = list_entry(tmp, struct cifs_tcon, tcon_list); tcon = list_entry(tmp, struct cifs_tcon, tcon_list);
if (!match_tcon(tcon, unc)) if (!match_tcon(tcon, volume_info->UNC))
continue; continue;
#ifdef CONFIG_CIFS_SMB2
if (tcon->snapshot_time != volume_info->snapshot_time)
continue;
#endif /* CONFIG_CIFS_SMB2 */
++tcon->tc_count; ++tcon->tc_count;
spin_unlock(&cifs_tcp_ses_lock); spin_unlock(&cifs_tcp_ses_lock);
return tcon; return tcon;
...@@ -2605,7 +2648,7 @@ cifs_find_tcon(struct cifs_ses *ses, const char *unc) ...@@ -2605,7 +2648,7 @@ cifs_find_tcon(struct cifs_ses *ses, const char *unc)
return NULL; return NULL;
} }
static void void
cifs_put_tcon(struct cifs_tcon *tcon) cifs_put_tcon(struct cifs_tcon *tcon)
{ {
unsigned int xid; unsigned int xid;
...@@ -2637,7 +2680,7 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info) ...@@ -2637,7 +2680,7 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
int rc, xid; int rc, xid;
struct cifs_tcon *tcon; struct cifs_tcon *tcon;
tcon = cifs_find_tcon(ses, volume_info->UNC); tcon = cifs_find_tcon(ses, volume_info);
if (tcon) { if (tcon) {
cifs_dbg(FYI, "Found match on UNC path\n"); cifs_dbg(FYI, "Found match on UNC path\n");
/* existing tcon already has a reference */ /* existing tcon already has a reference */
...@@ -2658,6 +2701,22 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info) ...@@ -2658,6 +2701,22 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
goto out_fail; goto out_fail;
} }
if (volume_info->snapshot_time) {
#ifdef CONFIG_CIFS_SMB2
if (ses->server->vals->protocol_id == 0) {
cifs_dbg(VFS,
"Use SMB2 or later for snapshot mount option\n");
rc = -EOPNOTSUPP;
goto out_fail;
} else
tcon->snapshot_time = volume_info->snapshot_time;
#else
cifs_dbg(VFS, "Snapshot mount option requires SMB2 support\n");
rc = -EOPNOTSUPP;
goto out_fail;
#endif /* CONFIG_CIFS_SMB2 */
}
tcon->ses = ses; tcon->ses = ses;
if (volume_info->password) { if (volume_info->password) {
tcon->password = kstrdup(volume_info->password, GFP_KERNEL); tcon->password = kstrdup(volume_info->password, GFP_KERNEL);
...@@ -3707,7 +3766,8 @@ cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *volume_info) ...@@ -3707,7 +3766,8 @@ cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *volume_info)
/* /*
* cifs_build_path_to_root works only when we have a valid tcon * cifs_build_path_to_root works only when we have a valid tcon
*/ */
full_path = cifs_build_path_to_root(volume_info, cifs_sb, tcon); full_path = cifs_build_path_to_root(volume_info, cifs_sb, tcon,
tcon->Flags & SMB_SHARE_IS_IN_DFS);
if (full_path == NULL) { if (full_path == NULL) {
rc = -ENOMEM; rc = -ENOMEM;
goto mount_fail_check; goto mount_fail_check;
...@@ -3793,7 +3853,7 @@ cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *volume_info) ...@@ -3793,7 +3853,7 @@ cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *volume_info)
else if (ses) else if (ses)
cifs_put_smb_ses(ses); cifs_put_smb_ses(ses);
else else
cifs_put_tcp_session(server); cifs_put_tcp_session(server, 0);
bdi_destroy(&cifs_sb->bdi); bdi_destroy(&cifs_sb->bdi);
} }
...@@ -4104,7 +4164,7 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, kuid_t fsuid) ...@@ -4104,7 +4164,7 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, kuid_t fsuid)
ses = cifs_get_smb_ses(master_tcon->ses->server, vol_info); ses = cifs_get_smb_ses(master_tcon->ses->server, vol_info);
if (IS_ERR(ses)) { if (IS_ERR(ses)) {
tcon = (struct cifs_tcon *)ses; tcon = (struct cifs_tcon *)ses;
cifs_put_tcp_session(master_tcon->ses->server); cifs_put_tcp_session(master_tcon->ses->server, 0);
goto out; goto out;
} }
......
...@@ -47,7 +47,7 @@ renew_parental_timestamps(struct dentry *direntry) ...@@ -47,7 +47,7 @@ renew_parental_timestamps(struct dentry *direntry)
char * char *
cifs_build_path_to_root(struct smb_vol *vol, struct cifs_sb_info *cifs_sb, cifs_build_path_to_root(struct smb_vol *vol, struct cifs_sb_info *cifs_sb,
struct cifs_tcon *tcon) struct cifs_tcon *tcon, int add_treename)
{ {
int pplen = vol->prepath ? strlen(vol->prepath) + 1 : 0; int pplen = vol->prepath ? strlen(vol->prepath) + 1 : 0;
int dfsplen; int dfsplen;
...@@ -59,7 +59,7 @@ cifs_build_path_to_root(struct smb_vol *vol, struct cifs_sb_info *cifs_sb, ...@@ -59,7 +59,7 @@ cifs_build_path_to_root(struct smb_vol *vol, struct cifs_sb_info *cifs_sb,
return full_path; return full_path;
} }
if (tcon->Flags & SMB_SHARE_IS_IN_DFS) if (add_treename)
dfsplen = strnlen(tcon->treeName, MAX_TREE_SIZE + 1); dfsplen = strnlen(tcon->treeName, MAX_TREE_SIZE + 1);
else else
dfsplen = 0; dfsplen = 0;
......
...@@ -777,6 +777,11 @@ cifs_reopen_persistent_handles(struct cifs_tcon *tcon) ...@@ -777,6 +777,11 @@ cifs_reopen_persistent_handles(struct cifs_tcon *tcon)
struct list_head *tmp1; struct list_head *tmp1;
struct list_head tmp_list; struct list_head tmp_list;
if (!tcon->use_persistent || !tcon->need_reopen_files)
return;
tcon->need_reopen_files = false;
cifs_dbg(FYI, "Reopen persistent handles"); cifs_dbg(FYI, "Reopen persistent handles");
INIT_LIST_HEAD(&tmp_list); INIT_LIST_HEAD(&tmp_list);
...@@ -793,7 +798,8 @@ cifs_reopen_persistent_handles(struct cifs_tcon *tcon) ...@@ -793,7 +798,8 @@ cifs_reopen_persistent_handles(struct cifs_tcon *tcon)
list_for_each_safe(tmp, tmp1, &tmp_list) { list_for_each_safe(tmp, tmp1, &tmp_list) {
open_file = list_entry(tmp, struct cifsFileInfo, rlist); open_file = list_entry(tmp, struct cifsFileInfo, rlist);
cifs_reopen_file(open_file, false /* do not flush */); if (cifs_reopen_file(open_file, false /* do not flush */))
tcon->need_reopen_files = true;
list_del_init(&open_file->rlist); list_del_init(&open_file->rlist);
cifsFileInfo_put(open_file); cifsFileInfo_put(open_file);
} }
......
...@@ -189,7 +189,7 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg) ...@@ -189,7 +189,7 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
xid = get_xid(); xid = get_xid();
cifs_sb = CIFS_SB(inode->i_sb); cifs_sb = CIFS_SB(inode->i_sb);
cifs_dbg(VFS, "cifs ioctl 0x%x\n", command); cifs_dbg(FYI, "cifs ioctl 0x%x\n", command);
switch (command) { switch (command) {
case FS_IOC_GETFLAGS: case FS_IOC_GETFLAGS:
if (pSMBFile == NULL) if (pSMBFile == NULL)
......
...@@ -45,13 +45,8 @@ ...@@ -45,13 +45,8 @@
(CIFS_MF_SYMLINK_LINK_OFFSET + CIFS_MF_SYMLINK_LINK_MAXLEN) (CIFS_MF_SYMLINK_LINK_OFFSET + CIFS_MF_SYMLINK_LINK_MAXLEN)
#define CIFS_MF_SYMLINK_LEN_FORMAT "XSym\n%04u\n" #define CIFS_MF_SYMLINK_LEN_FORMAT "XSym\n%04u\n"
#define CIFS_MF_SYMLINK_MD5_FORMAT \ #define CIFS_MF_SYMLINK_MD5_FORMAT "%16phN\n"
"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n" #define CIFS_MF_SYMLINK_MD5_ARGS(md5_hash) md5_hash
#define CIFS_MF_SYMLINK_MD5_ARGS(md5_hash) \
md5_hash[0], md5_hash[1], md5_hash[2], md5_hash[3], \
md5_hash[4], md5_hash[5], md5_hash[6], md5_hash[7], \
md5_hash[8], md5_hash[9], md5_hash[10], md5_hash[11],\
md5_hash[12], md5_hash[13], md5_hash[14], md5_hash[15]
static int static int
symlink_hash(unsigned int link_len, const char *link_str, u8 *md5_hash) symlink_hash(unsigned int link_len, const char *link_str, u8 *md5_hash)
......
...@@ -260,7 +260,7 @@ smb2_push_mandatory_locks(struct cifsFileInfo *cfile) ...@@ -260,7 +260,7 @@ smb2_push_mandatory_locks(struct cifsFileInfo *cfile)
* and check it for zero before using. * and check it for zero before using.
*/ */
max_buf = tlink_tcon(cfile->tlink)->ses->server->maxBuf; max_buf = tlink_tcon(cfile->tlink)->ses->server->maxBuf;
if (!max_buf) { if (max_buf < sizeof(struct smb2_lock_element)) {
free_xid(xid); free_xid(xid);
return -EINVAL; return -EINVAL;
} }
......
...@@ -250,16 +250,19 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon) ...@@ -250,16 +250,19 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon)
} }
cifs_mark_open_files_invalid(tcon); cifs_mark_open_files_invalid(tcon);
if (tcon->use_persistent)
tcon->need_reopen_files = true;
rc = SMB2_tcon(0, tcon->ses, tcon->treeName, tcon, nls_codepage); rc = SMB2_tcon(0, tcon->ses, tcon->treeName, tcon, nls_codepage);
mutex_unlock(&tcon->ses->session_mutex); mutex_unlock(&tcon->ses->session_mutex);
if (tcon->use_persistent)
cifs_reopen_persistent_handles(tcon);
cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc); cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc);
if (rc) if (rc)
goto out; goto out;
if (smb2_command != SMB2_INTERNAL_CMD)
queue_delayed_work(cifsiod_wq, &server->reconnect, 0);
atomic_inc(&tconInfoReconnectCount); atomic_inc(&tconInfoReconnectCount);
out: out:
/* /*
...@@ -280,7 +283,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon) ...@@ -280,7 +283,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon)
case SMB2_CHANGE_NOTIFY: case SMB2_CHANGE_NOTIFY:
case SMB2_QUERY_INFO: case SMB2_QUERY_INFO:
case SMB2_SET_INFO: case SMB2_SET_INFO:
return -EAGAIN; rc = -EAGAIN;
} }
unload_nls(nls_codepage); unload_nls(nls_codepage);
return rc; return rc;
...@@ -1972,6 +1975,55 @@ smb2_echo_callback(struct mid_q_entry *mid) ...@@ -1972,6 +1975,55 @@ smb2_echo_callback(struct mid_q_entry *mid)
add_credits(server, credits_received, CIFS_ECHO_OP); add_credits(server, credits_received, CIFS_ECHO_OP);
} }
void smb2_reconnect_server(struct work_struct *work)
{
struct TCP_Server_Info *server = container_of(work,
struct TCP_Server_Info, reconnect.work);
struct cifs_ses *ses;
struct cifs_tcon *tcon, *tcon2;
struct list_head tmp_list;
int tcon_exist = false;
/* Prevent simultaneous reconnects that can corrupt tcon->rlist list */
mutex_lock(&server->reconnect_mutex);
INIT_LIST_HEAD(&tmp_list);
cifs_dbg(FYI, "Need negotiate, reconnecting tcons\n");
spin_lock(&cifs_tcp_ses_lock);
list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
if (tcon->need_reconnect || tcon->need_reopen_files) {
tcon->tc_count++;
list_add_tail(&tcon->rlist, &tmp_list);
tcon_exist = true;
}
}
}
/*
* Get the reference to server struct to be sure that the last call of
* cifs_put_tcon() in the loop below won't release the server pointer.
*/
if (tcon_exist)
server->srv_count++;
spin_unlock(&cifs_tcp_ses_lock);
list_for_each_entry_safe(tcon, tcon2, &tmp_list, rlist) {
if (!smb2_reconnect(SMB2_INTERNAL_CMD, tcon))
cifs_reopen_persistent_handles(tcon);
list_del_init(&tcon->rlist);
cifs_put_tcon(tcon);
}
cifs_dbg(FYI, "Reconnecting tcons finished\n");
mutex_unlock(&server->reconnect_mutex);
/* now we can safely release srv struct */
if (tcon_exist)
cifs_put_tcp_session(server, 1);
}
int int
SMB2_echo(struct TCP_Server_Info *server) SMB2_echo(struct TCP_Server_Info *server)
{ {
...@@ -1984,32 +2036,11 @@ SMB2_echo(struct TCP_Server_Info *server) ...@@ -1984,32 +2036,11 @@ SMB2_echo(struct TCP_Server_Info *server)
cifs_dbg(FYI, "In echo request\n"); cifs_dbg(FYI, "In echo request\n");
if (server->tcpStatus == CifsNeedNegotiate) { if (server->tcpStatus == CifsNeedNegotiate) {
struct list_head *tmp, *tmp2; /* No need to send echo on newly established connections */
struct cifs_ses *ses; queue_delayed_work(cifsiod_wq, &server->reconnect, 0);
struct cifs_tcon *tcon; return rc;
cifs_dbg(FYI, "Need negotiate, reconnecting tcons\n");
spin_lock(&cifs_tcp_ses_lock);
list_for_each(tmp, &server->smb_ses_list) {
ses = list_entry(tmp, struct cifs_ses, smb_ses_list);
list_for_each(tmp2, &ses->tcon_list) {
tcon = list_entry(tmp2, struct cifs_tcon,
tcon_list);
/* add check for persistent handle reconnect */
if (tcon && tcon->need_reconnect) {
spin_unlock(&cifs_tcp_ses_lock);
rc = smb2_reconnect(SMB2_ECHO, tcon);
spin_lock(&cifs_tcp_ses_lock);
}
}
}
spin_unlock(&cifs_tcp_ses_lock);
} }
/* if no session, renegotiate failed above */
if (server->tcpStatus == CifsNeedNegotiate)
return -EIO;
rc = small_smb2_init(SMB2_ECHO, NULL, (void **)&req); rc = small_smb2_init(SMB2_ECHO, NULL, (void **)&req);
if (rc) if (rc)
return rc; return rc;
......
...@@ -80,6 +80,8 @@ ...@@ -80,6 +80,8 @@
#define SMB2_SET_INFO cpu_to_le16(SMB2_SET_INFO_HE) #define SMB2_SET_INFO cpu_to_le16(SMB2_SET_INFO_HE)
#define SMB2_OPLOCK_BREAK cpu_to_le16(SMB2_OPLOCK_BREAK_HE) #define SMB2_OPLOCK_BREAK cpu_to_le16(SMB2_OPLOCK_BREAK_HE)
#define SMB2_INTERNAL_CMD cpu_to_le16(0xFFFF)
#define NUMBER_OF_SMB2_COMMANDS 0x0013 #define NUMBER_OF_SMB2_COMMANDS 0x0013
/* BB FIXME - analyze following length BB */ /* BB FIXME - analyze following length BB */
......
...@@ -96,6 +96,7 @@ extern int smb2_open_file(const unsigned int xid, ...@@ -96,6 +96,7 @@ extern int smb2_open_file(const unsigned int xid,
extern int smb2_unlock_range(struct cifsFileInfo *cfile, extern int smb2_unlock_range(struct cifsFileInfo *cfile,
struct file_lock *flock, const unsigned int xid); struct file_lock *flock, const unsigned int xid);
extern int smb2_push_mandatory_locks(struct cifsFileInfo *cfile); extern int smb2_push_mandatory_locks(struct cifsFileInfo *cfile);
extern void smb2_reconnect_server(struct work_struct *work);
/* /*
* SMB2 Worker functions - most of protocol specific implementation details * SMB2 Worker functions - most of protocol specific implementation details
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include <crypto/skcipher.h> #include <linux/crypto.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/fs.h> #include <linux/fs.h>
...@@ -69,46 +69,22 @@ str_to_key(unsigned char *str, unsigned char *key) ...@@ -69,46 +69,22 @@ str_to_key(unsigned char *str, unsigned char *key)
static int static int
smbhash(unsigned char *out, const unsigned char *in, unsigned char *key) smbhash(unsigned char *out, const unsigned char *in, unsigned char *key)
{ {
int rc;
unsigned char key2[8]; unsigned char key2[8];
struct crypto_skcipher *tfm_des; struct crypto_cipher *tfm_des;
struct scatterlist sgin, sgout;
struct skcipher_request *req;
str_to_key(key, key2); str_to_key(key, key2);
tfm_des = crypto_alloc_skcipher("ecb(des)", 0, CRYPTO_ALG_ASYNC); tfm_des = crypto_alloc_cipher("des", 0, 0);
if (IS_ERR(tfm_des)) { if (IS_ERR(tfm_des)) {
rc = PTR_ERR(tfm_des);
cifs_dbg(VFS, "could not allocate des crypto API\n");
goto smbhash_err;
}
req = skcipher_request_alloc(tfm_des, GFP_KERNEL);
if (!req) {
rc = -ENOMEM;
cifs_dbg(VFS, "could not allocate des crypto API\n"); cifs_dbg(VFS, "could not allocate des crypto API\n");
goto smbhash_free_skcipher; return PTR_ERR(tfm_des);
} }
crypto_skcipher_setkey(tfm_des, key2, 8); crypto_cipher_setkey(tfm_des, key2, 8);
crypto_cipher_encrypt_one(tfm_des, out, in);
sg_init_one(&sgin, in, 8); crypto_free_cipher(tfm_des);
sg_init_one(&sgout, out, 8);
skcipher_request_set_callback(req, 0, NULL, NULL); return 0;
skcipher_request_set_crypt(req, &sgin, &sgout, 8, NULL);
rc = crypto_skcipher_encrypt(req);
if (rc)
cifs_dbg(VFS, "could not encrypt crypt key rc: %d\n", rc);
skcipher_request_free(req);
smbhash_free_skcipher:
crypto_free_skcipher(tfm_des);
smbhash_err:
return rc;
} }
static int static int
......
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