summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEnzo Matsumiya <ematsumiya@suse.de>2025-05-21 12:13:43 +0200
committerEnzo Matsumiya <ematsumiya@suse.de>2025-05-21 12:41:30 +0200
commita87cf769d6b0be1a0e733e33945f3d6ba468240b (patch)
tree6304d30df379bc85174347e57eeda025370dc278
parent477c57782070d23869eee0d8bf799547e3ced551 (diff)
downloadlinux-a87cf769d6b0be1a0e733e33945f3d6ba468240b.tar.gz
linux-a87cf769d6b0be1a0e733e33945f3d6ba468240b.tar.bz2
linux-a87cf769d6b0be1a0e733e33945f3d6ba468240b.zip
smb: client: move ifaces stuff from ses to server
Received network interfaces received belongs to the server (TCP_Server_Info) struct. Move the list and its accompanying management variables from cifs_ses to TCP_Server_Info and update referencing code. Signed-off-by: Enzo Matsumiya <ematsumiya@suse.de>
-rw-r--r--fs/smb/client/cifs_debug.c14
-rw-r--r--fs/smb/client/cifsglob.h32
-rw-r--r--fs/smb/client/connect.c19
-rw-r--r--fs/smb/client/misc.c9
-rw-r--r--fs/smb/client/sess.c50
-rw-r--r--fs/smb/client/smb2ops.c37
6 files changed, 86 insertions, 75 deletions
diff --git a/fs/smb/client/cifs_debug.c b/fs/smb/client/cifs_debug.c
index e03c890de0a0..0c2acc4e2cbb 100644
--- a/fs/smb/client/cifs_debug.c
+++ b/fs/smb/client/cifs_debug.c
@@ -576,20 +576,20 @@ skip_rdma:
cifs_debug_tcon(m, tcon);
}
- spin_lock(&ses->iface_lock);
- if (ses->iface_count)
+ spin_lock(&server->iface_lock);
+ if (server->iface_count)
seq_printf(m, "\n\n\tServer interfaces: %zu"
"\tLast updated: %lu seconds ago",
- ses->iface_count,
- (jiffies - ses->iface_last_update) / HZ);
+ server->iface_count,
+ (jiffies - server->iface_last_update) / HZ);
- last_iface = list_last_entry(&ses->iface_list,
+ last_iface = list_last_entry(&server->iface_list,
struct cifs_server_iface,
iface_head);
iface_min_speed = last_iface->speed;
j = 0;
- list_for_each_entry(iface, &ses->iface_list,
+ list_for_each_entry(iface, &server->iface_list,
iface_head) {
seq_printf(m, "\n\t%d)", ++j);
cifs_dump_iface(m, iface);
@@ -604,7 +604,7 @@ skip_rdma:
if (is_ses_using_iface(ses, iface))
seq_puts(m, "\t\t[CONNECTED]\n");
}
- spin_unlock(&ses->iface_lock);
+ spin_unlock(&server->iface_lock);
seq_puts(m, "\n\n\tMIDs: ");
spin_lock(&ses->chan_lock);
diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
index 04bc2056cd07..8631f3b9eaf7 100644
--- a/fs/smb/client/cifsglob.h
+++ b/fs/smb/client/cifsglob.h
@@ -839,6 +839,22 @@ struct TCP_Server_Info {
struct TCP_Server_Info *primary_server;
__u16 channel_sequence_num; /* incremented on primary channel on each chan reconnect */
+ /*
+ * Network interfaces available on the server.
+ * Managed only on the primary server instance, DO NOT ACCESS THESE ON CHANNEL SERVERS!
+ *
+ * Other channels can be opened by connecting and binding the session to interfaces from
+ * this list.
+ *
+ * iface_lock should be taken when accessing any of these fields.
+ */
+ spinlock_t iface_lock;
+ /* ========= begin: protected by iface_lock ======== */
+ struct list_head iface_list;
+ size_t iface_count;
+ unsigned long iface_last_update; /* jiffies */
+ /* ========= end: protected by iface_lock ======== */
+
#ifdef CONFIG_CIFS_SWN_UPCALL
bool use_swn_dstaddr;
struct sockaddr_storage swn_dstaddr;
@@ -1133,22 +1149,6 @@ struct cifs_ses {
__u8 smb3decryptionkey[SMB3_ENC_DEC_KEY_SIZE];
__u8 preauth_sha_hash[SMB2_PREAUTH_HASH_SIZE];
- /*
- * Network interfaces available on the server this session is
- * connected to.
- *
- * Other channels can be opened by connecting and binding this
- * session to interfaces from this list.
- *
- * iface_lock should be taken when accessing any of these fields
- */
- spinlock_t iface_lock;
- /* ========= begin: protected by iface_lock ======== */
- struct list_head iface_list;
- size_t iface_count;
- unsigned long iface_last_update; /* jiffies */
- /* ========= end: protected by iface_lock ======== */
-
spinlock_t chan_lock;
/* ========= begin: protected by chan_lock ======== */
#define CIFS_MAX_CHANNELS 16
diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c
index c2e859822744..c2c18aba830a 100644
--- a/fs/smb/client/connect.c
+++ b/fs/smb/client/connect.c
@@ -1661,6 +1661,7 @@ cifs_find_tcp_session(struct smb3_fs_context *ctx)
void
cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect)
{
+ struct cifs_server_iface *iface, *q;
struct task_struct *task;
spin_lock(&cifs_tcp_ses_lock);
@@ -1702,6 +1703,11 @@ cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect)
server->session_key.response = NULL;
server->session_key.len = 0;
+ spin_lock(&server->iface_lock);
+ list_for_each_entry_safe(iface, q, &server->iface_list, iface_head)
+ kref_put(&iface->refcount, release_iface);
+ spin_unlock(&server->iface_lock);
+
task = xchg(&server->tsk, NULL);
if (task) {
cpumask_clear_cpu(server->tsk_cpu, &cifsd_cpu_load);
@@ -1816,6 +1822,8 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx,
spin_unlock(&cifs_tcp_ses_lock);
tcp_ses->primary_server = primary_server;
}
+ spin_lock_init(&tcp_ses->iface_lock);
+ INIT_LIST_HEAD(&tcp_ses->iface_list);
init_waitqueue_head(&tcp_ses->response_q);
init_waitqueue_head(&tcp_ses->request_q);
INIT_LIST_HEAD(&tcp_ses->pending_mid_q);
@@ -4274,16 +4282,17 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
is_binding = !CIFS_ALL_CHANS_NEED_RECONNECT(ses);
spin_unlock(&ses->chan_lock);
- if (!is_binding) {
+ if (!is_binding)
ses->ses_status = SES_IN_SETUP;
-
- /* force iface_list refresh */
- ses->iface_last_update = 0;
- }
spin_unlock(&ses->ses_lock);
/* update ses ip_addr only for primary chan */
if (server == pserver) {
+ spin_lock(&server->srv_lock);
+ /* force iface_list refresh */
+ server->iface_last_update = 0;
+ spin_unlock(&server->srv_lock);
+
if (server->dstaddr.ss_family == AF_INET6)
scnprintf(ses->ip_addr, sizeof(ses->ip_addr), "%pI6", &addr6->sin6_addr);
else
diff --git a/fs/smb/client/misc.c b/fs/smb/client/misc.c
index 7b6ed9b23e71..85a89ccffd54 100644
--- a/fs/smb/client/misc.c
+++ b/fs/smb/client/misc.c
@@ -75,8 +75,6 @@ sesInfoAlloc(void)
INIT_LIST_HEAD(&ret_buf->smb_ses_list);
INIT_LIST_HEAD(&ret_buf->tcon_list);
mutex_init(&ret_buf->session_mutex);
- spin_lock_init(&ret_buf->iface_lock);
- INIT_LIST_HEAD(&ret_buf->iface_list);
spin_lock_init(&ret_buf->chan_lock);
}
return ret_buf;
@@ -85,8 +83,6 @@ sesInfoAlloc(void)
void
sesInfoFree(struct cifs_ses *buf_to_free)
{
- struct cifs_server_iface *iface = NULL, *niface = NULL;
-
if (buf_to_free == NULL) {
cifs_dbg(FYI, "Null buffer passed to sesInfoFree\n");
return;
@@ -103,11 +99,6 @@ sesInfoFree(struct cifs_ses *buf_to_free)
kfree(buf_to_free->domainName);
kfree(buf_to_free->dns_dom);
kfree_sensitive(buf_to_free->auth_key.response);
- spin_lock(&buf_to_free->iface_lock);
- list_for_each_entry_safe(iface, niface, &buf_to_free->iface_list,
- iface_head)
- kref_put(&iface->refcount, release_iface);
- spin_unlock(&buf_to_free->iface_lock);
kfree_sensitive(buf_to_free);
}
diff --git a/fs/smb/client/sess.c b/fs/smb/client/sess.c
index 5cff0fbf1982..af39c819822f 100644
--- a/fs/smb/client/sess.c
+++ b/fs/smb/client/sess.c
@@ -153,6 +153,7 @@ static int try_adding_channels(struct cifs_ses *ses, struct list_head *ifaces)
{
size_t weight = 0, min_speed = 0;
struct cifs_server_iface *iface = NULL, *niface = NULL, *last;
+ struct TCP_Server_Info *pserver = ses->server;
int rc = 0, left = ses->chan_max - ses->chan_count;
if (list_empty(ifaces))
@@ -160,10 +161,13 @@ static int try_adding_channels(struct cifs_ses *ses, struct list_head *ifaces)
last = list_last_entry(ifaces, struct cifs_server_iface, iface_head);
min_speed = last->speed;
- if (!list_empty(&ses->iface_list)) {
- last = list_last_entry(&ses->iface_list, struct cifs_server_iface, iface_head);
+
+ spin_lock(&pserver->iface_lock);
+ if (!list_empty(&pserver->iface_list)) {
+ last = list_last_entry(&pserver->iface_list, struct cifs_server_iface, iface_head);
min_speed = min_t(size_t, min_speed, last->speed);
}
+ spin_unlock(&pserver->iface_lock);
list_for_each_entry_safe(iface, niface, ifaces, iface_head) {
rc = 0;
@@ -184,19 +188,21 @@ static int try_adding_channels(struct cifs_ses *ses, struct list_head *ifaces)
rc = cifs_ses_add_channel(ses, iface);
if (!rc) {
cifs_info("successfully opened new channel on iface:%pIS\n", &iface->sockaddr);
- ses->iface_count++;
iface->is_active = 1;
iface->num_channels++;
iface->weight_fulfilled++;
kref_get(&iface->refcount);
- spin_lock(&ses->iface_lock);
- list_move(&iface->iface_head, &ses->iface_list);
- ses->iface_last_update = jiffies;
- spin_unlock(&ses->iface_lock);
+ spin_lock(&pserver->iface_lock);
+ pserver->iface_count++;
+ list_move(&iface->iface_head, &pserver->iface_list);
+ pserver->iface_last_update = jiffies;
+ spin_unlock(&pserver->iface_lock);
- if (--left == 0)
+ if (left-- == 0) {
+ left = 0;
break;
+ }
} else {
cifs_dbg(VFS, "failed to open extra channel on iface:%pIS rc=%d\n",
&iface->sockaddr, rc);
@@ -244,7 +250,7 @@ void
cifs_disable_secondary_channels(struct cifs_ses *ses)
{
int i, chan_count;
- struct TCP_Server_Info *server;
+ struct TCP_Server_Info *server, *pserver;
struct cifs_server_iface *iface;
spin_lock(&ses->chan_lock);
@@ -252,6 +258,7 @@ cifs_disable_secondary_channels(struct cifs_ses *ses)
if (chan_count == 1)
goto done;
+ pserver = ses->server;
ses->chan_count = 1;
/* for all secondary channels reset the need reconnect bit */
@@ -270,12 +277,12 @@ cifs_disable_secondary_channels(struct cifs_ses *ses)
spin_unlock(&ses->chan_lock);
if (iface) {
- spin_lock(&ses->iface_lock);
+ spin_lock(&pserver->iface_lock);
iface->num_channels--;
if (iface->weight_fulfilled)
iface->weight_fulfilled--;
kref_put(&iface->refcount, release_iface);
- spin_unlock(&ses->iface_lock);
+ spin_unlock(&pserver->iface_lock);
}
if (server) {
@@ -302,9 +309,11 @@ cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server)
struct cifs_server_iface *iface = NULL;
struct cifs_server_iface *old_iface = NULL;
struct cifs_server_iface *last_iface = NULL;
+ struct TCP_Server_Info *pserver;
struct sockaddr_storage ss;
spin_lock(&ses->chan_lock);
+ pserver = ses->server;
chan_index = cifs_ses_get_chan_index(ses, server);
if (chan_index == CIFS_INVAL_CHAN_INDEX) {
spin_unlock(&ses->chan_lock);
@@ -324,19 +333,18 @@ cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server)
ss = server->dstaddr;
spin_unlock(&server->srv_lock);
- spin_lock(&ses->iface_lock);
- if (!ses->iface_count) {
- spin_unlock(&ses->iface_lock);
- cifs_dbg(ONCE, "server %s does not advertise interfaces\n", ses->server->hostname);
+ spin_lock(&pserver->iface_lock);
+ if (!pserver->iface_count) {
+ spin_unlock(&pserver->iface_lock);
+ cifs_dbg(ONCE, "server %s does not advertise interfaces\n", pserver->hostname);
return;
}
- last_iface = list_last_entry(&ses->iface_list, struct cifs_server_iface,
- iface_head);
+ last_iface = list_last_entry(&pserver->iface_list, struct cifs_server_iface, iface_head);
iface_min_speed = last_iface->speed;
/* then look for a new one */
- list_for_each_entry(iface, &ses->iface_list, iface_head) {
+ list_for_each_entry(iface, &pserver->iface_list, iface_head) {
if (!chan_index) {
/* if we're trying to get the updated iface for primary channel */
if (!cifs_match_ipaddr((struct sockaddr *) &ss,
@@ -367,7 +375,7 @@ cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server)
break;
}
- if (list_entry_is_head(iface, &ses->iface_list, iface_head)) {
+ if (list_entry_is_head(iface, &pserver->iface_list, iface_head)) {
iface = NULL;
cifs_dbg(FYI, "unable to find a suitable iface\n");
}
@@ -381,7 +389,7 @@ cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server)
&old_iface->sockaddr);
}
- spin_unlock(&ses->iface_lock);
+ spin_unlock(&pserver->iface_lock);
return;
}
@@ -405,7 +413,7 @@ cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server)
iface->num_channels++;
iface->weight_fulfilled++;
}
- spin_unlock(&ses->iface_lock);
+ spin_unlock(&pserver->iface_lock);
spin_lock(&ses->chan_lock);
chan_index = cifs_ses_get_chan_index(ses, server);
diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
index 25f75146985f..f3efafa23fa4 100644
--- a/fs/smb/client/smb2ops.c
+++ b/fs/smb/client/smb2ops.c
@@ -625,7 +625,7 @@ static inline bool ifaces_need_update(unsigned long last_update)
static int
parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf, size_t buf_len,
- struct cifs_ses *ses, struct list_head *ifaces)
+ struct TCP_Server_Info *pserver, struct list_head *ifaces)
{
struct network_interface_info_ioctl_rsp *p;
struct sockaddr_in *addr4;
@@ -648,7 +648,7 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf, size_t buf
*/
if (bytes_left == 0) {
rc = -EOPNOTSUPP;
- ses->iface_last_update = jiffies;
+ pserver->iface_last_update = jiffies;
goto out;
}
@@ -662,7 +662,7 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf, size_t buf
if (!tmp_iface.rss_capable)
goto next_iface;
- if (tmp_iface.rdma_capable != ses->server->rdma)
+ if (tmp_iface.rdma_capable != pserver->rdma)
goto next_iface;
switch (p->Family) {
@@ -708,12 +708,12 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf, size_t buf
* iface_list is sorted by speed.
* Check if the new interface exists in that list.
*/
- spin_lock(&ses->iface_lock);
- list_for_each_entry_safe(iface, niface, &ses->iface_list, iface_head) {
+ spin_lock(&pserver->iface_lock);
+ list_for_each_entry_safe(iface, niface, &pserver->iface_list, iface_head) {
if (likely(iface->is_active)) {
ret = __iface_cmp(iface, &tmp_iface);
if (!ret) {
- spin_unlock(&ses->iface_lock);
+ spin_unlock(&pserver->iface_lock);
goto next_iface;
}
continue;
@@ -722,9 +722,9 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf, size_t buf
/* Take the opportunity and drop inactive ifaces. */
list_del(&iface->iface_head);
kref_put(&iface->refcount, release_iface);
- ses->iface_count--;
+ pserver->iface_count--;
}
- spin_unlock(&ses->iface_lock);
+ spin_unlock(&pserver->iface_lock);
/* no match. insert the entry in the list */
info = kmalloc(sizeof(struct cifs_server_iface), GFP_KERNEL);
@@ -737,7 +737,7 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf, size_t buf
/* add this new entry to the list */
kref_init(&info->refcount);
- cifs_dbg(FYI, "%s: adding iface[%zu]: %pIS\n", __func__, ses->iface_count,
+ cifs_dbg(FYI, "%s: adding iface[%zu]: %pIS\n", __func__, pserver->iface_count,
&info->sockaddr);
cifs_dbg(FYI, "%s: speed %zu bps\n", __func__, info->speed);
cifs_dbg(FYI, "%s: capabilities 0x%08x\n", __func__,
@@ -778,10 +778,14 @@ static int request_interfaces(const unsigned int xid, struct cifs_tcon *tcon,
struct TCP_Server_Info *pserver;
/* do not query too frequently */
- if (ses->iface_last_update &&
- time_before(jiffies, ses->iface_last_update +
- (SMB_INTERFACE_POLL_INTERVAL * HZ)))
+ pserver = ses->server;
+ spin_lock(&pserver->iface_lock);
+ if (pserver->iface_last_update &&
+ time_before(jiffies, pserver->iface_last_update + (SMB_INTERFACE_POLL_INTERVAL * HZ))) {
+ spin_unlock(&pserver->iface_lock);
return 0;
+ }
+ spin_unlock(&pserver->iface_lock);
rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID,
FSCTL_QUERY_NETWORK_INTERFACE_INFO,
@@ -806,13 +810,12 @@ static int request_interfaces(const unsigned int xid, struct cifs_tcon *tcon,
goto out;
}
- rc = parse_server_interfaces(out_buf, ret_data_len, ses, ifaces);
+ rc = parse_server_interfaces(out_buf, ret_data_len, pserver, ifaces);
if (rc)
goto out;
/* check if iface is still active */
spin_lock(&ses->chan_lock);
- pserver = ses->chans[0].server;
if (pserver && !cifs_chan_is_iface_active(ses, pserver)) {
spin_unlock(&ses->chan_lock);
cifs_chan_update_iface(ses, pserver);
@@ -874,9 +877,9 @@ void smb2_query_server_interfaces(struct work_struct *work)
/* Got interfaces, try to add channels. */
rc = cifs_try_adding_channels(ses, &ifaces);
if (!rc) {
- spin_lock(&ses->iface_lock);
- list_sort(NULL, &ses->iface_list, iface_cmp);
- spin_unlock(&ses->iface_lock);
+ spin_lock(&ses->server->iface_lock);
+ list_sort(NULL, &ses->server->iface_list, iface_cmp);
+ spin_unlock(&ses->server->iface_lock);
} else if (rc == -EAGAIN || rc == -EINPROGRESS) {
/*
* Interfaces are available, but failed to negotiate/sess setup on channel(s) --