summaryrefslogtreecommitdiff
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
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>
-rw-r--r--fs/smb/client/cifsproto.h2
-rw-r--r--fs/smb/client/sess.c48
-rw-r--r--fs/smb/client/smb2ops.c107
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);
}