Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

+41 -23
-1
fs/smb/client/cifsglob.h
··· 994 994 struct cifs_server_iface *iface = container_of(ref, 995 995 struct cifs_server_iface, 996 996 refcount); 997 - list_del_init(&iface->iface_head); 998 997 kfree(iface); 999 998 } 1000 999
+18 -11
fs/smb/client/connect.c
··· 216 216 /* If server is a channel, select the primary channel */ 217 217 pserver = SERVER_IS_CHAN(server) ? server->primary_server : server; 218 218 219 + /* 220 + * if the server has been marked for termination, there is a 221 + * chance that the remaining channels all need reconnect. To be 222 + * on the safer side, mark the session and trees for reconnect 223 + * for this scenario. This might cause a few redundant session 224 + * setup and tree connect requests, but it is better than not doing 225 + * a tree connect when needed, and all following requests failing 226 + */ 227 + if (server->terminate) { 228 + mark_smb_session = true; 229 + server = pserver; 230 + } 219 231 220 232 spin_lock(&cifs_tcp_ses_lock); 221 233 list_for_each_entry_safe(ses, nses, &pserver->smb_ses_list, smb_ses_list) { 222 - /* 223 - * if channel has been marked for termination, nothing to do 224 - * for the channel. in fact, we cannot find the channel for the 225 - * server. So safe to exit here 226 - */ 227 - if (server->terminate) 228 - break; 229 - 230 234 /* check if iface is still active */ 231 - if (!cifs_chan_is_iface_active(ses, server)) 232 - cifs_chan_update_iface(ses, server); 233 - 234 235 spin_lock(&ses->chan_lock); 236 + if (!cifs_chan_is_iface_active(ses, server)) { 237 + spin_unlock(&ses->chan_lock); 238 + cifs_chan_update_iface(ses, server); 239 + spin_lock(&ses->chan_lock); 240 + } 241 + 235 242 if (!mark_smb_session && cifs_chan_needs_reconnect(ses, server)) { 236 243 spin_unlock(&ses->chan_lock); 237 244 continue;
+23 -11
fs/smb/client/smb2ops.c
··· 595 595 } 596 596 597 597 /* 598 - * Go through iface_list and do kref_put to remove 599 - * any unused ifaces. ifaces in use will be removed 600 - * when the last user calls a kref_put on it 598 + * Go through iface_list and mark them as inactive 601 599 */ 602 600 list_for_each_entry_safe(iface, niface, &ses->iface_list, 603 - iface_head) { 601 + iface_head) 604 602 iface->is_active = 0; 605 - kref_put(&iface->refcount, release_iface); 606 - ses->iface_count--; 607 - } 603 + 608 604 spin_unlock(&ses->iface_lock); 609 605 610 606 /* ··· 674 678 iface_head) { 675 679 ret = iface_cmp(iface, &tmp_iface); 676 680 if (!ret) { 677 - /* just get a ref so that it doesn't get picked/freed */ 678 681 iface->is_active = 1; 679 - kref_get(&iface->refcount); 680 - ses->iface_count++; 681 682 spin_unlock(&ses->iface_lock); 682 683 goto next_iface; 683 684 } else if (ret < 0) { ··· 741 748 } 742 749 743 750 out: 751 + /* 752 + * Go through the list again and put the inactive entries 753 + */ 754 + spin_lock(&ses->iface_lock); 755 + list_for_each_entry_safe(iface, niface, &ses->iface_list, 756 + iface_head) { 757 + if (!iface->is_active) { 758 + list_del(&iface->iface_head); 759 + kref_put(&iface->refcount, release_iface); 760 + ses->iface_count--; 761 + } 762 + } 763 + spin_unlock(&ses->iface_lock); 764 + 744 765 return rc; 745 766 } 746 767 ··· 791 784 goto out; 792 785 793 786 /* check if iface is still active */ 787 + spin_lock(&ses->chan_lock); 794 788 pserver = ses->chans[0].server; 795 - if (pserver && !cifs_chan_is_iface_active(ses, pserver)) 789 + if (pserver && !cifs_chan_is_iface_active(ses, pserver)) { 790 + spin_unlock(&ses->chan_lock); 796 791 cifs_chan_update_iface(ses, pserver); 792 + spin_lock(&ses->chan_lock); 793 + } 794 + spin_unlock(&ses->chan_lock); 797 795 798 796 out: 799 797 kfree(out_buf);