summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteve French <stfrench@microsoft.com>2023-03-24 00:20:02 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2023-03-30 13:51:25 +0300
commit73227237b20c91ec5fd31579cf7d353e64a9d52c (patch)
tree6334aca79a8b12a1d7a9d8060c4e1c94bd5ed836
parent111d6ecaff7957ecf4b7bf926f19382ffd0c115c (diff)
downloadlinux-73227237b20c91ec5fd31579cf7d353e64a9d52c.tar.xz
smb3: fix unusable share after force unmount failure
commit 491eafce1a51c457701351a4bf40733799745314 upstream. If user does forced unmount ("umount -f") while files are still open on the share (as was seen in a Kubernetes example running on SMB3.1.1 mount) then we were marking the share as "TID_EXITING" in umount_begin() which caused all subsequent operations (except write) to fail ... but unfortunately when umount_begin() is called we do not know yet that there are open files or active references on the share that would prevent unmount from succeeding. Kubernetes had example when they were doing umount -f when files were open which caused the share to become unusable until the files were closed (and the umount retried). Fix this so that TID_EXITING is not set until we are about to send the tree disconnect (not at the beginning of forced umounts in umount_begin) so that if "umount -f" fails (due to open files or references) the mount is still usable. Cc: stable@vger.kernel.org Reviewed-by: Shyam Prasad N <sprasad@microsoft.com> Reviewed-by: Paulo Alcantara (SUSE) <pc@manguebit.com> Signed-off-by: Steve French <stfrench@microsoft.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--fs/cifs/cifsfs.c9
-rw-r--r--fs/cifs/cifssmb.c6
-rw-r--r--fs/cifs/connect.c1
-rw-r--r--fs/cifs/smb2pdu.c8
4 files changed, 11 insertions, 13 deletions
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 10e00c624922..8485d380cddf 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -730,13 +730,16 @@ static void cifs_umount_begin(struct super_block *sb)
spin_lock(&tcon->tc_lock);
if ((tcon->tc_count > 1) || (tcon->status == TID_EXITING)) {
/* we have other mounts to same share or we have
- already tried to force umount this and woken up
+ already tried to umount this and woken up
all waiting network requests, nothing to do */
spin_unlock(&tcon->tc_lock);
spin_unlock(&cifs_tcp_ses_lock);
return;
- } else if (tcon->tc_count == 1)
- tcon->status = TID_EXITING;
+ }
+ /*
+ * can not set tcon->status to TID_EXITING yet since we don't know if umount -f will
+ * fail later (e.g. due to open files). TID_EXITING will be set just before tdis req sent
+ */
spin_unlock(&tcon->tc_lock);
spin_unlock(&cifs_tcp_ses_lock);
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 8c014a3ff9e0..566e6a26b897 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -85,13 +85,11 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
/*
* only tree disconnect, open, and write, (and ulogoff which does not
- * have tcon) are allowed as we start force umount
+ * have tcon) are allowed as we start umount
*/
spin_lock(&tcon->tc_lock);
if (tcon->status == TID_EXITING) {
- if (smb_command != SMB_COM_WRITE_ANDX &&
- smb_command != SMB_COM_OPEN_ANDX &&
- smb_command != SMB_COM_TREE_DISCONNECT) {
+ if (smb_command != SMB_COM_TREE_DISCONNECT) {
spin_unlock(&tcon->tc_lock);
cifs_dbg(FYI, "can not send cmd %d while umounting\n",
smb_command);
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 5a889f5f5c3e..b41e94725afd 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -2363,6 +2363,7 @@ cifs_put_tcon(struct cifs_tcon *tcon)
WARN_ON(tcon->tc_count < 0);
list_del_init(&tcon->tcon_list);
+ tcon->status = TID_EXITING;
spin_unlock(&tcon->tc_lock);
spin_unlock(&cifs_tcp_ses_lock);
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 23926f754d2a..c1aba3dd5d34 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -225,13 +225,9 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
spin_lock(&tcon->tc_lock);
if (tcon->status == TID_EXITING) {
/*
- * only tree disconnect, open, and write,
- * (and ulogoff which does not have tcon)
- * are allowed as we start force umount.
+ * only tree disconnect allowed when disconnecting ...
*/
- if ((smb2_command != SMB2_WRITE) &&
- (smb2_command != SMB2_CREATE) &&
- (smb2_command != SMB2_TREE_DISCONNECT)) {
+ if (smb2_command != SMB2_TREE_DISCONNECT) {
spin_unlock(&tcon->tc_lock);
cifs_dbg(FYI, "can not send cmd %d while umounting\n",
smb2_command);