]> 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)
committerSteve French <stfrench@microsoft.com>
Thu, 18 Sep 2025 01:33:44 +0000 (20:33 -0500)
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>
fs/smb/client/cifsproto.h
fs/smb/client/inode.c
fs/smb/client/misc.c

index c34c533b2efade37792e52ab23ea52139084bc96..e8fba98690ce388fd523894052bbca4b0ec23d11 100644 (file)
@@ -312,8 +312,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 11d442e8b3d622e6987a023473fefda821f65620..1703f1285d36d27f8ce49763a78a1f28d05a998a 100644 (file)
@@ -1984,7 +1984,7 @@ static int __cifs_unlink(struct inode *dir, struct dentry *dentry, bool sillyren
        }
 
        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))) {
@@ -2538,10 +2538,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 da23cc12a52caa19dc2810a49ae368d7e787febe..dda6dece802ad2ae1008570ac09d8a2ec7a4625f 100644 (file)
@@ -832,33 +832,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);
@@ -868,7 +863,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);
 }
 
 /*