]> git.baikalelectronics.ru Git - kernel.git/commitdiff
cifs: properly invalidate cached root handle when closing it
authorEnzo Matsumiya <ematsumiya@suse.de>
Thu, 9 Sep 2021 21:46:45 +0000 (18:46 -0300)
committerSteve French <stfrench@microsoft.com>
Thu, 9 Sep 2021 22:34:38 +0000 (17:34 -0500)
Cached root file was not being completely invalidated sometimes.

Reproducing:
- With a DFS share with 2 targets, one disabled and one enabled
- start some I/O on the mount
  # while true; do ls /mnt/dfs; done
- at the same time, disable the enabled target and enable the disabled
  one
- wait for DFS cache to expire
- on reconnect, the previous cached root handle should be invalid, but
  open_cached_dir_by_dentry() will still try to use it, but throws a
  use-after-free warning (kref_get())

Make smb2_close_cached_fid() invalidate all fields every time, but only
send an SMB2_close() when the entry is still valid.

Signed-off-by: Enzo Matsumiya <ematsumiya@suse.de>
Reviewed-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/cifs/smb2ops.c

index ddc0e8f97872d26aceb823d2a65b0bb9f009e23c..bda606dc72b1f4dac44de87961c211fe9c4845fe 100644 (file)
@@ -689,13 +689,19 @@ smb2_close_cached_fid(struct kref *ref)
                cifs_dbg(FYI, "clear cached root file handle\n");
                SMB2_close(0, cfid->tcon, cfid->fid->persistent_fid,
                           cfid->fid->volatile_fid);
-               cfid->is_valid = false;
-               cfid->file_all_info_is_valid = false;
-               cfid->has_lease = false;
-               if (cfid->dentry) {
-                       dput(cfid->dentry);
-                       cfid->dentry = NULL;
-               }
+       }
+
+       /*
+        * We only check validity above to send SMB2_close,
+        * but we still need to invalidate these entries
+        * when this function is called
+        */
+       cfid->is_valid = false;
+       cfid->file_all_info_is_valid = false;
+       cfid->has_lease = false;
+       if (cfid->dentry) {
+               dput(cfid->dentry);
+               cfid->dentry = NULL;
        }
 }