Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion fs/cifs/cifs_debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -609,10 +609,13 @@ static int cifs_stats_proc_show(struct seq_file *m, void *v)
server->fastest_cmd[j],
server->slowest_cmd[j]);
for (j = 0; j < NUMBER_OF_SMB2_COMMANDS; j++)
if (atomic_read(&server->smb2slowcmd[j]))
if (atomic_read(&server->smb2slowcmd[j])) {
spin_lock(&server->srv_lock);
seq_printf(m, " %d slow responses from %s for command %d\n",
atomic_read(&server->smb2slowcmd[j]),
server->hostname, j);
spin_unlock(&server->srv_lock);
}
#endif /* STATS2 */
list_for_each(tmp2, &server->smb_ses_list) {
ses = list_entry(tmp2, struct cifs_ses,
Expand Down
12 changes: 6 additions & 6 deletions fs/cifs/cifs_debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,19 +95,19 @@ do { \

#define cifs_server_dbg_func(ratefunc, type, fmt, ...) \
do { \
const char *sn = ""; \
if (server && server->hostname) \
sn = server->hostname; \
spin_lock(&server->srv_lock); \
if ((type) & FYI && cifsFYI & CIFS_INFO) { \
pr_debug_ ## ratefunc("%s: \\\\%s " fmt, \
__FILE__, sn, ##__VA_ARGS__); \
__FILE__, server->hostname, \
##__VA_ARGS__); \
} else if ((type) & VFS) { \
pr_err_ ## ratefunc("VFS: \\\\%s " fmt, \
sn, ##__VA_ARGS__); \
server->hostname, ##__VA_ARGS__); \
} else if ((type) & NOISY && (NOISY != 0)) { \
pr_debug_ ## ratefunc("\\\\%s " fmt, \
sn, ##__VA_ARGS__); \
server->hostname, ##__VA_ARGS__); \
} \
spin_unlock(&server->srv_lock); \
} while (0)

#define cifs_server_dbg(type, fmt, ...) \
Expand Down
4 changes: 2 additions & 2 deletions fs/cifs/cifs_swn.c
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,7 @@ static int cifs_swn_store_swn_addr(const struct sockaddr_storage *new,
static int cifs_swn_reconnect(struct cifs_tcon *tcon, struct sockaddr_storage *addr)
{
/* Store the reconnect address */
mutex_lock(&tcon->ses->server->srv_mutex);
cifs_server_lock(tcon->ses->server);
if (!cifs_sockaddr_equal(&tcon->ses->server->dstaddr, addr)) {
int ret;

Expand Down Expand Up @@ -520,7 +520,7 @@ static int cifs_swn_reconnect(struct cifs_tcon *tcon, struct sockaddr_storage *a
tcon->ses->server->tcpStatus = CifsNeedReconnect;
spin_unlock(&GlobalMid_Lock);
}
mutex_unlock(&tcon->ses->server->srv_mutex);
cifs_server_unlock(tcon->ses->server);

return 0;
}
Expand Down
8 changes: 4 additions & 4 deletions fs/cifs/cifsencrypt.c
Original file line number Diff line number Diff line change
Expand Up @@ -245,9 +245,9 @@ int cifs_verify_signature(struct smb_rqst *rqst,
cpu_to_le32(expected_sequence_number);
cifs_pdu->Signature.Sequence.Reserved = 0;

mutex_lock(&server->srv_mutex);
cifs_server_lock(server);
rc = cifs_calc_signature(rqst, server, what_we_think_sig_should_be);
mutex_unlock(&server->srv_mutex);
cifs_server_unlock(server);

if (rc)
return rc;
Expand Down Expand Up @@ -716,7 +716,7 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)

memcpy(ses->auth_key.response + baselen, tiblob, tilen);

mutex_lock(&ses->server->srv_mutex);
cifs_server_lock(ses->server);

rc = cifs_alloc_hash("hmac(md5)",
&ses->server->secmech.hmacmd5,
Expand Down Expand Up @@ -768,7 +768,7 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__);

unlock:
mutex_unlock(&ses->server->srv_mutex);
cifs_server_unlock(ses->server);
setup_ntlmv2_rsp_ret:
kfree(tiblob);

Expand Down
21 changes: 20 additions & 1 deletion fs/cifs/cifsglob.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <linux/mm.h>
#include <linux/mempool.h>
#include <linux/workqueue.h>
#include <linux/sched/mm.h>
#include "cifs_fs_sb.h"
#include "cifsacl.h"
#include <crypto/internal/hash.h>
Expand Down Expand Up @@ -579,6 +580,7 @@ inc_rfc1001_len(void *buf, int count)
struct TCP_Server_Info {
struct list_head tcp_ses_list;
struct list_head smb_ses_list;
spinlock_t srv_lock; /* protect anything here that is not protected */
int srv_count; /* reference counter */
/* 15 character server name + 0x20 16th byte indicating type = srv */
char server_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL];
Expand All @@ -603,7 +605,8 @@ struct TCP_Server_Info {
unsigned int in_flight; /* number of requests on the wire to server */
unsigned int max_in_flight; /* max number of requests that were on wire */
spinlock_t req_lock; /* protect the two values above */
struct mutex srv_mutex;
struct mutex _srv_mutex;
unsigned int nofs_flag;
struct task_struct *tsk;
char server_GUID[16];
__u16 sec_mode;
Expand Down Expand Up @@ -695,6 +698,22 @@ struct TCP_Server_Info {
#endif
};

static inline void cifs_server_lock(struct TCP_Server_Info *server)
{
unsigned int nofs_flag = memalloc_nofs_save();

mutex_lock(&server->_srv_mutex);
server->nofs_flag = nofs_flag;
}

static inline void cifs_server_unlock(struct TCP_Server_Info *server)
{
unsigned int nofs_flag = server->nofs_flag;

mutex_unlock(&server->_srv_mutex);
memalloc_nofs_restore(nofs_flag);
}

struct cifs_credits {
unsigned int value;
unsigned int instance;
Expand Down
43 changes: 28 additions & 15 deletions fs/cifs/connect.c
Comment thread
kerneltoast marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,11 @@ static void reconn_set_next_dfs_target(struct TCP_Server_Info *server,

name = dfs_cache_get_tgt_name(*tgt_it);

spin_lock(&server->srv_lock);
kfree(server->hostname);

server->hostname = extract_hostname(name);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may schedule while atomic because extract_hostname() makes an allocation with GFP_KERNEL underneath the srv_lock spin lock.

Follow upstream by calling extract_hostname() before locking srv_lock, using a local variable to store the result.

spin_unlock(&server->srv_lock);
if (IS_ERR(server->hostname)) {
cifs_dbg(FYI,
"%s: failed to extract hostname from target: %ld\n",
Expand Down Expand Up @@ -261,7 +263,7 @@ cifs_reconnect(struct TCP_Server_Info *server)

/* do not want to be sending data on a socket we are freeing */
cifs_dbg(FYI, "%s: tearing down socket\n", __func__);
mutex_lock(&server->srv_mutex);
cifs_server_lock(server);
if (server->ssocket) {
cifs_dbg(FYI, "State: 0x%x Flags: 0x%lx\n",
server->ssocket->state, server->ssocket->flags);
Expand Down Expand Up @@ -291,7 +293,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
mid_entry->mid_flags |= MID_DELETED;
}
spin_unlock(&GlobalMid_Lock);
mutex_unlock(&server->srv_mutex);
cifs_server_unlock(server);

cifs_dbg(FYI, "%s: issuing mid callbacks\n", __func__);
list_for_each_safe(tmp, tmp2, &retry_list) {
Expand All @@ -302,15 +304,15 @@ cifs_reconnect(struct TCP_Server_Info *server)
}

if (cifs_rdma_enabled(server)) {
mutex_lock(&server->srv_mutex);
cifs_server_lock(server);
smbd_destroy(server);
mutex_unlock(&server->srv_mutex);
cifs_server_unlock(server);
}

do {
try_to_freeze();

mutex_lock(&server->srv_mutex);
cifs_server_lock(server);

#ifdef CONFIG_CIFS_SWN_UPCALL
if (server->use_swn_dstaddr) {
Expand Down Expand Up @@ -352,7 +354,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
rc = generic_ip_connect(server);
if (rc) {
cifs_dbg(FYI, "reconnect error %d\n", rc);
mutex_unlock(&server->srv_mutex);
cifs_server_unlock(server);
msleep(3000);
} else {
atomic_inc(&tcpSesReconnectCount);
Expand All @@ -364,7 +366,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
#ifdef CONFIG_CIFS_SWN_UPCALL
server->use_swn_dstaddr = false;
#endif
mutex_unlock(&server->srv_mutex);
cifs_server_unlock(server);
}
} while (server->tcpStatus == CifsNeedReconnect);

Expand Down Expand Up @@ -418,9 +420,7 @@ cifs_echo_request(struct work_struct *work)
goto requeue_echo;

rc = server->ops->echo ? server->ops->echo(server) : -ENOSYS;
if (rc)
cifs_dbg(FYI, "Unable to send echo request to server: %s\n",
server->hostname);
cifs_server_dbg(FYI, "send echo request: rc = %d\n", rc);

#ifdef CONFIG_CIFS_SWN_UPCALL
/* Check witness registrations */
Expand Down Expand Up @@ -1177,6 +1177,8 @@ static int match_server(struct TCP_Server_Info *server, struct smb3_fs_context *
{
struct sockaddr *addr = (struct sockaddr *)&ctx->dstaddr;

lockdep_assert_held(&cifs_tcp_ses_lock);

Comment on lines +1180 to +1181
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this lockdep assert. The upstream commit added lockdep_assert_held(&server->srv_lock); here because srv_lock needed to be held around match_server() in order to protect the hostname access. But you've already protected the hostname access by locking srv_lock directly inside of match_server().

if (ctx->nosharesock)
return 0;

Expand All @@ -1194,8 +1196,12 @@ static int match_server(struct TCP_Server_Info *server, struct smb3_fs_context *
if (!net_eq(cifs_net_ns(server), current->nsproxy->net_ns))
return 0;

if (strcasecmp(server->hostname, ctx->server_hostname))
spin_lock(&server->srv_lock);
if (strcasecmp(server->hostname, ctx->server_hostname)) {
spin_unlock(&server->srv_lock);
return 0;
}
spin_unlock(&server->srv_lock);

if (!match_address(server, addr,
(struct sockaddr *)&ctx->srcaddr))
Expand Down Expand Up @@ -1332,7 +1338,7 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx)
init_waitqueue_head(&tcp_ses->response_q);
init_waitqueue_head(&tcp_ses->request_q);
INIT_LIST_HEAD(&tcp_ses->pending_mid_q);
mutex_init(&tcp_ses->srv_mutex);
mutex_init(&tcp_ses->_srv_mutex);
memcpy(tcp_ses->workstation_RFC1001_name,
ctx->source_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL);
memcpy(tcp_ses->server_RFC1001_name,
Expand All @@ -1343,6 +1349,7 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx)
tcp_ses->lstrp = jiffies;
tcp_ses->compress_algorithm = cpu_to_le16(ctx->compression);
spin_lock_init(&tcp_ses->req_lock);
spin_lock_init(&tcp_ses->srv_lock);
INIT_LIST_HEAD(&tcp_ses->tcp_ses_list);
INIT_LIST_HEAD(&tcp_ses->smb_ses_list);
INIT_DELAYED_WORK(&tcp_ses->echo, cifs_echo_request);
Expand Down Expand Up @@ -1512,7 +1519,9 @@ cifs_setup_ipc(struct cifs_ses *ses, struct smb3_fs_context *ctx)
if (tcon == NULL)
return -ENOMEM;

spin_lock(&server->srv_lock);
scnprintf(unc, sizeof(unc), "\\\\%s\\IPC$", server->hostname);
spin_unlock(&server->srv_lock);

xid = get_xid();
tcon->ses = ses;
Expand Down Expand Up @@ -4081,7 +4090,9 @@ int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, const stru

if (!tcon->dfs_path) {
if (tcon->ipc) {
cifs_server_lock(server);
scnprintf(tree, MAX_TREE_SIZE, "\\\\%s\\IPC$", server->hostname);
cifs_server_unlock(server);
rc = ops->tree_connect(xid, tcon->ses, tree, tcon, nlsc);
} else {
rc = ops->tree_connect(xid, tcon->ses, tcon->treeName, tcon, nlsc);
Expand All @@ -4095,8 +4106,6 @@ int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, const stru
isroot = ref.server_type == DFS_TYPE_ROOT;
free_dfs_info_param(&ref);

extract_unc_hostname(server->hostname, &tcp_host, &tcp_host_len);

for (it = dfs_cache_get_tgt_iterator(&tl); it; it = dfs_cache_get_next_tgt(&tl, it)) {
bool target_match;

Expand All @@ -4114,10 +4123,13 @@ int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, const stru

extract_unc_hostname(share, &dfs_host, &dfs_host_len);

cifs_server_lock(server);
extract_unc_hostname(server->hostname, &tcp_host, &tcp_host_len);
if (dfs_host_len != tcp_host_len
|| strncasecmp(dfs_host, tcp_host, dfs_host_len) != 0) {
cifs_dbg(FYI, "%s: %.*s doesn't match %.*s\n", __func__, (int)dfs_host_len,
dfs_host, (int)tcp_host_len, tcp_host);
cifs_server_unlock(server);

rc = match_target_ip(server, dfs_host, dfs_host_len, &target_match);
if (rc) {
Expand All @@ -4129,7 +4141,8 @@ int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, const stru
cifs_dbg(FYI, "%s: skipping target\n", __func__);
continue;
}
}
} else
cifs_server_unlock(server);

if (tcon->ipc) {
scnprintf(tree, MAX_TREE_SIZE, "\\\\%s\\IPC$", share);
Expand Down
2 changes: 2 additions & 0 deletions fs/cifs/misc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1123,8 +1123,10 @@ int match_target_ip(struct TCP_Server_Info *server,
goto out;
}

spin_lock(&cifs_tcp_ses_lock);
*result = cifs_match_ipaddr((struct sockaddr *)&server->dstaddr,
&tipaddr);
spin_unlock(&cifs_tcp_ses_lock);
Comment thread
kerneltoast marked this conversation as resolved.
cifs_dbg(FYI, "%s: ip addresses match: %u\n", __func__, *result);
rc = 0;

Expand Down
6 changes: 3 additions & 3 deletions fs/cifs/sess.c
Original file line number Diff line number Diff line change
Expand Up @@ -903,14 +903,14 @@ sess_establish_session(struct sess_data *sess_data)
{
struct cifs_ses *ses = sess_data->ses;

mutex_lock(&ses->server->srv_mutex);
cifs_server_lock(ses->server);
if (!ses->server->session_estab) {
if (ses->server->sign) {
ses->server->session_key.response =
kmemdup(ses->auth_key.response,
ses->auth_key.len, GFP_KERNEL);
if (!ses->server->session_key.response) {
mutex_unlock(&ses->server->srv_mutex);
cifs_server_unlock(ses->server);
return -ENOMEM;
}
ses->server->session_key.len =
Expand All @@ -919,7 +919,7 @@ sess_establish_session(struct sess_data *sess_data)
ses->server->sequence_number = 0x2;
ses->server->session_estab = true;
}
mutex_unlock(&ses->server->srv_mutex);
cifs_server_unlock(ses->server);

cifs_dbg(FYI, "CIFS session established successfully\n");
spin_lock(&GlobalMid_Lock);
Expand Down
6 changes: 3 additions & 3 deletions fs/cifs/smb1ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,10 @@ send_nt_cancel(struct TCP_Server_Info *server, struct smb_rqst *rqst,
in_buf->WordCount = 0;
put_bcc(0, in_buf);

mutex_lock(&server->srv_mutex);
cifs_server_lock(server);
rc = cifs_sign_smb(in_buf, server, &mid->sequence_number);
if (rc) {
mutex_unlock(&server->srv_mutex);
cifs_server_unlock(server);
return rc;
}

Expand All @@ -66,7 +66,7 @@ send_nt_cancel(struct TCP_Server_Info *server, struct smb_rqst *rqst,
if (rc < 0)
server->sequence_number--;

mutex_unlock(&server->srv_mutex);
cifs_server_unlock(server);

cifs_dbg(FYI, "issued NT_CANCEL for mid %u, rc = %d\n",
get_mid(in_buf), rc);
Expand Down
Loading
Loading