Commit 6485ac65 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'smb3-client-fixes-6.3-rc3' of git://git.samba.org/sfrench/cifs-2.6

Pull cifs client fixes from Steve French:
 "Twelve cifs/smb3 client fixes (most also for stable)

   - forced umount fix

   - fix for two perf regressions

   - reconnect fixes

   - small debugging improvements

   - multichannel fixes"

* tag 'smb3-client-fixes-6.3-rc3' of git://git.samba.org/sfrench/cifs-2.6:
  smb3: fix unusable share after force unmount failure
  cifs: fix dentry lookups in directory handle cache
  smb3: lower default deferred close timeout to address perf regression
  cifs: fix missing unload_nls() in smb2_reconnect()
  cifs: avoid race conditions with parallel reconnects
  cifs: append path to open_enter trace event
  cifs: print session id while listing open files
  cifs: dump pending mids for all channels in DebugData
  cifs: empty interface list when server doesn't support query interfaces
  cifs: do not poll server interfaces too regularly
  cifs: lock chan_lock outside match_session
  cifs: check only tcon status on tcon related functions
parents da8e7da1 491eafce
......@@ -99,6 +99,23 @@ path_to_dentry(struct cifs_sb_info *cifs_sb, const char *path)
return dentry;
}
static const char *path_no_prefix(struct cifs_sb_info *cifs_sb,
const char *path)
{
size_t len = 0;
if (!*path)
return path;
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH) &&
cifs_sb->prepath) {
len = strlen(cifs_sb->prepath) + 1;
if (unlikely(len > strlen(path)))
return ERR_PTR(-EINVAL);
}
return path + len;
}
/*
* Open the and cache a directory handle.
* If error then *cfid is not initialized.
......@@ -125,6 +142,7 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
struct dentry *dentry = NULL;
struct cached_fid *cfid;
struct cached_fids *cfids;
const char *npath;
if (tcon == NULL || tcon->cfids == NULL || tcon->nohandlecache ||
is_smb1_server(tcon->ses->server))
......@@ -160,6 +178,20 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
return 0;
}
/*
* Skip any prefix paths in @path as lookup_positive_unlocked() ends up
* calling ->lookup() which already adds those through
* build_path_from_dentry(). Also, do it earlier as we might reconnect
* below when trying to send compounded request and then potentially
* having a different prefix path (e.g. after DFS failover).
*/
npath = path_no_prefix(cifs_sb, path);
if (IS_ERR(npath)) {
rc = PTR_ERR(npath);
kfree(utf16_path);
return rc;
}
/*
* We do not hold the lock for the open because in case
* SMB2_open needs to reconnect.
......@@ -184,6 +216,7 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
oparms = (struct cifs_open_parms) {
.tcon = tcon,
.path = path,
.create_options = cifs_create_options(cifs_sb, CREATE_NOT_FILE),
.desired_access = FILE_READ_ATTRIBUTES,
.disposition = FILE_OPEN,
......@@ -251,10 +284,10 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
(char *)&cfid->file_all_info))
cfid->file_all_info_is_valid = true;
if (!path[0])
if (!npath[0])
dentry = dget(cifs_sb->root);
else {
dentry = path_to_dentry(cifs_sb, path);
dentry = path_to_dentry(cifs_sb, npath);
if (IS_ERR(dentry)) {
rc = -ENOENT;
goto oshr_free;
......
......@@ -176,7 +176,7 @@ static int cifs_debug_files_proc_show(struct seq_file *m, void *v)
seq_puts(m, "# Version:1\n");
seq_puts(m, "# Format:\n");
seq_puts(m, "# <tree id> <persistent fid> <flags> <count> <pid> <uid>");
seq_puts(m, "# <tree id> <ses id> <persistent fid> <flags> <count> <pid> <uid>");
#ifdef CONFIG_CIFS_DEBUG2
seq_printf(m, " <filename> <mid>\n");
#else
......@@ -189,8 +189,9 @@ static int cifs_debug_files_proc_show(struct seq_file *m, void *v)
spin_lock(&tcon->open_file_lock);
list_for_each_entry(cfile, &tcon->openFileList, tlist) {
seq_printf(m,
"0x%x 0x%llx 0x%x %d %d %d %pd",
"0x%x 0x%llx 0x%llx 0x%x %d %d %d %pd",
tcon->tid,
ses->Suid,
cfile->fid.persistent_fid,
cfile->f_flags,
cfile->count,
......@@ -216,6 +217,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
{
struct mid_q_entry *mid_entry;
struct TCP_Server_Info *server;
struct TCP_Server_Info *chan_server;
struct cifs_ses *ses;
struct cifs_tcon *tcon;
struct cifs_server_iface *iface;
......@@ -474,23 +476,35 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
seq_puts(m, "\t\t[CONNECTED]\n");
}
spin_unlock(&ses->iface_lock);
seq_puts(m, "\n\n\tMIDs: ");
spin_lock(&ses->chan_lock);
for (j = 0; j < ses->chan_count; j++) {
chan_server = ses->chans[j].server;
if (!chan_server)
continue;
if (list_empty(&chan_server->pending_mid_q))
continue;
seq_printf(m, "\n\tServer ConnectionId: 0x%llx",
chan_server->conn_id);
spin_lock(&chan_server->mid_lock);
list_for_each_entry(mid_entry, &chan_server->pending_mid_q, qhead) {
seq_printf(m, "\n\t\tState: %d com: %d pid: %d cbdata: %p mid %llu",
mid_entry->mid_state,
le16_to_cpu(mid_entry->command),
mid_entry->pid,
mid_entry->callback_data,
mid_entry->mid);
}
spin_unlock(&chan_server->mid_lock);
}
spin_unlock(&ses->chan_lock);
seq_puts(m, "\n--\n");
}
if (i == 0)
seq_printf(m, "\n\t\t[NONE]");
seq_puts(m, "\n\n\tMIDs: ");
spin_lock(&server->mid_lock);
list_for_each_entry(mid_entry, &server->pending_mid_q, qhead) {
seq_printf(m, "\n\tState: %d com: %d pid:"
" %d cbdata: %p mid %llu\n",
mid_entry->mid_state,
le16_to_cpu(mid_entry->command),
mid_entry->pid,
mid_entry->callback_data,
mid_entry->mid);
}
spin_unlock(&server->mid_lock);
seq_printf(m, "\n--\n");
}
if (c == 0)
seq_printf(m, "\n\t[NONE]");
......
......@@ -731,13 +731,16 @@ static void cifs_umount_begin(struct super_block *sb)
spin_lock(&tcon->tc_lock);
if ((tcon->tc_count > 1) || (tcon->status == TID_EXITING)) {
/* we have other mounts to same share or we have
already tried to force umount this and woken up
already tried to umount this and woken up
all waiting network requests, nothing to do */
spin_unlock(&tcon->tc_lock);
spin_unlock(&cifs_tcp_ses_lock);
return;
} else if (tcon->tc_count == 1)
tcon->status = TID_EXITING;
}
/*
* can not set tcon->status to TID_EXITING yet since we don't know if umount -f will
* fail later (e.g. due to open files). TID_EXITING will be set just before tdis req sent
*/
spin_unlock(&tcon->tc_lock);
spin_unlock(&cifs_tcp_ses_lock);
......
......@@ -86,13 +86,11 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
/*
* only tree disconnect, open, and write, (and ulogoff which does not
* have tcon) are allowed as we start force umount
* have tcon) are allowed as we start umount
*/
spin_lock(&tcon->tc_lock);
if (tcon->status == TID_EXITING) {
if (smb_command != SMB_COM_WRITE_ANDX &&
smb_command != SMB_COM_OPEN_ANDX &&
smb_command != SMB_COM_TREE_DISCONNECT) {
if (smb_command != SMB_COM_TREE_DISCONNECT) {
spin_unlock(&tcon->tc_lock);
cifs_dbg(FYI, "can not send cmd %d while umounting\n",
smb_command);
......
......@@ -212,31 +212,42 @@ cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server,
cifs_chan_update_iface(ses, server);
spin_lock(&ses->chan_lock);
if (!mark_smb_session && cifs_chan_needs_reconnect(ses, server))
goto next_session;
if (!mark_smb_session && cifs_chan_needs_reconnect(ses, server)) {
spin_unlock(&ses->chan_lock);
continue;
}
if (mark_smb_session)
CIFS_SET_ALL_CHANS_NEED_RECONNECT(ses);
else
cifs_chan_set_need_reconnect(ses, server);
cifs_dbg(FYI, "%s: channel connect bitmap: 0x%lx\n",
__func__, ses->chans_need_reconnect);
/* If all channels need reconnect, then tcon needs reconnect */
if (!mark_smb_session && !CIFS_ALL_CHANS_NEED_RECONNECT(ses))
goto next_session;
if (!mark_smb_session && !CIFS_ALL_CHANS_NEED_RECONNECT(ses)) {
spin_unlock(&ses->chan_lock);
continue;
}
spin_unlock(&ses->chan_lock);
spin_lock(&ses->ses_lock);
ses->ses_status = SES_NEED_RECON;
spin_unlock(&ses->ses_lock);
list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
tcon->need_reconnect = true;
spin_lock(&tcon->tc_lock);
tcon->status = TID_NEED_RECON;
spin_unlock(&tcon->tc_lock);
}
if (ses->tcon_ipc) {
ses->tcon_ipc->need_reconnect = true;
spin_lock(&ses->tcon_ipc->tc_lock);
ses->tcon_ipc->status = TID_NEED_RECON;
spin_unlock(&ses->tcon_ipc->tc_lock);
}
next_session:
spin_unlock(&ses->chan_lock);
}
spin_unlock(&cifs_tcp_ses_lock);
}
......@@ -1721,7 +1732,7 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx,
return ERR_PTR(rc);
}
/* this function must be called with ses_lock held */
/* this function must be called with ses_lock and chan_lock held */
static int match_session(struct cifs_ses *ses, struct smb3_fs_context *ctx)
{
if (ctx->sectype != Unspecified &&
......@@ -1732,12 +1743,8 @@ static int match_session(struct cifs_ses *ses, struct smb3_fs_context *ctx)
* If an existing session is limited to less channels than
* requested, it should not be reused
*/
spin_lock(&ses->chan_lock);
if (ses->chan_max < ctx->max_channels) {
spin_unlock(&ses->chan_lock);
if (ses->chan_max < ctx->max_channels)
return 0;
}
spin_unlock(&ses->chan_lock);
switch (ses->sectype) {
case Kerberos:
......@@ -1865,10 +1872,13 @@ cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
spin_unlock(&ses->ses_lock);
continue;
}
spin_lock(&ses->chan_lock);
if (!match_session(ses, ctx)) {
spin_unlock(&ses->chan_lock);
spin_unlock(&ses->ses_lock);
continue;
}
spin_unlock(&ses->chan_lock);
spin_unlock(&ses->ses_lock);
++ses->ses_count;
......@@ -2314,6 +2324,7 @@ cifs_put_tcon(struct cifs_tcon *tcon)
WARN_ON(tcon->tc_count < 0);
list_del_init(&tcon->tcon_list);
tcon->status = TID_EXITING;
spin_unlock(&tcon->tc_lock);
spin_unlock(&cifs_tcp_ses_lock);
......@@ -2693,6 +2704,7 @@ cifs_match_super(struct super_block *sb, void *data)
spin_lock(&tcp_srv->srv_lock);
spin_lock(&ses->ses_lock);
spin_lock(&ses->chan_lock);
spin_lock(&tcon->tc_lock);
if (!match_server(tcp_srv, ctx, dfs_super_cmp) ||
!match_session(ses, ctx) ||
......@@ -2705,6 +2717,7 @@ cifs_match_super(struct super_block *sb, void *data)
rc = compare_mount_options(sb, mnt_data);
out:
spin_unlock(&tcon->tc_lock);
spin_unlock(&ses->chan_lock);
spin_unlock(&ses->ses_lock);
spin_unlock(&tcp_srv->srv_lock);
......@@ -3652,11 +3665,19 @@ cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses,
/* only send once per connect */
spin_lock(&server->srv_lock);
if (!server->ops->need_neg(server) ||
if (server->tcpStatus != CifsGood &&
server->tcpStatus != CifsNew &&
server->tcpStatus != CifsNeedNegotiate) {
spin_unlock(&server->srv_lock);
return -EHOSTDOWN;
}
if (!server->ops->need_neg(server) &&
server->tcpStatus == CifsGood) {
spin_unlock(&server->srv_lock);
return 0;
}
server->tcpStatus = CifsInNegotiate;
spin_unlock(&server->srv_lock);
......@@ -3690,23 +3711,28 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
bool is_binding = false;
spin_lock(&ses->ses_lock);
cifs_dbg(FYI, "%s: channel connect bitmap: 0x%lx\n",
__func__, ses->chans_need_reconnect);
if (ses->ses_status != SES_GOOD &&
ses->ses_status != SES_NEW &&
ses->ses_status != SES_NEED_RECON) {
spin_unlock(&ses->ses_lock);
return 0;
return -EHOSTDOWN;
}
/* only send once per connect */
spin_lock(&ses->chan_lock);
if (CIFS_ALL_CHANS_GOOD(ses) ||
cifs_chan_in_reconnect(ses, server)) {
if (CIFS_ALL_CHANS_GOOD(ses)) {
if (ses->ses_status == SES_NEED_RECON)
ses->ses_status = SES_GOOD;
spin_unlock(&ses->chan_lock);
spin_unlock(&ses->ses_lock);
return 0;
}
is_binding = !CIFS_ALL_CHANS_NEED_RECONNECT(ses);
cifs_chan_set_in_reconnect(ses, server);
is_binding = !CIFS_ALL_CHANS_NEED_RECONNECT(ses);
spin_unlock(&ses->chan_lock);
if (!is_binding)
......@@ -4036,9 +4062,13 @@ int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, const stru
/* only send once per connect */
spin_lock(&tcon->tc_lock);
if (tcon->ses->ses_status != SES_GOOD ||
(tcon->status != TID_NEW &&
tcon->status != TID_NEED_TCON)) {
if (tcon->status != TID_NEW &&
tcon->status != TID_NEED_TCON) {
spin_unlock(&tcon->tc_lock);
return -EHOSTDOWN;
}
if (tcon->status == TID_GOOD) {
spin_unlock(&tcon->tc_lock);
return 0;
}
......
......@@ -502,9 +502,13 @@ int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, const stru
/* only send once per connect */
spin_lock(&tcon->tc_lock);
if (tcon->ses->ses_status != SES_GOOD ||
(tcon->status != TID_NEW &&
tcon->status != TID_NEED_TCON)) {
if (tcon->status != TID_NEW &&
tcon->status != TID_NEED_TCON) {
spin_unlock(&tcon->tc_lock);
return -EHOSTDOWN;
}
if (tcon->status == TID_GOOD) {
spin_unlock(&tcon->tc_lock);
return 0;
}
......
......@@ -1191,7 +1191,7 @@ static int __refresh_tcon(const char *path, struct cifs_tcon *tcon, bool force_r
}
spin_lock(&ipc->tc_lock);
if (ses->ses_status != SES_GOOD || ipc->status != TID_GOOD) {
if (ipc->status != TID_GOOD) {
spin_unlock(&ipc->tc_lock);
cifs_dbg(FYI, "%s: skip cache refresh due to disconnected ipc\n", __func__);
goto out;
......
......@@ -174,13 +174,13 @@ cifs_mark_open_files_invalid(struct cifs_tcon *tcon)
struct list_head *tmp1;
/* only send once per connect */
spin_lock(&tcon->ses->ses_lock);
if ((tcon->ses->ses_status != SES_GOOD) || (tcon->status != TID_NEED_RECON)) {
spin_unlock(&tcon->ses->ses_lock);
spin_lock(&tcon->tc_lock);
if (tcon->status != TID_NEED_RECON) {
spin_unlock(&tcon->tc_lock);
return;
}
tcon->status = TID_IN_FILES_INVALIDATE;
spin_unlock(&tcon->ses->ses_lock);
spin_unlock(&tcon->tc_lock);
/* list all files open on tree connection and mark them invalid */
spin_lock(&tcon->open_file_lock);
......
......@@ -286,5 +286,5 @@ extern void smb3_update_mnt_flags(struct cifs_sb_info *cifs_sb);
* max deferred close timeout (jiffies) - 2^30
*/
#define SMB3_MAX_DCLOSETIMEO (1 << 30)
#define SMB3_DEF_DCLOSETIMEO (5 * HZ) /* Can increase later, other clients use larger */
#define SMB3_DEF_DCLOSETIMEO (1 * HZ) /* even 1 sec enough to help eg open/write/close/open/read */
#endif
......@@ -360,6 +360,7 @@ smb3_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
oparms = (struct cifs_open_parms) {
.tcon = tcon,
.cifs_sb = cifs_sb,
.path = path,
.desired_access = GENERIC_READ,
.create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR),
.disposition = FILE_OPEN,
......@@ -427,6 +428,7 @@ smb3_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
oparms = (struct cifs_open_parms) {
.tcon = tcon,
.cifs_sb = cifs_sb,
.path = path,
.desired_access = GENERIC_WRITE,
.create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR),
.disposition = FILE_CREATE,
......
......@@ -107,6 +107,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
vars->oparms = (struct cifs_open_parms) {
.tcon = tcon,
.path = full_path,
.desired_access = desired_access,
.disposition = create_disposition,
.create_options = cifs_create_options(cifs_sb, create_options),
......
......@@ -530,6 +530,14 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
p = buf;
spin_lock(&ses->iface_lock);
/* do not query too frequently, this time with lock held */
if (ses->iface_last_update &&
time_before(jiffies, ses->iface_last_update +
(SMB_INTERFACE_POLL_INTERVAL * HZ))) {
spin_unlock(&ses->iface_lock);
return 0;
}
/*
* Go through iface_list and do kref_put to remove
* any unused ifaces. ifaces in use will be removed
......@@ -696,6 +704,12 @@ SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon, bool in_
struct network_interface_info_ioctl_rsp *out_buf = NULL;
struct cifs_ses *ses = tcon->ses;
/* do not query too frequently */
if (ses->iface_last_update &&
time_before(jiffies, ses->iface_last_update +
(SMB_INTERFACE_POLL_INTERVAL * HZ)))
return 0;
rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID,
FSCTL_QUERY_NETWORK_INTERFACE_INFO,
NULL /* no data input */, 0 /* no data input */,
......@@ -703,7 +717,7 @@ SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon, bool in_
if (rc == -EOPNOTSUPP) {
cifs_dbg(FYI,
"server does not support query network interfaces\n");
goto out;
ret_data_len = 0;
} else if (rc != 0) {
cifs_tcon_dbg(VFS, "error %d on ioctl to get interface list\n", rc);
goto out;
......@@ -731,6 +745,7 @@ smb3_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon,
oparms = (struct cifs_open_parms) {
.tcon = tcon,
.path = "",
.desired_access = FILE_READ_ATTRIBUTES,
.disposition = FILE_OPEN,
.create_options = cifs_create_options(cifs_sb, 0),
......@@ -774,6 +789,7 @@ smb2_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon,
oparms = (struct cifs_open_parms) {
.tcon = tcon,
.path = "",
.desired_access = FILE_READ_ATTRIBUTES,
.disposition = FILE_OPEN,
.create_options = cifs_create_options(cifs_sb, 0),
......@@ -821,6 +837,7 @@ smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon,
oparms = (struct cifs_open_parms) {
.tcon = tcon,
.path = full_path,
.desired_access = FILE_READ_ATTRIBUTES,
.disposition = FILE_OPEN,
.create_options = cifs_create_options(cifs_sb, 0),
......@@ -1105,6 +1122,7 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
oparms = (struct cifs_open_parms) {
.tcon = tcon,
.path = path,
.desired_access = FILE_WRITE_EA,
.disposition = FILE_OPEN,
.create_options = cifs_create_options(cifs_sb, 0),
......@@ -2096,6 +2114,7 @@ smb3_notify(const unsigned int xid, struct file *pfile,
tcon = cifs_sb_master_tcon(cifs_sb);
oparms = (struct cifs_open_parms) {
.tcon = tcon,
.path = path,
.desired_access = FILE_READ_ATTRIBUTES | FILE_READ_DATA,
.disposition = FILE_OPEN,
.create_options = cifs_create_options(cifs_sb, 0),
......@@ -2168,6 +2187,7 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
oparms = (struct cifs_open_parms) {
.tcon = tcon,
.path = path,
.desired_access = FILE_READ_ATTRIBUTES | FILE_READ_DATA,
.disposition = FILE_OPEN,
.create_options = cifs_create_options(cifs_sb, 0),
......@@ -2500,6 +2520,7 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
oparms = (struct cifs_open_parms) {
.tcon = tcon,
.path = path,
.desired_access = desired_access,
.disposition = FILE_OPEN,
.create_options = cifs_create_options(cifs_sb, 0),
......@@ -2634,6 +2655,7 @@ smb311_queryfs(const unsigned int xid, struct cifs_tcon *tcon,
oparms = (struct cifs_open_parms) {
.tcon = tcon,
.path = "",
.desired_access = FILE_READ_ATTRIBUTES,
.disposition = FILE_OPEN,
.create_options = cifs_create_options(cifs_sb, 0),
......@@ -2928,6 +2950,7 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
oparms = (struct cifs_open_parms) {
.tcon = tcon,
.path = full_path,
.desired_access = FILE_READ_ATTRIBUTES,
.disposition = FILE_OPEN,
.create_options = cifs_create_options(cifs_sb, create_options),
......@@ -3068,6 +3091,7 @@ smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon,
oparms = (struct cifs_open_parms) {
.tcon = tcon,
.path = full_path,
.desired_access = FILE_READ_ATTRIBUTES,
.disposition = FILE_OPEN,
.create_options = cifs_create_options(cifs_sb, OPEN_REPARSE_POINT),
......@@ -3208,6 +3232,7 @@ get_smb2_acl_by_path(struct cifs_sb_info *cifs_sb,
oparms = (struct cifs_open_parms) {
.tcon = tcon,
.path = path,
.desired_access = READ_CONTROL,
.disposition = FILE_OPEN,
/*
......
......@@ -144,7 +144,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
struct TCP_Server_Info *server)
{
int rc = 0;
struct nls_table *nls_codepage;
struct nls_table *nls_codepage = NULL;
struct cifs_ses *ses;
/*
......@@ -165,13 +165,9 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
spin_lock(&tcon->tc_lock);
if (tcon->status == TID_EXITING) {
/*
* only tree disconnect, open, and write,
* (and ulogoff which does not have tcon)
* are allowed as we start force umount.
* only tree disconnect allowed when disconnecting ...
*/
if ((smb2_command != SMB2_WRITE) &&
(smb2_command != SMB2_CREATE) &&
(smb2_command != SMB2_TREE_DISCONNECT)) {
if (smb2_command != SMB2_TREE_DISCONNECT) {
spin_unlock(&tcon->tc_lock);
cifs_dbg(FYI, "can not send cmd %d while umounting\n",
smb2_command);
......@@ -203,6 +199,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
}
spin_unlock(&server->srv_lock);
again:
rc = cifs_wait_for_server_reconnect(server, tcon->retry);
if (rc)
return rc;
......@@ -219,8 +216,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
tcon->ses->chans_need_reconnect,
tcon->need_reconnect);
nls_codepage = load_nls_default();
mutex_lock(&ses->session_mutex);
/*
* Recheck after acquire mutex. If another thread is negotiating
* and the server never sends an answer the socket will be closed
......@@ -229,28 +225,38 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
spin_lock(&server->srv_lock);
if (server->tcpStatus == CifsNeedReconnect) {
spin_unlock(&server->srv_lock);
mutex_unlock(&ses->session_mutex);
if (tcon->retry)
goto again;
rc = -EHOSTDOWN;
goto out;
}
spin_unlock(&server->srv_lock);
nls_codepage = load_nls_default();
/*
* need to prevent multiple threads trying to simultaneously
* reconnect the same SMB session
*/
spin_lock(&ses->ses_lock);
spin_lock(&ses->chan_lock);
if (!cifs_chan_needs_reconnect(ses, server)) {
if (!cifs_chan_needs_reconnect(ses, server) &&
ses->ses_status == SES_GOOD) {
spin_unlock(&ses->chan_lock);
spin_unlock(&ses->ses_lock);
/* this means that we only need to tree connect */
if (tcon->need_reconnect)
goto skip_sess_setup;
mutex_unlock(&ses->session_mutex);
goto out;
}
spin_unlock(&ses->chan_lock);
spin_unlock(&ses->ses_lock);
mutex_lock(&ses->session_mutex);
rc = cifs_negotiate_protocol(0, ses, server);
if (!rc) {
rc = cifs_setup_session(0, ses, server, nls_codepage);
......@@ -266,10 +272,8 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
mutex_unlock(&ses->session_mutex);
goto out;
}
mutex_unlock(&ses->session_mutex);
skip_sess_setup:
mutex_lock(&ses->session_mutex);
if (!tcon->need_reconnect) {
mutex_unlock(&ses->session_mutex);
goto out;
......@@ -284,7 +288,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc);
if (rc) {
/* If sess reconnected but tcon didn't, something strange ... */
pr_warn_once("reconnect tcon failed rc = %d\n", rc);
cifs_dbg(VFS, "reconnect tcon failed rc = %d\n", rc);
goto out;
}
......@@ -1256,9 +1260,9 @@ SMB2_sess_alloc_buffer(struct SMB2_sess_data *sess_data)
if (rc)
return rc;
spin_lock(&ses->chan_lock);
is_binding = !CIFS_ALL_CHANS_NEED_RECONNECT(ses);
spin_unlock(&ses->chan_lock);
spin_lock(&ses->ses_lock);
is_binding = (ses->ses_status == SES_GOOD);
spin_unlock(&ses->ses_lock);
if (is_binding) {
req->hdr.SessionId = cpu_to_le64(ses->Suid);
......@@ -1416,9 +1420,9 @@ SMB2_auth_kerberos(struct SMB2_sess_data *sess_data)
goto out_put_spnego_key;
}
spin_lock(&ses->chan_lock);
is_binding = !CIFS_ALL_CHANS_NEED_RECONNECT(ses);
spin_unlock(&ses->chan_lock);
spin_lock(&ses->ses_lock);
is_binding = (ses->ses_status == SES_GOOD);
spin_unlock(&ses->ses_lock);
/* keep session key if binding */
if (!is_binding) {
......@@ -1542,9 +1546,9 @@ SMB2_sess_auth_rawntlmssp_negotiate(struct SMB2_sess_data *sess_data)
cifs_dbg(FYI, "rawntlmssp session setup challenge phase\n");
spin_lock(&ses->chan_lock);
is_binding = !CIFS_ALL_CHANS_NEED_RECONNECT(ses);
spin_unlock(&ses->chan_lock);
spin_lock(&ses->ses_lock);
is_binding = (ses->ses_status == SES_GOOD);
spin_unlock(&ses->ses_lock);
/* keep existing ses id and flags if binding */
if (!is_binding) {
......@@ -1610,9 +1614,9 @@ SMB2_sess_auth_rawntlmssp_authenticate(struct SMB2_sess_data *sess_data)
rsp = (struct smb2_sess_setup_rsp *)sess_data->iov[0].iov_base;
spin_lock(&ses->chan_lock);
is_binding = !CIFS_ALL_CHANS_NEED_RECONNECT(ses);
spin_unlock(&ses->chan_lock);
spin_lock(&ses->ses_lock);
is_binding = (ses->ses_status == SES_GOOD);
spin_unlock(&ses->ses_lock);
/* keep existing ses id and flags if binding */
if (!is_binding) {
......@@ -2705,7 +2709,7 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
rqst.rq_nvec = n_iov;
/* no need to inc num_remote_opens because we close it just below */
trace_smb3_posix_mkdir_enter(xid, tcon->tid, ses->Suid, CREATE_NOT_FILE,
trace_smb3_posix_mkdir_enter(xid, tcon->tid, ses->Suid, full_path, CREATE_NOT_FILE,
FILE_WRITE_ATTRIBUTES);
/* resource #4: response buffer */
rc = cifs_send_recv(xid, ses, server,
......@@ -2973,7 +2977,7 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
if (rc)
goto creat_exit;
trace_smb3_open_enter(xid, tcon->tid, tcon->ses->Suid,
trace_smb3_open_enter(xid, tcon->tid, tcon->ses->Suid, oparms->path,
oparms->create_options, oparms->desired_access);
rc = cifs_send_recv(xid, ses, server,
......
......@@ -81,6 +81,7 @@ int smb2_get_sign_key(__u64 ses_id, struct TCP_Server_Info *server, u8 *key)
struct cifs_ses *ses = NULL;
int i;
int rc = 0;
bool is_binding = false;
spin_lock(&cifs_tcp_ses_lock);
......@@ -97,9 +98,12 @@ int smb2_get_sign_key(__u64 ses_id, struct TCP_Server_Info *server, u8 *key)
goto out;
found:
spin_lock(&ses->ses_lock);
spin_lock(&ses->chan_lock);
if (cifs_chan_needs_reconnect(ses, server) &&
!CIFS_ALL_CHANS_NEED_RECONNECT(ses)) {
is_binding = (cifs_chan_needs_reconnect(ses, server) &&
ses->ses_status == SES_GOOD);
if (is_binding) {
/*
* If we are in the process of binding a new channel
* to an existing session, use the master connection
......@@ -107,6 +111,7 @@ int smb2_get_sign_key(__u64 ses_id, struct TCP_Server_Info *server, u8 *key)
*/
memcpy(key, ses->smb3signingkey, SMB3_SIGN_KEY_SIZE);
spin_unlock(&ses->chan_lock);
spin_unlock(&ses->ses_lock);
goto out;
}
......@@ -119,10 +124,12 @@ int smb2_get_sign_key(__u64 ses_id, struct TCP_Server_Info *server, u8 *key)
if (chan->server == server) {
memcpy(key, chan->signkey, SMB3_SIGN_KEY_SIZE);
spin_unlock(&ses->chan_lock);
spin_unlock(&ses->ses_lock);
goto out;
}
}
spin_unlock(&ses->chan_lock);
spin_unlock(&ses->ses_lock);
cifs_dbg(VFS,
"%s: Could not find channel signing key for session 0x%llx\n",
......@@ -392,11 +399,15 @@ generate_smb3signingkey(struct cifs_ses *ses,
bool is_binding = false;
int chan_index = 0;
spin_lock(&ses->ses_lock);
spin_lock(&ses->chan_lock);
is_binding = !CIFS_ALL_CHANS_NEED_RECONNECT(ses);
is_binding = (cifs_chan_needs_reconnect(ses, server) &&
ses->ses_status == SES_GOOD);
chan_index = cifs_ses_get_chan_index(ses, server);
/* TODO: introduce ref counting for channels when the can be freed */
spin_unlock(&ses->chan_lock);
spin_unlock(&ses->ses_lock);
/*
* All channels use the same encryption/decryption keys but
......
......@@ -701,13 +701,15 @@ DECLARE_EVENT_CLASS(smb3_open_enter_class,
TP_PROTO(unsigned int xid,
__u32 tid,
__u64 sesid,
const char *full_path,
int create_options,
int desired_access),
TP_ARGS(xid, tid, sesid, create_options, desired_access),
TP_ARGS(xid, tid, sesid, full_path, create_options, desired_access),
TP_STRUCT__entry(
__field(unsigned int, xid)
__field(__u32, tid)
__field(__u64, sesid)
__string(path, full_path)
__field(int, create_options)
__field(int, desired_access)
),
......@@ -715,11 +717,12 @@ DECLARE_EVENT_CLASS(smb3_open_enter_class,
__entry->xid = xid;
__entry->tid = tid;
__entry->sesid = sesid;
__assign_str(path, full_path);
__entry->create_options = create_options;
__entry->desired_access = desired_access;
),
TP_printk("xid=%u sid=0x%llx tid=0x%x cr_opts=0x%x des_access=0x%x",
__entry->xid, __entry->sesid, __entry->tid,
TP_printk("xid=%u sid=0x%llx tid=0x%x path=%s cr_opts=0x%x des_access=0x%x",
__entry->xid, __entry->sesid, __entry->tid, __get_str(path),
__entry->create_options, __entry->desired_access)
)
......@@ -728,9 +731,10 @@ DEFINE_EVENT(smb3_open_enter_class, smb3_##name, \
TP_PROTO(unsigned int xid, \
__u32 tid, \
__u64 sesid, \
const char *full_path, \
int create_options, \
int desired_access), \
TP_ARGS(xid, tid, sesid, create_options, desired_access))
TP_ARGS(xid, tid, sesid, full_path, create_options, desired_access))
DEFINE_SMB3_OPEN_ENTER_EVENT(open_enter);
DEFINE_SMB3_OPEN_ENTER_EVENT(posix_mkdir_enter);
......
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