summaryrefslogtreecommitdiff
path: root/fs/smb/client/smb2ops.c
diff options
context:
space:
mode:
authorEnzo Matsumiya <ematsumiya@suse.de>2025-05-16 19:07:01 -0300
committerEnzo Matsumiya <ematsumiya@suse.de>2025-05-16 19:07:01 -0300
commit9832c65abfcf3c22068a1a8a72d71afd775970a2 (patch)
treeedfc6ca64074c670876db60acd0039dcd2b49d75 /fs/smb/client/smb2ops.c
parent5222a1aa127b92acc0381a399e504a88762ebee4 (diff)
downloadlinux-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>
Diffstat (limited to 'fs/smb/client/smb2ops.c')
-rw-r--r--fs/smb/client/smb2ops.c107
1 files changed, 42 insertions, 65 deletions
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);
}