diff options
author | Enzo Matsumiya <ematsumiya@suse.de> | 2025-05-16 19:07:01 -0300 |
---|---|---|
committer | Enzo Matsumiya <ematsumiya@suse.de> | 2025-05-16 19:07:01 -0300 |
commit | 9832c65abfcf3c22068a1a8a72d71afd775970a2 (patch) | |
tree | edfc6ca64074c670876db60acd0039dcd2b49d75 | |
parent | 5222a1aa127b92acc0381a399e504a88762ebee4 (diff) | |
download | linux-multichannel-fixes.tar.gz linux-multichannel-fixes.tar.bz2 linux-multichannel-fixes.zip |
smb: client: ifaces tmp WIPmultichannel-fixes
Signed-off-by: Enzo Matsumiya <ematsumiya@suse.de>
-rw-r--r-- | fs/smb/client/cifsproto.h | 2 | ||||
-rw-r--r-- | fs/smb/client/sess.c | 48 | ||||
-rw-r--r-- | fs/smb/client/smb2ops.c | 107 |
3 files changed, 66 insertions, 91 deletions
diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h index d5e66391c26f..8ecba11aea78 100644 --- a/fs/smb/client/cifsproto.h +++ b/fs/smb/client/cifsproto.h @@ -618,7 +618,7 @@ enum securityEnum cifs_select_sectype(struct TCP_Server_Info *, int cifs_alloc_hash(const char *name, struct shash_desc **sdesc); void cifs_free_hash(struct shash_desc **sdesc); -int cifs_try_adding_channels(struct cifs_ses *ses); +int cifs_try_adding_channels(struct cifs_ses *ses, struct list_head *ifaces); bool is_ses_using_iface(struct cifs_ses *ses, struct cifs_server_iface *iface); void cifs_ses_mark_for_reconnect(struct cifs_ses *ses); diff --git a/fs/smb/client/sess.c b/fs/smb/client/sess.c index 3ba123d95958..fd68f1d1ebd2 100644 --- a/fs/smb/client/sess.c +++ b/fs/smb/client/sess.c @@ -149,17 +149,23 @@ cifs_chan_is_iface_active(struct cifs_ses *ses, * >0: number of channels remaining to be opened * <0: error from cifs_ses_add_channel() */ -static int try_adding_channels(struct cifs_ses *ses) +static int try_adding_channels(struct cifs_ses *ses, struct list_head *ifaces) { - size_t iface_weight = 0, iface_min_speed = 0; - struct cifs_server_iface *iface = NULL, *niface = NULL; - struct cifs_server_iface *last_iface = NULL; + size_t weight = 0, min_speed = 0; + struct cifs_server_iface *iface = NULL, *niface = NULL, *last; int rc = 0, left = ses->chan_max - ses->chan_count; - last_iface = list_last_entry(&ses->iface_list, struct cifs_server_iface, iface_head); - iface_min_speed = last_iface->speed; + if (list_empty(ifaces)) + return 0; - list_for_each_entry_safe(iface, niface, &ses->iface_list, iface_head) { + 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); + min_speed = min_t(size_t, min_speed, last->speed); + } + + list_for_each_entry_safe(iface, niface, ifaces, iface_head) { rc = 0; /* do not mix rdma and non-rdma interfaces */ @@ -167,40 +173,32 @@ static int try_adding_channels(struct cifs_ses *ses) continue; /* skip ifaces that are unusable */ - if (!iface->is_active || (is_ses_using_iface(ses, iface) && !iface->rss_capable)) + if (!iface->is_active || !iface->rss_capable) continue; 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); - break; - } - /* check if we already allocated enough channels */ - iface_weight = iface->speed / iface_min_speed; - if (iface->weight_fulfilled >= iface_weight) { + weight = iface->speed / min_speed; + if (iface->weight_fulfilled >= weight) { spin_unlock(&ses->iface_lock); continue; } - - /* take ref before unlock */ - kref_get(&iface->refcount); - spin_unlock(&ses->iface_lock); + rc = cifs_ses_add_channel(ses, iface); - spin_lock(&ses->iface_lock); + spin_lock(&ses->iface_lock); if (!rc) { cifs_info("successfully opened new channel on iface:%pIS\n", &iface->sockaddr); + list_move(&iface->iface_head, &ses->iface_list); + ses->iface_count++; + iface->is_active = 1; iface->num_channels++; iface->weight_fulfilled++; left--; } else { cifs_dbg(VFS, "failed to open extra channel on iface:%pIS rc=%d\n", &iface->sockaddr, rc); - kref_put(&iface->refcount, release_iface); iface->weight_fulfilled++; if (rc != -EAGAIN) { spin_unlock(&ses->iface_lock); @@ -213,7 +211,7 @@ static int try_adding_channels(struct cifs_ses *ses) return rc ?: left; } -int cifs_try_adding_channels(struct cifs_ses *ses) +int cifs_try_adding_channels(struct cifs_ses *ses, struct list_head *ifaces) { int rc, retries = 0; @@ -226,7 +224,7 @@ try_again: } spin_unlock(&ses->chan_lock); - rc = try_adding_channels(ses); + rc = try_adding_channels(ses, ifaces); if (!rc) return 0; diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c index d9f8c29c09e9..92d7bdfcca26 100644 --- a/fs/smb/client/smb2ops.c +++ b/fs/smb/client/smb2ops.c @@ -617,9 +617,15 @@ static int iface_cmp(void *unused, const struct list_head *a, const struct list_ return __iface_cmp(ifa, ifb); } +static inline bool ifaces_need_update(unsigned long last_update) +{ + return (last_update && + time_before(jiffies, last_update + (SMB_INTERFACE_POLL_INTERVAL * HZ))); +} + static int -parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf, - size_t buf_len, struct cifs_ses *ses) +parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf, size_t buf_len, + struct cifs_ses *ses, struct list_head *ifaces) { struct network_interface_info_ioctl_rsp *p; struct sockaddr_in *addr4; @@ -637,22 +643,9 @@ 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 mark them as inactive - */ - list_for_each_entry_safe(iface, niface, &ses->iface_list, - iface_head) - iface->is_active = 0; - old_count = ses->iface_count; + /* If we got here, it means we queried the server */ + ses->iface_last_update = jiffies; spin_unlock(&ses->iface_lock); /* @@ -705,33 +698,33 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf, &addr6->sin6_addr); break; default: - cifs_dbg(VFS, - "%s: skipping unsupported socket family\n", - __func__); + cifs_dbg(VFS, "%s: skipping unsupported socket family\n", __func__); goto next_iface; } /* - * The iface_list is assumed to be sorted by speed. + * iface_list is sorted by speed. * Check if the new interface exists in that list. - * NEVER change iface. it could be in use. - * Add a new one instead */ spin_lock(&ses->iface_lock); - list_for_each_entry_safe(iface, niface, &ses->iface_list, - iface_head) { - ret = __iface_cmp(iface, &tmp_iface); - if (!ret) { - iface->is_active = 1; + list_for_each_entry_safe(iface, niface, &ses->iface_list, iface_head) { + if (likely(iface->is_active)) { + ret = __iface_cmp(iface, &tmp_iface); spin_unlock(&ses->iface_lock); - goto next_iface; + if (!ret) + goto next_iface; + continue; } + + /* Take the opportunity and drop inactive ifaces. */ + list_del(&iface->iface_head); + kref_put(&iface->refcount, release_iface); + ses->iface_count--; } spin_unlock(&ses->iface_lock); /* no match. insert the entry in the list */ - info = kmalloc(sizeof(struct cifs_server_iface), - GFP_KERNEL); + info = kmalloc(sizeof(struct cifs_server_iface), GFP_KERNEL); if (!info) { rc = -ENOMEM; goto out; @@ -740,7 +733,6 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf, /* add this new entry to the list */ kref_init(&info->refcount); - info->is_active = 1; cifs_dbg(FYI, "%s: adding iface[%zu]: %pIS\n", __func__, ses->iface_count, &info->sockaddr); @@ -749,8 +741,7 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf, le32_to_cpu(p->Capability)); spin_lock(&ses->iface_lock); - list_add_tail(&info->iface_head, &ses->iface_list); - ses->iface_count++; + list_add_tail(&info->iface_head, ifaces); spin_unlock(&ses->iface_lock); next_iface: nb_iface++; @@ -772,31 +763,13 @@ next_iface: /* Azure rounds the buffer size up 8, to a 16 byte boundary */ if ((bytes_left > 8) || p->Next) cifs_dbg(VFS, "%s: incomplete interface info\n", __func__); - - ses->iface_last_update = jiffies; - out: - /* - * Put inactive entries, then sort the list (only if new ifaces added, to save some cycles). - */ - spin_lock(&ses->iface_lock); - list_for_each_entry_safe(iface, niface, &ses->iface_list, - iface_head) { - if (!iface->is_active) { - list_del(&iface->iface_head); - kref_put(&iface->refcount, release_iface); - ses->iface_count--; - } - } - - if (old_count != ses->iface_count) - list_sort(NULL, &ses->iface_list, iface_cmp); - spin_unlock(&ses->iface_lock); - + list_sort(NULL, ifaces, iface_cmp); return rc; } -static int request_interfaces(const unsigned int xid, struct cifs_tcon *tcon) +static int request_interfaces(const unsigned int xid, struct cifs_tcon *tcon, + struct list_head *ifaces) { int rc; unsigned int ret_data_len = 0; @@ -833,7 +806,7 @@ static int request_interfaces(const unsigned int xid, struct cifs_tcon *tcon) goto out; } - rc = parse_server_interfaces(out_buf, ret_data_len, ses); + rc = parse_server_interfaces(out_buf, ret_data_len, ses, ifaces); if (rc) goto out; @@ -858,6 +831,7 @@ void smb2_query_server_interfaces(struct work_struct *work) struct cifs_ses *ses = tcon->ses; unsigned long delay = SMB_INTERFACE_POLL_INTERVAL * HZ; int xid, rc, resched = 1; + LIST_HEAD(ifaces); if (!tcon->ipc || !ses) return; @@ -870,16 +844,14 @@ void smb2_query_server_interfaces(struct work_struct *work) spin_lock(&tcon->tc_lock); if (tcon->status != TID_GOOD) { spin_unlock(&tcon->tc_lock); - cifs_put_smb_ses(ses); - return; + goto out_free; } spin_unlock(&tcon->tc_lock); spin_lock(&ses->ses_lock); if (ses->ses_status != SES_GOOD) { spin_unlock(&ses->ses_lock); - cifs_put_smb_ses(ses); - return; + goto out_free; } spin_unlock(&ses->ses_lock); @@ -887,12 +859,12 @@ void smb2_query_server_interfaces(struct work_struct *work) * query server network interfaces, in case they change */ xid = get_xid(); - rc = request_interfaces(xid, tcon); + rc = request_interfaces(xid, tcon, &ifaces); free_xid(xid); if (rc) { if (rc == -EOPNOTSUPP) - return; + goto out_free; cifs_dbg(FYI, "%s: failed to query server interfaces: %d\n", __func__, rc); @@ -900,7 +872,7 @@ void smb2_query_server_interfaces(struct work_struct *work) } /* Got interfaces, try to add channels. */ - rc = cifs_try_adding_channels(ses); + rc = cifs_try_adding_channels(ses, &ifaces); if (rc) { /* * Interfaces are available, but failed to negotiate/sess setup on channel(s) -- @@ -911,12 +883,17 @@ void smb2_query_server_interfaces(struct work_struct *work) } out: spin_lock(&ses->ses_lock); - resched = ses->ses_count > 1; + + + + + + resched = ses->ses_count > 1; //// dont use this !!! spin_unlock(&ses->ses_lock); if (resched) queue_delayed_work(cifsiod_wq, &tcon->query_interfaces, delay); - +out_free: cifs_put_smb_ses(ses); } |