All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/4] cifs: fix DFS failover
@ 2021-02-24 23:59 Paulo Alcantara
  2021-02-24 23:59 ` [PATCH 2/4] cifs: check all path components in resolved dfs target Paulo Alcantara
                   ` (3 more replies)
  0 siblings, 4 replies; 10+ messages in thread
From: Paulo Alcantara @ 2021-02-24 23:59 UTC (permalink / raw)
  To: linux-cifs, smfrench; +Cc: Paulo Alcantara

In do_dfs_failover(), the mount_get_conns() function requires the full
fs context in order to get new connection to server, so clone the
original context and change it accordingly when retrying the DFS
targets in the referral.

If failover was successful, then update original context with the new
UNC, prefix path and ip address.

Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
---
 fs/cifs/connect.c | 123 ++++++++++++++++++++++------------------------
 1 file changed, 59 insertions(+), 64 deletions(-)

diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index cd6dbeaf2166..a800e055c614 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -3045,96 +3045,91 @@ static int update_vol_info(const struct dfs_cache_tgt_iterator *tgt_it,
 	return 0;
 }
 
-static int setup_dfs_tgt_conn(const char *path, const char *full_path,
-			      const struct dfs_cache_tgt_iterator *tgt_it,
-			      struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx,
-			      unsigned int *xid, struct TCP_Server_Info **server,
-			      struct cifs_ses **ses, struct cifs_tcon **tcon)
-{
-	int rc;
-	struct dfs_info3_param ref = {0};
-	char *mdata = NULL;
-	struct smb3_fs_context fake_ctx = {NULL};
-	char *fake_devname = NULL;
-
-	cifs_dbg(FYI, "%s: dfs path: %s\n", __func__, path);
-
-	rc = dfs_cache_get_tgt_referral(path, tgt_it, &ref);
-	if (rc)
-		return rc;
-
-	mdata = cifs_compose_mount_options(cifs_sb->ctx->mount_options,
-					   full_path + 1, &ref,
-					   &fake_devname);
-	free_dfs_info_param(&ref);
-
-	if (IS_ERR(mdata)) {
-		rc = PTR_ERR(mdata);
-		mdata = NULL;
-	} else
-		rc = cifs_setup_volume_info(&fake_ctx, mdata, fake_devname);
-
-	kfree(mdata);
-	kfree(fake_devname);
-
-	if (!rc) {
-		/*
-		 * We use a 'fake_ctx' here because we need pass it down to the
-		 * mount_{get,put} functions to test connection against new DFS
-		 * targets.
-		 */
-		mount_put_conns(cifs_sb, *xid, *server, *ses, *tcon);
-		rc = mount_get_conns(&fake_ctx, cifs_sb, xid, server, ses,
-				     tcon);
-		if (!rc || (*server && *ses)) {
-			/*
-			 * We were able to connect to new target server.
-			 * Update current context with new target server.
-			 */
-			rc = update_vol_info(tgt_it, &fake_ctx, ctx);
-		}
-	}
-	smb3_cleanup_fs_context_contents(&fake_ctx);
-	return rc;
-}
-
 static int do_dfs_failover(const char *path, const char *full_path, struct cifs_sb_info *cifs_sb,
 			   struct smb3_fs_context *ctx, struct cifs_ses *root_ses,
 			   unsigned int *xid, struct TCP_Server_Info **server,
 			   struct cifs_ses **ses, struct cifs_tcon **tcon)
 {
 	int rc;
-	struct dfs_cache_tgt_list tgt_list;
+	struct dfs_cache_tgt_list tgt_list = {0};
 	struct dfs_cache_tgt_iterator *tgt_it = NULL;
+	struct smb3_fs_context tmp_ctx = {NULL};
 
 	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS)
 		return -EOPNOTSUPP;
 
+	cifs_dbg(FYI, "%s: path=%s full_path=%s\n", __func__, path, full_path);
+
 	rc = dfs_cache_noreq_find(path, NULL, &tgt_list);
 	if (rc)
 		return rc;
