cifs: handle cases where a channel is closed
[ Upstream commit 0c51cc6f2cb0108e7d49805f6e089cd85caab279 ] So far, SMB multichannel could only scale up, but not scale down the number of channels. In this series of patch, we now allow the client to deal with the case of multichannel disabled on the server when the share is mounted. With that change, we now need the ability to scale down the channels. This change allows the client to deal with cases of missing channels more gracefully. Signed-off-by: Shyam Prasad N <sprasad@microsoft.com> Signed-off-by: Steve French <stfrench@microsoft.com> Stable-dep-of: 78e727e58e54 ("cifs: update iface_last_update on each query-and-update") Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
38298acb78
commit
c395f798a7
|
@ -138,6 +138,11 @@ cifs_dump_channel(struct seq_file *m, int i, struct cifs_chan *chan)
|
||||||
{
|
{
|
||||||
struct TCP_Server_Info *server = chan->server;
|
struct TCP_Server_Info *server = chan->server;
|
||||||
|
|
||||||
|
if (!server) {
|
||||||
|
seq_printf(m, "\n\n\t\tChannel: %d DISABLED", i+1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
seq_printf(m, "\n\n\t\tChannel: %d ConnectionId: 0x%llx"
|
seq_printf(m, "\n\n\t\tChannel: %d ConnectionId: 0x%llx"
|
||||||
"\n\t\tNumber of credits: %d,%d,%d Dialect 0x%x"
|
"\n\t\tNumber of credits: %d,%d,%d Dialect 0x%x"
|
||||||
"\n\t\tTCP status: %d Instance: %d"
|
"\n\t\tTCP status: %d Instance: %d"
|
||||||
|
|
|
@ -1060,6 +1060,7 @@ struct cifs_ses {
|
||||||
spinlock_t chan_lock;
|
spinlock_t chan_lock;
|
||||||
/* ========= begin: protected by chan_lock ======== */
|
/* ========= begin: protected by chan_lock ======== */
|
||||||
#define CIFS_MAX_CHANNELS 16
|
#define CIFS_MAX_CHANNELS 16
|
||||||
|
#define CIFS_INVAL_CHAN_INDEX (-1)
|
||||||
#define CIFS_ALL_CHANNELS_SET(ses) \
|
#define CIFS_ALL_CHANNELS_SET(ses) \
|
||||||
((1UL << (ses)->chan_count) - 1)
|
((1UL << (ses)->chan_count) - 1)
|
||||||
#define CIFS_ALL_CHANS_GOOD(ses) \
|
#define CIFS_ALL_CHANS_GOOD(ses) \
|
||||||
|
|
|
@ -622,7 +622,7 @@ bool is_server_using_iface(struct TCP_Server_Info *server,
|
||||||
bool is_ses_using_iface(struct cifs_ses *ses, struct cifs_server_iface *iface);
|
bool is_ses_using_iface(struct cifs_ses *ses, struct cifs_server_iface *iface);
|
||||||
void cifs_ses_mark_for_reconnect(struct cifs_ses *ses);
|
void cifs_ses_mark_for_reconnect(struct cifs_ses *ses);
|
||||||
|
|
||||||
unsigned int
|
int
|
||||||
cifs_ses_get_chan_index(struct cifs_ses *ses,
|
cifs_ses_get_chan_index(struct cifs_ses *ses,
|
||||||
struct TCP_Server_Info *server);
|
struct TCP_Server_Info *server);
|
||||||
void
|
void
|
||||||
|
|
|
@ -169,8 +169,12 @@ cifs_signal_cifsd_for_reconnect(struct TCP_Server_Info *server,
|
||||||
list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) {
|
list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) {
|
||||||
spin_lock(&ses->chan_lock);
|
spin_lock(&ses->chan_lock);
|
||||||
for (i = 0; i < ses->chan_count; i++) {
|
for (i = 0; i < ses->chan_count; i++) {
|
||||||
|
if (!ses->chans[i].server)
|
||||||
|
continue;
|
||||||
|
|
||||||
spin_lock(&ses->chans[i].server->srv_lock);
|
spin_lock(&ses->chans[i].server->srv_lock);
|
||||||
ses->chans[i].server->tcpStatus = CifsNeedReconnect;
|
if (ses->chans[i].server->tcpStatus != CifsExiting)
|
||||||
|
ses->chans[i].server->tcpStatus = CifsNeedReconnect;
|
||||||
spin_unlock(&ses->chans[i].server->srv_lock);
|
spin_unlock(&ses->chans[i].server->srv_lock);
|
||||||
}
|
}
|
||||||
spin_unlock(&ses->chan_lock);
|
spin_unlock(&ses->chan_lock);
|
||||||
|
|
|
@ -69,7 +69,7 @@ bool is_ses_using_iface(struct cifs_ses *ses, struct cifs_server_iface *iface)
|
||||||
|
|
||||||
/* channel helper functions. assumed that chan_lock is held by caller. */
|
/* channel helper functions. assumed that chan_lock is held by caller. */
|
||||||
|
|
||||||
unsigned int
|
int
|
||||||
cifs_ses_get_chan_index(struct cifs_ses *ses,
|
cifs_ses_get_chan_index(struct cifs_ses *ses,
|
||||||
struct TCP_Server_Info *server)
|
struct TCP_Server_Info *server)
|
||||||
{
|
{
|
||||||
|
@ -85,14 +85,17 @@ cifs_ses_get_chan_index(struct cifs_ses *ses,
|
||||||
cifs_dbg(VFS, "unable to get chan index for server: 0x%llx",
|
cifs_dbg(VFS, "unable to get chan index for server: 0x%llx",
|
||||||
server->conn_id);
|
server->conn_id);
|
||||||
WARN_ON(1);
|
WARN_ON(1);
|
||||||
return 0;
|
return CIFS_INVAL_CHAN_INDEX;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
cifs_chan_set_in_reconnect(struct cifs_ses *ses,
|
cifs_chan_set_in_reconnect(struct cifs_ses *ses,
|
||||||
struct TCP_Server_Info *server)
|
struct TCP_Server_Info *server)
|
||||||
{
|
{
|
||||||
unsigned int chan_index = cifs_ses_get_chan_index(ses, server);
|
int chan_index = cifs_ses_get_chan_index(ses, server);
|
||||||
|
|
||||||
|
if (chan_index == CIFS_INVAL_CHAN_INDEX)
|
||||||
|
return;
|
||||||
|
|
||||||
ses->chans[chan_index].in_reconnect = true;
|
ses->chans[chan_index].in_reconnect = true;
|
||||||
}
|
}
|
||||||
|
@ -102,6 +105,8 @@ cifs_chan_clear_in_reconnect(struct cifs_ses *ses,
|
||||||
struct TCP_Server_Info *server)
|
struct TCP_Server_Info *server)
|
||||||
{
|
{
|
||||||
unsigned int chan_index = cifs_ses_get_chan_index(ses, server);
|
unsigned int chan_index = cifs_ses_get_chan_index(ses, server);
|
||||||
|
if (chan_index == CIFS_INVAL_CHAN_INDEX)
|
||||||
|
return;
|
||||||
|
|
||||||
ses->chans[chan_index].in_reconnect = false;
|
ses->chans[chan_index].in_reconnect = false;
|
||||||
}
|
}
|
||||||
|
@ -111,6 +116,8 @@ cifs_chan_in_reconnect(struct cifs_ses *ses,
|
||||||
struct TCP_Server_Info *server)
|
struct TCP_Server_Info *server)
|
||||||
{
|
{
|
||||||
unsigned int chan_index = cifs_ses_get_chan_index(ses, server);
|
unsigned int chan_index = cifs_ses_get_chan_index(ses, server);
|
||||||
|
if (chan_index == CIFS_INVAL_CHAN_INDEX)
|
||||||
|
return true; /* err on the safer side */
|
||||||
|
|
||||||
return CIFS_CHAN_IN_RECONNECT(ses, chan_index);
|
return CIFS_CHAN_IN_RECONNECT(ses, chan_index);
|
||||||
}
|
}
|
||||||
|
@ -120,6 +127,8 @@ cifs_chan_set_need_reconnect(struct cifs_ses *ses,
|
||||||
struct TCP_Server_Info *server)
|
struct TCP_Server_Info *server)
|
||||||
{
|
{
|
||||||
unsigned int chan_index = cifs_ses_get_chan_index(ses, server);
|
unsigned int chan_index = cifs_ses_get_chan_index(ses, server);
|
||||||
|
if (chan_index == CIFS_INVAL_CHAN_INDEX)
|
||||||
|
return;
|
||||||
|
|
||||||
set_bit(chan_index, &ses->chans_need_reconnect);
|
set_bit(chan_index, &ses->chans_need_reconnect);
|
||||||
cifs_dbg(FYI, "Set reconnect bitmask for chan %u; now 0x%lx\n",
|
cifs_dbg(FYI, "Set reconnect bitmask for chan %u; now 0x%lx\n",
|
||||||
|
@ -131,6 +140,8 @@ cifs_chan_clear_need_reconnect(struct cifs_ses *ses,
|
||||||
struct TCP_Server_Info *server)
|
struct TCP_Server_Info *server)
|
||||||
{
|
{
|
||||||
unsigned int chan_index = cifs_ses_get_chan_index(ses, server);
|
unsigned int chan_index = cifs_ses_get_chan_index(ses, server);
|
||||||
|
if (chan_index == CIFS_INVAL_CHAN_INDEX)
|
||||||
|
return;
|
||||||
|
|
||||||
clear_bit(chan_index, &ses->chans_need_reconnect);
|
clear_bit(chan_index, &ses->chans_need_reconnect);
|
||||||
cifs_dbg(FYI, "Cleared reconnect bitmask for chan %u; now 0x%lx\n",
|
cifs_dbg(FYI, "Cleared reconnect bitmask for chan %u; now 0x%lx\n",
|
||||||
|
@ -142,6 +153,8 @@ cifs_chan_needs_reconnect(struct cifs_ses *ses,
|
||||||
struct TCP_Server_Info *server)
|
struct TCP_Server_Info *server)
|
||||||
{
|
{
|
||||||
unsigned int chan_index = cifs_ses_get_chan_index(ses, server);
|
unsigned int chan_index = cifs_ses_get_chan_index(ses, server);
|
||||||
|
if (chan_index == CIFS_INVAL_CHAN_INDEX)
|
||||||
|
return true; /* err on the safer side */
|
||||||
|
|
||||||
return CIFS_CHAN_NEEDS_RECONNECT(ses, chan_index);
|
return CIFS_CHAN_NEEDS_RECONNECT(ses, chan_index);
|
||||||
}
|
}
|
||||||
|
@ -151,6 +164,8 @@ cifs_chan_is_iface_active(struct cifs_ses *ses,
|
||||||
struct TCP_Server_Info *server)
|
struct TCP_Server_Info *server)
|
||||||
{
|
{
|
||||||
unsigned int chan_index = cifs_ses_get_chan_index(ses, server);
|
unsigned int chan_index = cifs_ses_get_chan_index(ses, server);
|
||||||
|
if (chan_index == CIFS_INVAL_CHAN_INDEX)
|
||||||
|
return true; /* err on the safer side */
|
||||||
|
|
||||||
return ses->chans[chan_index].iface &&
|
return ses->chans[chan_index].iface &&
|
||||||
ses->chans[chan_index].iface->is_active;
|
ses->chans[chan_index].iface->is_active;
|
||||||
|
@ -293,7 +308,7 @@ cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server)
|
||||||
|
|
||||||
spin_lock(&ses->chan_lock);
|
spin_lock(&ses->chan_lock);
|
||||||
chan_index = cifs_ses_get_chan_index(ses, server);
|
chan_index = cifs_ses_get_chan_index(ses, server);
|
||||||
if (!chan_index) {
|
if (chan_index == CIFS_INVAL_CHAN_INDEX) {
|
||||||
spin_unlock(&ses->chan_lock);
|
spin_unlock(&ses->chan_lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -403,6 +418,11 @@ cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server)
|
||||||
|
|
||||||
spin_lock(&ses->chan_lock);
|
spin_lock(&ses->chan_lock);
|
||||||
chan_index = cifs_ses_get_chan_index(ses, server);
|
chan_index = cifs_ses_get_chan_index(ses, server);
|
||||||
|
if (chan_index == CIFS_INVAL_CHAN_INDEX) {
|
||||||
|
spin_unlock(&ses->chan_lock);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
ses->chans[chan_index].iface = iface;
|
ses->chans[chan_index].iface = iface;
|
||||||
|
|
||||||
/* No iface is found. if secondary chan, drop connection */
|
/* No iface is found. if secondary chan, drop connection */
|
||||||
|
|
|
@ -413,7 +413,13 @@ generate_smb3signingkey(struct cifs_ses *ses,
|
||||||
ses->ses_status == SES_GOOD);
|
ses->ses_status == SES_GOOD);
|
||||||
|
|
||||||
chan_index = cifs_ses_get_chan_index(ses, server);
|
chan_index = cifs_ses_get_chan_index(ses, server);
|
||||||
/* TODO: introduce ref counting for channels when the can be freed */
|
if (chan_index == CIFS_INVAL_CHAN_INDEX) {
|
||||||
|
spin_unlock(&ses->chan_lock);
|
||||||
|
spin_unlock(&ses->ses_lock);
|
||||||
|
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
spin_unlock(&ses->chan_lock);
|
spin_unlock(&ses->chan_lock);
|
||||||
spin_unlock(&ses->ses_lock);
|
spin_unlock(&ses->ses_lock);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue