Twelve cifs/smb3 client fixes (most also for stable)
-----BEGIN PGP SIGNATURE----- iQGzBAABCgAdFiEE6fsu8pdIjtWE/DpLiiy9cAdyT1EFAmQfpFcACgkQiiy9cAdy T1HP5gv9H0VQqA6xoclGmC3vwc1wpn7rg87FKZ9g12MEu22dS6mg2LsOBLwFeHRH mdxGOQv9uHrTNlFnwcKqSVB0hRGAFCKS07bL1iO8vTHTMbY7dCxV3CKgLQh64APb vy01SuGxkCQ8NyRWXY02fDE/n72Jhn7bWIsj/BQavVPyaI6l3BTjd//Za2kAMRAg aWddwC4YpkwZ+FJkldvQNOsRMHwkMHT6bieojyetdjILXZpf2mLzKL7/zU11n6or /y5YdSa+CClOm5STpVinXZ/HuuwiCnFVX9jvHJE2NpD5/quvA8k7G+rn/v1pQ+gn qFNG7Wu0VLWoi4oBHk2bkbb1oQz9hY9pOu+B5xYiKqPWrYlHP42qOrInDc4F1pfp kkSlEjNaLTa4xLlrcQLkIid45/9b0WdOtD/KKJAfeer/yTq0O3+jSGlSODhA0/nh w6OooBNwc6OFPZrLIrKzHDG54oFh7Q30q3hi2NGgLh8EP5uUA9+SD2h31xG1yH0Q lpxAY1rZ =oxu5 -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
6485ac65af
@ -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 @@ skip_rdma:
|
||||
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);
|
||||
|
||||
/* If all channels need reconnect, then tcon needs reconnect */
|
||||
if (!mark_smb_session && !CIFS_ALL_CHANS_NEED_RECONNECT(ses))
|
||||
goto next_session;
|
||||
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)) {
|
||||
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 @@ out_err:
|
||||
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 @@ skip_sess_setup:
|
||||
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 @@ found:
|
||||
*/
|
||||
memcpy(key, ses->smb3signingkey, SMB3_SIGN_KEY_SIZE);
|
||||
spin_unlock(&ses->chan_lock);
|
||||
spin_unlock(&ses->ses_lock);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -119,10 +124,12 @@ found:
|
||||
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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user