linux-cifs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH][SMB3 client] DFS/reconnect fixes part 3 of 4
@ 2022-12-17 16:08 Steve French
  0 siblings, 0 replies; only message in thread
From: Steve French @ 2022-12-17 16:08 UTC (permalink / raw)
  To: CIFS; +Cc: Paulo Alcantara

[-- Attachment #1: Type: text/plain, Size: 144 bytes --]

More from Paulo's recent DFS/reconnect patch series (resending to list
since they seem to have bounced when sent earlier)



-- 
Thanks,

Steve

[-- Attachment #2: 0009-cifs-refresh-root-referrals.patch --]
[-- Type: text/x-patch, Size: 3429 bytes --]

From 62eb9ddcf601a223c638b4e573a3c74b58f5d2b5 Mon Sep 17 00:00:00 2001
From: Paulo Alcantara <pc@cjr.nz>
Date: Tue, 13 Dec 2022 11:30:30 -0300
Subject: [PATCH 09/14] cifs: refresh root referrals

Also refresh cached root referrals so the other cached referrals may
have a better chance to have a working root server to issue the
referrals on.

Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
Signed-off-by: Steve French <stfrench@microsoft.com>
---
 fs/cifs/dfs_cache.c | 40 ++++++++++++++++++++++------------------
 1 file changed, 22 insertions(+), 18 deletions(-)

diff --git a/fs/cifs/dfs_cache.c b/fs/cifs/dfs_cache.c
index 95cc3951420e..cb83b86eafe6 100644
--- a/fs/cifs/dfs_cache.c
+++ b/fs/cifs/dfs_cache.c
@@ -1346,14 +1346,15 @@ static void mark_for_reconnect_if_needed(struct cifs_tcon *tcon, struct dfs_cach
 /* Refresh dfs referral of tcon and mark it for reconnect if needed */
 static int __refresh_tcon(const char *path, struct cifs_tcon *tcon, bool force_refresh)
 {
+	struct dfs_cache_tgt_list tl = DFS_CACHE_TGT_LIST_INIT(tl);
 	struct cifs_ses *ses = CIFS_DFS_ROOT_SES(tcon->ses);
-	struct cache_entry *ce;
+	struct cifs_tcon *ipc = ses->tcon_ipc;
 	struct dfs_info3_param *refs = NULL;
-	int numrefs = 0;
 	bool needs_refresh = false;
-	struct dfs_cache_tgt_list tl = DFS_CACHE_TGT_LIST_INIT(tl);
-	int rc = 0;
+	struct cache_entry *ce;
 	unsigned int xid;
+	int numrefs = 0;
+	int rc = 0;
 
 	xid = get_xid();
 
@@ -1372,6 +1373,14 @@ static int __refresh_tcon(const char *path, struct cifs_tcon *tcon, bool force_r
 		goto out;
 	}
 
+	spin_lock(&ipc->tc_lock);
+	if (ses->ses_status != SES_GOOD || ipc->status != TID_GOOD) {
+		spin_unlock(&ipc->tc_lock);
+		cifs_dbg(FYI, "%s: skip cache refresh due to disconnected ipc\n", __func__);
+		goto out;
+	}
+	spin_unlock(&ipc->tc_lock);
+
 	rc = get_dfs_referral(xid, ses, path, &refs, &numrefs);
 	if (!rc) {
 		/* Create or update a cache entry with the new referral */
@@ -1457,9 +1466,9 @@ int dfs_cache_remount_fs(struct cifs_sb_info *cifs_sb)
 static void refresh_cache_worker(struct work_struct *work)
 {
 	struct TCP_Server_Info *server;
-	struct cifs_ses *ses;
 	struct cifs_tcon *tcon, *ntcon;
 	struct list_head tcons;
+	struct cifs_ses *ses;
 
 	INIT_LIST_HEAD(&tcons);
 
@@ -1469,23 +1478,15 @@ static void refresh_cache_worker(struct work_struct *work)
 			continue;
 
 		list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
-			struct cifs_ses *root_ses = CIFS_DFS_ROOT_SES(ses);
-
-			spin_lock(&root_ses->ses_lock);
-			if (root_ses->ses_status != SES_GOOD) {
-				spin_unlock(&root_ses->ses_lock);
-				continue;
+			if (ses->tcon_ipc) {
+				ses->ses_count++;
+				list_add_tail(&ses->tcon_ipc->ulist, &tcons);
 			}
-			spin_unlock(&root_ses->ses_lock);
-
 			list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
-				spin_lock(&tcon->tc_lock);
-				if (!tcon->ipc && tcon->status != TID_NEW &&
-				    tcon->status != TID_NEED_TCON) {
+				if (!tcon->ipc) {
 					tcon->tc_count++;
 					list_add_tail(&tcon->ulist, &tcons);
 				}
-				spin_unlock(&tcon->tc_lock);
 			}
 		}
 	}
@@ -1501,7 +1502,10 @@ static void refresh_cache_worker(struct work_struct *work)
 			__refresh_tcon(server->leaf_fullpath + 1, tcon, false);
 		mutex_unlock(&server->refpath_lock);
 
-		cifs_put_tcon(tcon);
+		if (tcon->ipc)
+			cifs_put_smb_ses(tcon->ses);
+		else
+			cifs_put_tcon(tcon);
 	}
 
 	spin_lock(&cache_ttl_lock);
-- 
2.34.1


[-- Attachment #3: 0008-cifs-fix-refresh-of-cached-referrals.patch --]
[-- Type: text/x-patch, Size: 11358 bytes --]

From e27e056f08026726f36275f91ced76c88127818d Mon Sep 17 00:00:00 2001
From: Paulo Alcantara <pc@cjr.nz>
Date: Tue, 13 Dec 2022 01:23:16 -0300
Subject: [PATCH 08/14] cifs: fix refresh of cached referrals

We can't rely on cifs_tcon::ses to refresh cached referral as the
server target might not respond to referrals, e.g. share is not hosted
in a DFS root server.  Consider the following

  mount //dom/dfs/link -> /root1/dfs/link -> /fs0/share

where fs0 can't get a referral for "/root1/dfs/link".

To simplify and fix the access of dfs root sessions, store the dfs
root session pointer directly to new sessions so making it easier to
select the appropriate ipc connection and use it for failover or cache
refresh.

Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
Signed-off-by: Steve French <stfrench@microsoft.com>
---
 fs/cifs/cifsglob.h  |   3 +
 fs/cifs/connect.c   |   5 +-
 fs/cifs/dfs.c       |   6 ++
 fs/cifs/dfs_cache.c | 140 ++++++++------------------------------------
 4 files changed, 37 insertions(+), 117 deletions(-)

diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 2e2976f1874f..cfdd5bf701a1 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -107,6 +107,8 @@
 
 #define CIFS_MAX_WORKSTATION_LEN  (__NEW_UTS_LEN + 1)  /* reasonable max for client */
 
+#define CIFS_DFS_ROOT_SES(ses) ((ses)->dfs_root_ses ?: (ses))
+
 /*
  * CIFS vfs client Status information (based on what we know.)
  */
@@ -1099,6 +1101,7 @@ struct cifs_ses {
 	 */
 	unsigned long chans_need_reconnect;
 	/* ========= end: protected by chan_lock ======== */
+	struct cifs_ses *dfs_root_ses;
 };
 
 static inline bool
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index a66cb23a954e..db3a2b3ac497 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -4150,7 +4150,8 @@ static int __tree_connect_dfs_target(const unsigned int xid, struct cifs_tcon *t
 	int rc;
 	struct TCP_Server_Info *server = tcon->ses->server;
 	const struct smb_version_operations *ops = server->ops;
-	struct cifs_tcon *ipc = tcon->ses->tcon_ipc;
+	struct cifs_ses *root_ses = CIFS_DFS_ROOT_SES(tcon->ses);
+	struct cifs_tcon *ipc = root_ses->tcon_ipc;
 	char *share = NULL, *prefix = NULL;
 	const char *tcp_host;
 	size_t tcp_host_len;
@@ -4208,7 +4209,7 @@ static int __tree_connect_dfs_target(const unsigned int xid, struct cifs_tcon *t
 		 * reconnect so either the demultiplex thread or the echo worker will reconnect to
 		 * newly resolved target.
 		 */
-		if (dfs_cache_find(xid, tcon->ses, cifs_sb->local_nls, cifs_remap(cifs_sb), target,
+		if (dfs_cache_find(xid, root_ses, cifs_sb->local_nls, cifs_remap(cifs_sb), target,
 				   NULL, &ntl)) {
 			rc = ops->tree_connect(xid, tcon->ses, tree, tcon, cifs_sb->local_nls);
 			if (rc)
diff --git a/fs/cifs/dfs.c b/fs/cifs/dfs.c
index 88a0cab335b4..fbc8e880a1fe 100644
--- a/fs/cifs/dfs.c
+++ b/fs/cifs/dfs.c
@@ -95,7 +95,13 @@ static int get_session(struct cifs_mount_ctx *mnt_ctx, const char *full_path)
 	ctx->leaf_fullpath = (char *)full_path;
 	rc = cifs_mount_get_session(mnt_ctx);
 	ctx->leaf_fullpath = NULL;
+	if (!rc) {
+		struct cifs_ses *ses = mnt_ctx->ses;
 
+		mutex_lock(&ses->session_mutex);
+		ses->dfs_root_ses = mnt_ctx->root_ses;
+		mutex_unlock(&ses->session_mutex);
+	}
 	return rc;
 }
 
diff --git a/fs/cifs/dfs_cache.c b/fs/cifs/dfs_cache.c
index bef672534397..95cc3951420e 100644
--- a/fs/cifs/dfs_cache.c
+++ b/fs/cifs/dfs_cache.c
@@ -83,27 +83,6 @@ static void refresh_cache_worker(struct work_struct *work);
 
 static DECLARE_DELAYED_WORK(refresh_task, refresh_cache_worker);
 
-static void get_ipc_unc(const char *ref_path, char *ipc, size_t ipclen)
-{
-	const char *host;
-	size_t len;
-
-	extract_unc_hostname(ref_path, &host, &len);
-	scnprintf(ipc, ipclen, "\\\\%.*s\\IPC$", (int)len, host);
-}
-
-static struct cifs_ses *find_ipc_from_server_path(struct cifs_ses **ses, const char *path)
-{
-	char unc[SERVER_NAME_LENGTH + sizeof("//x/IPC$")] = {0};
-
-	get_ipc_unc(path, unc, sizeof(unc));
-	for (; *ses; ses++) {
-		if (!strcasecmp(unc, (*ses)->tcon_ipc->tree_name))
-			return *ses;
-	}
-	return ERR_PTR(-ENOENT);
-}
-
 static void __mount_group_release(struct mount_group *mg)
 {
 	int i;
@@ -760,8 +739,6 @@ static int get_dfs_referral(const unsigned int xid, struct cifs_ses *ses, const
 	int rc;
 	int i;
 
-	cifs_dbg(FYI, "%s: get an DFS referral for %s\n", __func__, path);
-
 	*refs = NULL;
 	*numrefs = 0;
 
@@ -770,6 +747,7 @@ static int get_dfs_referral(const unsigned int xid, struct cifs_ses *ses, const
 	if (unlikely(!cache_cp))
 		return -EINVAL;
 
+	cifs_dbg(FYI, "%s: ipc=%s referral=%s\n", __func__, ses->tcon_ipc->tree_name, path);
 	rc =  ses->server->ops->get_dfs_refer(xid, ses, path, refs, numrefs, cache_cp,
 					      NO_MAP_UNI_RSVD);
 	if (!rc) {
@@ -1366,10 +1344,9 @@ static void mark_for_reconnect_if_needed(struct cifs_tcon *tcon, struct dfs_cach
 }
 
 /* Refresh dfs referral of tcon and mark it for reconnect if needed */
-static int __refresh_tcon(const char *path, struct cifs_ses **sessions, struct cifs_tcon *tcon,
-			  bool force_refresh)
+static int __refresh_tcon(const char *path, struct cifs_tcon *tcon, bool force_refresh)
 {
-	struct cifs_ses *ses;
+	struct cifs_ses *ses = CIFS_DFS_ROOT_SES(tcon->ses);
 	struct cache_entry *ce;
 	struct dfs_info3_param *refs = NULL;
 	int numrefs = 0;
@@ -1378,11 +1355,7 @@ static int __refresh_tcon(const char *path, struct cifs_ses **sessions, struct c
 	int rc = 0;
 	unsigned int xid;
 
-	ses = find_ipc_from_server_path(sessions, path);
-	if (IS_ERR(ses)) {
-		cifs_dbg(FYI, "%s: could not find ipc session\n", __func__);
-		return PTR_ERR(ses);
-	}
+	xid = get_xid();
 
 	down_read(&htable_rw_lock);
 	ce = lookup_cache_entry(path);
@@ -1399,12 +1372,9 @@ static int __refresh_tcon(const char *path, struct cifs_ses **sessions, struct c
 		goto out;
 	}
 
-	xid = get_xid();
 	rc = get_dfs_referral(xid, ses, path, &refs, &numrefs);
-	free_xid(xid);
-
-	/* Create or update a cache entry with the new referral */
 	if (!rc) {
+		/* Create or update a cache entry with the new referral */
 		dump_refs(refs, numrefs);
 
 		down_write(&htable_rw_lock);
@@ -1419,24 +1389,20 @@ static int __refresh_tcon(const char *path, struct cifs_ses **sessions, struct c
 	}
 
 out:
+	free_xid(xid);
 	dfs_cache_free_tgts(&tl);
 	free_dfs_info_array(refs, numrefs);
 	return rc;
 }
 
-static int refresh_tcon(struct cifs_ses **sessions, struct cifs_tcon *tcon, bool force_refresh)
+static int refresh_tcon(struct cifs_tcon *tcon, bool force_refresh)
 {
 	struct TCP_Server_Info *server = tcon->ses->server;
 
 	mutex_lock(&server->refpath_lock);
-	if (server->origin_fullpath) {
-		if (server->leaf_fullpath && strcasecmp(server->leaf_fullpath,
-							server->origin_fullpath))
-			__refresh_tcon(server->leaf_fullpath + 1, sessions, tcon, force_refresh);
-		__refresh_tcon(server->origin_fullpath + 1, sessions, tcon, force_refresh);
-	}
+	if (server->leaf_fullpath)
+		__refresh_tcon(server->leaf_fullpath + 1, tcon, force_refresh);
 	mutex_unlock(&server->refpath_lock);
-
 	return 0;
 }
 
@@ -1454,9 +1420,6 @@ int dfs_cache_remount_fs(struct cifs_sb_info *cifs_sb)
 {
 	struct cifs_tcon *tcon;
 	struct TCP_Server_Info *server;
-	struct mount_group *mg;
-	struct cifs_ses *sessions[CACHE_MAX_ENTRIES + 1] = {NULL};
-	int rc;
 
 	if (!cifs_sb || !cifs_sb->master_tlink)
 		return -EINVAL;
@@ -1473,21 +1436,6 @@ int dfs_cache_remount_fs(struct cifs_sb_info *cifs_sb)
 		cifs_dbg(FYI, "%s: no dfs mount group id\n", __func__);
 		return -EINVAL;
 	}
-
-	mutex_lock(&mount_group_list_lock);
-	mg = find_mount_group_locked(&cifs_sb->dfs_mount_id);
-	if (IS_ERR(mg)) {
-		mutex_unlock(&mount_group_list_lock);
-		cifs_dbg(FYI, "%s: no ipc session for refreshing referral\n", __func__);
-		return PTR_ERR(mg);
-	}
-	kref_get(&mg->refcount);
-	mutex_unlock(&mount_group_list_lock);
-
-	spin_lock(&mg->lock);
-	memcpy(&sessions, mg->sessions, mg->num_sessions * sizeof(mg->sessions[0]));
-	spin_unlock(&mg->lock);
-
 	/*
 	 * After reconnecting to a different server, unique ids won't match anymore, so we disable
 	 * serverino. This prevents dentry revalidation to think the dentry are stale (ESTALE).
@@ -1498,17 +1446,15 @@ int dfs_cache_remount_fs(struct cifs_sb_info *cifs_sb)
 	 * that have different prefix paths.
 	 */
 	cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH;
-	rc = refresh_tcon(sessions, tcon, true);
 
-	kref_put(&mg->refcount, mount_group_release);
-	return rc;
+	return refresh_tcon(tcon, true);
 }
 
 /*
- * Refresh all active dfs mounts regardless of whether they are in cache or not.
- * (cache can be cleared)
+ * Worker that will refresh DFS cache from all active mounts based on lowest TTL value
+ * from a DFS referral.
  */
-static void refresh_mounts(struct cifs_ses **sessions)
+static void refresh_cache_worker(struct work_struct *work)
 {
 	struct TCP_Server_Info *server;
 	struct cifs_ses *ses;
@@ -1523,9 +1469,19 @@ static void refresh_mounts(struct cifs_ses **sessions)
 			continue;
 
 		list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
+			struct cifs_ses *root_ses = CIFS_DFS_ROOT_SES(ses);
+
+			spin_lock(&root_ses->ses_lock);
+			if (root_ses->ses_status != SES_GOOD) {
+				spin_unlock(&root_ses->ses_lock);
+				continue;
+			}
+			spin_unlock(&root_ses->ses_lock);
+
 			list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
 				spin_lock(&tcon->tc_lock);
-				if (!tcon->ipc && !tcon->need_reconnect) {
+				if (!tcon->ipc && tcon->status != TID_NEW &&
+				    tcon->status != TID_NEED_TCON) {
 					tcon->tc_count++;
 					list_add_tail(&tcon->ulist, &tcons);
 				}
@@ -1542,57 +1498,11 @@ static void refresh_mounts(struct cifs_ses **sessions)
 
 		mutex_lock(&server->refpath_lock);
 		if (server->leaf_fullpath)
-			__refresh_tcon(server->leaf_fullpath + 1, sessions, tcon, false);
+			__refresh_tcon(server->leaf_fullpath + 1, tcon, false);
 		mutex_unlock(&server->refpath_lock);
 
 		cifs_put_tcon(tcon);
 	}
-}
-
-/*
- * Worker that will refresh DFS cache and active mounts based on lowest TTL value from a DFS
- * referral.
- */
-static void refresh_cache_worker(struct work_struct *work)
-{
-	struct list_head mglist;
-	struct mount_group *mg, *tmp_mg;
-	struct cifs_ses *sessions[CACHE_MAX_ENTRIES + 1] = {NULL};
-	int max_sessions = ARRAY_SIZE(sessions) - 1;
-	int i = 0, count;
-
-	INIT_LIST_HEAD(&mglist);
-
-	/* Get refereces of mount groups */
-	mutex_lock(&mount_group_list_lock);
-	list_for_each_entry(mg, &mount_group_list, list) {
-		kref_get(&mg->refcount);
-		list_add(&mg->refresh_list, &mglist);
-	}
-	mutex_unlock(&mount_group_list_lock);
-
-	/* Fill in local array with an NULL-terminated list of all referral server sessions */
-	list_for_each_entry(mg, &mglist, refresh_list) {
-		if (i >= max_sessions)
-			break;
-
-		spin_lock(&mg->lock);
-		if (i + mg->num_sessions > max_sessions)
-			count = max_sessions - i;
-		else
-			count = mg->num_sessions;
-		memcpy(&sessions[i], mg->sessions, count * sizeof(mg->sessions[0]));
-		spin_unlock(&mg->lock);
-		i += count;
-	}
-
-	if (sessions[0])
-		refresh_mounts(sessions);
-
-	list_for_each_entry_safe(mg, tmp_mg, &mglist, refresh_list) {
-		list_del_init(&mg->refresh_list);
-		kref_put(&mg->refcount, mount_group_release);
-	}
 
 	spin_lock(&cache_ttl_lock);
 	queue_delayed_work(dfscache_wq, &refresh_task, cache_ttl * HZ);
-- 
2.34.1


[-- Attachment #4: 0007-cifs-don-t-refresh-cached-referrals-from-unactive-mo.patch --]
[-- Type: text/x-patch, Size: 3082 bytes --]

From 0ce17b4bdb508d223cc07db324ae33113edaf938 Mon Sep 17 00:00:00 2001
From: Paulo Alcantara <pc@cjr.nz>
Date: Tue, 13 Dec 2022 00:29:22 -0300
Subject: [PATCH 07/14] cifs: don't refresh cached referrals from unactive
 mounts

There is no point refreshing cached referrals from unactive mounts as
they will no longer be used and new mounts will either create or
refresh them anyway.

Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
Signed-off-by: Steve French <stfrench@microsoft.com>
---
 fs/cifs/dfs_cache.c | 73 +--------------------------------------------
 1 file changed, 1 insertion(+), 72 deletions(-)

diff --git a/fs/cifs/dfs_cache.c b/fs/cifs/dfs_cache.c
index bf5e674f43b8..bef672534397 100644
--- a/fs/cifs/dfs_cache.c
+++ b/fs/cifs/dfs_cache.c
@@ -1549,74 +1549,6 @@ static void refresh_mounts(struct cifs_ses **sessions)
 	}
 }
 
-static void refresh_cache(struct cifs_ses **sessions)
-{
-	int i;
-	struct cifs_ses *ses;
-	unsigned int xid;
-	char *ref_paths[CACHE_MAX_ENTRIES];
-	int count = 0;
-	struct cache_entry *ce;
-
-	/*
-	 * Refresh all cached entries.  Get all new referrals outside critical section to avoid
-	 * starvation while performing SMB2 IOCTL on broken or slow connections.
-
-	 * The cache entries may cover more paths than the active mounts
-	 * (e.g. domain-based DFS referrals or multi tier DFS setups).
-	 */
-	down_read(&htable_rw_lock);
-	for (i = 0; i < CACHE_HTABLE_SIZE; i++) {
-		struct hlist_head *l = &cache_htable[i];
-
-		hlist_for_each_entry(ce, l, hlist) {
-			if (count == ARRAY_SIZE(ref_paths))
-				goto out_unlock;
-			if (hlist_unhashed(&ce->hlist) || !cache_entry_expired(ce) ||
-			    IS_ERR(find_ipc_from_server_path(sessions, ce->path)))
-				continue;
-			ref_paths[count++] = kstrdup(ce->path, GFP_ATOMIC);
-		}
-	}
-
-out_unlock:
-	up_read(&htable_rw_lock);
-
-	for (i = 0; i < count; i++) {
-		char *path = ref_paths[i];
-		struct dfs_info3_param *refs = NULL;
-		int numrefs = 0;
-		int rc = 0;
-
-		if (!path)
-			continue;
-
-		ses = find_ipc_from_server_path(sessions, path);
-		if (IS_ERR(ses))
-			goto next_referral;
-
-		xid = get_xid();
-		rc = get_dfs_referral(xid, ses, path, &refs, &numrefs);
-		free_xid(xid);
-
-		if (!rc) {
-			down_write(&htable_rw_lock);
-			ce = lookup_cache_entry(path);
-			/*
-			 * We need to re-check it because other tasks might have it deleted or
-			 * updated.
-			 */
-			if (!IS_ERR(ce) && cache_entry_expired(ce))
-				update_cache_entry_locked(ce, refs, numrefs);
-			up_write(&htable_rw_lock);
-		}
-
-next_referral:
-		kfree(path);
-		free_dfs_info_array(refs, numrefs);
-	}
-}
-
 /*
  * Worker that will refresh DFS cache and active mounts based on lowest TTL value from a DFS
  * referral.
@@ -1654,11 +1586,8 @@ static void refresh_cache_worker(struct work_struct *work)
 		i += count;
 	}
 
-	if (sessions[0]) {
-		/* Refresh all active mounts and cached entries */
+	if (sessions[0])
 		refresh_mounts(sessions);
-		refresh_cache(sessions);
-	}
 
 	list_for_each_entry_safe(mg, tmp_mg, &mglist, refresh_list) {
 		list_del_init(&mg->refresh_list);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2022-12-17 16:09 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-12-17 16:08 [PATCH][SMB3 client] DFS/reconnect fixes part 3 of 4 Steve French

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).