+	/*
+	 * We use a 'tmp_ctx' here because we need pass it down to the mount_{get,put} functions to
+	 * test connection against new DFS targets.
+	 */
+	rc = smb3_fs_context_dup(&tmp_ctx, ctx);
+	if (rc)
+		goto out;
 
 	for (;;) {
+		struct dfs_info3_param ref = {0};
+		char *fake_devname = NULL, *mdata = NULL;
+
 		/* Get next DFS target server - if any */
 		rc = get_next_dfs_tgt(path, &tgt_list, &tgt_it);
 		if (rc)
 			break;
-		/* Connect to next DFS target */
-		rc = setup_dfs_tgt_conn(path, full_path, tgt_it, cifs_sb, ctx, xid, server, ses,
-					tcon);
-		if (!rc || (*server && *ses))
+
+		rc = dfs_cache_get_tgt_referral(path, tgt_it, &ref);
+		if (rc)
 			break;
+
+		cifs_dbg(FYI, "%s: old ctx: UNC=%s prepath=%s\n", __func__, tmp_ctx.UNC,
+			 tmp_ctx.prepath);
+
+		mdata = cifs_compose_mount_options(cifs_sb->ctx->mount_options, full_path + 1, &ref,
+						   &fake_devname);
+		free_dfs_info_param(&ref);
+
+		if (IS_ERR(mdata)) {
+			rc = PTR_ERR(mdata);
+			mdata = NULL;
+		} else
+			rc = cifs_setup_volume_info(&tmp_ctx, mdata, fake_devname);
+
+		kfree(mdata);
+		kfree(fake_devname);
+
+		if (rc)
+			break;
+
+		cifs_dbg(FYI, "%s: new ctx: UNC=%s prepath=%s\n", __func__, tmp_ctx.UNC,
+			 tmp_ctx.prepath);
+
+		mount_put_conns(cifs_sb, *xid, *server, *ses, *tcon);
+		rc = mount_get_conns(&tmp_ctx, cifs_sb, xid, server, ses, tcon);
+		if (!rc || (*server && *ses)) {
+			/*
+			 * We were able to connect to new target server. Update current context with
+			 * new target server.
+			 */
+			rc = update_vol_info(tgt_it, &tmp_ctx, ctx);
+			break;
+		}
 	}
 	if (!rc) {
+		cifs_dbg(FYI, "%s: final ctx: UNC=%s prepath=%s\n", __func__, tmp_ctx.UNC,
+			 tmp_ctx.prepath);
 		/*
-		 * Update DFS target hint in DFS referral cache with the target
-		 * server we successfully reconnected to.
+		 * Update DFS target hint in DFS referral cache with the target server we
+		 * successfully reconnected to.
 		 */
-		rc = dfs_cache_update_tgthint(*xid, root_ses ? root_ses : *ses,
-					      cifs_sb->local_nls,
-					      cifs_remap(cifs_sb), path,
-					      tgt_it);
+		rc = dfs_cache_update_tgthint(*xid, root_ses ? root_ses : *ses, cifs_sb->local_nls,
+					      cifs_remap(cifs_sb), path, tgt_it);
 	}
+
+out:
+	smb3_cleanup_fs_context_contents(&tmp_ctx);
 	dfs_cache_free_tgts(&tgt_list);
 	return rc;
 }
-- 
2.30.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 2/4] cifs: check all path components in resolved dfs target
  2021-02-24 23:59 [PATCH 1/4] cifs: fix DFS failover Paulo Alcantara
@ 2021-02-24 23:59 ` Paulo Alcantara
  2021-02-24 23:59 ` [PATCH 3/4] cifs: introduce helper for finding referral server Paulo Alcantara
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 10+ messages in thread
From: Paulo Alcantara @ 2021-02-24 23:59 UTC (permalink / raw)
  To: linux-cifs, smfrench; +Cc: Paulo Alcantara

Handle the case where a resolved target share is like
//server/users/dir, and the user "foo" has no read permission to
access the parent folder "users" but has access to the final path
component "dir".

is_path_remote() already implements that, so call it directly.

Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
---
 fs/cifs/connect.c | 93 +++++++++++++++++------------------------------
 1 file changed, 33 insertions(+), 60 deletions(-)

diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index a800e055c614..f1729890aca5 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -3287,73 +3287,46 @@ static void put_root_ses(struct cifs_ses *ses)
 		cifs_put_smb_ses(ses);
 }
 
