hulk inclusion category: bugfix bugzilla: https://atomgit.com/openeuler/kernel/issues/9783 -------------------------------- Commit 3b11912af75f ("[Backport] cifs: Fix busy dentry used after unmounting") fixed the issue in cifs where deferred close of a file led to a dentry reference count not being released in umount, by flushing deferredclose_wq in cifs_kill_sb to solve it. However, the cifs DIO path suffers from the same busy-dentry problem caused by a delayed dentry reference-count release: process A[dio] process B[cifsd] process C[close] cifs_direct_writev ... smb2_writev_callback wait_for_completion_killable queue_work(cifsiod_wq, xx)[1] cifs_uncached_writev_complete complete(&ctx->done)[2] kref_put(&ctx->refcount, xxx) // write done! cifs_close _cifsFileInfo_put[3] --cfile->count // count = 1 kref_put(&wdata->refcount, xx) ... _cifsFileInfo_put --cfile->count // count = 0 queue_work(fileinfo_put_wq, xx)[4] cifsFileInfo_put_work cifsFileInfo_put_final dput At [1] the work is queued onto cifsiod_wq. At [2] the foreground thread waiting on the write is woken up; after the write path exits and closes the file, at [3] the cfile reference count has not yet dropped to 0, so the final dput is not called synchronously. The cifsiod worker then drops the cfile reference count to 0 and calls the final dput on fileinfo_put_wq at [4]. If the umount path is triggered before [4], it results in the following warning: BUG: Dentry 00000000eab1f070{i=9a917b66ae404fec,n=test} still in use (1) [unmount of cifs cifs] Therefore, cifsiod_wq/fileinfo_put_wq/serverclose_wq need to be flushed. Fixes: b28b211c8d8f ("cifs: open files should not hold ref on superblock") Signed-off-by: Zizhi Wo <wozizhi@huawei.com> --- fs/smb/client/cifsfs.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/smb/client/cifsfs.c b/fs/smb/client/cifsfs.c index a2887b978dc8..f6d74e961414 100644 --- a/fs/smb/client/cifsfs.c +++ b/fs/smb/client/cifsfs.c @@ -298,10 +298,13 @@ static void cifs_kill_sb(struct super_block *sb) /* Wait for all pending oplock breaks to complete */ flush_workqueue(cifsoplockd_wq); /* Wait for all opened files to release */ flush_workqueue(deferredclose_wq); + flush_workqueue(cifsiod_wq); + flush_workqueue(serverclose_wq); + flush_workqueue(fileinfo_put_wq); /* finally release root dentry */ dput(cifs_sb->root); cifs_sb->root = NULL; } -- 2.52.0