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) ...@@ -99,6 +99,23 @@ path_to_dentry(struct cifs_sb_info *cifs_sb, const char *path)
return dentry; 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. * Open the and cache a directory handle.
* If error then *cfid is not initialized. * If error then *cfid is not initialized.
...@@ -125,6 +142,7 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, ...@@ -125,6 +142,7 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
struct dentry *dentry = NULL; struct dentry *dentry = NULL;
struct cached_fid *cfid; struct cached_fid *cfid;
struct cached_fids *cfids; struct cached_fids *cfids;
const char *npath;
if (tcon == NULL || tcon->cfids == NULL || tcon->nohandlecache || if (tcon == NULL || tcon->cfids == NULL || tcon->nohandlecache ||
is_smb1_server(tcon->ses->server)) is_smb1_server(tcon->ses->server))
...@@ -160,6 +178,20 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, ...@@ -160,6 +178,20 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
return 0; 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 * We do not hold the lock for the open because in case
* SMB2_open needs to reconnect. * SMB2_open needs to reconnect.
...@@ -184,6 +216,7 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, ...@@ -184,6 +216,7 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
oparms = (struct cifs_open_parms) { oparms = (struct cifs_open_parms) {
.tcon = tcon, .tcon = tcon,
.path = path,
.create_options = cifs_create_options(cifs_sb, CREATE_NOT_FILE), .create_options = cifs_create_options(cifs_sb, CREATE_NOT_FILE),
.desired_access = FILE_READ_ATTRIBUTES, .desired_access = FILE_READ_ATTRIBUTES,
.disposition = FILE_OPEN, .disposition = FILE_OPEN,
...@@ -251,10 +284,10 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, ...@@ -251,10 +284,10 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
(char *)&cfid->file_all_info)) (char *)&cfid->file_all_info))
cfid->file_all_info_is_valid = true; cfid->file_all_info_is_valid = true;
if (!path[0]) if (!npath[0])
dentry = dget(cifs_sb->root); dentry = dget(cifs_sb->root);
else { else {
dentry = path_to_dentry(cifs_sb, path); dentry = path_to_dentry(cifs_sb, npath);
if (IS_ERR(dentry)) { if (IS_ERR(dentry)) {
rc = -ENOENT; rc = -ENOENT;
goto oshr_free; goto oshr_free;
......
...@@ -176,7 +176,7 @@ static int cifs_debug_files_proc_show(struct seq_file *m, void *v) ...@@ -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, "# Version:1\n");
seq_puts(m, "# Format:\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 #ifdef CONFIG_CIFS_DEBUG2
seq_printf(m, " <filename> <mid>\n"); seq_printf(m, " <filename> <mid>\n");
#else #else
...@@ -189,8 +189,9 @@ static int cifs_debug_files_proc_show(struct seq_file *m, void *v) ...@@ -189,8 +189,9 @@ static int cifs_debug_files_proc_show(struct seq_file *m, void *v)
spin_lock(&tcon->open_file_lock); spin_lock(&tcon->open_file_lock);
list_for_each_entry(cfile, &tcon->openFileList, tlist) { list_for_each_entry(cfile, &tcon->openFileList, tlist) {
seq_printf(m, 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, tcon->tid,
ses->Suid,
cfile->fid.persistent_fid, cfile->fid.persistent_fid,
cfile->f_flags, cfile->f_flags,
cfile->count, cfile->count,
...@@ -216,6 +217,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) ...@@ -216,6 +217,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
{ {
struct mid_q_entry *mid_entry; struct mid_q_entry *mid_entry;
struct TCP_Server_Info *server; struct TCP_Server_Info *server;
struct TCP_Server_Info *chan_server;
struct cifs_ses *ses; struct cifs_ses *ses;
struct cifs_tcon *tcon; struct cifs_tcon *tcon;
struct cifs_server_iface *iface; struct cifs_server_iface *iface;
...@@ -474,23 +476,35 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) ...@@ -474,23 +476,35 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
seq_puts(m, "\t\t[CONNECTED]\n"); seq_puts(m, "\t\t[CONNECTED]\n");
} }
spin_unlock(&ses->iface_lock); 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) if (i == 0)
seq_printf(m, "\n\t\t[NONE]"); 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) if (c == 0)
seq_printf(m, "\n\t[NONE]"); seq_printf(m, "\n\t[NONE]");
......
...@@ -731,13 +731,16 @@ static void cifs_umount_begin(struct super_block *sb) ...@@ -731,13 +731,16 @@ static void cifs_umount_begin(struct super_block *sb)
spin_lock(&tcon->tc_lock); spin_lock(&tcon->tc_lock);
if ((tcon->tc_count > 1) || (tcon->status == TID_EXITING)) { if ((tcon->tc_count > 1) || (tcon->status == TID_EXITING)) {
/* we have other mounts to same share or we have /* 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 */ all waiting network requests, nothing to do */
spin_unlock(&tcon->tc_lock); spin_unlock(&tcon->tc_lock);
spin_unlock(&cifs_tcp_ses_lock); spin_unlock(&cifs_tcp_ses_lock);
return; 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(&tcon->tc_lock);
spin_unlock(&cifs_tcp_ses_lock); spin_unlock(&cifs_tcp_ses_lock);
......
...@@ -86,13 +86,11 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command) ...@@ -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 * 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); spin_lock(&tcon->tc_lock);
if (tcon->status == TID_EXITING) { if (tcon->status == TID_EXITING) {
if (smb_command != SMB_COM_WRITE_ANDX && if (smb_command != SMB_COM_TREE_DISCONNECT) {
smb_command != SMB_COM_OPEN_ANDX &&
smb_command != SMB_COM_TREE_DISCONNECT) {
spin_unlock(&tcon->tc_lock); spin_unlock(&tcon->tc_lock);
cifs_dbg(FYI, "can not send cmd %d while umounting\n", cifs_dbg(FYI, "can not send cmd %d while umounting\n",
smb_command); smb_command);
......
...@@ -212,31 +212,42 @@ cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server, ...@@ -212,31 +212,42 @@ cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server,
cifs_chan_update_iface(ses, server); cifs_chan_update_iface(ses, server);
spin_lock(&ses->chan_lock); spin_lock(&ses->chan_lock);
if (!mark_smb_session && cifs_chan_needs_reconnect(ses, server)) if (!mark_smb_session && cifs_chan_needs_reconnect(ses, server)) {
goto next_session; spin_unlock(&ses->chan_lock);
continue;
}
if (mark_smb_session) if (mark_smb_session)
CIFS_SET_ALL_CHANS_NEED_RECONNECT(ses); CIFS_SET_ALL_CHANS_NEED_RECONNECT(ses);
else else
cifs_chan_set_need_reconnect(ses, server); 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 all channels need reconnect, then tcon needs reconnect */
if (!mark_smb_session && !CIFS_ALL_CHANS_NEED_RECONNECT(ses)) if (!mark_smb_session && !CIFS_ALL_CHANS_NEED_RECONNECT(ses)) {
goto next_session; spin_unlock(&ses->chan_lock);
continue;
}
spin_unlock(&ses->chan_lock);
spin_lock(&ses->ses_lock);
ses->ses_status = SES_NEED_RECON; ses->ses_status = SES_NEED_RECON;
spin_unlock(&ses->ses_lock);
list_for_each_entry(tcon, &ses->tcon_list, tcon_list) { list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
tcon->need_reconnect = true; tcon->need_reconnect = true;
spin_lock(&tcon->tc_lock);
tcon->status = TID_NEED_RECON; tcon->status = TID_NEED_RECON;
spin_unlock(&tcon->tc_lock);
} }
if (ses->tcon_ipc) { if (ses->tcon_ipc) {
ses->tcon_ipc->need_reconnect = true; ses->tcon_ipc->need_reconnect = true;
spin_lock(&ses->tcon_ipc->tc_lock);
ses->tcon_ipc->status = TID_NEED_RECON; 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); spin_unlock(&cifs_tcp_ses_lock);
} }
...@@ -1721,7 +1732,7 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx, ...@@ -1721,7 +1732,7 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx,
return ERR_PTR(rc); 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) static int match_session(struct cifs_ses *ses, struct smb3_fs_context *ctx)
{ {
if (ctx->sectype != Unspecified && if (ctx->sectype != Unspecified &&
...@@ -1732,12 +1743,8 @@ static int match_session(struct cifs_ses *ses, struct smb3_fs_context *ctx) ...@@ -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 * If an existing session is limited to less channels than
* requested, it should not be reused * requested, it should not be reused
*/ */
spin_lock(&ses->chan_lock); if (ses->chan_max < ctx->max_channels)
if (ses->chan_max < ctx->max_channels) {
spin_unlock(&ses->chan_lock);
return 0; return 0;
}
spin_unlock(&ses->chan_lock);
switch (ses->sectype) { switch (ses->sectype) {
case Kerberos: case Kerberos:
...@@ -1865,10 +1872,13 @@ cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx) ...@@ -1865,10 +1872,13 @@ cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
spin_unlock(&ses->ses_lock); spin_unlock(&ses->ses_lock);
continue; continue;
} }
spin_lock(&ses->chan_lock);
if (!match_session(ses, ctx)) { if (!match_session(ses, ctx)) {
spin_unlock(&ses->chan_lock);
spin_unlock(&ses->ses_lock); spin_unlock(&ses->ses_lock);
continue; continue;
} }
spin_unlock(&ses->chan_lock);
spin_unlock(&ses->ses_lock); spin_unlock(&ses->ses_lock);
++ses->ses_count; ++ses->ses_count;
...@@ -2314,6 +2324,7 @@ cifs_put_tcon(struct cifs_tcon *tcon) ...@@ -2314,6 +2324,7 @@ cifs_put_tcon(struct cifs_tcon *tcon)
WARN_ON(tcon->tc_count < 0); WARN_ON(tcon->tc_count < 0);
list_del_init(&tcon->tcon_list); list_del_init(&tcon->tcon_list);
tcon->status = TID_EXITING;
spin_unlock(&tcon->tc_lock); spin_unlock(&tcon->tc_lock);
spin_unlock(&cifs_tcp_ses_lock); spin_unlock(&cifs_tcp_ses_lock);
...@@ -2693,6 +2704,7 @@ cifs_match_super(struct super_block *sb, void *data) ...@@ -2693,6 +2704,7 @@ cifs_match_super(struct super_block *sb, void *data)
spin_lock(&tcp_srv->srv_lock); spin_lock(&tcp_srv->srv_lock);
spin_lock(&ses->ses_lock); spin_lock(&ses->ses_lock);
spin_lock(&ses->chan_lock);
spin_lock(&tcon->tc_lock); spin_lock(&tcon->tc_lock);
if (!match_server(tcp_srv, ctx, dfs_super_cmp) || if (!match_server(tcp_srv, ctx, dfs_super_cmp) ||
!match_session(ses, ctx) || !match_session(ses, ctx) ||
...@@ -2705,6 +2717,7 @@ cifs_match_super(struct super_block *sb, void *data) ...@@ -2705,6 +2717,7 @@ cifs_match_super(struct super_block *sb, void *data)
rc = compare_mount_options(sb, mnt_data); rc = compare_mount_options(sb, mnt_data);
out: out:
spin_unlock(&tcon->tc_lock); spin_unlock(&tcon->tc_lock);
spin_unlock(&ses->chan_lock);
spin_unlock(&ses->ses_lock); spin_unlock(&ses->ses_lock);
spin_unlock(&tcp_srv->srv_lock); spin_unlock(&tcp_srv->srv_lock);
...@@ -3652,11 +3665,19 @@ cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses, ...@@ -3652,11 +3665,19 @@ cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses,
/* only send once per connect */ /* only send once per connect */
spin_lock(&server->srv_lock); spin_lock(&server->srv_lock);
if (!server->ops->need_neg(server) || if (server->tcpStatus != CifsGood &&
server->tcpStatus != CifsNew &&
server->tcpStatus != CifsNeedNegotiate) { server->tcpStatus != CifsNeedNegotiate) {
spin_unlock(&server->srv_lock);
return -EHOSTDOWN;
}
if (!server->ops->need_neg(server) &&
server->tcpStatus == CifsGood) {
spin_unlock(&server->srv_lock); spin_unlock(&server->srv_lock);
return 0; return 0;
} }
server->tcpStatus = CifsInNegotiate; server->tcpStatus = CifsInNegotiate;
spin_unlock(&server->srv_lock); spin_unlock(&server->srv_lock);
...@@ -3690,23 +3711,28 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses, ...@@ -3690,23 +3711,28 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
bool is_binding = false; bool is_binding = false;
spin_lock(&ses->ses_lock); 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 && if (ses->ses_status != SES_GOOD &&
ses->ses_status != SES_NEW && ses->ses_status != SES_NEW &&
ses->ses_status != SES_NEED_RECON) { ses->ses_status != SES_NEED_RECON) {
spin_unlock(&ses->ses_lock); spin_unlock(&ses->ses_lock);
return 0; return -EHOSTDOWN;
} }
/* only send once per connect */ /* only send once per connect */
spin_lock(&ses->chan_lock); spin_lock(&ses->chan_lock);
if (CIFS_ALL_CHANS_GOOD(ses) || if (CIFS_ALL_CHANS_GOOD(ses)) {
cifs_chan_in_reconnect(ses, server)) { if (ses->ses_status == SES_NEED_RECON)
ses->ses_status = SES_GOOD;
spin_unlock(&ses->chan_lock); spin_unlock(&ses->chan_lock);
spin_unlock(&ses->ses_lock); spin_unlock(&ses->ses_lock);
return 0; return 0;
} }
is_binding = !CIFS_ALL_CHANS_NEED_RECONNECT(ses);
cifs_chan_set_in_reconnect(ses, server); cifs_chan_set_in_reconnect(ses, server);
is_binding = !CIFS_ALL_CHANS_NEED_RECONNECT(ses);
spin_unlock(&ses->chan_lock); spin_unlock(&ses->chan_lock);
if (!is_binding) if (!is_binding)
...@@ -4036,9 +4062,13 @@ int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, const stru ...@@ -4036,9 +4062,13 @@ int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, const stru
/* only send once per connect */ /* only send once per connect */
spin_lock(&tcon->tc_lock); spin_lock(&tcon->tc_lock);
if (tcon->ses->ses_status != SES_GOOD || if (tcon->status != TID_NEW &&
(tcon->status != TID_NEW && tcon->status != TID_NEED_TCON) {
tcon->status != TID_NEED_TCON)) { spin_unlock(&tcon->tc_lock);
return -EHOSTDOWN;
}
if (tcon->status == TID_GOOD) {
spin_unlock(&tcon->tc_lock); spin_unlock(&tcon->tc_lock);
return 0; return 0;
} }
......
...@@ -502,9 +502,13 @@ int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, const stru ...@@ -502,9 +502,13 @@ int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, const stru
/* only send once per connect */ /* only send once per connect */
spin_lock(&tcon->tc_lock); spin_lock(&tcon->tc_lock);
if (tcon->ses->ses_status != SES_GOOD || if (tcon->status != TID_NEW &&
(tcon->status != TID_NEW && tcon->status != TID_NEED_TCON) {
tcon->status != TID_NEED_TCON)) { spin_unlock(&tcon->tc_lock);
return -EHOSTDOWN;
}
if (tcon->status == TID_GOOD) {
spin_unlock(&tcon->tc_lock); spin_unlock(&tcon->tc_lock);
return 0; return 0;
} }
......
...@@ -1191,7 +1191,7 @@ static int __refresh_tcon(const char *path, struct cifs_tcon *tcon, bool force_r ...@@ -1191,7 +1191,7 @@ static int __refresh_tcon(const char *path, struct cifs_tcon *tcon, bool force_r
} }
spin_lock(&ipc->tc_lock); 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); spin_unlock(&ipc->tc_lock);
cifs_dbg(FYI, "%s: skip cache refresh due to disconnected ipc\n", __func__); cifs_dbg(FYI, "%s: skip cache refresh due to disconnected ipc\n", __func__);
goto out; goto out;
......
...@@ -174,13 +174,13 @@ cifs_mark_open_files_invalid(struct cifs_tcon *tcon) ...@@ -174,13 +174,13 @@ cifs_mark_open_files_invalid(struct cifs_tcon *tcon)
struct list_head *tmp1; struct list_head *tmp1;
/* only send once per connect */ /* only send once per connect */
spin_lock(&tcon->ses->ses_lock); spin_lock(&tcon->tc_lock);
if ((tcon->ses->ses_status != SES_GOOD) || (tcon->status != TID_NEED_RECON)) { if (tcon->status != TID_NEED_RECON) {
spin_unlock(&tcon->ses->ses_lock); spin_unlock(&tcon->tc_lock);
return; return;
} }
tcon->status = TID_IN_FILES_INVALIDATE; 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 */ /* list all files open on tree connection and mark them invalid */
spin_lock(&tcon->open_file_lock); spin_lock(&tcon->open_file_lock);
......
...@@ -286,5 +286,5 @@ extern void smb3_update_mnt_flags(struct cifs_sb_info *cifs_sb); ...@@ -286,5 +286,5 @@ extern void smb3_update_mnt_flags(struct cifs_sb_info *cifs_sb);
* max deferred close timeout (jiffies) - 2^30 * max deferred close timeout (jiffies) - 2^30
*/ */
#define SMB3_MAX_DCLOSETIMEO (1 << 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 #endif
...@@ -360,6 +360,7 @@ smb3_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, ...@@ -360,6 +360,7 @@ smb3_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
oparms = (struct cifs_open_parms) { oparms = (struct cifs_open_parms) {
.tcon = tcon, .tcon = tcon,
.cifs_sb = cifs_sb, .cifs_sb = cifs_sb,
.path = path,
.desired_access = GENERIC_READ, .desired_access = GENERIC_READ,
.create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR), .create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR),
.disposition = FILE_OPEN, .disposition = FILE_OPEN,
...@@ -427,6 +428,7 @@ smb3_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, ...@@ -427,6 +428,7 @@ smb3_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
oparms = (struct cifs_open_parms) { oparms = (struct cifs_open_parms) {
.tcon = tcon, .tcon = tcon,
.cifs_sb = cifs_sb, .cifs_sb = cifs_sb,
.path = path,
.desired_access = GENERIC_WRITE, .desired_access = GENERIC_WRITE,
.create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR), .create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR),
.disposition = FILE_CREATE, .disposition = FILE_CREATE,
......
...@@ -107,6 +107,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -107,6 +107,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
vars->oparms = (struct cifs_open_parms) { vars->oparms = (struct cifs_open_parms) {
.tcon = tcon, .tcon = tcon,
.path = full_path,
.desired_access = desired_access, .desired_access = desired_access,
.disposition = create_disposition, .disposition = create_disposition,
.create_options = cifs_create_options(cifs_sb, create_options), .create_options = cifs_create_options(cifs_sb, create_options),
......
...@@ -530,6 +530,14 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf, ...@@ -530,6 +530,14 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
p = buf; p = buf;
spin_lock(&ses->iface_lock); 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 * Go through iface_list and do kref_put to remove
* any unused ifaces. ifaces in use will be removed * 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_ ...@@ -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 network_interface_info_ioctl_rsp *out_buf = NULL;
struct cifs_ses *ses = tcon->ses; 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, rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID,
FSCTL_QUERY_NETWORK_INTERFACE_INFO, FSCTL_QUERY_NETWORK_INTERFACE_INFO,
NULL /* no data input */, 0 /* no data input */, 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_ ...@@ -703,7 +717,7 @@ SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon, bool in_
if (rc == -EOPNOTSUPP) { if (rc == -EOPNOTSUPP) {
cifs_dbg(FYI, cifs_dbg(FYI,
"server does not support query network interfaces\n"); "server does not support query network interfaces\n");
goto out; ret_data_len = 0;
} else if (rc != 0) { } else if (rc != 0) {
cifs_tcon_dbg(VFS, "error %d on ioctl to get interface list\n", rc); cifs_tcon_dbg(VFS, "error %d on ioctl to get interface list\n", rc);
goto out; goto out;
...@@ -731,6 +745,7 @@ smb3_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -731,6 +745,7 @@ smb3_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon,
oparms = (struct cifs_open_parms) { oparms = (struct cifs_open_parms) {
.tcon = tcon, .tcon = tcon,
.path = "",
.desired_access = FILE_READ_ATTRIBUTES, .desired_access = FILE_READ_ATTRIBUTES,
.disposition = FILE_OPEN, .disposition = FILE_OPEN,
.create_options = cifs_create_options(cifs_sb, 0), .create_options = cifs_create_options(cifs_sb, 0),
...@@ -774,6 +789,7 @@ smb2_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -774,6 +789,7 @@ smb2_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon,
oparms = (struct cifs_open_parms) { oparms = (struct cifs_open_parms) {
.tcon = tcon, .tcon = tcon,
.path = "",
.desired_access = FILE_READ_ATTRIBUTES, .desired_access = FILE_READ_ATTRIBUTES,
.disposition = FILE_OPEN, .disposition = FILE_OPEN,
.create_options = cifs_create_options(cifs_sb, 0), .create_options = cifs_create_options(cifs_sb, 0),
...@@ -821,6 +837,7 @@ smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -821,6 +837,7 @@ smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon,
oparms = (struct cifs_open_parms) { oparms = (struct cifs_open_parms) {
.tcon = tcon, .tcon = tcon,
.path = full_path,
.desired_access = FILE_READ_ATTRIBUTES, .desired_access = FILE_READ_ATTRIBUTES,
.disposition = FILE_OPEN, .disposition = FILE_OPEN,
.create_options = cifs_create_options(cifs_sb, 0), .create_options = cifs_create_options(cifs_sb, 0),
...@@ -1105,6 +1122,7 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -1105,6 +1122,7 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
oparms = (struct cifs_open_parms) { oparms = (struct cifs_open_parms) {
.tcon = tcon, .tcon = tcon,
.path = path,
.desired_access = FILE_WRITE_EA, .desired_access = FILE_WRITE_EA,
.disposition = FILE_OPEN, .disposition = FILE_OPEN,
.create_options = cifs_create_options(cifs_sb, 0), .create_options = cifs_create_options(cifs_sb, 0),
...@@ -2096,6 +2114,7 @@ smb3_notify(const unsigned int xid, struct file *pfile, ...@@ -2096,6 +2114,7 @@ smb3_notify(const unsigned int xid, struct file *pfile,
tcon = cifs_sb_master_tcon(cifs_sb); tcon = cifs_sb_master_tcon(cifs_sb);
oparms = (struct cifs_open_parms) { oparms = (struct cifs_open_parms) {
.tcon = tcon, .tcon = tcon,
.path = path,
.desired_access = FILE_READ_ATTRIBUTES | FILE_READ_DATA, .desired_access = FILE_READ_ATTRIBUTES | FILE_READ_DATA,
.disposition = FILE_OPEN, .disposition = FILE_OPEN,
.create_options = cifs_create_options(cifs_sb, 0), .create_options = cifs_create_options(cifs_sb, 0),
...@@ -2168,6 +2187,7 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -2168,6 +2187,7 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
oparms = (struct cifs_open_parms) { oparms = (struct cifs_open_parms) {
.tcon = tcon, .tcon = tcon,
.path = path,
.desired_access = FILE_READ_ATTRIBUTES | FILE_READ_DATA, .desired_access = FILE_READ_ATTRIBUTES | FILE_READ_DATA,
.disposition = FILE_OPEN, .disposition = FILE_OPEN,
.create_options = cifs_create_options(cifs_sb, 0), .create_options = cifs_create_options(cifs_sb, 0),
...@@ -2500,6 +2520,7 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -2500,6 +2520,7 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
oparms = (struct cifs_open_parms) { oparms = (struct cifs_open_parms) {
.tcon = tcon, .tcon = tcon,
.path = path,
.desired_access = desired_access, .desired_access = desired_access,
.disposition = FILE_OPEN, .disposition = FILE_OPEN,
.create_options = cifs_create_options(cifs_sb, 0), .create_options = cifs_create_options(cifs_sb, 0),
...@@ -2634,6 +2655,7 @@ smb311_queryfs(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -2634,6 +2655,7 @@ smb311_queryfs(const unsigned int xid, struct cifs_tcon *tcon,
oparms = (struct cifs_open_parms) { oparms = (struct cifs_open_parms) {
.tcon = tcon, .tcon = tcon,
.path = "",
.desired_access = FILE_READ_ATTRIBUTES, .desired_access = FILE_READ_ATTRIBUTES,
.disposition = FILE_OPEN, .disposition = FILE_OPEN,
.create_options = cifs_create_options(cifs_sb, 0), .create_options = cifs_create_options(cifs_sb, 0),
...@@ -2928,6 +2950,7 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -2928,6 +2950,7 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
oparms = (struct cifs_open_parms) { oparms = (struct cifs_open_parms) {
.tcon = tcon, .tcon = tcon,
.path = full_path,
.desired_access = FILE_READ_ATTRIBUTES, .desired_access = FILE_READ_ATTRIBUTES,
.disposition = FILE_OPEN, .disposition = FILE_OPEN,
.create_options = cifs_create_options(cifs_sb, create_options), .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, ...@@ -3068,6 +3091,7 @@ smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon,
oparms = (struct cifs_open_parms) { oparms = (struct cifs_open_parms) {
.tcon = tcon, .tcon = tcon,
.path = full_path,
.desired_access = FILE_READ_ATTRIBUTES, .desired_access = FILE_READ_ATTRIBUTES,
.disposition = FILE_OPEN, .disposition = FILE_OPEN,
.create_options = cifs_create_options(cifs_sb, OPEN_REPARSE_POINT), .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, ...@@ -3208,6 +3232,7 @@ get_smb2_acl_by_path(struct cifs_sb_info *cifs_sb,
oparms = (struct cifs_open_parms) { oparms = (struct cifs_open_parms) {
.tcon = tcon, .tcon = tcon,
.path = path,
.desired_access = READ_CONTROL, .desired_access = READ_CONTROL,
.disposition = FILE_OPEN, .disposition = FILE_OPEN,
/* /*
......
...@@ -144,7 +144,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon, ...@@ -144,7 +144,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
struct TCP_Server_Info *server) struct TCP_Server_Info *server)
{ {
int rc = 0; int rc = 0;
struct nls_table *nls_codepage; struct nls_table *nls_codepage = NULL;
struct cifs_ses *ses; struct cifs_ses *ses;
/* /*
...@@ -165,13 +165,9 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon, ...@@ -165,13 +165,9 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
spin_lock(&tcon->tc_lock); spin_lock(&tcon->tc_lock);
if (tcon->status == TID_EXITING) { if (tcon->status == TID_EXITING) {
/* /*
* only tree disconnect, open, and write, * only tree disconnect allowed when disconnecting ...
* (and ulogoff which does not have tcon)
* are allowed as we start force umount.
*/ */
if ((smb2_command != SMB2_WRITE) && if (smb2_command != SMB2_TREE_DISCONNECT) {
(smb2_command != SMB2_CREATE) &&
(smb2_command != SMB2_TREE_DISCONNECT)) {
spin_unlock(&tcon->tc_lock); spin_unlock(&tcon->tc_lock);
cifs_dbg(FYI, "can not send cmd %d while umounting\n", cifs_dbg(FYI, "can not send cmd %d while umounting\n",
smb2_command); smb2_command);
...@@ -203,6 +199,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon, ...@@ -203,6 +199,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
} }
spin_unlock(&server->srv_lock); spin_unlock(&server->srv_lock);
again:
rc = cifs_wait_for_server_reconnect(server, tcon->retry); rc = cifs_wait_for_server_reconnect(server, tcon->retry);
if (rc) if (rc)
return rc; return rc;
...@@ -219,8 +216,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon, ...@@ -219,8 +216,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
tcon->ses->chans_need_reconnect, tcon->ses->chans_need_reconnect,
tcon->need_reconnect); tcon->need_reconnect);
nls_codepage = load_nls_default(); mutex_lock(&ses->session_mutex);
/* /*
* Recheck after acquire mutex. If another thread is negotiating * Recheck after acquire mutex. If another thread is negotiating
* and the server never sends an answer the socket will be closed * 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, ...@@ -229,28 +225,38 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
spin_lock(&server->srv_lock); spin_lock(&server->srv_lock);
if (server->tcpStatus == CifsNeedReconnect) { if (server->tcpStatus == CifsNeedReconnect) {
spin_unlock(&server->srv_lock); spin_unlock(&server->srv_lock);
mutex_unlock(&ses->session_mutex);
if (tcon->retry)
goto again;
rc = -EHOSTDOWN; rc = -EHOSTDOWN;
goto out; goto out;
} }
spin_unlock(&server->srv_lock); spin_unlock(&server->srv_lock);
nls_codepage = load_nls_default();
/* /*
* need to prevent multiple threads trying to simultaneously * need to prevent multiple threads trying to simultaneously
* reconnect the same SMB session * reconnect the same SMB session
*/ */
spin_lock(&ses->ses_lock);
spin_lock(&ses->chan_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->chan_lock);
spin_unlock(&ses->ses_lock);
/* this means that we only need to tree connect */ /* this means that we only need to tree connect */
if (tcon->need_reconnect) if (tcon->need_reconnect)
goto skip_sess_setup; goto skip_sess_setup;
mutex_unlock(&ses->session_mutex);
goto out; goto out;
} }
spin_unlock(&ses->chan_lock); spin_unlock(&ses->chan_lock);
spin_unlock(&ses->ses_lock);
mutex_lock(&ses->session_mutex);
rc = cifs_negotiate_protocol(0, ses, server); rc = cifs_negotiate_protocol(0, ses, server);
if (!rc) { if (!rc) {
rc = cifs_setup_session(0, ses, server, nls_codepage); rc = cifs_setup_session(0, ses, server, nls_codepage);
...@@ -266,10 +272,8 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon, ...@@ -266,10 +272,8 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
mutex_unlock(&ses->session_mutex); mutex_unlock(&ses->session_mutex);
goto out; goto out;
} }
mutex_unlock(&ses->session_mutex);
skip_sess_setup: skip_sess_setup:
mutex_lock(&ses->session_mutex);
if (!tcon->need_reconnect) { if (!tcon->need_reconnect) {
mutex_unlock(&ses->session_mutex); mutex_unlock(&ses->session_mutex);
goto out; goto out;
...@@ -284,7 +288,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon, ...@@ -284,7 +288,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc); cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc);
if (rc) { if (rc) {
/* If sess reconnected but tcon didn't, something strange ... */ /* 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; goto out;
} }
...@@ -1256,9 +1260,9 @@ SMB2_sess_alloc_buffer(struct SMB2_sess_data *sess_data) ...@@ -1256,9 +1260,9 @@ SMB2_sess_alloc_buffer(struct SMB2_sess_data *sess_data)
if (rc) if (rc)
return rc; return rc;
spin_lock(&ses->chan_lock); spin_lock(&ses->ses_lock);
is_binding = !CIFS_ALL_CHANS_NEED_RECONNECT(ses); is_binding = (ses->ses_status == SES_GOOD);
spin_unlock(&ses->chan_lock); spin_unlock(&ses->ses_lock);
if (is_binding) { if (is_binding) {
req->hdr.SessionId = cpu_to_le64(ses->Suid); req->hdr.SessionId = cpu_to_le64(ses->Suid);
...@@ -1416,9 +1420,9 @@ SMB2_auth_kerberos(struct SMB2_sess_data *sess_data) ...@@ -1416,9 +1420,9 @@ SMB2_auth_kerberos(struct SMB2_sess_data *sess_data)
goto out_put_spnego_key; goto out_put_spnego_key;
} }
spin_lock(&ses->chan_lock); spin_lock(&ses->ses_lock);
is_binding = !CIFS_ALL_CHANS_NEED_RECONNECT(ses); is_binding = (ses->ses_status == SES_GOOD);
spin_unlock(&ses->chan_lock); spin_unlock(&ses->ses_lock);
/* keep session key if binding */ /* keep session key if binding */
if (!is_binding) { if (!is_binding) {
...@@ -1542,9 +1546,9 @@ SMB2_sess_auth_rawntlmssp_negotiate(struct SMB2_sess_data *sess_data) ...@@ -1542,9 +1546,9 @@ SMB2_sess_auth_rawntlmssp_negotiate(struct SMB2_sess_data *sess_data)
cifs_dbg(FYI, "rawntlmssp session setup challenge phase\n"); cifs_dbg(FYI, "rawntlmssp session setup challenge phase\n");
spin_lock(&ses->chan_lock); spin_lock(&ses->ses_lock);
is_binding = !CIFS_ALL_CHANS_NEED_RECONNECT(ses); is_binding = (ses->ses_status == SES_GOOD);
spin_unlock(&ses->chan_lock); spin_unlock(&ses->ses_lock);
/* keep existing ses id and flags if binding */ /* keep existing ses id and flags if binding */
if (!is_binding) { if (!is_binding) {
...@@ -1610,9 +1614,9 @@ SMB2_sess_auth_rawntlmssp_authenticate(struct SMB2_sess_data *sess_data) ...@@ -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; rsp = (struct smb2_sess_setup_rsp *)sess_data->iov[0].iov_base;
spin_lock(&ses->chan_lock); spin_lock(&ses->ses_lock);
is_binding = !CIFS_ALL_CHANS_NEED_RECONNECT(ses); is_binding = (ses->ses_status == SES_GOOD);
spin_unlock(&ses->chan_lock); spin_unlock(&ses->ses_lock);
/* keep existing ses id and flags if binding */ /* keep existing ses id and flags if binding */
if (!is_binding) { if (!is_binding) {
...@@ -2705,7 +2709,7 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode, ...@@ -2705,7 +2709,7 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
rqst.rq_nvec = n_iov; rqst.rq_nvec = n_iov;
/* no need to inc num_remote_opens because we close it just below */ /* 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); FILE_WRITE_ATTRIBUTES);
/* resource #4: response buffer */ /* resource #4: response buffer */
rc = cifs_send_recv(xid, ses, server, rc = cifs_send_recv(xid, ses, server,
...@@ -2973,7 +2977,7 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, ...@@ -2973,7 +2977,7 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
if (rc) if (rc)
goto creat_exit; 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); oparms->create_options, oparms->desired_access);
rc = cifs_send_recv(xid, ses, server, 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) ...@@ -81,6 +81,7 @@ int smb2_get_sign_key(__u64 ses_id, struct TCP_Server_Info *server, u8 *key)
struct cifs_ses *ses = NULL; struct cifs_ses *ses = NULL;
int i; int i;
int rc = 0; int rc = 0;
bool is_binding = false;
spin_lock(&cifs_tcp_ses_lock); 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) ...@@ -97,9 +98,12 @@ int smb2_get_sign_key(__u64 ses_id, struct TCP_Server_Info *server, u8 *key)
goto out; goto out;
found: found:
spin_lock(&ses->ses_lock);
spin_lock(&ses->chan_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 * If we are in the process of binding a new channel
* to an existing session, use the master connection * 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) ...@@ -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); memcpy(key, ses->smb3signingkey, SMB3_SIGN_KEY_SIZE);
spin_unlock(&ses->chan_lock); spin_unlock(&ses->chan_lock);
spin_unlock(&ses->ses_lock);
goto out; goto out;
} }
...@@ -119,10 +124,12 @@ int smb2_get_sign_key(__u64 ses_id, struct TCP_Server_Info *server, u8 *key) ...@@ -119,10 +124,12 @@ int smb2_get_sign_key(__u64 ses_id, struct TCP_Server_Info *server, u8 *key)
if (chan->server == server) { if (chan->server == server) {
memcpy(key, chan->signkey, SMB3_SIGN_KEY_SIZE); memcpy(key, chan->signkey, SMB3_SIGN_KEY_SIZE);
spin_unlock(&ses->chan_lock); spin_unlock(&ses->chan_lock);
spin_unlock(&ses->ses_lock);
goto out; goto out;
} }
} }
spin_unlock(&ses->chan_lock); spin_unlock(&ses->chan_lock);
spin_unlock(&ses->ses_lock);
cifs_dbg(VFS, cifs_dbg(VFS,
"%s: Could not find channel signing key for session 0x%llx\n", "%s: Could not find channel signing key for session 0x%llx\n",
...@@ -392,11 +399,15 @@ generate_smb3signingkey(struct cifs_ses *ses, ...@@ -392,11 +399,15 @@ generate_smb3signingkey(struct cifs_ses *ses,
bool is_binding = false; bool is_binding = false;
int chan_index = 0; int chan_index = 0;
spin_lock(&ses->ses_lock);
spin_lock(&ses->chan_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); chan_index = cifs_ses_get_chan_index(ses, server);
/* TODO: introduce ref counting for channels when the can be freed */ /* TODO: introduce ref counting for channels when the can be freed */
spin_unlock(&ses->chan_lock); spin_unlock(&ses->chan_lock);
spin_unlock(&ses->ses_lock);
/* /*
* All channels use the same encryption/decryption keys but * All channels use the same encryption/decryption keys but
......
...@@ -701,13 +701,15 @@ DECLARE_EVENT_CLASS(smb3_open_enter_class, ...@@ -701,13 +701,15 @@ DECLARE_EVENT_CLASS(smb3_open_enter_class,
TP_PROTO(unsigned int xid, TP_PROTO(unsigned int xid,
__u32 tid, __u32 tid,
__u64 sesid, __u64 sesid,
const char *full_path,
int create_options, int create_options,
int desired_access), 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( TP_STRUCT__entry(
__field(unsigned int, xid) __field(unsigned int, xid)
__field(__u32, tid) __field(__u32, tid)
__field(__u64, sesid) __field(__u64, sesid)
__string(path, full_path)
__field(int, create_options) __field(int, create_options)
__field(int, desired_access) __field(int, desired_access)
), ),
...@@ -715,11 +717,12 @@ DECLARE_EVENT_CLASS(smb3_open_enter_class, ...@@ -715,11 +717,12 @@ DECLARE_EVENT_CLASS(smb3_open_enter_class,
__entry->xid = xid; __entry->xid = xid;
__entry->tid = tid; __entry->tid = tid;
__entry->sesid = sesid; __entry->sesid = sesid;
__assign_str(path, full_path);
__entry->create_options = create_options; __entry->create_options = create_options;
__entry->desired_access = desired_access; __entry->desired_access = desired_access;
), ),
TP_printk("xid=%u sid=0x%llx tid=0x%x cr_opts=0x%x des_access=0x%x", 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, __entry->xid, __entry->sesid, __entry->tid, __get_str(path),
__entry->create_options, __entry->desired_access) __entry->create_options, __entry->desired_access)
) )
...@@ -728,9 +731,10 @@ DEFINE_EVENT(smb3_open_enter_class, smb3_##name, \ ...@@ -728,9 +731,10 @@ DEFINE_EVENT(smb3_open_enter_class, smb3_##name, \
TP_PROTO(unsigned int xid, \ TP_PROTO(unsigned int xid, \
__u32 tid, \ __u32 tid, \
__u64 sesid, \ __u64 sesid, \
const char *full_path, \
int create_options, \ int create_options, \
int desired_access), \ 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(open_enter);
DEFINE_SMB3_OPEN_ENTER_EVENT(posix_mkdir_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