-/* Check if a path component is remote and then update @dfs_path accordingly */
-static int check_dfs_prepath(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx,
-			     const unsigned int xid, struct TCP_Server_Info *server,
-			     struct cifs_tcon *tcon, char **dfs_path)
+/* Set up next dfs prefix path in @dfs_path */
+static int next_dfs_prepath(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx,
+			    const unsigned int xid, struct TCP_Server_Info *server,
+			    struct cifs_tcon *tcon, char **dfs_path)
 {
-	char *path, *s;
-	char sep = CIFS_DIR_SEP(cifs_sb), tmp;
-	char *npath;
-	int rc = 0;
-	int added_treename = tcon->Flags & SMB_SHARE_IS_IN_DFS;
-	int skip = added_treename;
+	char *path, *npath;
+	int added_treename = is_tcon_dfs(tcon);
+	int rc;
 
 	path = cifs_build_path_to_root(ctx, cifs_sb, tcon, added_treename);
 	if (!path)
 		return -ENOMEM;
 
-	/*
-	 * Walk through the path components in @path and check if they're accessible. In case any of
-	 * the components is -EREMOTE, then update @dfs_path with the next DFS referral request path
-	 * (NOT including the remaining components).
-	 */
-	s = path;
-	do {
-		/* skip separators */
-		while (*s && *s == sep)
-			s++;
-		if (!*s)
-			break;
-		/* next separator */
-		while (*s && *s != sep)
-			s++;
-		/*
-		 * if the treename is added, we then have to skip the first
-		 * part within the separators
-		 */
-		if (skip) {
-			skip = 0;
-			continue;
+	rc = is_path_remote(cifs_sb, ctx, xid, server, tcon);
+	if (rc == -EREMOTE) {
+		struct smb3_fs_context v = {NULL};
+		/* if @path contains a tree name, skip it in the prefix path */
+		if (added_treename) {
+			rc = smb3_parse_devname(path, &v);
+			if (rc)
+				goto out;
+			npath = build_unc_path_to_root(&v, cifs_sb, true);
+			smb3_cleanup_fs_context_contents(&v);
+		} else {
+			v.UNC = ctx->UNC;
+			v.prepath = path + 1;
+			npath = build_unc_path_to_root(&v, cifs_sb, true);
 		}
-		tmp = *s;
-		*s = 0;
-		rc = server->ops->is_path_accessible(xid, tcon, cifs_sb, path);
-		if (rc && rc == -EREMOTE) {
-			struct smb3_fs_context v = {NULL};
-			/* if @path contains a tree name, skip it in the prefix path */
-			if (added_treename) {
-				rc = smb3_parse_devname(path, &v);
-				if (rc)
-					break;
-				rc = -EREMOTE;
-				npath = build_unc_path_to_root(&v, cifs_sb, true);
-				smb3_cleanup_fs_context_contents(&v);
-			} else {
-				v.UNC = ctx->UNC;
-				v.prepath = path + 1;
-				npath = build_unc_path_to_root(&v, cifs_sb, true);
-			}
-			if (IS_ERR(npath)) {
-				rc = PTR_ERR(npath);
-				break;
-			}
-			kfree(*dfs_path);
-			*dfs_path = npath;
+
+		if (IS_ERR(npath)) {
+			rc = PTR_ERR(npath);
+			goto out;
 		}
-		*s = tmp;
-	} while (rc == 0);
 
+		kfree(*dfs_path);
+		*dfs_path = npath;
+		rc = -EREMOTE;
+	}
+
+out:
 	kfree(path);
 	return rc;
 }
@@ -3439,8 +3412,8 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
 			put_root_ses(root_ses);
 			set_root_ses(cifs_sb, ses, &root_ses);
 		}
-		/* Check for remaining path components and then continue chasing them (-EREMOTE) */
-		rc = check_dfs_prepath(cifs_sb, ctx, xid, server, tcon, &ref_path);
+		/* Get next dfs path and then continue chasing them if -EREMOTE */
+		rc = next_dfs_prepath(cifs_sb, ctx, xid, server, tcon, &ref_path);
 		/* Prevent recursion on broken link referrals */
 		if (rc == -EREMOTE && ++count > MAX_NESTED_LINKS)
 			rc = -ELOOP;
-- 
2.30.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 3/4] cifs: introduce helper for finding referral server
  2021-02-24 23:59 [PATCH 1/4] cifs: fix DFS failover Paulo Alcantara
  2021-02-24 23:59 ` [PATCH 2/4] cifs: check all path components in resolved dfs target Paulo Alcantara
@ 2021-02-24 23:59 ` Paulo Alcantara
  2021-02-24 23:59 ` [PATCH 4/4] cifs: fix nodfs mount option Paulo Alcantara
  2021-02-25  1:17 ` [PATCH 1/4] cifs: fix DFS failover Steve French
  3 siblings, 0 replies; 10+ messages in thread
From: Paulo Alcantara @ 2021-02-24 23:59 UTC (permalink / raw)
  To: linux-cifs, smfrench; +Cc: Paulo Alcantara

Some servers seem to mistakenly report different values for
capabilities and share flags, so we can't always rely on those values
to decide whether the resolved target can handle any new DFS
referrals.

Add a new helper is_referral_server() to check if all resolved targets
can handle new DFS referrals by directly looking at the
GET_DFS_REFERRAL.ReferralHeaderFlags value as specified in MS-DFSC
2.2.4 RESP_GET_DFS_REFERRAL in addition to is_tcon_dfs().

Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
---
 fs/cifs/connect.c   | 35 ++++++++++++++++++++++++++++++++++-
 fs/cifs/dfs_cache.c | 33 +++++++++++++++++----------------
 2 files changed, 51 insertions(+), 17 deletions(-)

diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index f1729890aca5..37452b2e24b8 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -3331,6 +3331,33 @@ static int next_dfs_prepath(struct cifs_sb_info *cifs_sb, struct smb3_fs_context
 	return rc;
 }
 
