summaryrefslogtreecommitdiff
path: root/fs/cifs/cifsproto.h
diff options
context:
space:
mode:
authorPaulo Alcantara <pc@manguebit.com>2023-04-23 23:26:51 -0300
committerSteve French <stfrench@microsoft.com>2023-05-04 16:54:44 -0500
commit8e3554150d6c80a84b3cb046615d1a0e943811dc (patch)
tree6c90574389254fe3e7881bddd59483d676736783 /fs/cifs/cifsproto.h
parent6be2ea33a4093402252724a00c4af8033725184c (diff)
cifs: fix sharing of DFS connections
When matching DFS connections, we can't rely on the values set in cifs_sb_info::prepath and cifs_tcon::tree_name as they might change during DFS failover. The DFS referrals related to a specific DFS tcon are already matched earlier in match_server(), therefore we can safely skip those checks altogether as the connection is guaranteed to be unique for the DFS tcon. Besides, when creating or finding an SMB session, make sure to also refcount any DFS root session related to it (cifs_ses::dfs_root_ses), so if a new DFS mount ends up reusing the connection from the old mount while there was an umount(2) still in progress (e.g. umount(2) -> cifs_umount() -> reconnect -> cifs_put_tcon()), the connection could potentially be put right after the umount(2) finished. Patch has minor update to include fix for unused variable issue noted by the kernel test robot Reported-by: kernel test robot <lkp@intel.com> Link: https://lore.kernel.org/oe-kbuild-all/202305041040.j7W2xQSy-lkp@intel.com/ Cc: stable@vger.kernel.org # v6.2+ Signed-off-by: Paulo Alcantara (SUSE) <pc@manguebit.com> Signed-off-by: Steve French <stfrench@microsoft.com>
Diffstat (limited to 'fs/cifs/cifsproto.h')
-rw-r--r--fs/cifs/cifsproto.h44
1 files changed, 43 insertions, 1 deletions
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index e2eff66eefab..c1c704990b98 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -8,6 +8,7 @@
#ifndef _CIFSPROTO_H
#define _CIFSPROTO_H
#include <linux/nls.h>
+#include <linux/ctype.h>
#include "trace.h"
#ifdef CONFIG_CIFS_DFS_UPCALL
#include "dfs_cache.h"
@@ -572,7 +573,7 @@ extern int E_md4hash(const unsigned char *passwd, unsigned char *p16,
extern struct TCP_Server_Info *
cifs_find_tcp_session(struct smb3_fs_context *ctx);
-extern void cifs_put_smb_ses(struct cifs_ses *ses);
+void __cifs_put_smb_ses(struct cifs_ses *ses);
extern struct cifs_ses *
cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx);
@@ -696,4 +697,45 @@ struct super_block *cifs_get_tcon_super(struct cifs_tcon *tcon);
void cifs_put_tcon_super(struct super_block *sb);
int cifs_wait_for_server_reconnect(struct TCP_Server_Info *server, bool retry);
+/* Put references of @ses and @ses->dfs_root_ses */
+static inline void cifs_put_smb_ses(struct cifs_ses *ses)
+{
+ struct cifs_ses *rses = ses->dfs_root_ses;
+
+ __cifs_put_smb_ses(ses);
+ if (rses)
+ __cifs_put_smb_ses(rses);
+}
+
+/* Get an active reference of @ses and @ses->dfs_root_ses.
+ *
+ * NOTE: make sure to call this function when incrementing reference count of
+ * @ses to ensure that any DFS root session attached to it (@ses->dfs_root_ses)
+ * will also get its reference count incremented.
+ *
+ * cifs_put_smb_ses() will put both references, so call it when you're done.
+ */
+static inline void cifs_smb_ses_inc_refcount(struct cifs_ses *ses)
+{
+ lockdep_assert_held(&cifs_tcp_ses_lock);
+
+ ses->ses_count++;
+ if (ses->dfs_root_ses)
+ ses->dfs_root_ses->ses_count++;
+}
+
+static inline bool dfs_src_pathname_equal(const char *s1, const char *s2)
+{
+ if (strlen(s1) != strlen(s2))
+ return false;
+ for (; *s1; s1++, s2++) {
+ if (*s1 == '/' || *s1 == '\\') {
+ if (*s2 != '/' && *s2 != '\\')
+ return false;
+ } else if (tolower(*s1) != tolower(*s2))
+ return false;
+ }
+ return true;
+}
+
#endif /* _CIFSPROTO_H */