diff options
| author | Enzo Matsumiya <ematsumiya@suse.de> | 2025-05-21 12:13:43 +0200 |
|---|---|---|
| committer | Enzo Matsumiya <ematsumiya@suse.de> | 2025-05-21 12:41:30 +0200 |
| commit | a87cf769d6b0be1a0e733e33945f3d6ba468240b (patch) | |
| tree | 6304d30df379bc85174347e57eeda025370dc278 | |
| parent | 477c57782070d23869eee0d8bf799547e3ced551 (diff) | |
| download | linux-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.c | 14 | ||||
| -rw-r--r-- | fs/smb/client/cifsglob.h | 32 | ||||
| -rw-r--r-- | fs/smb/client/connect.c | 19 | ||||
| -rw-r--r-- | fs/smb/client/misc.c | 9 | ||||
| -rw-r--r-- | fs/smb/client/sess.c | 50 | ||||
| -rw-r--r-- | fs/smb/client/smb2ops.c | 37 |
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) -- |
