]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
smb: client: fix filename matching of deferred files
authorPaulo Alcantara <pc@manguebit.org>
Wed, 17 Sep 2025 19:03:22 +0000 (16:03 -0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 25 Sep 2025 09:13:49 +0000 (11:13 +0200)
[ Upstream commit 93ed9a2951308db374cba4562533dde97bac70d3 ]

Fix the following case where the client would end up closing both
deferred files (foo.tmp & foo) after unlink(foo) due to strstr() call
in cifs_close_deferred_file_under_dentry():

  fd1 = openat(AT_FDCWD, "foo", O_WRONLY|O_CREAT|O_TRUNC, 0666);
  fd2 = openat(AT_FDCWD, "foo.tmp", O_WRONLY|O_CREAT|O_TRUNC, 0666);
  close(fd1);
  close(fd2);
  unlink("foo");

Fixes: e3fc065682eb ("cifs: Deferred close performance improvements")
Signed-off-by: Paulo Alcantara (Red Hat) <pc@manguebit.org>
Reviewed-by: Enzo Matsumiya <ematsumiya@suse.de>
Cc: Frank Sorenson <sorenson@redhat.com>
Cc: David Howells <dhowells@redhat.com>
Cc: linux-cifs@vger.kernel.org
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
fs/smb/client/cifsproto.h
fs/smb/client/inode.c
fs/smb/client/misc.c

index fee7bc9848a36aa4478d14f6ff5d5e280bc1d56b..b59647291363b67c567a464a042cd8cc76274130 100644 (file)
@@ -298,8 +298,8 @@ extern void cifs_close_deferred_file(struct cifsInodeInfo *cifs_inode);
 
 extern void cifs_close_all_deferred_files(struct cifs_tcon *cifs_tcon);
 
-extern void cifs_close_deferred_file_under_dentry(struct cifs_tcon *cifs_tcon,
-                               const char *path);
+void cifs_close_deferred_file_under_dentry(struct cifs_tcon *cifs_tcon,
+                                          struct dentry *dentry);
 
 extern void cifs_mark_open_handles_for_deleted_file(struct inode *inode,
                                const char *path);
index c0df2c1841243e97e67c82693d159608251eabc7..e06d02b68c5387a41de5ce499b1e3e39fab3d4fb 100644 (file)
@@ -1958,7 +1958,7 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
        }
 
        netfs_wait_for_outstanding_io(inode);
-       cifs_close_deferred_file_under_dentry(tcon, full_path);
+       cifs_close_deferred_file_under_dentry(tcon, dentry);
 #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
        if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP &
                                le64_to_cpu(tcon->fsUnixInfo.Capability))) {
@@ -2489,10 +2489,10 @@ cifs_rename2(struct mnt_idmap *idmap, struct inode *source_dir,
                goto cifs_rename_exit;
        }
 
-       cifs_close_deferred_file_under_dentry(tcon, from_name);
+       cifs_close_deferred_file_under_dentry(tcon, source_dentry);
        if (d_inode(target_dentry) != NULL) {
                netfs_wait_for_outstanding_io(d_inode(target_dentry));
-               cifs_close_deferred_file_under_dentry(tcon, to_name);
+               cifs_close_deferred_file_under_dentry(tcon, target_dentry);
        }
 
        rc = cifs_do_rename(xid, source_dentry, from_name, target_dentry,
index 57b6b191293eea426ad47d02fa0520fb46ad353b..499f791df77998bcb8d988126f30b22b5f245358 100644 (file)
@@ -829,33 +829,28 @@ cifs_close_all_deferred_files(struct cifs_tcon *tcon)
                kfree(tmp_list);
        }
 }
-void
-cifs_close_deferred_file_under_dentry(struct cifs_tcon *tcon, const char *path)
+
+void cifs_close_deferred_file_under_dentry(struct cifs_tcon *tcon,
+                                          struct dentry *dentry)
 {
-       struct cifsFileInfo *cfile;
        struct file_list *tmp_list, *tmp_next_list;
-       void *page;
-       const char *full_path;
+       struct cifsFileInfo *cfile;
        LIST_HEAD(file_head);
 
-       page = alloc_dentry_path();
        spin_lock(&tcon->open_file_lock);
        list_for_each_entry(cfile, &tcon->openFileList, tlist) {
-               full_path = build_path_from_dentry(cfile->dentry, page);
-               if (strstr(full_path, path)) {
-                       if (delayed_work_pending(&cfile->deferred)) {
-                               if (cancel_delayed_work(&cfile->deferred)) {
-                                       spin_lock(&CIFS_I(d_inode(cfile->dentry))->deferred_lock);
-                                       cifs_del_deferred_close(cfile);
-                                       spin_unlock(&CIFS_I(d_inode(cfile->dentry))->deferred_lock);
-
-                                       tmp_list = kmalloc(sizeof(struct file_list), GFP_ATOMIC);
-                                       if (tmp_list == NULL)
-                                               break;
-                                       tmp_list->cfile = cfile;
-                                       list_add_tail(&tmp_list->list, &file_head);
-                               }
-                       }
+               if ((cfile->dentry == dentry) &&
+                   delayed_work_pending(&cfile->deferred) &&
+                   cancel_delayed_work(&cfile->deferred)) {
+                       spin_lock(&CIFS_I(d_inode(cfile->dentry))->deferred_lock);
+                       cifs_del_deferred_close(cfile);
+                       spin_unlock(&CIFS_I(d_inode(cfile->dentry))->deferred_lock);
+
+                       tmp_list = kmalloc(sizeof(struct file_list), GFP_ATOMIC);
+                       if (tmp_list == NULL)
+                               break;
+                       tmp_list->cfile = cfile;
+                       list_add_tail(&tmp_list->list, &file_head);
                }
        }
        spin_unlock(&tcon->open_file_lock);
@@ -865,7 +860,6 @@ cifs_close_deferred_file_under_dentry(struct cifs_tcon *tcon, const char *path)
                list_del(&tmp_list->list);
                kfree(tmp_list);
        }
-       free_dentry_path(page);
 }
 
 /*