updated based on Paulo's feedback (moved the TID_EXITING up so it is inside the tc_locktc_unlock). See attached. On Thu, Mar 23, 2023 at 4:30 PM Steve French <smfrench@xxxxxxxxx> wrote: > > 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@xxxxxxxxxxxxxxx > Signed-off-by: Steve French <stfrench@xxxxxxxxxxxxx> > > > > -- > Thanks, > > Steve -- Thanks, Steve
From ff8cfffba059b3b8db9152312a62335926724fa2 Mon Sep 17 00:00:00 2001 From: Bharath SM <bharathsm@xxxxxxxxxxxxx> Date: Thu, 23 Mar 2023 19:05:00 +0000 Subject: [PATCH 3/3] SMB3: Close deferred file handles if we get handle lease break We should not cache deferred file handles if we dont have handle lease on a file. And we should immediately close all deferred handles in case of handle lease break. This is very important e.g. to prevent access denied errors in writing to the same file from a different client (during this interval while the close is deferred). Signed-off-by: Bharath SM <bharathsm@xxxxxxxxxxxxx> Fixes: 9e31678fb403 ("SMB3: fix lease break timeout when multiple deferred close handles for the same file.") Cc: stable@xxxxxxxxxxxxxxx # 6.0+ Signed-off-by: Steve French <stfrench@xxxxxxxxxxxxx> --- fs/cifs/cifsproto.h | 3 ++- fs/cifs/file.c | 21 +++++++++++++++++++++ fs/cifs/misc.c | 4 ++-- 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index e2eff66eefab..d2819d449f05 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -278,7 +278,8 @@ extern void cifs_add_deferred_close(struct cifsFileInfo *cfile, extern void cifs_del_deferred_close(struct cifsFileInfo *cfile); -extern void cifs_close_deferred_file(struct cifsInodeInfo *cifs_inode); +extern void cifs_close_deferred_file(struct cifsInodeInfo *cifs_inode, + bool wait_oplock_handler); extern void cifs_close_all_deferred_files(struct cifs_tcon *cifs_tcon); diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 6831a9949c43..47f61a51f552 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -4884,6 +4884,9 @@ void cifs_oplock_break(struct work_struct *work) struct cifsInodeInfo *cinode = CIFS_I(inode); struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); struct TCP_Server_Info *server = tcon->ses->server; + bool is_deferred = false; + struct cifs_deferred_close *dclose; + int rc = 0; bool purge_cache = false; @@ -4921,6 +4924,23 @@ void cifs_oplock_break(struct work_struct *work) cifs_dbg(VFS, "Push locks rc = %d\n", rc); oplock_break_ack: + /* + * When oplock break is received and there are no active file handles + * but cached file handles, then schedule deferred close immediately. + * So, new open will not use cached handle. + */ + spin_lock(&CIFS_I(inode)->deferred_lock); + is_deferred = cifs_is_deferred_close(cfile, &dclose); + spin_unlock(&CIFS_I(inode)->deferred_lock); + if (!CIFS_CACHE_HANDLE(cinode) && is_deferred && + cfile->deferred_close_scheduled && delayed_work_pending(&cfile->deferred)) { + if (cancel_delayed_work(&cfile->deferred)) { + _cifsFileInfo_put(cfile, false, false); + cifs_close_deferred_file(cinode, false); + goto oplock_break_done; + } + } + /* * releasing stale oplock after recent reconnect of smb session using * a now incorrect file handle is not a data integrity issue but do @@ -4933,6 +4953,7 @@ void cifs_oplock_break(struct work_struct *work) cifs_dbg(FYI, "Oplock release rc = %d\n", rc); } +oplock_break_done: _cifsFileInfo_put(cfile, false /* do not wait for ourself */, false); cifs_done_oplock_break(cinode); } diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index b44fb51968bf..fe4bf1f9de91 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -735,7 +735,7 @@ cifs_del_deferred_close(struct cifsFileInfo *cfile) } void -cifs_close_deferred_file(struct cifsInodeInfo *cifs_inode) +cifs_close_deferred_file(struct cifsInodeInfo *cifs_inode, bool wait_oplock_handler) { struct cifsFileInfo *cfile = NULL; struct file_list *tmp_list, *tmp_next_list; @@ -762,7 +762,7 @@ cifs_close_deferred_file(struct cifsInodeInfo *cifs_inode) spin_unlock(&cifs_inode->open_file_lock); list_for_each_entry_safe(tmp_list, tmp_next_list, &file_head, list) { - _cifsFileInfo_put(tmp_list->cfile, true, false); + _cifsFileInfo_put(tmp_list->cfile, wait_oplock_handler, false); list_del(&tmp_list->list); kfree(tmp_list); } -- 2.34.1