Skip to content

Commit

Permalink
Merge branch 'for-next' of git://git.samba.org/sfrench/cifs-2.6
Browse files Browse the repository at this point in the history
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
  • Loading branch information
torvalds committed Dec 24, 2016
2 parents 3a77fa8 + 374402a commit 1dd5c6b
Show file tree
Hide file tree
Showing 14 changed files with 177 additions and 90 deletions.
14 changes: 9 additions & 5 deletions fs/cifs/cifsencrypt.c
Original file line number Diff line number Diff line change
Expand Up @@ -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->domainName) {
rc = find_domain_name(ses, nls_cp);
if (rc) {
cifs_dbg(VFS, "error %d finding domain name\n",
rc);
goto setup_ntlmv2_rsp_ret;
if (ses->domainAuto) {
rc = find_domain_name(ses, nls_cp);
if (rc) {
cifs_dbg(VFS, "error %d finding domain name\n",
rc);
goto setup_ntlmv2_rsp_ret;
}
} else {
ses->domainName = kstrdup("", GFP_KERNEL);
}
}
} else {
Expand Down
2 changes: 1 addition & 1 deletion fs/cifs/cifsfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -615,7 +615,7 @@ cifs_get_root(struct smb_vol *vol, struct super_block *sb)
return dget(sb->s_root);

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)
return ERR_PTR(-ENOMEM);