+/* Check if resolved targets can handle any DFS referrals */
+static int is_referral_server(const char *ref_path, struct cifs_tcon *tcon, bool *ref_server)
+{
+	int rc;
+	struct dfs_info3_param ref = {0};
+
+	if (is_tcon_dfs(tcon)) {
+		*ref_server = true;
+	} else {
+		cifs_dbg(FYI, "%s: ref_path=%s\n", __func__, ref_path);
+
+		rc = dfs_cache_noreq_find(ref_path, &ref, NULL);
+		if (rc) {
+			cifs_dbg(VFS, "%s: dfs_cache_noreq_find: failed (rc=%d)\n", __func__, rc);
+			return rc;
+		}
+		cifs_dbg(FYI, "%s: ref.flags=0x%x\n", __func__, ref.flags);
+		/*
+		 * Check if all targets are capable of handling DFS referrals as per
+		 * MS-DFSC 2.2.4 RESP_GET_DFS_REFERRAL.
+		 */
+		*ref_server = !!(ref.flags & DFSREF_REFERRAL_SERVER);
+		free_dfs_info_param(&ref);
+	}
+	return 0;
+}
+
 int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
 {
 	int rc = 0;
@@ -3342,6 +3369,7 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
 	char *ref_path = NULL, *full_path = NULL;
 	char *oldmnt = NULL;
 	char *mntdata = NULL;
+	bool ref_server = false;
 
 	rc = mount_get_conns(ctx, cifs_sb, &xid, &server, &ses, &tcon);
 	/*
@@ -3407,11 +3435,16 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
 			break;
 		if (!tcon)
 			continue;
+
 		/* Make sure that requests go through new root servers */
-		if (is_tcon_dfs(tcon)) {
+		rc = is_referral_server(ref_path + 1, tcon, &ref_server);
+		if (rc)
+			break;
+		if (ref_server) {
 			put_root_ses(root_ses);
 			set_root_ses(cifs_sb, ses, &root_ses);
 		}
+
 		/* Get next dfs path and then continue chasing them if -EREMOTE */
 		rc = next_dfs_prepath(cifs_sb, ctx, xid, server, tcon, &ref_path);
 		/* Prevent recursion on broken link referrals */
diff --git a/fs/cifs/dfs_cache.c b/fs/cifs/dfs_cache.c
index 4950ab0486ae..098b4bc8da59 100644
--- a/fs/cifs/dfs_cache.c
+++ b/fs/cifs/dfs_cache.c
@@ -37,11 +37,12 @@ struct cache_dfs_tgt {
 struct cache_entry {
 	struct hlist_node hlist;
 	const char *path;
-	int ttl;
-	int srvtype;
-	int flags;
+	int hdr_flags; /* RESP_GET_DFS_REFERRAL.ReferralHeaderFlags */
+	int ttl; /* DFS_REREFERRAL_V3.TimeToLive */
+	int srvtype; /* DFS_REREFERRAL_V3.ServerType */
+	int ref_flags; /* DFS_REREFERRAL_V3.ReferralEntryFlags */
 	struct timespec64 etime;
-	int path_consumed;
+	int path_consumed; /* RESP_GET_DFS_REFERRAL.PathConsumed */
 	int numtgts;
 	struct list_head tlist;
 	struct cache_dfs_tgt *tgthint;
@@ -166,14 +167,11 @@ static int dfscache_proc_show(struct seq_file *m, void *v)
 				continue;
 
 			seq_printf(m,
-				   "cache entry: path=%s,type=%s,ttl=%d,etime=%ld,"
-				   "interlink=%s,path_consumed=%d,expired=%s\n",
-				   ce->path,
-				   ce->srvtype == DFS_TYPE_ROOT ? "root" : "link",
-				   ce->ttl, ce->etime.tv_nsec,
-				   IS_INTERLINK_SET(ce->flags) ? "yes" : "no",
-				   ce->path_consumed,
-				   cache_entry_expired(ce) ? "yes" : "no");
+				   "cache entry: path=%s,type=%s,ttl=%d,etime=%ld,hdr_flags=0x%x,ref_flags=0x%x,interlink=%s,path_consumed=%d,expired=%s\n",
+				   ce->path, ce->srvtype == DFS_TYPE_ROOT ? "root" : "link",
+				   ce->ttl, ce->etime.tv_nsec, ce->ref_flags, ce->hdr_flags,
+				   IS_INTERLINK_SET(ce->hdr_flags) ? "yes" : "no",
+				   ce->path_consumed, cache_entry_expired(ce) ? "yes" : "no");
 
 			list_for_each_entry(t, &ce->tlist, list) {
 				seq_printf(m, "  %s%s\n",
@@ -236,11 +234,12 @@ static inline void dump_tgts(const struct cache_entry *ce)
 
 static inline void dump_ce(const struct cache_entry *ce)
 {
-	cifs_dbg(FYI, "cache entry: path=%s,type=%s,ttl=%d,etime=%ld,interlink=%s,path_consumed=%d,expired=%s\n",
+	cifs_dbg(FYI, "cache entry: path=%s,type=%s,ttl=%d,etime=%ld,hdr_flags=0x%x,ref_flags=0x%x,interlink=%s,path_consumed=%d,expired=%s\n",
 		 ce->path,
 		 ce->srvtype == DFS_TYPE_ROOT ? "root" : "link", ce->ttl,
 		 ce->etime.tv_nsec,
-		 IS_INTERLINK_SET(ce->flags) ? "yes" : "no",
+		 ce->hdr_flags, ce->ref_flags,
+		 IS_INTERLINK_SET(ce->hdr_flags) ? "yes" : "no",
 		 ce->path_consumed,
 		 cache_entry_expired(ce) ? "yes" : "no");
 	dump_tgts(ce);
@@ -381,7 +380,8 @@ static int copy_ref_data(const struct dfs_info3_param *refs, int numrefs,
 	ce->ttl = refs[0].ttl;
 	ce->etime = get_expire_time(ce->ttl);
 	ce->srvtype = refs[0].server_type;
-	ce->flags = refs[0].ref_flag;
+	ce->hdr_flags = refs[0].flags;
+	ce->ref_flags = refs[0].ref_flag;
 	ce->path_consumed = refs[0].path_consumed;
 
 	for (i = 0; i < numrefs; i++) {
@@ -799,7 +799,8 @@ static int setup_referral(const char *path, struct cache_entry *ce,
 	ref->path_consumed = ce->path_consumed;
 	ref->ttl = ce->ttl;
 	ref->server_type = ce->srvtype;
-	ref->ref_flag = ce->flags;
+	ref->ref_flag = ce->ref_flags;
+	ref->flags = ce->hdr_flags;
 
 	return 0;
 
-- 
2.30.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 4/4] cifs: fix nodfs mount option
  2021-02-24 23:59 [PATCH 1/4] cifs: fix DFS failover Paulo Alcantara
  2021-02-24 23:59 ` [PATCH 2/4] cifs: check all path components in resolved dfs target Paulo Alcantara
  2021-02-24 23:59 ` [PATCH 3/4] cifs: introduce helper for finding referral server Paulo Alcantara
@ 2021-02-24 23:59 ` Paulo Alcantara
  2021-02-25  6:04   ` Shyam Prasad N
  2021-02-25  1:17 ` [PATCH 1/4] cifs: fix DFS failover Steve French
  3 siblings, 1 reply; 10+ messages in thread
From: Paulo Alcantara @ 2021-02-24 23:59 UTC (permalink / raw)
  To: linux-cifs, smfrench; +Cc: Paulo Alcantara

Skip DFS resolving when mounting with 'nodfs' even if
CONFIG_CIFS_DFS_UPCALL is enabled.

Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
---
 fs/cifs/connect.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 37452b2e24b8..6ab5f96fe1b4 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -3373,15 +3373,15 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
 
 	rc = mount_get_conns(ctx, cifs_sb, &xid, &server, &ses, &tcon);
 	/*
-	 * Unconditionally try to get an DFS referral (even cached) to determine whether it is an
-	 * DFS mount.
+	 * If called with 'nodfs' mount option, then skip DFS resolving.  Otherwise unconditionally
+	 * try to get an DFS referral (even cached) to determine whether it is an DFS mount.
 	 *
 	 * Skip prefix path to provide support for DFS referrals from w2k8 servers which don't seem
 	 * to respond with PATH_NOT_COVERED to requests that include the prefix.
 	 */
-	if (dfs_cache_find(xid, ses, cifs_sb->local_nls, cifs_remap(cifs_sb), ctx->UNC + 1, NULL,
+	if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS) ||
+	    dfs_cache_find(xid, ses, cifs_sb->local_nls, cifs_remap(cifs_sb), ctx->UNC + 1, NULL,
 			   NULL)) {
-		/* No DFS referral was returned.  Looks like a regular share. */
 		if (rc)
 			goto error;
 		/* Check if it is fully accessible and then mount it */
-- 
2.30.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/4] cifs: fix DFS failover
  2021-02-24 23:59 [PATCH 1/4] cifs: fix DFS failover Paulo Alcantara
                   ` (2 preceding siblings ...)
  2021-02-24 23:59 ` [PATCH 4/4] cifs: fix nodfs mount option Paulo Alcantara
@ 2021-02-25  1:17 ` Steve French
  2021-02-25  1:23   ` Paulo Alcantara
  3 siblings, 1 reply; 10+ messages in thread
From: Steve French @ 2021-02-25  1:17 UTC (permalink / raw)
  To: Paulo Alcantara; +Cc: CIFS

is this series of 4 identical with
   https://git.cjr.nz/linux.git/commit/?h=dfs-fixes-v2

On Wed, Feb 24, 2021 at 6:00 PM Paulo Alcantara <pc@cjr.nz> wrote:
>
> In do_dfs_failover(), the mount_get_conns() function requires the full
> fs context in order to get new connection to server, so clone the
> original context and change it accordingly when retrying the DFS
> targets in the referral.
>
> If failover was successful, then update original context with the new
> UNC, prefix path and ip address.
>
> Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
> ---
>  fs/cifs/connect.c | 123 ++++++++++++++++++++++------------------------
>  1 file changed, 59 insertions(+), 64 deletions(-)
>
> diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
> index cd6dbeaf2166..a800e055c614 100644
> --- a/fs/cifs/connect.c
> +++ b/fs/cifs/connect.c
> @@ -3045,96 +3045,91 @@ static int update_vol_info(const struct dfs_cache_tgt_iterator *tgt_it,
>         return 0;
>  }
>
> -static int setup_dfs_tgt_conn(const char *path, const char *full_path,
> -                             const struct dfs_cache_tgt_iterator *tgt_it,
> -                             struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx,
> -                             unsigned int *xid, struct TCP_Server_Info **server,
> -                             struct cifs_ses **ses, struct cifs_tcon **tcon)
> -{
> -       int rc;
> -       struct dfs_info3_param ref = {0};
> -       char *mdata = NULL;
> -       struct smb3_fs_context fake_ctx = {NULL};
> -       char *fake_devname = NULL;
> -
> -       cifs_dbg(FYI, "%s: dfs path: %s\n", __func__, path);
> -
> -       rc = dfs_cache_get_tgt_referral(path, tgt_it, &ref);
> -       if (rc)
> -               return rc;
> -
> -       mdata = cifs_compose_mount_options(cifs_sb->ctx->mount_options,
> -                                          full_path + 1, &ref,
> -                                          &fake_devname);
> -       free_dfs_info_param(&ref);
> -
> -       if (IS_ERR(mdata)) {
> -               rc = PTR_ERR(mdata);
> -               mdata = NULL;
> -       } else
> -               rc = cifs_setup_volume_info(&fake_ctx, mdata, fake_devname);
> -
> -       kfree(mdata);
> -       kfree(fake_devname);
> -
> -       if (!rc) {
> -               /*
> -                * We use a 'fake_ctx' here because we need pass it down to the
> -                * mount_{get,put} functions to test connection against new DFS
> -                * targets.
> -                */
> -               mount_put_conns(cifs_sb, *xid, *server, *ses, *tcon);
> -               rc = mount_get_conns(&fake_ctx, cifs_sb, xid, server, ses,
> -                                    tcon);
> -               if (!rc || (*server && *ses)) {
> -                       /*
> -                        * We were able to connect to new target server.
> -                        * Update current context with new target server.
> -                        */
> -                       rc = update_vol_info(tgt_it, &fake_ctx, ctx);
> -               }
> -       }
> -       smb3_cleanup_fs_context_contents(&fake_ctx);
> -       return rc;
> -}
> -
>  static int do_dfs_failover(const char *path, const char *full_path, struct cifs_sb_info *cifs_sb,
>                            struct smb3_fs_context *ctx, struct cifs_ses *root_ses,
>                            unsigned int *xid, struct TCP_Server_Info **server,
>                            struct cifs_ses **ses, struct cifs_tcon **tcon)
>  {
>         int rc;
> -       struct dfs_cache_tgt_list tgt_list;
> +       struct dfs_cache_tgt_list tgt_list = {0};
>         struct dfs_cache_tgt_iterator *tgt_it = NULL;
> +       struct smb3_fs_context tmp_ctx = {NULL};
>
>         if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS)
>                 return -EOPNOTSUPP;
>
> +       cifs_dbg(FYI, "%s: path=%s full_path=%s\n", __func__, path, full_path);
> +
>         rc = dfs_cache_noreq_find(path, NULL, &tgt_list);
>         if (rc)
>                 return rc;
> +       /*
> +        * We use a 'tmp_ctx' here because we need pass it down to the mount_{get,put} functions to
> +        * test connection against new DFS targets.
> +        */
> +       rc = smb3_fs_context_dup(&tmp_ctx, ctx);
> +       if (rc)
> +               goto out;
>
>         for (;;) {
> +               struct dfs_info3_param ref = {0};
> +               char *fake_devname = NULL, *mdata = NULL;
> +
>                 /* Get next DFS target server - if any */
>                 rc = get_next_dfs_tgt(path, &tgt_list, &tgt_it);
>                 if (rc)
>                         break;
> -               /* Connect to next DFS target */
> -               rc = setup_dfs_tgt_conn(path, full_path, tgt_it, cifs_sb, ctx, xid, server, ses,
> -                                       tcon);
> -               if (!rc || (*server && *ses))
> +
> +               rc = dfs_cache_get_tgt_referral(path, tgt_it, &ref);
> +               if (rc)
>                         break;
> +
> +               cifs_dbg(FYI, "%s: old ctx: UNC=%s prepath=%s\n", __func__, tmp_ctx.UNC,
> +                        tmp_ctx.prepath);
> +
> +               mdata = cifs_compose_mount_options(cifs_sb->ctx->mount_options, full_path + 1, &ref,
> +                                                  &fake_devname);
> +               free_dfs_info_param(&ref);
> +
> +               if (IS_ERR(mdata)) {
> +                       rc = PTR_ERR(mdata);
> +                       mdata = NULL;
> +               } else
> +                       rc = cifs_setup_volume_info(&tmp_ctx, mdata, fake_devname);
> +
> +               kfree(mdata);
> +               kfree(fake_devname);
> +
> +               if (rc)
> +                       break;
> +
> +               cifs_dbg(FYI, "%s: new ctx: UNC=%s prepath=%s\n", __func__, tmp_ctx.UNC,
> +                        tmp_ctx.prepath);
> +
> +               mount_put_conns(cifs_sb, *xid, *server, *ses, *tcon);
> +               rc = mount_get_conns(&tmp_ctx, cifs_sb, xid, server, ses, tcon);
> +               if (!rc || (*server && *ses)) {
> +                       /*
> +                        * We were able to connect to new target server. Update current context with
> +                        * new target server.
> +                        */
> +                       rc = update_vol_info(tgt_it, &tmp_ctx, ctx);
> +                       break;
> +               }
>         }
>         if (!rc) {
> +               cifs_dbg(FYI, "%s: final ctx: UNC=%s prepath=%s\n", __func__, tmp_ctx.UNC,
> +                        tmp_ctx.prepath);
>                 /*
> -                * Update DFS target hint in DFS referral cache with the target
> -                * server we successfully reconnected to.
> +                * Update DFS target hint in DFS referral cache with the target server we
> +                * successfully reconnected to.
>                  */
> -               rc = dfs_cache_update_tgthint(*xid, root_ses ? root_ses : *ses,
> -                                             cifs_sb->local_nls,
> -                                             cifs_remap(cifs_sb), path,
> -                                             tgt_it);
> +               rc = dfs_cache_update_tgthint(*xid, root_ses ? root_ses : *ses, cifs_sb->local_nls,
> +                                             cifs_remap(cifs_sb), path, tgt_it);
>         }
> +
> +out:
> +       smb3_cleanup_fs_context_contents(&tmp_ctx);
>         dfs_cache_free_tgts(&tgt_list);
>         return rc;
>  }
> --
> 2.30.1
>


-- 
Thanks,

Steve

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/4] cifs: fix DFS failover
  2021-02-25  1:17 ` [PATCH 1/4] cifs: fix DFS failover Steve French
@ 2021-02-25  1:23   ` Paulo Alcantara
  2021-02-25  3:34     ` Steve French
  0 siblings, 1 reply; 10+ messages in thread
From: Paulo Alcantara @ 2021-02-25  1:23 UTC (permalink / raw)
  To: Steve French; +Cc: CIFS

Steve French <smfrench@gmail.com> writes:

> is this series of 4 identical with
>    https://git.cjr.nz/linux.git/commit/?h=dfs-fixes-v2

Nope.  Please pull from git://git.cjr.nz/linux.git dfs-fixes

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/4] cifs: fix DFS failover
  2021-02-25  1:23   ` Paulo Alcantara
@ 2021-02-25  3:34     ` Steve French
  2021-02-25 18:25       ` Steve French
  0 siblings, 1 reply; 10+ messages in thread
From: Steve French @ 2021-02-25  3:34 UTC (permalink / raw)
  To: Paulo Alcantara; +Cc: CIFS

git diff dfs-fixes..dfs-fixes-v2      showed no differences between
the two branches

And should we cc: Stable #5.10

On Wed, Feb 24, 2021 at 7:23 PM Paulo Alcantara <pc@cjr.nz> wrote:
>
> Steve French <smfrench@gmail.com> writes:
>
> > is this series of 4 identical with
> >    https://git.cjr.nz/linux.git/commit/?h=dfs-fixes-v2
>
> Nope.  Please pull from git://git.cjr.nz/linux.git dfs-fixes



-- 
Thanks,

Steve

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 4/4] cifs: fix nodfs mount option
  2021-02-24 23:59 ` [PATCH 4/4] cifs: fix nodfs mount option Paulo Alcantara
@ 2021-02-25  6:04   ` Shyam Prasad N
  0 siblings, 0 replies; 10+ messages in thread
From: Shyam Prasad N @ 2021-02-25  6:04 UTC (permalink / raw)
  To: Paulo Alcantara; +Cc: CIFS, Steve French

Reviewed-by: Shyam Prasad N <sprasad@microsoft.com>

On Thu, Feb 25, 2021 at 10:16 AM Paulo Alcantara <pc@cjr.nz> wrote:
>
> Skip DFS resolving when mounting with 'nodfs' even if
> CONFIG_CIFS_DFS_UPCALL is enabled.
>
> Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
> ---
>  fs/cifs/connect.c | 8 ++++----
>  1 file changed, 4 insertions(+), 4 deletions(-)
>
> diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
> index 37452b2e24b8..6ab5f96fe1b4 100644
> --- a/fs/cifs/connect.c
> +++ b/fs/cifs/connect.c
> @@ -3373,15 +3373,15 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
>
>         rc = mount_get_conns(ctx, cifs_sb, &xid, &server, &ses, &tcon);
>         /*
> -        * Unconditionally try to get an DFS referral (even cached) to determine whether it is an
> -        * DFS mount.
> +        * If called with 'nodfs' mount option, then skip DFS resolving.  Otherwise unconditionally
> +        * try to get an DFS referral (even cached) to determine whether it is an DFS mount.
>          *
>          * Skip prefix path to provide support for DFS referrals from w2k8 servers which don't seem
>          * to respond with PATH_NOT_COVERED to requests that include the prefix.
>          */
> -       if (dfs_cache_find(xid, ses, cifs_sb->local_nls, cifs_remap(cifs_sb), ctx->UNC + 1, NULL,
> +       if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS) ||
> +           dfs_cache_find(xid, ses, cifs_sb->local_nls, cifs_remap(cifs_sb), ctx->UNC + 1, NULL,
>                            NULL)) {
> -               /* No DFS referral was returned.  Looks like a regular share. */
>                 if (rc)
>                         goto error;
>                 /* Check if it is fully accessible and then mount it */
> --
> 2.30.1
>


-- 
Regards,
Shyam

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/4] cifs: fix DFS failover
  2021-02-25  3:34     ` Steve French
@ 2021-02-25 18:25       ` Steve French
  2021-02-25 18:25         ` Steve French
  0 siblings, 1 reply; 10+ messages in thread
From: Steve French @ 2021-02-25 18:25 UTC (permalink / raw)
  To: Paulo Alcantara; +Cc: CIFS

I pushed the 4 in your email attachment to cifs-2.6 for-next

They differed only in patch 3 from the one in dfs-fixes-v2

Let me know if the correct version is in for-next

On Wed, Feb 24, 2021 at 9:34 PM Steve French <smfrench@gmail.com> wrote:
>
> git diff dfs-fixes..dfs-fixes-v2      showed no differences between
> the two branches
>
> And should we cc: Stable #5.10
>
> On Wed, Feb 24, 2021 at 7:23 PM Paulo Alcantara <pc@cjr.nz> wrote:
> >
> > Steve French <smfrench@gmail.com> writes:
> >
> > > is this series of 4 identical with
> > >    https://git.cjr.nz/linux.git/commit/?h=dfs-fixes-v2
> >
> > Nope.  Please pull from git://git.cjr.nz/linux.git dfs-fixes
>
>
>
> --
> Thanks,
>
> Steve



-- 
Thanks,

Steve

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/4] cifs: fix DFS failover
  2021-02-25 18:25       ` Steve French
@ 2021-02-25 18:25         ` Steve French
  0 siblings, 0 replies; 10+ messages in thread
From: Steve French @ 2021-02-25 18:25 UTC (permalink / raw)
  To: Paulo Alcantara; +Cc: CIFS

I also added cc: stable # 5.11

On Thu, Feb 25, 2021 at 12:25 PM Steve French <smfrench@gmail.com> wrote:
>
> I pushed the 4 in your email attachment to cifs-2.6 for-next
>
> They differed only in patch 3 from the one in dfs-fixes-v2
>
> Let me know if the correct version is in for-next
>
> On Wed, Feb 24, 2021 at 9:34 PM Steve French <smfrench@gmail.com> wrote:
> >
> > git diff dfs-fixes..dfs-fixes-v2      showed no differences between
> > the two branches
> >
> > And should we cc: Stable #5.10
> >
> > On Wed, Feb 24, 2021 at 7:23 PM Paulo Alcantara <pc@cjr.nz> wrote:
> > >
> > > Steve French <smfrench@gmail.com> writes:
> > >
> > > > is this series of 4 identical with
> > > >    https://git.cjr.nz/linux.git/commit/?h=dfs-fixes-v2
> > >
> > > Nope.  Please pull from git://git.cjr.nz/linux.git dfs-fixes
> >
> >
> >
> > --
> > Thanks,
> >
> > Steve
>
>
>
> --
> Thanks,
>
> Steve



-- 
Thanks,

Steve

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2021-02-25 18:26 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-02-24 23:59 [PATCH 1/4] cifs: fix DFS failover Paulo Alcantara
2021-02-24 23:59 ` [PATCH 2/4] cifs: check all path components in resolved dfs target Paulo Alcantara
2021-02-24 23:59 ` [PATCH 3/4] cifs: introduce helper for finding referral server Paulo Alcantara
2021-02-24 23:59 ` [PATCH 4/4] cifs: fix nodfs mount option Paulo Alcantara
2021-02-25  6:04   ` Shyam Prasad N
2021-02-25  1:17 ` [PATCH 1/4] cifs: fix DFS failover Steve French
2021-02-25  1:23   ` Paulo Alcantara
2021-02-25  3:34     ` Steve French
2021-02-25 18:25       ` Steve French
2021-02-25 18:25         ` Steve French

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.