Three important multichannel smb3 client fixes
-----BEGIN PGP SIGNATURE----- iQGyBAABCgAdFiEE6fsu8pdIjtWE/DpLiiy9cAdyT1EFAmWWRDMACgkQiiy9cAdy T1E+tAv4g15Kh9JeSaO/x1oyujKSDnEALWGvriwj9EC6+Z+MzQQyyPxB4uUyRuSN uts/QgvpK4LW2jIhyTaBfU9xRfhJYup1B+vaBtij6NwKfnxYo1PJCdAj8yelAfCW 7mgqSiIGMRbRFz3jnFbb5vQS3H32Hpje0h32Rh3LiKrS6q+9exCJDHA6jqQ5JwvP /BrDeJ0vykyUjvjxcYQaeWZDkXEy7bysVVq+3qOEr9HSwX7Jv1f6JOLLpUoTTWx9 LPkBus02JOAWX6FUWewVdx1ar9cTafA54rzS3hrpT2lxjuMhSmL6v9Br9MCsAMnI oWMWfjyefAM6ss4m/pAD178WZ61f1urIRrTRJJUwcWA+XjXTF6dXXZvMFdzqjYW5 k6nMhDfFXzSzywwSFmlQwh/00NPVzX7DuGjgd3ZdJ7z6bvFvltwZtkRPMVK7zvHc X8LWAWYuaLku4yj3PJa3FiBrSYPsztTX3NLqQq+5vcxxTDCOcFduXComvvEosSiq 4UbhxHU= =0P5G -----END PGP SIGNATURE----- Merge tag '6.7-rc8-smb3-mchan-fixes' of git://git.samba.org/sfrench/cifs-2.6 Pull smb client fixes from Steve French: "Three important multichannel smb3 client fixes found in recent testing: - fix oops due to incorrect refcounting of interfaces after disabling multichannel - fix possible unrecoverable session state after disabling multichannel with active sessions - fix two places that were missing use of chan_lock" * tag '6.7-rc8-smb3-mchan-fixes' of git://git.samba.org/sfrench/cifs-2.6: cifs: do not depend on release_iface for maintaining iface_list cifs: cifs_chan_is_iface_active should be called with chan_lock held cifs: after disabling multichannel, mark tcon for reconnect
This commit is contained in:
commit
3eca89454a
@ -994,7 +994,6 @@ release_iface(struct kref *ref)
|
||||
struct cifs_server_iface *iface = container_of(ref,
|
||||
struct cifs_server_iface,
|
||||
refcount);
|
||||
list_del_init(&iface->iface_head);
|
||||
kfree(iface);
|
||||
}
|
||||
|
||||
|
@ -216,22 +216,29 @@ cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server,
|
||||
/* If server is a channel, select the primary channel */
|
||||
pserver = SERVER_IS_CHAN(server) ? server->primary_server : server;
|
||||
|
||||
/*
|
||||
* if the server has been marked for termination, there is a
|
||||
* chance that the remaining channels all need reconnect. To be
|
||||
* on the safer side, mark the session and trees for reconnect
|
||||
* for this scenario. This might cause a few redundant session
|
||||
* setup and tree connect requests, but it is better than not doing
|
||||
* a tree connect when needed, and all following requests failing
|
||||
*/
|
||||
if (server->terminate) {
|
||||
mark_smb_session = true;
|
||||
server = pserver;
|
||||
}
|
||||
|
||||
spin_lock(&cifs_tcp_ses_lock);
|
||||
list_for_each_entry_safe(ses, nses, &pserver->smb_ses_list, smb_ses_list) {
|
||||
/*
|
||||
* if channel has been marked for termination, nothing to do
|
||||
* for the channel. in fact, we cannot find the channel for the
|
||||
* server. So safe to exit here
|
||||
*/
|
||||
if (server->terminate)
|
||||
break;
|
||||
|
||||
/* check if iface is still active */
|
||||
if (!cifs_chan_is_iface_active(ses, server))
|
||||
cifs_chan_update_iface(ses, server);
|
||||
|
||||
spin_lock(&ses->chan_lock);
|
||||
if (!cifs_chan_is_iface_active(ses, server)) {
|
||||
spin_unlock(&ses->chan_lock);
|
||||
cifs_chan_update_iface(ses, server);
|
||||
spin_lock(&ses->chan_lock);
|
||||
}
|
||||
|
||||
if (!mark_smb_session && cifs_chan_needs_reconnect(ses, server)) {
|
||||
spin_unlock(&ses->chan_lock);
|
||||
continue;
|
||||
|
@ -595,16 +595,12 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
|
||||
}
|
||||
|
||||
/*
|
||||
* Go through iface_list and do kref_put to remove
|
||||
* any unused ifaces. ifaces in use will be removed
|
||||
* when the last user calls a kref_put on it
|
||||
* Go through iface_list and mark them as inactive
|
||||
*/
|
||||
list_for_each_entry_safe(iface, niface, &ses->iface_list,
|
||||
iface_head) {
|
||||
iface_head)
|
||||
iface->is_active = 0;
|
||||
kref_put(&iface->refcount, release_iface);
|
||||
ses->iface_count--;
|
||||
}
|
||||
|
||||
spin_unlock(&ses->iface_lock);
|
||||
|
||||
/*
|
||||
@ -678,10 +674,7 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
|
||||
iface_head) {
|
||||
ret = iface_cmp(iface, &tmp_iface);
|
||||
if (!ret) {
|
||||
/* just get a ref so that it doesn't get picked/freed */
|
||||
iface->is_active = 1;
|
||||
kref_get(&iface->refcount);
|
||||
ses->iface_count++;
|
||||
spin_unlock(&ses->iface_lock);
|
||||
goto next_iface;
|
||||
} else if (ret < 0) {
|
||||
@ -748,6 +741,20 @@ next_iface:
|
||||
}
|
||||
|
||||
out:
|
||||
/*
|
||||
* Go through the list again and put the inactive entries
|
||||
*/
|
||||
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--;
|
||||
}
|
||||
}
|
||||
spin_unlock(&ses->iface_lock);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -784,9 +791,14 @@ SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon, bool in_
|
||||
goto out;
|
||||
|
||||
/* check if iface is still active */
|
||||
spin_lock(&ses->chan_lock);
|
||||
pserver = ses->chans[0].server;
|
||||
if (pserver && !cifs_chan_is_iface_active(ses, pserver))
|
||||
if (pserver && !cifs_chan_is_iface_active(ses, pserver)) {
|
||||
spin_unlock(&ses->chan_lock);
|
||||
cifs_chan_update_iface(ses, pserver);
|
||||
spin_lock(&ses->chan_lock);
|
||||
}
|
||||
spin_unlock(&ses->chan_lock);
|
||||
|
||||
out:
|
||||
kfree(out_buf);
|
||||
|
Loading…
Reference in New Issue
Block a user