Expand Down
8 changes: 8 additions & 0 deletions fs/cifs/cifsglob.h
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,7 @@ struct smb_vol {
bool persistent:1;
bool nopersistent:1;
bool resilient:1; /* noresilient not required since not fored for CA */
bool domainauto:1;
unsigned int rsize;
unsigned int wsize;
bool sockopt_tcp_nodelay:1;
Expand All @@ -525,6 +526,7 @@ struct smb_vol {
struct sockaddr_storage srcaddr; /* allow binding to a local IP */
struct nls_table *local_nls;
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 */
};

Expand Down Expand Up @@ -646,6 +648,8 @@ struct TCP_Server_Info {
unsigned int max_read;
unsigned int max_write;
__u8 preauth_hash[512];
struct delayed_work reconnect; /* reconnect workqueue job */
struct mutex reconnect_mutex; /* prevent simultaneous reconnects */
#endif /* CONFIG_CIFS_SMB2 */
unsigned long echo_interval;
};
Expand Down Expand Up @@ -827,6 +831,7 @@ struct cifs_ses {
enum securityEnum sectype; /* what security flavor was specified? */
bool sign; /* is signing required? */
bool need_reconnect:1; /* connection reset, uid now invalid */
bool domainAuto:1;
#ifdef CONFIG_CIFS_SMB2
__u16 session_flags;
__u8 smb3signingkey[SMB3_SIGN_KEY_SIZE];
Expand All @@ -849,6 +854,7 @@ cap_unix(struct cifs_ses *ses)
struct cifs_tcon {
struct list_head tcon_list;
int tc_count;
struct list_head rlist; /* reconnect list */
struct list_head openFileList;
spinlock_t open_file_lock; /* protects list above */
struct cifs_ses *ses; /* pointer to session associated with */
Expand Down Expand Up @@ -922,6 +928,7 @@ struct cifs_tcon {
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 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_persistent:1; /* use persistent instead of durable handles */
#ifdef CONFIG_CIFS_SMB2
Expand All @@ -932,6 +939,7 @@ struct cifs_tcon {
__u32 maximal_access;
__u32 vol_serial_number;
__le64 vol_create_time;
__u64 snapshot_time; /* for timewarp tokens - timestamp of snapshot */
__u32 ss_flags; /* sector size flags */
__u32 perf_sector_size; /* best sector size for perf */
__u32 max_chunks;
Expand Down
6 changes: 5 additions & 1 deletion fs/cifs/cifsproto.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ extern void exit_cifs_spnego(void);
extern char *build_path_from_dentry(struct dentry *);
extern char *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);
extern char *build_wildcard_path_from_dentry(struct dentry *direntry);
extern char *cifs_compose_mount_options(const char *sb_mountdata,
const char *fullpath, const struct dfs_info3_param *ref,
Expand Down Expand Up @@ -206,6 +207,9 @@ extern void cifs_add_pending_open_locked(struct cifs_fid *fid,
struct tcon_link *tlink,
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)
extern void cifs_dfs_release_automount_timer(void);
Expand Down
82 changes: 71 additions & 11 deletions fs/cifs/connect.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@
#include "nterr.h"
#include "rfc1002pdu.h"
#include "fscache.h"
#ifdef CONFIG_CIFS_SMB2
#include "smb2proto.h"
#endif

#define CIFS_PORT 445
#define RFC1001_PORT 139
Expand Down Expand Up @@ -89,13 +92,15 @@ enum {
Opt_multiuser, Opt_sloppy, Opt_nosharesock,
Opt_persistent, Opt_nopersistent,
Opt_resilient, Opt_noresilient,
Opt_domainauto,

/* Mount options which take numeric value */
Opt_backupuid, Opt_backupgid, Opt_uid,
Opt_cruid, Opt_gid, Opt_file_mode,
Opt_dirmode, Opt_port,
Opt_rsize, Opt_wsize, Opt_actimeo,
Opt_echo_interval, Opt_max_credits,
Opt_snapshot,

/* Mount options which take string value */
Opt_user, Opt_pass, Opt_ip,
Expand Down Expand Up @@ -177,6 +182,7 @@ static const match_table_t cifs_mount_option_tokens = {
{ Opt_nopersistent, "nopersistenthandles"},
{ Opt_resilient, "resilienthandles"},
{ Opt_noresilient, "noresilienthandles"},
{ Opt_domainauto, "domainauto"},

{ Opt_backupuid, "backupuid=%s" },
{ Opt_backupgid, "backupgid=%s" },
Expand All @@ -192,6 +198,7 @@ static const match_table_t cifs_mount_option_tokens = {
{ Opt_actimeo, "actimeo=%s" },
{ Opt_echo_interval, "echo_interval=%s" },
{ Opt_max_credits, "max_credits=%s" },
{ Opt_snapshot, "snapshot=%s" },

{ Opt_blank_user, "user=" },
{ Opt_blank_user, "username=" },
Expand Down Expand Up @@ -1500,6 +1507,9 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
case Opt_noresilient:
vol->resilient = false; /* already the default */
break;
case Opt_domainauto:
vol->domainauto = true;
break;

/* Numeric Values */
case Opt_backupuid:
Expand Down Expand Up @@ -1602,6 +1612,14 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
}
vol->echo_interval = option;
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:
if (get_option_ul(args, &option) || (option < 20) ||
(option > 60000)) {
Expand Down Expand Up @@ -2101,8 +2119,8 @@ cifs_find_tcp_session(struct smb_vol *vol)
return NULL;
}

static void
cifs_put_tcp_session(struct TCP_Server_Info *server)
void
cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect)
{
struct task_struct *task;

Expand All @@ -2119,6 +2137,19 @@ cifs_put_tcp_session(struct TCP_Server_Info *server)

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);
server->tcpStatus = CifsExiting;
spin_unlock(&GlobalMid_Lock);
Expand Down Expand Up @@ -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->smb_ses_list);
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,
sizeof(tcp_ses->srcaddr));
memcpy(&tcp_ses->dstaddr, &volume_info->dstaddr,
Expand Down Expand Up @@ -2341,7 +2376,7 @@ cifs_put_smb_ses(struct cifs_ses *ses)
spin_unlock(&cifs_tcp_ses_lock);

sesInfoFree(ses);
cifs_put_tcp_session(server);
cifs_put_tcp_session(server, 0);
}

#ifdef CONFIG_KEYS
Expand Down Expand Up @@ -2515,7 +2550,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
mutex_unlock(&ses->session_mutex);

/* existing SMB ses has a server reference already */
cifs_put_tcp_session(server);
cifs_put_tcp_session(server, 0);
free_xid(xid);
return ses;
}
Expand Down Expand Up @@ -2549,6 +2584,8 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
if (!ses->domainName)
goto get_ses_fail;
}
if (volume_info->domainauto)
ses->domainAuto = volume_info->domainauto;
ses->cred_uid = volume_info->cred_uid;
ses->linux_uid = volume_info->linux_uid;

Expand Down Expand Up @@ -2587,16 +2624,22 @@ static int match_tcon(struct cifs_tcon *tcon, const char *unc)
}

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 cifs_tcon *tcon;

spin_lock(&cifs_tcp_ses_lock);
list_for_each(tmp, &ses->tcon_list) {
tcon = list_entry(tmp, struct cifs_tcon, tcon_list);
if (!match_tcon(tcon, unc))
if (!match_tcon(tcon, volume_info->UNC))
continue;

#ifdef CONFIG_CIFS_SMB2
if (tcon->snapshot_time != volume_info->snapshot_time)
continue;
#endif /* CONFIG_CIFS_SMB2 */

++tcon->tc_count;
spin_unlock(&cifs_tcp_ses_lock);
return tcon;
Expand All @@ -2605,7 +2648,7 @@ cifs_find_tcon(struct cifs_ses *ses, const char *unc)
return NULL;
}

static void
void
cifs_put_tcon(struct cifs_tcon *tcon)
{
unsigned int xid;
Expand Down Expand Up @@ -2637,7 +2680,7 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
int rc, xid;
struct cifs_tcon *tcon;

tcon = cifs_find_tcon(ses, volume_info->UNC);
tcon = cifs_find_tcon(ses, volume_info);
if (tcon) {
cifs_dbg(FYI, "Found match on UNC path\n");
/* existing tcon already has a reference */
Expand All @@ -2658,6 +2701,22 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
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;
if (volume_info->password) {
tcon->password = kstrdup(volume_info->password, GFP_KERNEL);
Expand Down Expand Up @@ -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
*/
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) {
rc = -ENOMEM;
goto mount_fail_check;
Expand Down Expand Up @@ -3793,7 +3853,7 @@ cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *volume_info)
else if (ses)
cifs_put_smb_ses(ses);
else
cifs_put_tcp_session(server);
cifs_put_tcp_session(server, 0);
bdi_destroy(&cifs_sb->bdi);
}

Expand Down Expand Up @@ -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);
if (IS_ERR(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;
}

Expand Down
4 changes: 2 additions & 2 deletions fs/cifs/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ renew_parental_timestamps(struct dentry *direntry)

char *
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 dfsplen;
Expand All @@ -59,7 +59,7 @@ cifs_build_path_to_root(struct smb_vol *vol, struct cifs_sb_info *cifs_sb,
return full_path;
}

if (tcon->Flags & SMB_SHARE_IS_IN_DFS)
if (add_treename)
dfsplen = strnlen(tcon->treeName, MAX_TREE_SIZE + 1);
else
dfsplen = 0;
Expand Down
8 changes: 7 additions & 1 deletion fs/cifs/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -777,6 +777,11 @@ cifs_reopen_persistent_handles(struct cifs_tcon *tcon)
struct list_head *tmp1;
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");
INIT_LIST_HEAD(&tmp_list);

Expand All @@ -793,7 +798,8 @@ cifs_reopen_persistent_handles(struct cifs_tcon *tcon)

list_for_each_safe(tmp, tmp1, &tmp_list) {
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);
cifsFileInfo_put(open_file);
}
Expand Down
2 changes: 1 addition & 1 deletion fs/cifs/ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
xid = get_xid();

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) {
case FS_IOC_GETFLAGS:
if (pSMBFile == NULL)
Expand Down
Loading

0 comments on commit 1dd5c6b

Please sign in to comment.