diff options
author | Enzo Matsumiya <ematsumiya@suse.de> | 2025-06-22 17:04:10 -0300 |
---|---|---|
committer | Enzo Matsumiya <ematsumiya@suse.de> | 2025-06-22 17:04:10 -0300 |
commit | 5aea01db0af37260e4a0a0d17b6f22f4f1764d7e (patch) | |
tree | 62b2060c58bfd79ef6808103314933be93468f85 | |
parent | d829bbabf99c4bfbdb82a1a8d24d71e76f3dd53b (diff) | |
download | linux-multichannel-fixes-v3.tar.gz linux-multichannel-fixes-v3.tar.bz2 linux-multichannel-fixes-v3.zip |
smb: client: multichannel picking WIPmultichannel-fixes-v3
Signed-off-by: Enzo Matsumiya <ematsumiya@suse.de>
-rw-r--r-- | fs/smb/client/cifsglob.h | 7 | ||||
-rw-r--r-- | fs/smb/client/cifsproto.h | 1 | ||||
-rw-r--r-- | fs/smb/client/connect.c | 7 | ||||
-rw-r--r-- | fs/smb/client/file.c | 4 | ||||
-rw-r--r-- | fs/smb/client/misc.c | 3 | ||||
-rw-r--r-- | fs/smb/client/sess.c | 5 | ||||
-rw-r--r-- | fs/smb/client/smb2pdu.c | 6 | ||||
-rw-r--r-- | fs/smb/client/transport.c | 134 |
8 files changed, 62 insertions, 105 deletions
diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index 24d05d16d70e..436d96484ec1 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -1101,6 +1101,8 @@ release_iface(struct kref *ref) struct cifs_chan { struct list_head head; + size_t used; + size_t same_cpu; unsigned int in_reconnect : 1; /* if session setup in progress for this channel */ struct TCP_Server_Info *server; struct cifs_server_iface *iface; /* interface in use */ @@ -1172,11 +1174,12 @@ struct cifs_ses { ((ses)->chans[(index)].in_reconnect) struct cifs_chan chans[CIFS_MAX_CHANNELS]; /* this only stores channels for management */ - struct list_head chans_lru; /* for cifs_pick_channel() */ - struct list_head chans_lru_io; /* for cifs_pick_io_channel() */ + struct list_head chans_prio; /* for cifs_pick_channel() */ size_t chan_count; size_t chan_max; + size_t fast_picks; + size_t fast_first; size_t slow_picks; size_t chan_changes; diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h index 3fd18ef176ef..ea11f718a69d 100644 --- a/fs/smb/client/cifsproto.h +++ b/fs/smb/client/cifsproto.h @@ -101,7 +101,6 @@ extern int cifs_call_async(struct TCP_Server_Info *server, mid_handle_t *handle, void *cbdata, const int flags, const struct cifs_credits *exist_credits); extern struct TCP_Server_Info *cifs_pick_channel(struct cifs_ses *ses); -extern struct TCP_Server_Info *cifs_pick_io_channel(struct cifs_ses *ses); extern int cifs_send_recv(const unsigned int xid, struct cifs_ses *ses, struct TCP_Server_Info *server, struct smb_rqst *rqst, int *resp_buf_type, diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c index 90c8286ae39d..104e44092ceb 100644 --- a/fs/smb/client/connect.c +++ b/fs/smb/client/connect.c @@ -1751,6 +1751,7 @@ static int cifsd_start(struct TCP_Server_Info *server) if (!IS_ERR(server->tsk)) { cpumask_set_cpu(cifsd_cur_cpu, &cifsd_cpu_load); server->tsk_cpu = cifsd_cur_cpu = cpu; + pr_err("%s: starting on CPU %d\n", __func__, cpu); } else { ret = PTR_ERR(server->tsk); server->tsk = NULL; @@ -2180,10 +2181,12 @@ void __cifs_put_smb_ses(struct cifs_ses *ses) list_del_init(&ses->smb_ses_list); spin_unlock(&cifs_tcp_ses_lock); - pr_err("%s: channel changes %zu, fast %zu, slow %zu\n", __func__, ses->chan_changes, ses->fast_picks, ses->slow_picks); + pr_err("%s: channel changes %zu, fast %zu (first picks %zu), slow %zu\n", __func__, ses->chan_changes, ses->fast_picks, ses->fast_first, ses->slow_picks); /* close any extra channels */ + pr_err("%s: chan 0 used %zu times (recent cpu %zu)\n", __func__, ses->chans[0].used, ses->chans[0].same_cpu); for (i = 1; i < ses->chan_count; i++) { + pr_err("%s: chan %zu used %zu times (recent cpu %zu)\n", __func__, i, ses->chans[i].used, ses->chans[i].same_cpu); list_del_init(&ses->chans[i].head); if (ses->chans[i].iface) { kref_put(&ses->chans[i].iface->refcount, release_iface); @@ -2512,7 +2515,7 @@ retry_old_session: /* add server as first channel */ spin_lock(&ses->chan_lock); ses->chans[0].server = server; - list_add(&ses->chans[0].head, &ses->chans_lru); + list_add(&ses->chans[0].head, &ses->chans_prio); ses->chan_count = 1; ses->chan_max = ctx->multichannel ? ctx->max_channels:1; ses->chans_need_reconnect = 1; diff --git a/fs/smb/client/file.c b/fs/smb/client/file.c index aae2d5ff5176..9835672267d2 100644 --- a/fs/smb/client/file.c +++ b/fs/smb/client/file.c @@ -60,7 +60,7 @@ static void cifs_prepare_write(struct netfs_io_subrequest *subreq) wdata->have_xid = true; } - server = cifs_pick_io_channel(tlink_tcon(open_file->tlink)->ses); + server = cifs_pick_channel(tlink_tcon(open_file->tlink)->ses); wdata->server = server; retry: @@ -157,7 +157,7 @@ static int cifs_prepare_read(struct netfs_io_subrequest *subreq) rdata->have_xid = true; } - server = cifs_pick_io_channel(tlink_tcon(req->cfile->tlink)->ses); + server = cifs_pick_channel(tlink_tcon(req->cfile->tlink)->ses); rdata->server = server; if (cifs_sb->ctx->rsize == 0) { diff --git a/fs/smb/client/misc.c b/fs/smb/client/misc.c index a0962aeef79f..43fd3b95ec91 100644 --- a/fs/smb/client/misc.c +++ b/fs/smb/client/misc.c @@ -74,8 +74,7 @@ sesInfoAlloc(void) ++ret_buf->ses_count; INIT_LIST_HEAD(&ret_buf->smb_ses_list); INIT_LIST_HEAD(&ret_buf->tcon_list); - INIT_LIST_HEAD(&ret_buf->chans_lru); - INIT_LIST_HEAD(&ret_buf->chans_lru_io); + INIT_LIST_HEAD(&ret_buf->chans_prio); mutex_init(&ret_buf->session_mutex); spin_lock_init(&ret_buf->chan_lock); } diff --git a/fs/smb/client/sess.c b/fs/smb/client/sess.c index 68e405bfe9cc..b26ede68e889 100644 --- a/fs/smb/client/sess.c +++ b/fs/smb/client/sess.c @@ -565,10 +565,9 @@ cifs_ses_add_channel(struct cifs_ses *ses, rc = cifs_negotiate_protocol(xid, ses, chan->server); if (!rc) { rc = cifs_setup_session(xid, ses, chan->server, ses->local_nls); - if (!rc) { + if (!rc) /* channel is ready to be used */ - list_add(&chan->head, &ses->chans_lru); - } + list_add_tail(&chan->head, &ses->chans_prio); } mutex_unlock(&ses->session_mutex); diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c index 776e1d3d4c2f..6a31c0de0e69 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -3387,11 +3387,7 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, replay_again: /* reinitialize for possible replay */ flags = 0; - if (opcode == FSCTL_SRV_COPYCHUNK || opcode == FSCTL_SRV_COPYCHUNK_WRITE || - opcode == FSCTL_SET_ZERO_DATA) - server = cifs_pick_io_channel(ses); - else - server = cifs_pick_channel(ses); + server = cifs_pick_channel(ses); if (!server) return -EIO; diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c index f25f075293c3..00560120e0ca 100644 --- a/fs/smb/client/transport.c +++ b/fs/smb/client/transport.c @@ -1006,101 +1006,76 @@ cifs_cancelled_callback(struct mid_q_entry *mid) release_mid(mid); } -enum { - CIFS_CHAN_GOOD, - CIFS_CHAN_SLOW, - CIFS_CHAN_STUCK, -}; +static inline bool chan_is_stuck(struct TCP_Server_Info *chan) +{ + unsigned long echo = chan->echo_interval; + + if (echo) + echo = msecs_to_jiffies(echo * 1000); + else + echo = msecs_to_jiffies(SMB_ECHO_INTERVAL_DEFAULT * 3 * 1000); -static inline int chan_responsiveness(struct cifs_chan *chan, unsigned int in_flight) + return time_is_before_jiffies(chan->lstrp + echo); +} + +static inline bool chan_is_good(struct TCP_Server_Info *chan) { - unsigned long lstrp = chan->server->lstrp; - unsigned long echo = msecs_to_jiffies(chan->server->echo_interval * 1000); - unsigned long now = jiffies; unsigned long threshold; - if (in_flight == 0) - return CIFS_CHAN_GOOD; - threshold = msecs_to_jiffies(clamp_t(unsigned long, slow_rsp_threshold * 1000, 500, 3000)); - if (time_after(lstrp + threshold, now)) - return CIFS_CHAN_GOOD; - if (time_after(lstrp + echo, now)) - return CIFS_CHAN_SLOW; + if (chan->in_flight < 10) + return time_is_after_jiffies(chan->lstrp + threshold); - return CIFS_CHAN_STUCK; + return !chan_is_stuck(chan); } -static struct cifs_chan *fast_pick_channel(struct list_head *list) +static struct cifs_chan *fast_pick_channel(struct cifs_ses *ses) { struct cifs_chan *cur, *next = NULL; - if (likely(!list_is_singular(list))) { - cur = list_first_entry(list, struct cifs_chan, head); -check_next: - if (cur->server->in_flight < 5) { - if (chan_responsiveness(cur, cur->server->in_flight) == CIFS_CHAN_GOOD) - return cur; - - if (!next) { - next = list_next_entry_circular(cur, list, head); - cur = next; - goto check_next; - } - } + cur = list_first_entry(&ses->chans_prio, struct cifs_chan, head); + if (chan_is_good(cur->server)) { + ses->fast_first++; + return cur; } - return NULL; -} + if (likely(!list_is_singular(&ses->chans_prio))) { + next = list_next_entry_circular(cur, &ses->chans_prio, head); + if (chan_is_good(next->server)) + return next; + } -static struct cifs_chan *slow_pick_channel(struct cifs_ses *ses) -{ - int i; + // warm path + if (!chan_is_stuck(cur->server)) + return cur; - for (i = 1; i < ses->chan_count; i++) - if (chan_responsiveness(&ses->chans[i], ses->chans[i].server->in_flight) == CIFS_CHAN_GOOD) - return &ses->chans[i]; + if (next && !chan_is_stuck(next->server)) + return next; - return &ses->chans[0]; + // cold, will call slow pick + return NULL; } -#if 0 -static struct TCP_Server_Info *pick_channel(struct cifs_ses *ses, bool io) +static struct cifs_chan *slow_pick_channel(struct cifs_ses *ses) { struct cifs_chan *chan; + int i; - spin_lock(&ses->chan_lock); - if (ses->chan_count == 1) { - chan = &ses->chans[0]; - goto out; - } + for (i = 0; i < ses->chan_count; i++) { + chan = &ses->chans[i]; - chan = fast_pick_channel(&ses->chans_lru); - if (likely(chan)) { - ses->fast_picks++; - goto out; - } + if (chan_is_good(chan->server) || !chan_is_stuck(ses->chans[0].server)) + return chan; - chan = fast_pick_channel(&ses->chans_lru_io); - if (chan) { - ses->fast_picks++; - goto out; + cifs_dbg(VFS, "%s: channel %d might be stuck (last response %lus ago)\n", + __func__, i, (jiffies - chan->server->lstrp) / HZ); } - ses->slow_picks++; - chan = slow_pick_channel(ses); -out: - if (!io) - list_move_tail(&chan->head, &ses->chans_lru); - else - list_move_tail(&chan->head, &ses->chans_lru_io); - spin_unlock(&ses->chan_lock); - return chan->server; + return &ses->chans[0]; } -#endif -static struct TCP_Server_Info *pick_channel(struct cifs_ses *ses, bool io) +struct TCP_Server_Info *cifs_pick_channel(struct cifs_ses *ses) { struct cifs_chan *chan; @@ -1110,39 +1085,22 @@ static struct TCP_Server_Info *pick_channel(struct cifs_ses *ses, bool io) goto out; } - chan = fast_pick_channel(&ses->chans_lru); + chan = fast_pick_channel(ses); if (likely(chan)) { ses->fast_picks++; goto out; } - chan = fast_pick_channel(&ses->chans_lru_io); - if (chan) { - ses->fast_picks++; - goto out; - } - ses->slow_picks++; chan = slow_pick_channel(ses); out: - if (!io) - list_move_tail(&chan->head, &ses->chans_lru); - else - list_move_tail(&chan->head, &ses->chans_lru_io); + list_move_tail(&chan->head, &ses->chans_prio); + chan->used++; + spin_unlock(&ses->chan_lock); return chan->server; } -struct TCP_Server_Info *cifs_pick_channel(struct cifs_ses *ses) -{ - return pick_channel(ses, false); -} - -struct TCP_Server_Info *cifs_pick_io_channel(struct cifs_ses *ses) -{ - return pick_channel(ses, true); -} - int compound_send_recv(const unsigned int xid, struct cifs_ses *ses, struct TCP_Server_Info *server, |