linux-cifs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/17] cifs.ko fixes
@ 2023-08-17 15:33 Paulo Alcantara
  2023-08-17 15:33 ` [PATCH 01/17] smb: client: introduce DFS_CACHE_TGT_LIST() Paulo Alcantara
                   ` (17 more replies)
  0 siblings, 18 replies; 21+ messages in thread
From: Paulo Alcantara @ 2023-08-17 15:33 UTC (permalink / raw)
  To: smfrench; +Cc: linux-cifs, Paulo Alcantara

Hi Steve,

Follow patchset with DFS, reparse point and -Wframe-larger-than fixes
for v6.6.

Please review & test.

Paulo Alcantara (17):
  smb: client: introduce DFS_CACHE_TGT_LIST()
  smb: client: ensure to try all targets when finding nested links
  smb: client: move some params to cifs_open_info_data
  smb: client: make smb2_compound_op() return resp buffer on success
  smb: client: rename cifs_dfs_ref.c to namespace.c
  smb: client: get rid of dfs naming in automount code
  smb: client: get rid of dfs code dep in namespace.c
  smb: client: parse reparse point flag in create response
  smb: client: do not query reparse points twice on symlinks
  smb: client: query reparse points in older dialects
  smb: cilent: set reparse mount points as automounts
  smb: client: reduce stack usage in cifs_try_adding_channels()
  smb: client: reduce stack usage in cifs_demultiplex_thread()
  smb: client: reduce stack usage in smb_send_rqst()
  smb: client: reduce stack usage in smb2_set_ea()
  smb: client: reduce stack usage in smb2_query_info_compound()
  smb: client: reduce stack usage in smb2_query_reparse_point()

 fs/smb/client/Makefile                        |   5 +-
 fs/smb/client/cifsfs.c                        |   2 +-
 fs/smb/client/cifsfs.h                        |  11 +-
 fs/smb/client/cifsglob.h                      |  69 ++-
 fs/smb/client/cifsproto.h                     |   9 +-
 fs/smb/client/connect.c                       |   8 +-
 fs/smb/client/dfs.c                           | 291 +++++-----
 fs/smb/client/dfs.h                           | 141 +++--
 fs/smb/client/dfs_cache.c                     |  10 +-
 fs/smb/client/dfs_cache.h                     |  12 +-
 fs/smb/client/dir.c                           |   4 +-
 fs/smb/client/inode.c                         | 530 ++++++++++--------
 fs/smb/client/{cifs_dfs_ref.c => namespace.c} | 113 ++--
 fs/smb/client/readdir.c                       |  23 +-
 fs/smb/client/sess.c                          |  68 ++-
 fs/smb/client/smb1ops.c                       |  26 +-
 fs/smb/client/smb2inode.c                     | 199 ++++---
 fs/smb/client/smb2ops.c                       | 283 +++-------
 fs/smb/client/smb2proto.h                     |  17 +-
 fs/smb/client/transport.c                     |  29 +-
 20 files changed, 993 insertions(+), 857 deletions(-)
 rename fs/smb/client/{cifs_dfs_ref.c => namespace.c} (62%)

-- 
2.41.0


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

* [PATCH 01/17] smb: client: introduce DFS_CACHE_TGT_LIST()
  2023-08-17 15:33 [PATCH 00/17] cifs.ko fixes Paulo Alcantara
@ 2023-08-17 15:33 ` Paulo Alcantara
  2023-08-17 15:34 ` [PATCH 02/17] smb: client: ensure to try all targets when finding nested links Paulo Alcantara
                   ` (16 subsequent siblings)
  17 siblings, 0 replies; 21+ messages in thread
From: Paulo Alcantara @ 2023-08-17 15:33 UTC (permalink / raw)
  To: smfrench; +Cc: linux-cifs, Paulo Alcantara

Add new helper which declares and initialises target list of a DFS
referral rather having to do both separately.

No functional changes.

Signed-off-by: Paulo Alcantara (SUSE) <pc@manguebit.com>
---
 fs/smb/client/connect.c   | 4 ++--
 fs/smb/client/dfs.c       | 6 +++---
 fs/smb/client/dfs_cache.c | 4 ++--
 fs/smb/client/dfs_cache.h | 6 +++++-
 4 files changed, 12 insertions(+), 8 deletions(-)

diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c
index 238538dde4e3..b3461d5d0f7d 100644
--- a/fs/smb/client/connect.c
+++ b/fs/smb/client/connect.c
@@ -453,10 +453,10 @@ static int reconnect_target_unlocked(struct TCP_Server_Info *server, struct dfs_
 
 static int reconnect_dfs_server(struct TCP_Server_Info *server)
 {
-	int rc = 0;
-	struct dfs_cache_tgt_list tl = DFS_CACHE_TGT_LIST_INIT(tl);
 	struct dfs_cache_tgt_iterator *target_hint = NULL;
+	DFS_CACHE_TGT_LIST(tl);
 	int num_targets = 0;
+	int rc = 0;
 
 	/*
 	 * Determine the number of dfs targets the referral path in @cifs_sb resolves to.
diff --git a/fs/smb/client/dfs.c b/fs/smb/client/dfs.c
index ee772c3d9f00..c837800c49d4 100644
--- a/fs/smb/client/dfs.c
+++ b/fs/smb/client/dfs.c
@@ -174,7 +174,7 @@ static int __dfs_mount_share(struct cifs_mount_ctx *mnt_ctx)
 	}
 
 	do {
-		struct dfs_cache_tgt_list tl = DFS_CACHE_TGT_LIST_INIT(tl);
+		DFS_CACHE_TGT_LIST(tl);
 
 		rc = dfs_get_referral(mnt_ctx, ref_path + 1, NULL, &tl);
 		if (rc) {
@@ -426,7 +426,7 @@ static int __tree_connect_dfs_target(const unsigned int xid, struct cifs_tcon *t
 	/* Try to tree connect to all dfs targets */
 	for (; tit; tit = dfs_cache_get_next_tgt(tl, tit)) {
 		const char *target = dfs_cache_get_tgt_name(tit);
-		struct dfs_cache_tgt_list ntl = DFS_CACHE_TGT_LIST_INIT(ntl);
+		DFS_CACHE_TGT_LIST(ntl);
 
 		kfree(share);
 		kfree(prefix);
@@ -520,7 +520,7 @@ int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, const stru
 	int rc;
 	struct TCP_Server_Info *server = tcon->ses->server;
 	const struct smb_version_operations *ops = server->ops;
-	struct dfs_cache_tgt_list tl = DFS_CACHE_TGT_LIST_INIT(tl);
+	DFS_CACHE_TGT_LIST(tl);
 	struct cifs_sb_info *cifs_sb = NULL;
 	struct super_block *sb = NULL;
 	struct dfs_info3_param ref = {0};
diff --git a/fs/smb/client/dfs_cache.c b/fs/smb/client/dfs_cache.c
index 33adf43a01f1..89b8af831a43 100644
--- a/fs/smb/client/dfs_cache.c
+++ b/fs/smb/client/dfs_cache.c
@@ -1177,9 +1177,9 @@ static bool is_ses_good(struct cifs_ses *ses)
 /* Refresh dfs referral of tcon and mark it for reconnect if needed */
 static int __refresh_tcon(const char *path, struct cifs_ses *ses, bool force_refresh)
 {
-	struct dfs_cache_tgt_list old_tl = DFS_CACHE_TGT_LIST_INIT(old_tl);
-	struct dfs_cache_tgt_list new_tl = DFS_CACHE_TGT_LIST_INIT(new_tl);
 	struct TCP_Server_Info *server = ses->server;
+	DFS_CACHE_TGT_LIST(old_tl);
+	DFS_CACHE_TGT_LIST(new_tl);
 	bool needs_refresh = false;
 	struct cache_entry *ce;
 	unsigned int xid;
diff --git a/fs/smb/client/dfs_cache.h b/fs/smb/client/dfs_cache.h
index c6d89cd6d4fd..c6abc524855f 100644
--- a/fs/smb/client/dfs_cache.h
+++ b/fs/smb/client/dfs_cache.h
@@ -16,7 +16,11 @@
 extern struct workqueue_struct *dfscache_wq;
 extern atomic_t dfs_cache_ttl;
 
-#define DFS_CACHE_TGT_LIST_INIT(var) { .tl_numtgts = 0, .tl_list = LIST_HEAD_INIT((var).tl_list), }
+#define DFS_CACHE_TGT_LIST_INIT(var) \
+	{ .tl_numtgts = 0, .tl_list = LIST_HEAD_INIT((var).tl_list), }
+
+#define DFS_CACHE_TGT_LIST(var) \
+	struct dfs_cache_tgt_list var = DFS_CACHE_TGT_LIST_INIT(var)
 
 struct dfs_cache_tgt_list {
 	int tl_numtgts;
-- 
2.41.0


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

* [PATCH 02/17] smb: client: ensure to try all targets when finding nested links
  2023-08-17 15:33 [PATCH 00/17] cifs.ko fixes Paulo Alcantara
  2023-08-17 15:33 ` [PATCH 01/17] smb: client: introduce DFS_CACHE_TGT_LIST() Paulo Alcantara
@ 2023-08-17 15:34 ` Paulo Alcantara
  2023-08-17 15:34 ` [PATCH 03/17] smb: client: move some params to cifs_open_info_data Paulo Alcantara
                   ` (15 subsequent siblings)
  17 siblings, 0 replies; 21+ messages in thread
From: Paulo Alcantara @ 2023-08-17 15:34 UTC (permalink / raw)
  To: smfrench; +Cc: linux-cifs, Paulo Alcantara

With current implementation, when a nested DFS link is found during
mount(2), the client follows the referral and then try to connect to
all of its targets.  If all targets failed, the client bails out
rather than retrying remaining targets from previous referral.

Fix this by stacking all referrals and targets so the client can retry
remaining targets from previous referrals in case all targets of
current referral have failed.

Thanks to samba, this can be easily tested like below

* Run the following under dfs folder in samba server

  $ ln -s "msdfs:srv\\bad-share" link1
  $ ln -s "msdfs:srv\\dfs\\link1,srv\\good-share" link0

* Before patch

  $ mount.cifs //srv/dfs/link0 /mnt -o ...
  mount error(2): No such file or directory
  Refer to the mount.cifs(8) manual page (e.g. man mount.cifs)...

* After patch

  $ mount.cifs //srv/dfs/link0 /mnt -o ...
  # ls /mnt
  bar  fileshare1  sub

Signed-off-by: Paulo Alcantara (SUSE) <pc@manguebit.com>
---
 fs/smb/client/cifsglob.h  |  16 ++-
 fs/smb/client/dfs.c       | 271 ++++++++++++++++++++------------------
 fs/smb/client/dfs.h       | 104 +++++++++++++++
 fs/smb/client/dfs_cache.c |   6 +-
 fs/smb/client/dfs_cache.h |   6 +-
 5 files changed, 265 insertions(+), 138 deletions(-)

diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
index 657dee4b2c8c..712557c2d526 100644
--- a/fs/smb/client/cifsglob.h
+++ b/fs/smb/client/cifsglob.h
@@ -1721,11 +1721,23 @@ struct cifs_mount_ctx {
 	struct list_head dfs_ses_list;
 };
 
+static inline void __free_dfs_info_param(struct dfs_info3_param *param)
+{
+	kfree(param->path_name);
+	kfree(param->node_name);
+}
+
 static inline void free_dfs_info_param(struct dfs_info3_param *param)
+{
+	if (param)
+		__free_dfs_info_param(param);
+}
+
+static inline void zfree_dfs_info_param(struct dfs_info3_param *param)
 {
 	if (param) {
-		kfree(param->path_name);
-		kfree(param->node_name);
+		__free_dfs_info_param(param);
+		memset(param, 0, sizeof(*param));
 	}
 }
 
diff --git a/fs/smb/client/dfs.c b/fs/smb/client/dfs.c
index c837800c49d4..71ee74041884 100644
--- a/fs/smb/client/dfs.c
+++ b/fs/smb/client/dfs.c
@@ -3,7 +3,6 @@
  * Copyright (c) 2022 Paulo Alcantara <palcantara@suse.de>
  */
 
-#include <linux/namei.h>
 #include "cifsproto.h"
 #include "cifs_debug.h"
 #include "dns_resolve.h"
@@ -96,51 +95,134 @@ static int add_root_smb_session(struct cifs_mount_ctx *mnt_ctx)
 	return 0;
 }
 
-static int get_dfs_conn(struct cifs_mount_ctx *mnt_ctx, const char *ref_path, const char *full_path,
-			const struct dfs_cache_tgt_iterator *tit)
+static inline int parse_dfs_target(struct smb3_fs_context *ctx,
+				   struct dfs_ref_walk *rw,
+				   struct dfs_info3_param *tgt)
+{
+	int rc;
+	const char *fpath = ref_walk_fpath(rw) + 1;
+
+	rc = ref_walk_get_tgt(rw, tgt);
+	if (!rc)
+		rc = dfs_parse_target_referral(fpath, tgt, ctx);
+	return rc;
+}
+
+static int set_ref_paths(struct cifs_mount_ctx *mnt_ctx,
+			 struct dfs_info3_param *tgt,
+			 struct dfs_ref_walk *rw)
+{
+	struct smb3_fs_context *ctx = mnt_ctx->fs_ctx;
+	struct cifs_sb_info *cifs_sb = mnt_ctx->cifs_sb;
+	char *ref_path, *full_path;
+	int rc;
+
+	full_path = smb3_fs_context_fullpath(ctx, CIFS_DIR_SEP(cifs_sb));
+	if (IS_ERR(full_path))
+		return PTR_ERR(full_path);
+
+	if (!tgt || (tgt->server_type == DFS_TYPE_LINK &&
+		     DFS_INTERLINK(tgt->flags)))
+		ref_path = dfs_get_path(cifs_sb, ctx->UNC);
+	else
+		ref_path = dfs_get_path(cifs_sb, full_path);
+	if (IS_ERR(ref_path)) {
+		rc = PTR_ERR(ref_path);
+		kfree(full_path);
+		return rc;
+	}
+	ref_walk_path(rw) = ref_path;
+	ref_walk_fpath(rw) = full_path;
+	return 0;
+}
+
+static int __dfs_referral_walk(struct cifs_mount_ctx *mnt_ctx,
+			       struct dfs_ref_walk *rw)
 {
 	struct smb3_fs_context *ctx = mnt_ctx->fs_ctx;
-	struct dfs_info3_param ref = {};
+	struct dfs_info3_param tgt = {};
 	bool is_refsrv;
-	int rc, rc2;
-
-	rc = dfs_cache_get_tgt_referral(ref_path + 1, tit, &ref);
-	if (rc)
-		return rc;
-
-	rc = dfs_parse_target_referral(full_path + 1, &ref, ctx);
-	if (rc)
-		goto out;
-
-	cifs_mount_put_conns(mnt_ctx);
-	rc = get_session(mnt_ctx, ref_path);
-	if (rc)
-		goto out;
-
-	is_refsrv = !!(ref.flags & DFSREF_REFERRAL_SERVER);
-
-	rc = -EREMOTE;
-	if (ref.flags & DFSREF_STORAGE_SERVER) {
-		rc = cifs_mount_get_tcon(mnt_ctx);
-		if (rc)
-			goto out;
-
-		/* some servers may not advertise referral capability under ref.flags */
-		is_refsrv |= is_tcon_dfs(mnt_ctx->tcon);
-
-		rc = cifs_is_path_remote(mnt_ctx);
-	}
-
-	dfs_cache_noreq_update_tgthint(ref_path + 1, tit);
-
-	if (rc == -EREMOTE && is_refsrv) {
-		rc2 = add_root_smb_session(mnt_ctx);
-		if (rc2)
-			rc = rc2;
-	}
+	int rc = -ENOENT;
+
+again:
+	do {
+		if (ref_walk_empty(rw)) {
+			rc = dfs_get_referral(mnt_ctx, ref_walk_path(rw) + 1,
+					      NULL, ref_walk_tl(rw));
+			if (rc) {
+				rc = cifs_mount_get_tcon(mnt_ctx);
+				if (!rc)
+					rc = cifs_is_path_remote(mnt_ctx);
+				continue;
+			}
+			if (!ref_walk_num_tgts(rw)) {
+				rc = -ENOENT;
+				continue;
+			}
+		}
+
+		while (ref_walk_next_tgt(rw)) {
+			rc = parse_dfs_target(ctx, rw, &tgt);
+			if (rc)
+				continue;
+
+			cifs_mount_put_conns(mnt_ctx);
+			rc = get_session(mnt_ctx, ref_walk_path(rw));
+			if (rc)
+				continue;
+
+			is_refsrv = tgt.server_type == DFS_TYPE_ROOT ||
+				DFS_INTERLINK(tgt.flags);
+			ref_walk_set_tgt_hint(rw);
+
+			if (tgt.flags & DFSREF_STORAGE_SERVER) {
+				rc = cifs_mount_get_tcon(mnt_ctx);
+				if (!rc)
+					rc = cifs_is_path_remote(mnt_ctx);
+				if (!rc)
+					break;
+				if (rc != -EREMOTE)
+					continue;
+			}
+
+			if (is_refsrv) {
+				rc = add_root_smb_session(mnt_ctx);
+				if (rc)
+					goto out;
+			}
+
+			rc = ref_walk_advance(rw);
+			if (!rc) {
+				rc = set_ref_paths(mnt_ctx, &tgt, rw);
+				if (!rc) {
+					rc = -EREMOTE;
+					goto again;
+				}
+			}
+			if (rc != -ELOOP)
+				goto out;
+		}
+	} while (rc && ref_walk_descend(rw));
 
 out:
-	free_dfs_info_param(&ref);
+	free_dfs_info_param(&tgt);
+	return rc;
+}
+
+static int dfs_referral_walk(struct cifs_mount_ctx *mnt_ctx)
+{
+	struct dfs_ref_walk *rw;
+	int rc;
+
+	rw = ref_walk_alloc();
+	if (IS_ERR(rw))
+		return PTR_ERR(rw);
+
+	ref_walk_init(rw);
+	rc = set_ref_paths(mnt_ctx, NULL, rw);
+	if (!rc)
+		rc = __dfs_referral_walk(mnt_ctx, rw);
+	ref_walk_free(rw);
 	return rc;
 }
 
@@ -148,105 +230,36 @@ static int __dfs_mount_share(struct cifs_mount_ctx *mnt_ctx)
 {
 	struct cifs_sb_info *cifs_sb = mnt_ctx->cifs_sb;
 	struct smb3_fs_context *ctx = mnt_ctx->fs_ctx;
-	char *ref_path = NULL, *full_path = NULL;
-	struct dfs_cache_tgt_iterator *tit;
 	struct cifs_tcon *tcon;
-	char *origin_fullpath = NULL;
-	char sep = CIFS_DIR_SEP(cifs_sb);
-	int num_links = 0;
+	char *origin_fullpath;
 	int rc;
 
-	ref_path = dfs_get_path(cifs_sb, ctx->UNC);
-	if (IS_ERR(ref_path))
-		return PTR_ERR(ref_path);
+	origin_fullpath = dfs_get_path(cifs_sb, ctx->source);
+	if (IS_ERR(origin_fullpath))
+		return PTR_ERR(origin_fullpath);
 
-	full_path = smb3_fs_context_fullpath(ctx, sep);
-	if (IS_ERR(full_path)) {
-		rc = PTR_ERR(full_path);
-		full_path = NULL;
+	rc = dfs_referral_walk(mnt_ctx);
+	if (rc)
 		goto out;
-	}
 
-	origin_fullpath = kstrdup(full_path, GFP_KERNEL);
-	if (!origin_fullpath) {
-		rc = -ENOMEM;
-		goto out;
+	tcon = mnt_ctx->tcon;
+	spin_lock(&tcon->tc_lock);
+	if (!tcon->origin_fullpath) {
+		tcon->origin_fullpath = origin_fullpath;
+		origin_fullpath = NULL;
 	}
-
-	do {
-		DFS_CACHE_TGT_LIST(tl);
-
-		rc = dfs_get_referral(mnt_ctx, ref_path + 1, NULL, &tl);
-		if (rc) {
-			rc = cifs_mount_get_tcon(mnt_ctx);
-			if (!rc)
-				rc = cifs_is_path_remote(mnt_ctx);
-			break;
-		}
-
-		tit = dfs_cache_get_tgt_iterator(&tl);
-		if (!tit) {
-			cifs_dbg(VFS, "%s: dfs referral (%s) with no targets\n", __func__,
-				 ref_path + 1);
-			rc = -ENOENT;
-			dfs_cache_free_tgts(&tl);
-			break;
-		}
-
-		do {
-			rc = get_dfs_conn(mnt_ctx, ref_path, full_path, tit);
-			if (!rc)
-				break;
-			if (rc == -EREMOTE) {
-				if (++num_links > MAX_NESTED_LINKS) {
-					rc = -ELOOP;
-					break;
-				}
-				kfree(ref_path);
-				kfree(full_path);
-				ref_path = full_path = NULL;
-
-				full_path = smb3_fs_context_fullpath(ctx, sep);
-				if (IS_ERR(full_path)) {
-					rc = PTR_ERR(full_path);
-					full_path = NULL;
-				} else {
-					ref_path = dfs_get_path(cifs_sb, full_path);
-					if (IS_ERR(ref_path)) {
-						rc = PTR_ERR(ref_path);
-						ref_path = NULL;
-					}
-				}
-				break;
-			}
-		} while ((tit = dfs_cache_get_next_tgt(&tl, tit)));
-		dfs_cache_free_tgts(&tl);
-	} while (rc == -EREMOTE);
-
-	if (!rc) {
-		tcon = mnt_ctx->tcon;
-
-		spin_lock(&tcon->tc_lock);
-		if (!tcon->origin_fullpath) {
-			tcon->origin_fullpath = origin_fullpath;
-			origin_fullpath = NULL;
-		}
-		spin_unlock(&tcon->tc_lock);
-
-		if (list_empty(&tcon->dfs_ses_list)) {
-			list_replace_init(&mnt_ctx->dfs_ses_list,
-					  &tcon->dfs_ses_list);
-			queue_delayed_work(dfscache_wq, &tcon->dfs_cache_work,
-					   dfs_cache_get_ttl() * HZ);
-		} else {
-			dfs_put_root_smb_sessions(&mnt_ctx->dfs_ses_list);
-		}
+	spin_unlock(&tcon->tc_lock);
+
+	if (list_empty(&tcon->dfs_ses_list)) {
+		list_replace_init(&mnt_ctx->dfs_ses_list, &tcon->dfs_ses_list);
+		queue_delayed_work(dfscache_wq, &tcon->dfs_cache_work,
+				   dfs_cache_get_ttl() * HZ);
+	} else {
+		dfs_put_root_smb_sessions(&mnt_ctx->dfs_ses_list);
 	}
 
 out:
 	kfree(origin_fullpath);
-	kfree(ref_path);
-	kfree(full_path);
 	return rc;
 }
 
diff --git a/fs/smb/client/dfs.h b/fs/smb/client/dfs.h
index 98e9d2aca6a7..c0a9eea6a2c5 100644
--- a/fs/smb/client/dfs.h
+++ b/fs/smb/client/dfs.h
@@ -9,6 +9,110 @@
 #include "cifsglob.h"
 #include "fs_context.h"
 #include "cifs_unicode.h"
+#include <linux/namei.h>
+
+#define DFS_INTERLINK(v) \
+	(((v) & DFSREF_REFERRAL_SERVER) && !((v) & DFSREF_STORAGE_SERVER))
+
+struct dfs_ref {
+	char *path;
+	char *full_path;
+	struct dfs_cache_tgt_list tl;
+	struct dfs_cache_tgt_iterator *tit;
+};
+
+struct dfs_ref_walk {
+	struct dfs_ref *ref;
+	struct dfs_ref refs[MAX_NESTED_LINKS];
+};
+
+#define ref_walk_start(w)	((w)->refs)
+#define ref_walk_end(w)	(&(w)->refs[ARRAY_SIZE((w)->refs) - 1])
+#define ref_walk_cur(w)	((w)->ref)
+#define ref_walk_descend(w)	(--ref_walk_cur(w) >= ref_walk_start(w))
+
+#define ref_walk_tit(w)	(ref_walk_cur(w)->tit)
+#define ref_walk_empty(w)	(!ref_walk_tit(w))
+#define ref_walk_path(w)	(ref_walk_cur(w)->path)
+#define ref_walk_fpath(w)	(ref_walk_cur(w)->full_path)
+#define ref_walk_tl(w)		(&ref_walk_cur(w)->tl)
+
+static inline struct dfs_ref_walk *ref_walk_alloc(void)
+{
+	struct dfs_ref_walk *rw;
+
+	rw = kmalloc(sizeof(*rw), GFP_KERNEL);
+	if (!rw)
+		return ERR_PTR(-ENOMEM);
+	return rw;
+}
+
+static inline void ref_walk_init(struct dfs_ref_walk *rw)
+{
+	memset(rw, 0, sizeof(*rw));
+	ref_walk_cur(rw) = ref_walk_start(rw);
+}
+
+static inline void __ref_walk_free(struct dfs_ref *ref)
+{
+	kfree(ref->path);
+	kfree(ref->full_path);
+	dfs_cache_free_tgts(&ref->tl);
+	memset(ref, 0, sizeof(*ref));
+}
+
+static inline void ref_walk_free(struct dfs_ref_walk *rw)
+{
+	struct dfs_ref *ref = ref_walk_start(rw);
+
+	for (; ref <= ref_walk_end(rw); ref++)
+		__ref_walk_free(ref);
+	kfree(rw);
+}
+
+static inline int ref_walk_advance(struct dfs_ref_walk *rw)
+{
+	struct dfs_ref *ref = ref_walk_cur(rw) + 1;
+
+	if (ref > ref_walk_end(rw))
+		return -ELOOP;
+	__ref_walk_free(ref);
+	ref_walk_cur(rw) = ref;
+	return 0;
+}
+
+static inline struct dfs_cache_tgt_iterator *
+ref_walk_next_tgt(struct dfs_ref_walk *rw)
+{
+	struct dfs_cache_tgt_iterator *tit;
+	struct dfs_ref *ref = ref_walk_cur(rw);
+
+	if (!ref->tit)
+		tit = dfs_cache_get_tgt_iterator(&ref->tl);
+	else
+		tit = dfs_cache_get_next_tgt(&ref->tl, ref->tit);
+	ref->tit = tit;
+	return tit;
+}
+
+static inline int ref_walk_get_tgt(struct dfs_ref_walk *rw,
+				   struct dfs_info3_param *tgt)
+{
+	zfree_dfs_info_param(tgt);
+	return dfs_cache_get_tgt_referral(ref_walk_path(rw) + 1,
+					  ref_walk_tit(rw), tgt);
+}
+
+static inline int ref_walk_num_tgts(struct dfs_ref_walk *rw)
+{
+	return dfs_cache_get_nr_tgts(ref_walk_tl(rw));
+}
+
+static inline void ref_walk_set_tgt_hint(struct dfs_ref_walk *rw)
+{
+	dfs_cache_noreq_update_tgthint(ref_walk_path(rw) + 1,
+				       ref_walk_tit(rw));
+}
 
 struct dfs_root_ses {
 	struct list_head list;
diff --git a/fs/smb/client/dfs_cache.c b/fs/smb/client/dfs_cache.c
index 89b8af831a43..508d831fabe3 100644
--- a/fs/smb/client/dfs_cache.c
+++ b/fs/smb/client/dfs_cache.c
@@ -29,8 +29,6 @@
 #define CACHE_MIN_TTL		120 /* 2 minutes */
 #define CACHE_DEFAULT_TTL	300 /* 5 minutes */
 
-#define IS_DFS_INTERLINK(v) (((v) & DFSREF_REFERRAL_SERVER) && !((v) & DFSREF_STORAGE_SERVER))
-
 struct cache_dfs_tgt {
 	char *name;
 	int path_consumed;
@@ -174,7 +172,7 @@ static int dfscache_proc_show(struct seq_file *m, void *v)
 				   "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->hdr_flags, ce->ref_flags,
-				   IS_DFS_INTERLINK(ce->hdr_flags) ? "yes" : "no",
+				   DFS_INTERLINK(ce->hdr_flags) ? "yes" : "no",
 				   ce->path_consumed, cache_entry_expired(ce) ? "yes" : "no");
 
 			list_for_each_entry(t, &ce->tlist, list) {
@@ -243,7 +241,7 @@ static inline void dump_ce(const struct cache_entry *ce)
 		 ce->srvtype == DFS_TYPE_ROOT ? "root" : "link", ce->ttl,
 		 ce->etime.tv_nsec,
 		 ce->hdr_flags, ce->ref_flags,
-		 IS_DFS_INTERLINK(ce->hdr_flags) ? "yes" : "no",
+		 DFS_INTERLINK(ce->hdr_flags) ? "yes" : "no",
 		 ce->path_consumed,
 		 cache_entry_expired(ce) ? "yes" : "no");
 	dump_tgts(ce);
diff --git a/fs/smb/client/dfs_cache.h b/fs/smb/client/dfs_cache.h
index c6abc524855f..18a08a2ca93b 100644
--- a/fs/smb/client/dfs_cache.h
+++ b/fs/smb/client/dfs_cache.h
@@ -55,8 +55,8 @@ static inline struct dfs_cache_tgt_iterator *
 dfs_cache_get_next_tgt(struct dfs_cache_tgt_list *tl,
 		       struct dfs_cache_tgt_iterator *it)
 {
-	if (!tl || list_empty(&tl->tl_list) || !it ||
-	    list_is_last(&it->it_list, &tl->tl_list))
+	if (!tl || !tl->tl_numtgts || list_empty(&tl->tl_list) ||
+	    !it || list_is_last(&it->it_list, &tl->tl_list))
 		return NULL;
 	return list_next_entry(it, it_list);
 }
@@ -75,7 +75,7 @@ static inline void dfs_cache_free_tgts(struct dfs_cache_tgt_list *tl)
 {
 	struct dfs_cache_tgt_iterator *it, *nit;
 
-	if (!tl || list_empty(&tl->tl_list))
+	if (!tl || !tl->tl_numtgts || list_empty(&tl->tl_list))
 		return;
 	list_for_each_entry_safe(it, nit, &tl->tl_list, it_list) {
 		list_del(&it->it_list);
-- 
2.41.0


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

* [PATCH 03/17] smb: client: move some params to cifs_open_info_data
  2023-08-17 15:33 [PATCH 00/17] cifs.ko fixes Paulo Alcantara
  2023-08-17 15:33 ` [PATCH 01/17] smb: client: introduce DFS_CACHE_TGT_LIST() Paulo Alcantara
  2023-08-17 15:34 ` [PATCH 02/17] smb: client: ensure to try all targets when finding nested links Paulo Alcantara
@ 2023-08-17 15:34 ` Paulo Alcantara
  2023-08-17 15:34 ` [PATCH 04/17] smb: client: make smb2_compound_op() return resp buffer on success Paulo Alcantara
                   ` (14 subsequent siblings)
  17 siblings, 0 replies; 21+ messages in thread
From: Paulo Alcantara @ 2023-08-17 15:34 UTC (permalink / raw)
  To: smfrench; +Cc: linux-cifs, Paulo Alcantara

Instead of passing @adjust_tz and some reparse point related fields as
parameters in ->query_path_info() and
{smb311_posix,cifs}_info_to_fattr() calls, move them to
cifs_open_info_data structure as they can be easily accessed through
@data.

No functional changes.

Signed-off-by: Paulo Alcantara (SUSE) <pc@manguebit.com>
---
 fs/smb/client/cifsglob.h  | 14 ++++++--
 fs/smb/client/inode.c     | 68 ++++++++++++++++++---------------------
 fs/smb/client/smb1ops.c   | 15 +++++----
 fs/smb/client/smb2inode.c | 29 +++++++++--------
 fs/smb/client/smb2proto.h | 17 ++++++----
 5 files changed, 77 insertions(+), 66 deletions(-)

diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
index 712557c2d526..4792de20a447 100644
--- a/fs/smb/client/cifsglob.h
+++ b/fs/smb/client/cifsglob.h
@@ -186,6 +186,12 @@ struct cifs_cred {
 };
 
 struct cifs_open_info_data {
+	bool adjust_tz;
+	union {
+		bool reparse_point;
+		bool symlink;
+	};
+	__u32 reparse_tag;
 	char *symlink_target;
 	union {
 		struct smb2_file_all_info fi;
@@ -318,9 +324,11 @@ struct smb_version_operations {
 	int (*is_path_accessible)(const unsigned int, struct cifs_tcon *,
 				  struct cifs_sb_info *, const char *);
 	/* query path data from the server */
-	int (*query_path_info)(const unsigned int xid, struct cifs_tcon *tcon,
-			       struct cifs_sb_info *cifs_sb, const char *full_path,
-			       struct cifs_open_info_data *data, bool *adjust_tz, bool *reparse);
+	int (*query_path_info)(const unsigned int xid,
+			       struct cifs_tcon *tcon,
+			       struct cifs_sb_info *cifs_sb,
+			       const char *full_path,
+			       struct cifs_open_info_data *data);
 	/* query file data from the server */
 	int (*query_file_info)(const unsigned int xid, struct cifs_tcon *tcon,
 			       struct cifsFileInfo *cfile, struct cifs_open_info_data *data);
diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c
index c3eeae07e139..0d11e63042e2 100644
--- a/fs/smb/client/inode.c
+++ b/fs/smb/client/inode.c
@@ -632,10 +632,11 @@ static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path,
 }
 
 /* Fill a cifs_fattr struct with info from POSIX info struct */
-static void smb311_posix_info_to_fattr(struct cifs_fattr *fattr, struct cifs_open_info_data *data,
+static void smb311_posix_info_to_fattr(struct cifs_fattr *fattr,
+				       struct cifs_open_info_data *data,
 				       struct cifs_sid *owner,
 				       struct cifs_sid *group,
-				       struct super_block *sb, bool adjust_tz, bool symlink)
+				       struct super_block *sb)
 {
 	struct smb311_posix_qinfo *info = &data->posix_fi;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
@@ -655,7 +656,7 @@ static void smb311_posix_info_to_fattr(struct cifs_fattr *fattr, struct cifs_ope
 	fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime);
 	fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime);
 
-	if (adjust_tz) {
+	if (data->adjust_tz) {
 		fattr->cf_ctime.tv_sec += tcon->ses->server->timeAdj;
 		fattr->cf_mtime.tv_sec += tcon->ses->server->timeAdj;
 	}
@@ -669,7 +670,7 @@ static void smb311_posix_info_to_fattr(struct cifs_fattr *fattr, struct cifs_ope
 	/* The srv fs device id is overridden on network mount so setting rdev isn't needed here */
 	/* fattr->cf_rdev = le32_to_cpu(info->DeviceId); */
 
-	if (symlink) {
+	if (data->symlink) {
 		fattr->cf_mode |= S_IFLNK;
 		fattr->cf_dtype = DT_LNK;
 		fattr->cf_symlink_target = data->symlink_target;
@@ -690,13 +691,14 @@ static void smb311_posix_info_to_fattr(struct cifs_fattr *fattr, struct cifs_ope
 		fattr->cf_mode, fattr->cf_uniqueid, fattr->cf_nlink);
 }
 
-static void cifs_open_info_to_fattr(struct cifs_fattr *fattr, struct cifs_open_info_data *data,
-				    struct super_block *sb, bool adjust_tz, bool symlink,
-				    u32 reparse_tag)
+static void cifs_open_info_to_fattr(struct cifs_fattr *fattr,
+				    struct cifs_open_info_data *data,
+				    struct super_block *sb)
 {
 	struct smb2_file_all_info *info = &data->fi;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
 	struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
+	u32 reparse_tag = data->reparse_tag;
 
 	memset(fattr, 0, sizeof(*fattr));
 	fattr->cf_cifsattrs = le32_to_cpu(info->Attributes);
@@ -711,7 +713,7 @@ static void cifs_open_info_to_fattr(struct cifs_fattr *fattr, struct cifs_open_i
 	fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime);
 	fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime);
 
-	if (adjust_tz) {
+	if (data->adjust_tz) {
 		fattr->cf_ctime.tv_sec += tcon->ses->server->timeAdj;
 		fattr->cf_mtime.tv_sec += tcon->ses->server->timeAdj;
 	}
@@ -736,7 +738,7 @@ static void cifs_open_info_to_fattr(struct cifs_fattr *fattr, struct cifs_open_i
 	} else if (reparse_tag == IO_REPARSE_TAG_LX_BLK) {
 		fattr->cf_mode |= S_IFBLK | cifs_sb->ctx->file_mode;
 		fattr->cf_dtype = DT_BLK;
-	} else if (symlink || reparse_tag == IO_REPARSE_TAG_SYMLINK ||
+	} else if (data->symlink || reparse_tag == IO_REPARSE_TAG_SYMLINK ||
 		   reparse_tag == IO_REPARSE_TAG_NFS) {
 		fattr->cf_mode = S_IFLNK;
 		fattr->cf_dtype = DT_LNK;
@@ -789,8 +791,6 @@ cifs_get_file_info(struct file *filp)
 	struct cifsFileInfo *cfile = filp->private_data;
 	struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
 	struct TCP_Server_Info *server = tcon->ses->server;
-	bool symlink = false;
-	u32 tag = 0;
 
 	if (!server->ops->query_file_info)
 		return -ENOSYS;
@@ -800,11 +800,12 @@ cifs_get_file_info(struct file *filp)
 	switch (rc) {
 	case 0:
 		/* TODO: add support to query reparse tag */
+		data.adjust_tz = false;
 		if (data.symlink_target) {
-			symlink = true;
-			tag = IO_REPARSE_TAG_SYMLINK;
+			data.symlink = true;
+			data.reparse_tag = IO_REPARSE_TAG_SYMLINK;
 		}
-		cifs_open_info_to_fattr(&fattr, &data, inode->i_sb, false, symlink, tag);
+		cifs_open_info_to_fattr(&fattr, &data, inode->i_sb);
 		break;
 	case -EREMOTE:
 		cifs_create_dfs_fattr(&fattr, inode->i_sb);
@@ -968,14 +969,11 @@ int cifs_get_inode_info(struct inode **inode, const char *full_path,
 	struct TCP_Server_Info *server;
 	struct tcon_link *tlink;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
-	bool adjust_tz = false;
 	struct cifs_fattr fattr = {0};
-	bool is_reparse_point = false;
 	struct cifs_open_info_data tmp_data = {};
 	void *smb1_backup_rsp_buf = NULL;
 	int rc = 0;
 	int tmprc = 0;
-	__u32 reparse_tag = 0;
 
 	tlink = cifs_sb_tlink(cifs_sb);
 	if (IS_ERR(tlink))
@@ -992,8 +990,8 @@ int cifs_get_inode_info(struct inode **inode, const char *full_path,
 			cifs_dbg(FYI, "No need to revalidate cached inode sizes\n");
 			goto out;
 		}
-		rc = server->ops->query_path_info(xid, tcon, cifs_sb, full_path, &tmp_data,
-						  &adjust_tz, &is_reparse_point);
+		rc = server->ops->query_path_info(xid, tcon, cifs_sb,
+						  full_path, &tmp_data);
 		data = &tmp_data;
 	}
 
@@ -1008,24 +1006,23 @@ int cifs_get_inode_info(struct inode **inode, const char *full_path,
 		 * since we have to check if its reparse tag matches a known
 		 * special file type e.g. symlink or fifo or char etc.
 		 */
-		if (is_reparse_point && data->symlink_target) {
-			reparse_tag = IO_REPARSE_TAG_SYMLINK;
+		if (data->reparse_point && data->symlink_target) {
+			data->reparse_tag = IO_REPARSE_TAG_SYMLINK;
 		} else if ((le32_to_cpu(data->fi.Attributes) & ATTR_REPARSE) &&
 			   server->ops->query_reparse_tag) {
 			tmprc = server->ops->query_reparse_tag(xid, tcon, cifs_sb, full_path,
-							    &reparse_tag);
-			if (tmprc)
-				cifs_dbg(FYI, "%s: query_reparse_tag: rc = %d\n", __func__, tmprc);
+							       &data->reparse_tag);
+			cifs_dbg(FYI, "%s: query_reparse_tag: rc = %d\n", __func__, tmprc);
 			if (server->ops->query_symlink) {
-				tmprc = server->ops->query_symlink(xid, tcon, cifs_sb, full_path,
+				tmprc = server->ops->query_symlink(xid, tcon, cifs_sb,
+								   full_path,
 								   &data->symlink_target,
-								   is_reparse_point);
-				if (tmprc)
-					cifs_dbg(FYI, "%s: query_symlink: rc = %d\n", __func__,
-						 tmprc);
+								   data->reparse_point);
+				cifs_dbg(FYI, "%s: query_symlink: rc = %d\n",
+					 __func__, tmprc);
 			}
 		}
-		cifs_open_info_to_fattr(&fattr, data, sb, adjust_tz, is_reparse_point, reparse_tag);
+		cifs_open_info_to_fattr(&fattr, data, sb);
 		break;
 	case -EREMOTE:
 		/* DFS link, no metadata available on this server */
@@ -1168,9 +1165,7 @@ smb311_posix_get_inode_info(struct inode **inode,
 	struct cifs_tcon *tcon;
 	struct tcon_link *tlink;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
-	bool adjust_tz = false;
 	struct cifs_fattr fattr = {0};
-	bool symlink = false;
 	struct cifs_open_info_data data = {};
 	struct cifs_sid owner, group;
 	int rc = 0;
@@ -1190,9 +1185,9 @@ smb311_posix_get_inode_info(struct inode **inode,
 		goto out;
 	}
 
-	rc = smb311_posix_query_path_info(xid, tcon, cifs_sb, full_path, &data,
-					  &owner, &group, &adjust_tz,
-					  &symlink);
+	rc = smb311_posix_query_path_info(xid, tcon, cifs_sb,
+					  full_path, &data,
+					  &owner, &group);
 
 	/*
 	 * 2. Convert it to internal cifs metadata (fattr)
@@ -1200,8 +1195,7 @@ smb311_posix_get_inode_info(struct inode **inode,
 
 	switch (rc) {
 	case 0:
-		smb311_posix_info_to_fattr(&fattr, &data, &owner, &group,
-					   sb, adjust_tz, symlink);
+		smb311_posix_info_to_fattr(&fattr, &data, &owner, &group, sb);
 		break;
 	case -EREMOTE:
 		/* DFS link, no metadata available on this server */
diff --git a/fs/smb/client/smb1ops.c b/fs/smb/client/smb1ops.c
index 7d1b3fc014d9..094ef4fe2219 100644
--- a/fs/smb/client/smb1ops.c
+++ b/fs/smb/client/smb1ops.c
@@ -542,14 +542,17 @@ cifs_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon,
 	return rc;
 }
 
-static int cifs_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
-				struct cifs_sb_info *cifs_sb, const char *full_path,
-				struct cifs_open_info_data *data, bool *adjustTZ, bool *symlink)
+static int cifs_query_path_info(const unsigned int xid,
+				struct cifs_tcon *tcon,
+				struct cifs_sb_info *cifs_sb,
+				const char *full_path,
+				struct cifs_open_info_data *data)
 {
 	int rc;
 	FILE_ALL_INFO fi = {};
 
-	*symlink = false;
+	data->symlink = false;
+	data->adjust_tz = false;
 
 	/* could do find first instead but this returns more info */
 	rc = CIFSSMBQPathInfo(xid, tcon, full_path, &fi, 0 /* not legacy */, cifs_sb->local_nls,
@@ -562,7 +565,7 @@ static int cifs_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
 	if ((rc == -EOPNOTSUPP) || (rc == -EINVAL)) {
 		rc = SMBQueryInformation(xid, tcon, full_path, &fi, cifs_sb->local_nls,
 					 cifs_remap(cifs_sb));
-		*adjustTZ = true;
+		data->adjust_tz = true;
 	}
 
 	if (!rc) {
@@ -589,7 +592,7 @@ static int cifs_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
 		/* Need to check if this is a symbolic link or not */
 		tmprc = CIFS_open(xid, &oparms, &oplock, NULL);
 		if (tmprc == -EOPNOTSUPP)
-			*symlink = true;
+			data->symlink = true;
 		else if (tmprc == 0)
 			CIFSSMBClose(xid, tcon, fid.netfid);
 	}
diff --git a/fs/smb/client/smb2inode.c b/fs/smb/client/smb2inode.c
index 8e696fbd72fa..260b2ed23cbd 100644
--- a/fs/smb/client/smb2inode.c
+++ b/fs/smb/client/smb2inode.c
@@ -541,9 +541,11 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
 	return rc;
 }
 
-int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
-			 struct cifs_sb_info *cifs_sb, const char *full_path,
-			 struct cifs_open_info_data *data, bool *adjust_tz, bool *reparse)
+int smb2_query_path_info(const unsigned int xid,
+			 struct cifs_tcon *tcon,
+			 struct cifs_sb_info *cifs_sb,
+			 const char *full_path,
+			 struct cifs_open_info_data *data)
 {
 	__u32 create_options = 0;
 	struct cifsFileInfo *cfile;
@@ -553,8 +555,8 @@ int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
 	bool islink;
 	int rc, rc2;
 
-	*adjust_tz = false;
-	*reparse = false;
+	data->adjust_tz = false;
+	data->reparse_point = false;
 
 	if (strcmp(full_path, ""))
 		rc = -ENOENT;
@@ -588,7 +590,7 @@ int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
 			if (rc)
 				goto out;
 
-			*reparse = true;
+			data->reparse_point = true;
 			create_options |= OPEN_REPARSE_POINT;
 
 			/* Failed on a symbolic link - query a reparse point info */
@@ -619,12 +621,13 @@ int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
 }
 
 
-int smb311_posix_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
-				 struct cifs_sb_info *cifs_sb, const char *full_path,
+int smb311_posix_query_path_info(const unsigned int xid,
+				 struct cifs_tcon *tcon,
+				 struct cifs_sb_info *cifs_sb,
+				 const char *full_path,
 				 struct cifs_open_info_data *data,
 				 struct cifs_sid *owner,
-				 struct cifs_sid *group,
-				 bool *adjust_tz, bool *reparse)
+				 struct cifs_sid *group)
 {
 	int rc;
 	__u32 create_options = 0;
@@ -636,8 +639,8 @@ int smb311_posix_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
 	size_t sidsbuflen = 0;
 	size_t owner_len, group_len;
 
-	*adjust_tz = false;
-	*reparse = false;
+	data->adjust_tz = false;
+	data->reparse_point = false;
 
 	/*
 	 * BB TODO: Add support for using the cached root handle.
@@ -659,7 +662,7 @@ int smb311_posix_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
 			if (rc)
 				goto out;
 		}
-		*reparse = true;
+		data->reparse_point = true;
 		create_options |= OPEN_REPARSE_POINT;
 
 		/* Failed on a symbolic link - query a reparse point info */
diff --git a/fs/smb/client/smb2proto.h b/fs/smb/client/smb2proto.h
index d5d7ffb7711c..46eff9ec302a 100644
--- a/fs/smb/client/smb2proto.h
+++ b/fs/smb/client/smb2proto.h
@@ -56,9 +56,11 @@ extern int smb3_handle_read_data(struct TCP_Server_Info *server,
 extern int smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon,
 				struct cifs_sb_info *cifs_sb, const char *path,
 				__u32 *reparse_tag);
-int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
-			 struct cifs_sb_info *cifs_sb, const char *full_path,
-			 struct cifs_open_info_data *data, bool *adjust_tz, bool *reparse);
+int smb2_query_path_info(const unsigned int xid,
+			 struct cifs_tcon *tcon,
+			 struct cifs_sb_info *cifs_sb,
+			 const char *full_path,
+			 struct cifs_open_info_data *data);
 extern int smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
 			      const char *full_path, __u64 size,
 			      struct cifs_sb_info *cifs_sb, bool set_alloc);
@@ -275,12 +277,13 @@ extern int smb2_query_info_compound(const unsigned int xid,
 				    struct kvec *rsp, int *buftype,
 				    struct cifs_sb_info *cifs_sb);
 /* query path info from the server using SMB311 POSIX extensions*/
-int smb311_posix_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
-				 struct cifs_sb_info *cifs_sb, const char *full_path,
+int smb311_posix_query_path_info(const unsigned int xid,
+				 struct cifs_tcon *tcon,
+				 struct cifs_sb_info *cifs_sb,
+				 const char *full_path,
 				 struct cifs_open_info_data *data,
 				 struct cifs_sid *owner,
-				 struct cifs_sid *group,
-				 bool *adjust_tz, bool *reparse);
+				 struct cifs_sid *group);
 int posix_info_parse(const void *beg, const void *end,
 		     struct smb2_posix_info_parsed *out);
 int posix_info_sid_size(const void *beg, const void *end);
-- 
2.41.0


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

* [PATCH 04/17] smb: client: make smb2_compound_op() return resp buffer on success
  2023-08-17 15:33 [PATCH 00/17] cifs.ko fixes Paulo Alcantara
                   ` (2 preceding siblings ...)
  2023-08-17 15:34 ` [PATCH 03/17] smb: client: move some params to cifs_open_info_data Paulo Alcantara
@ 2023-08-17 15:34 ` Paulo Alcantara
  2023-08-17 15:34 ` [PATCH 05/17] smb: client: rename cifs_dfs_ref.c to namespace.c Paulo Alcantara
                   ` (13 subsequent siblings)
  17 siblings, 0 replies; 21+ messages in thread
From: Paulo Alcantara @ 2023-08-17 15:34 UTC (permalink / raw)
  To: smfrench; +Cc: linux-cifs, Paulo Alcantara

If @out_iov and @out_buftype are passed, then return compounded
responses regardless whether the request failed or not.  This will be
useful for detecting reparse points on SMB2_CREATE responses as
specified in MS-SMB2 2.2.14.

No functional changes.

Signed-off-by: Paulo Alcantara (SUSE) <pc@manguebit.com>
---
 fs/smb/client/smb2inode.c | 52 +++++++++++++++++++--------------------
 1 file changed, 26 insertions(+), 26 deletions(-)

diff --git a/fs/smb/client/smb2inode.c b/fs/smb/client/smb2inode.c
index 260b2ed23cbd..69a2969ecdf5 100644
--- a/fs/smb/client/smb2inode.c
+++ b/fs/smb/client/smb2inode.c
@@ -52,15 +52,16 @@ struct cop_vars {
  * note: If cfile is passed, the reference to it is dropped here.
  * So make sure that you do not reuse cfile after return from this func.
  *
- * If passing @err_iov and @err_buftype, ensure to make them both large enough (>= 3) to hold all
- * error responses.  Caller is also responsible for freeing them up.
+ * If passing @out_iov and @out_buftype, ensure to make them both large enough
+ * (>= 3) to hold all compounded responses.  Caller is also responsible for
+ * freeing them up with free_rsp_buf().
  */
 static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
 			    struct cifs_sb_info *cifs_sb, const char *full_path,
 			    __u32 desired_access, __u32 create_disposition, __u32 create_options,
 			    umode_t mode, void *ptr, int command, struct cifsFileInfo *cfile,
 			    __u8 **extbuf, size_t *extbuflen,
-			    struct kvec *err_iov, int *err_buftype)
+			    struct kvec *out_iov, int *out_buftype)
 {
 	struct cop_vars *vars = NULL;
 	struct kvec *rsp_iov;
@@ -529,9 +530,9 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
 	if (cfile)
 		cifsFileInfo_put(cfile);
 
-	if (rc && err_iov && err_buftype) {
-		memcpy(err_iov, rsp_iov, 3 * sizeof(*err_iov));
-		memcpy(err_buftype, resp_buftype, 3 * sizeof(*err_buftype));
+	if (out_iov && out_buftype) {
+		memcpy(out_iov, rsp_iov, 3 * sizeof(*out_iov));
+		memcpy(out_buftype, resp_buftype, 3 * sizeof(*out_buftype));
 	} else {
 		free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
 		free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
@@ -550,8 +551,8 @@ int smb2_query_path_info(const unsigned int xid,
 	__u32 create_options = 0;
 	struct cifsFileInfo *cfile;
 	struct cached_fid *cfid = NULL;
-	struct kvec err_iov[3] = {};
-	int err_buftype[3] = {};
+	struct kvec out_iov[3] = {};
+	int out_buftype[3] = {};
 	bool islink;
 	int rc, rc2;
 
@@ -577,15 +578,15 @@ int smb2_query_path_info(const unsigned int xid,
 	cifs_get_readable_path(tcon, full_path, &cfile);
 	rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, FILE_READ_ATTRIBUTES, FILE_OPEN,
 			      create_options, ACL_NO_MODE, data, SMB2_OP_QUERY_INFO, cfile,
-			      NULL, NULL, err_iov, err_buftype);
+			      NULL, NULL, out_iov, out_buftype);
 	if (rc) {
-		struct smb2_hdr *hdr = err_iov[0].iov_base;
+		struct smb2_hdr *hdr = out_iov[0].iov_base;
 
-		if (unlikely(!hdr || err_buftype[0] == CIFS_NO_BUFFER))
+		if (unlikely(!hdr || out_buftype[0] == CIFS_NO_BUFFER))
 			goto out;
 		if (rc == -EOPNOTSUPP && hdr->Command == SMB2_CREATE &&
 		    hdr->Status == STATUS_STOPPED_ON_SYMLINK) {
-			rc = smb2_parse_symlink_response(cifs_sb, err_iov,
+			rc = smb2_parse_symlink_response(cifs_sb, out_iov,
 							 &data->symlink_target);
 			if (rc)
 				goto out;
@@ -614,13 +615,12 @@ int smb2_query_path_info(const unsigned int xid,
 	}
 
 out:
-	free_rsp_buf(err_buftype[0], err_iov[0].iov_base);
-	free_rsp_buf(err_buftype[1], err_iov[1].iov_base);
-	free_rsp_buf(err_buftype[2], err_iov[2].iov_base);
+	free_rsp_buf(out_buftype[0], out_iov[0].iov_base);
+	free_rsp_buf(out_buftype[1], out_iov[1].iov_base);
+	free_rsp_buf(out_buftype[2], out_iov[2].iov_base);
 	return rc;
 }
 
-
 int smb311_posix_query_path_info(const unsigned int xid,
 				 struct cifs_tcon *tcon,
 				 struct cifs_sb_info *cifs_sb,
@@ -632,8 +632,8 @@ int smb311_posix_query_path_info(const unsigned int xid,
 	int rc;
 	__u32 create_options = 0;
 	struct cifsFileInfo *cfile;
-	struct kvec err_iov[3] = {};
-	int err_buftype[3] = {};
+	struct kvec out_iov[3] = {};
+	int out_buftype[3] = {};
 	__u8 *sidsbuf = NULL;
 	__u8 *sidsbuf_end = NULL;
 	size_t sidsbuflen = 0;
@@ -652,13 +652,13 @@ int smb311_posix_query_path_info(const unsigned int xid,
 	cifs_get_readable_path(tcon, full_path, &cfile);
 	rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, FILE_READ_ATTRIBUTES, FILE_OPEN,
 			      create_options, ACL_NO_MODE, data, SMB2_OP_POSIX_QUERY_INFO, cfile,
-			      &sidsbuf, &sidsbuflen, err_iov, err_buftype);
+			      &sidsbuf, &sidsbuflen, out_iov, out_buftype);
 	if (rc == -EOPNOTSUPP) {
 		/* BB TODO: When support for special files added to Samba re-verify this path */
-		if (err_iov[0].iov_base && err_buftype[0] != CIFS_NO_BUFFER &&
-		    ((struct smb2_hdr *)err_iov[0].iov_base)->Command == SMB2_CREATE &&
-		    ((struct smb2_hdr *)err_iov[0].iov_base)->Status == STATUS_STOPPED_ON_SYMLINK) {
-			rc = smb2_parse_symlink_response(cifs_sb, err_iov, &data->symlink_target);
+		if (out_iov[0].iov_base && out_buftype[0] != CIFS_NO_BUFFER &&
+		    ((struct smb2_hdr *)out_iov[0].iov_base)->Command == SMB2_CREATE &&
+		    ((struct smb2_hdr *)out_iov[0].iov_base)->Status == STATUS_STOPPED_ON_SYMLINK) {
+			rc = smb2_parse_symlink_response(cifs_sb, out_iov, &data->symlink_target);
 			if (rc)
 				goto out;
 		}
@@ -694,9 +694,9 @@ int smb311_posix_query_path_info(const unsigned int xid,
 
 out:
 	kfree(sidsbuf);
-	free_rsp_buf(err_buftype[0], err_iov[0].iov_base);
-	free_rsp_buf(err_buftype[1], err_iov[1].iov_base);
-	free_rsp_buf(err_buftype[2], err_iov[2].iov_base);
+	free_rsp_buf(out_buftype[0], out_iov[0].iov_base);
+	free_rsp_buf(out_buftype[1], out_iov[1].iov_base);
+	free_rsp_buf(out_buftype[2], out_iov[2].iov_base);
 	return rc;
 }
 
-- 
2.41.0


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

* [PATCH 05/17] smb: client: rename cifs_dfs_ref.c to namespace.c
  2023-08-17 15:33 [PATCH 00/17] cifs.ko fixes Paulo Alcantara
                   ` (3 preceding siblings ...)
  2023-08-17 15:34 ` [PATCH 04/17] smb: client: make smb2_compound_op() return resp buffer on success Paulo Alcantara
@ 2023-08-17 15:34 ` Paulo Alcantara
  2023-08-17 15:34 ` [PATCH 06/17] smb: client: get rid of dfs naming in automount code Paulo Alcantara
                   ` (12 subsequent siblings)
  17 siblings, 0 replies; 21+ messages in thread
From: Paulo Alcantara @ 2023-08-17 15:34 UTC (permalink / raw)
  To: smfrench; +Cc: linux-cifs, Paulo Alcantara

The automount code will handle both DFS links and reparse files that
are mount points.

Signed-off-by: Paulo Alcantara (SUSE) <pc@manguebit.com>
---
 fs/smb/client/Makefile                        | 2 +-
 fs/smb/client/{cifs_dfs_ref.c => namespace.c} | 0
 2 files changed, 1 insertion(+), 1 deletion(-)
 rename fs/smb/client/{cifs_dfs_ref.c => namespace.c} (100%)

diff --git a/fs/smb/client/Makefile b/fs/smb/client/Makefile
index 304a7f6cc13a..851e6ba65e9b 100644
--- a/fs/smb/client/Makefile
+++ b/fs/smb/client/Makefile
@@ -21,7 +21,7 @@ cifs-$(CONFIG_CIFS_XATTR) += xattr.o
 
 cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o
 
-cifs-$(CONFIG_CIFS_DFS_UPCALL) += cifs_dfs_ref.o dfs_cache.o dfs.o
+cifs-$(CONFIG_CIFS_DFS_UPCALL) += namespace.o dfs_cache.o dfs.o
 
 cifs-$(CONFIG_CIFS_SWN_UPCALL) += netlink.o cifs_swn.o
 
diff --git a/fs/smb/client/cifs_dfs_ref.c b/fs/smb/client/namespace.c
similarity index 100%
rename from fs/smb/client/cifs_dfs_ref.c
rename to fs/smb/client/namespace.c
-- 
2.41.0


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

* [PATCH 06/17] smb: client: get rid of dfs naming in automount code
  2023-08-17 15:33 [PATCH 00/17] cifs.ko fixes Paulo Alcantara
                   ` (4 preceding siblings ...)
  2023-08-17 15:34 ` [PATCH 05/17] smb: client: rename cifs_dfs_ref.c to namespace.c Paulo Alcantara
@ 2023-08-17 15:34 ` Paulo Alcantara
  2023-08-17 15:34 ` [PATCH 07/17] smb: client: get rid of dfs code dep in namespace.c Paulo Alcantara
                   ` (11 subsequent siblings)
  17 siblings, 0 replies; 21+ messages in thread
From: Paulo Alcantara @ 2023-08-17 15:34 UTC (permalink / raw)
  To: smfrench; +Cc: linux-cifs, Paulo Alcantara

Automount code will handle both DFS links and reparse mount points.

Also, get rid of BUG_ON() in cifs_release_automount_timer() while
we're at it.

Signed-off-by: Paulo Alcantara (SUSE) <pc@manguebit.com>
---
 fs/smb/client/cifsfs.c    |  2 +-
 fs/smb/client/cifsfs.h    |  6 +++---
 fs/smb/client/cifsproto.h |  4 ++--
 fs/smb/client/dir.c       |  4 ++--
 fs/smb/client/inode.c     |  2 +-
 fs/smb/client/namespace.c | 42 +++++++++++++++++++--------------------
 6 files changed, 30 insertions(+), 30 deletions(-)

diff --git a/fs/smb/client/cifsfs.c b/fs/smb/client/cifsfs.c
index a4d8b0ea1c8c..d49fd2bf71b0 100644
--- a/fs/smb/client/cifsfs.c
+++ b/fs/smb/client/cifsfs.c
@@ -1805,7 +1805,7 @@ exit_cifs(void)
 	cifs_dbg(NOISY, "exit_smb3\n");
 	unregister_filesystem(&cifs_fs_type);
 	unregister_filesystem(&smb3_fs_type);
-	cifs_dfs_release_automount_timer();
+	cifs_release_automount_timer();
 	exit_cifs_idmap();
 #ifdef CONFIG_CIFS_SWN_UPCALL
 	cifs_genl_exit();
diff --git a/fs/smb/client/cifsfs.h b/fs/smb/client/cifsfs.h
index 15c8cc4b6680..99075970716e 100644
--- a/fs/smb/client/cifsfs.h
+++ b/fs/smb/client/cifsfs.h
@@ -81,7 +81,7 @@ extern int cifs_fiemap(struct inode *, struct fiemap_extent_info *, u64 start,
 
 extern const struct inode_operations cifs_file_inode_ops;
 extern const struct inode_operations cifs_symlink_inode_ops;
-extern const struct inode_operations cifs_dfs_referral_inode_operations;
+extern const struct inode_operations cifs_namespace_inode_operations;
 
 
 /* Functions related to files and directories */
@@ -119,9 +119,9 @@ extern const struct dentry_operations cifs_dentry_ops;
 extern const struct dentry_operations cifs_ci_dentry_ops;
 
 #ifdef CONFIG_CIFS_DFS_UPCALL
-extern struct vfsmount *cifs_dfs_d_automount(struct path *path);
+extern struct vfsmount *cifs_d_automount(struct path *path);
 #else
-static inline struct vfsmount *cifs_dfs_d_automount(struct path *path)
+static inline struct vfsmount *cifs_d_automount(struct path *path)
 {
 	return ERR_PTR(-EREMOTE);
 }
diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h
index 1d71d658e167..c7a7484efbd2 100644
--- a/fs/smb/client/cifsproto.h
+++ b/fs/smb/client/cifsproto.h
@@ -296,9 +296,9 @@ extern void cifs_put_tcp_session(struct TCP_Server_Info *server,
 extern void cifs_put_tcon(struct cifs_tcon *tcon);
 
 #if IS_ENABLED(CONFIG_CIFS_DFS_UPCALL)
-extern void cifs_dfs_release_automount_timer(void);
+extern void cifs_release_automount_timer(void);
 #else /* ! IS_ENABLED(CONFIG_CIFS_DFS_UPCALL) */
-#define cifs_dfs_release_automount_timer()	do { } while (0)
+#define cifs_release_automount_timer()	do { } while (0)
 #endif /* ! IS_ENABLED(CONFIG_CIFS_DFS_UPCALL) */
 
 void cifs_proc_init(void);
diff --git a/fs/smb/client/dir.c b/fs/smb/client/dir.c
index 30b1e1bfd204..580a27a3a7e6 100644
--- a/fs/smb/client/dir.c
+++ b/fs/smb/client/dir.c
@@ -797,7 +797,7 @@ cifs_d_revalidate(struct dentry *direntry, unsigned int flags)
 
 const struct dentry_operations cifs_dentry_ops = {
 	.d_revalidate = cifs_d_revalidate,
-	.d_automount = cifs_dfs_d_automount,
+	.d_automount = cifs_d_automount,
 /* d_delete:       cifs_d_delete,      */ /* not needed except for debugging */
 };
 
@@ -872,5 +872,5 @@ const struct dentry_operations cifs_ci_dentry_ops = {
 	.d_revalidate = cifs_d_revalidate,
 	.d_hash = cifs_ci_hash,
 	.d_compare = cifs_ci_compare,
-	.d_automount = cifs_dfs_d_automount,
+	.d_automount = cifs_d_automount,
 };
diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c
index 0d11e63042e2..0d4a78561acc 100644
--- a/fs/smb/client/inode.c
+++ b/fs/smb/client/inode.c
@@ -60,7 +60,7 @@ static void cifs_set_ops(struct inode *inode)
 	case S_IFDIR:
 #ifdef CONFIG_CIFS_DFS_UPCALL
 		if (IS_AUTOMOUNT(inode)) {
-			inode->i_op = &cifs_dfs_referral_inode_operations;
+			inode->i_op = &cifs_namespace_inode_operations;
 		} else {
 #else /* NO DFS support, treat as a directory */
 		{
diff --git a/fs/smb/client/namespace.c b/fs/smb/client/namespace.c
index b1c2499b1c3b..af64f2add873 100644
--- a/fs/smb/client/namespace.c
+++ b/fs/smb/client/namespace.c
@@ -1,7 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 /*
- *   Contains the CIFS DFS referral mounting routines used for handling
- *   traversal via DFS junction point
+ *   Contains mounting routines used for handling traversal via SMB junctions.
  *
  *   Copyright (c) 2007 Igor Mammedov
  *   Copyright (C) International Business Machines  Corp., 2008
@@ -24,27 +23,28 @@
 #include "dfs.h"
 #include "fs_context.h"
 
-static LIST_HEAD(cifs_dfs_automount_list);
+static LIST_HEAD(cifs_automount_list);
 
-static void cifs_dfs_expire_automounts(struct work_struct *work);
-static DECLARE_DELAYED_WORK(cifs_dfs_automount_task,
-			    cifs_dfs_expire_automounts);
-static int cifs_dfs_mountpoint_expiry_timeout = 500 * HZ;
+static void cifs_expire_automounts(struct work_struct *work);
+static DECLARE_DELAYED_WORK(cifs_automount_task,
+			    cifs_expire_automounts);
+static int cifs_mountpoint_expiry_timeout = 500 * HZ;
 
-static void cifs_dfs_expire_automounts(struct work_struct *work)
+static void cifs_expire_automounts(struct work_struct *work)
 {
-	struct list_head *list = &cifs_dfs_automount_list;
+	struct list_head *list = &cifs_automount_list;
 
 	mark_mounts_for_expiry(list);
 	if (!list_empty(list))
-		schedule_delayed_work(&cifs_dfs_automount_task,
-				      cifs_dfs_mountpoint_expiry_timeout);
+		schedule_delayed_work(&cifs_automount_task,
+				      cifs_mountpoint_expiry_timeout);
 }
 
-void cifs_dfs_release_automount_timer(void)
+void cifs_release_automount_timer(void)
 {
-	BUG_ON(!list_empty(&cifs_dfs_automount_list));
-	cancel_delayed_work_sync(&cifs_dfs_automount_task);
+	if (WARN_ON(!list_empty(&cifs_automount_list)))
+		return;
+	cancel_delayed_work_sync(&cifs_automount_task);
 }
 
 /**
@@ -132,7 +132,7 @@ static int set_dest_addr(struct smb3_fs_context *ctx)
 /*
  * Create a vfsmount that we can automount
  */
-static struct vfsmount *cifs_dfs_do_automount(struct path *path)
+static struct vfsmount *cifs_do_automount(struct path *path)
 {
 	int rc;
 	struct dentry *mntpt = path->dentry;
@@ -214,25 +214,25 @@ static struct vfsmount *cifs_dfs_do_automount(struct path *path)
 /*
  * Attempt to automount the referral
  */
-struct vfsmount *cifs_dfs_d_automount(struct path *path)
+struct vfsmount *cifs_d_automount(struct path *path)
 {
 	struct vfsmount *newmnt;
 
 	cifs_dbg(FYI, "%s: %pd\n", __func__, path->dentry);
 
-	newmnt = cifs_dfs_do_automount(path);
+	newmnt = cifs_do_automount(path);
 	if (IS_ERR(newmnt)) {
 		cifs_dbg(FYI, "leaving %s [automount failed]\n" , __func__);
 		return newmnt;
 	}
 
 	mntget(newmnt); /* prevent immediate expiration */
-	mnt_set_expiry(newmnt, &cifs_dfs_automount_list);
-	schedule_delayed_work(&cifs_dfs_automount_task,
-			      cifs_dfs_mountpoint_expiry_timeout);
+	mnt_set_expiry(newmnt, &cifs_automount_list);
+	schedule_delayed_work(&cifs_automount_task,
+			      cifs_mountpoint_expiry_timeout);
 	cifs_dbg(FYI, "leaving %s [ok]\n" , __func__);
 	return newmnt;
 }
 
-const struct inode_operations cifs_dfs_referral_inode_operations = {
+const struct inode_operations cifs_namespace_inode_operations = {
 };
-- 
2.41.0


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

* [PATCH 07/17] smb: client: get rid of dfs code dep in namespace.c
  2023-08-17 15:33 [PATCH 00/17] cifs.ko fixes Paulo Alcantara
                   ` (5 preceding siblings ...)
  2023-08-17 15:34 ` [PATCH 06/17] smb: client: get rid of dfs naming in automount code Paulo Alcantara
@ 2023-08-17 15:34 ` Paulo Alcantara
  2023-08-17 15:34 ` [PATCH 08/17] smb: client: parse reparse point flag in create response Paulo Alcantara
                   ` (10 subsequent siblings)
  17 siblings, 0 replies; 21+ messages in thread
From: Paulo Alcantara @ 2023-08-17 15:34 UTC (permalink / raw)
  To: smfrench; +Cc: linux-cifs, Paulo Alcantara

Make namespace.c being built without requiring
CONFIG_CIFS_DFS_UPCALL=y by moving set_dest_addr() to dfs.c and call
it at the beginning of dfs_mount_share() so it can chase the DFS link
starting from the correct server in @ctx->dstaddr.

Signed-off-by: Paulo Alcantara (SUSE) <pc@manguebit.com>
---
 fs/smb/client/Makefile    |  5 ++--
 fs/smb/client/cifsfs.h    |  7 -----
 fs/smb/client/cifsproto.h |  4 ---
 fs/smb/client/dfs.c       | 16 +++++++++++
 fs/smb/client/dfs.h       | 37 --------------------------
 fs/smb/client/inode.c     |  4 ---
 fs/smb/client/namespace.c | 56 ++++++++++++++++++++++++++-------------
 7 files changed, 57 insertions(+), 72 deletions(-)

diff --git a/fs/smb/client/Makefile b/fs/smb/client/Makefile
index 851e6ba65e9b..0b07eb94c93b 100644
--- a/fs/smb/client/Makefile
+++ b/fs/smb/client/Makefile
@@ -11,7 +11,8 @@ cifs-y := trace.o cifsfs.o cifs_debug.o connect.o dir.o file.o \
 	  readdir.o ioctl.o sess.o export.o unc.o winucase.o \
 	  smb2ops.o smb2maperror.o smb2transport.o \
 	  smb2misc.o smb2pdu.o smb2inode.o smb2file.o cifsacl.o fs_context.o \
-	  dns_resolve.o cifs_spnego_negtokeninit.asn1.o asn1.o
+	  dns_resolve.o cifs_spnego_negtokeninit.asn1.o asn1.o \
+	  namespace.o
 
 $(obj)/asn1.o: $(obj)/cifs_spnego_negtokeninit.asn1.h
 
@@ -21,7 +22,7 @@ cifs-$(CONFIG_CIFS_XATTR) += xattr.o
 
 cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o
 
-cifs-$(CONFIG_CIFS_DFS_UPCALL) += namespace.o dfs_cache.o dfs.o
+cifs-$(CONFIG_CIFS_DFS_UPCALL) += dfs_cache.o dfs.o
 
 cifs-$(CONFIG_CIFS_SWN_UPCALL) += netlink.o cifs_swn.o
 
diff --git a/fs/smb/client/cifsfs.h b/fs/smb/client/cifsfs.h
index 99075970716e..532c38fe07cd 100644
--- a/fs/smb/client/cifsfs.h
+++ b/fs/smb/client/cifsfs.h
@@ -118,14 +118,7 @@ extern void cifs_pages_write_redirty(struct inode *inode, loff_t start, unsigned
 extern const struct dentry_operations cifs_dentry_ops;
 extern const struct dentry_operations cifs_ci_dentry_ops;
 
-#ifdef CONFIG_CIFS_DFS_UPCALL
 extern struct vfsmount *cifs_d_automount(struct path *path);
-#else
-static inline struct vfsmount *cifs_d_automount(struct path *path)
-{
-	return ERR_PTR(-EREMOTE);
-}
-#endif
 
 /* Functions related to symlinks */
 extern const char *cifs_get_link(struct dentry *, struct inode *,
diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h
index c7a7484efbd2..694d16acdf61 100644
--- a/fs/smb/client/cifsproto.h
+++ b/fs/smb/client/cifsproto.h
@@ -295,11 +295,7 @@ extern void cifs_put_tcp_session(struct TCP_Server_Info *server,
 				 int from_reconnect);
 extern void cifs_put_tcon(struct cifs_tcon *tcon);
 
-#if IS_ENABLED(CONFIG_CIFS_DFS_UPCALL)
 extern void cifs_release_automount_timer(void);
-#else /* ! IS_ENABLED(CONFIG_CIFS_DFS_UPCALL) */
-#define cifs_release_automount_timer()	do { } while (0)
-#endif /* ! IS_ENABLED(CONFIG_CIFS_DFS_UPCALL) */
 
 void cifs_proc_init(void);
 void cifs_proc_clean(void);
diff --git a/fs/smb/client/dfs.c b/fs/smb/client/dfs.c
index 71ee74041884..81b84151450d 100644
--- a/fs/smb/client/dfs.c
+++ b/fs/smb/client/dfs.c
@@ -263,12 +263,28 @@ static int __dfs_mount_share(struct cifs_mount_ctx *mnt_ctx)
 	return rc;
 }
 
+/* Resolve UNC hostname in @ctx->source and set ip addr in @ctx->dstaddr */
+static int update_fs_context_dstaddr(struct smb3_fs_context *ctx)
+{
+	struct sockaddr *addr = (struct sockaddr *)&ctx->dstaddr;
+	int rc;
+
+	rc = dns_resolve_server_name_to_ip(ctx->source, addr, NULL);
+	if (!rc)
+		cifs_set_port(addr, ctx->port);
+	return rc;
+}
+
 int dfs_mount_share(struct cifs_mount_ctx *mnt_ctx, bool *isdfs)
 {
 	struct smb3_fs_context *ctx = mnt_ctx->fs_ctx;
 	bool nodfs = ctx->nodfs;
 	int rc;
 
+	rc = update_fs_context_dstaddr(ctx);
+	if (rc)
+		return rc;
+
 	*isdfs = false;
 	rc = get_session(mnt_ctx, NULL);
 	if (rc)
diff --git a/fs/smb/client/dfs.h b/fs/smb/client/dfs.h
index c0a9eea6a2c5..875ab7ae57fc 100644
--- a/fs/smb/client/dfs.h
+++ b/fs/smb/client/dfs.h
@@ -138,43 +138,6 @@ static inline int dfs_get_referral(struct cifs_mount_ctx *mnt_ctx, const char *p
 			      cifs_remap(cifs_sb), path, ref, tl);
 }
 
-/* Return DFS full path out of a dentry set for automount */
-static inline char *dfs_get_automount_devname(struct dentry *dentry, void *page)
-{
-	struct cifs_sb_info *cifs_sb = CIFS_SB(dentry->d_sb);
-	struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
-	size_t len;
-	char *s;
-
-	spin_lock(&tcon->tc_lock);
-	if (unlikely(!tcon->origin_fullpath)) {
-		spin_unlock(&tcon->tc_lock);
-		return ERR_PTR(-EREMOTE);
-	}
-	spin_unlock(&tcon->tc_lock);
-
-	s = dentry_path_raw(dentry, page, PATH_MAX);
-	if (IS_ERR(s))
-		return s;
-	/* for root, we want "" */
-	if (!s[1])
-		s++;
-
-	spin_lock(&tcon->tc_lock);
-	len = strlen(tcon->origin_fullpath);
-	if (s < (char *)page + len) {
-		spin_unlock(&tcon->tc_lock);
-		return ERR_PTR(-ENAMETOOLONG);
-	}
-
-	s -= len;
-	memcpy(s, tcon->origin_fullpath, len);
-	spin_unlock(&tcon->tc_lock);
-	convert_delimiter(s, '/');
-
-	return s;
-}
-
 static inline void dfs_put_root_smb_sessions(struct list_head *head)
 {
 	struct dfs_root_ses *root, *tmp;
diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c
index 0d4a78561acc..da2ec48dc0f6 100644
--- a/fs/smb/client/inode.c
+++ b/fs/smb/client/inode.c
@@ -58,13 +58,9 @@ static void cifs_set_ops(struct inode *inode)
 			inode->i_data.a_ops = &cifs_addr_ops;
 		break;
 	case S_IFDIR:
-#ifdef CONFIG_CIFS_DFS_UPCALL
 		if (IS_AUTOMOUNT(inode)) {
 			inode->i_op = &cifs_namespace_inode_operations;
 		} else {
-#else /* NO DFS support, treat as a directory */
-		{
-#endif
 			inode->i_op = &cifs_dir_inode_ops;
 			inode->i_fop = &cifs_dir_ops;
 		}
diff --git a/fs/smb/client/namespace.c b/fs/smb/client/namespace.c
index af64f2add873..3252fe33f7a3 100644
--- a/fs/smb/client/namespace.c
+++ b/fs/smb/client/namespace.c
@@ -6,6 +6,7 @@
  *   Copyright (C) International Business Machines  Corp., 2008
  *   Author(s): Igor Mammedov (niallain@gmail.com)
  *		Steve French (sfrench@us.ibm.com)
+ *   Copyright (c) 2023 Paulo Alcantara <palcantara@suse.de>
  */
 
 #include <linux/dcache.h>
@@ -18,9 +19,7 @@
 #include "cifsglob.h"
 #include "cifsproto.h"
 #include "cifsfs.h"
-#include "dns_resolve.h"
 #include "cifs_debug.h"
-#include "dfs.h"
 #include "fs_context.h"
 
 static LIST_HEAD(cifs_automount_list);
@@ -118,15 +117,41 @@ cifs_build_devname(char *nodename, const char *prepath)
 	return dev;
 }
 
-static int set_dest_addr(struct smb3_fs_context *ctx)
+/* Return full path out of a dentry set for automount */
+static char *automount_fullpath(struct dentry *dentry, void *page)
 {
-	struct sockaddr *addr = (struct sockaddr *)&ctx->dstaddr;
-	int rc;
+	struct cifs_sb_info *cifs_sb = CIFS_SB(dentry->d_sb);
+	struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
+	size_t len;
+	char *s;
 
-	rc = dns_resolve_server_name_to_ip(ctx->source, addr, NULL);
-	if (!rc)
-		cifs_set_port(addr, ctx->port);
-	return rc;
+	spin_lock(&tcon->tc_lock);
+	if (unlikely(!tcon->origin_fullpath)) {
+		spin_unlock(&tcon->tc_lock);
+		return ERR_PTR(-EREMOTE);
+	}
+	spin_unlock(&tcon->tc_lock);
+
+	s = dentry_path_raw(dentry, page, PATH_MAX);
+	if (IS_ERR(s))
+		return s;
+	/* for root, we want "" */
+	if (!s[1])
+		s++;
+
+	spin_lock(&tcon->tc_lock);
+	len = strlen(tcon->origin_fullpath);
+	if (s < (char *)page + len) {
+		spin_unlock(&tcon->tc_lock);
+		return ERR_PTR(-ENAMETOOLONG);
+	}
+
+	s -= len;
+	memcpy(s, tcon->origin_fullpath, len);
+	spin_unlock(&tcon->tc_lock);
+	convert_delimiter(s, '/');
+
+	return s;
 }
 
 /*
@@ -166,7 +191,7 @@ static struct vfsmount *cifs_do_automount(struct path *path)
 	ctx = smb3_fc2context(fc);
 
 	page = alloc_dentry_path();
-	full_path = dfs_get_automount_devname(mntpt, page);
+	full_path = automount_fullpath(mntpt, page);
 	if (IS_ERR(full_path)) {
 		mnt = ERR_CAST(full_path);
 		goto out;
@@ -196,15 +221,10 @@ static struct vfsmount *cifs_do_automount(struct path *path)
 		ctx->source = NULL;
 		goto out;
 	}
-	cifs_dbg(FYI, "%s: ctx: source=%s UNC=%s prepath=%s dstaddr=%pISpc\n",
-		 __func__, ctx->source, ctx->UNC, ctx->prepath, &ctx->dstaddr);
-
-	rc = set_dest_addr(ctx);
-	if (!rc)
-		mnt = fc_mount(fc);
-	else
-		mnt = ERR_PTR(rc);
+	cifs_dbg(FYI, "%s: ctx: source=%s UNC=%s prepath=%s\n",
+		 __func__, ctx->source, ctx->UNC, ctx->prepath);
 
+	mnt = fc_mount(fc);
 out:
 	put_fs_context(fc);
 	free_dentry_path(page);
-- 
2.41.0


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

* [PATCH 08/17] smb: client: parse reparse point flag in create response
  2023-08-17 15:33 [PATCH 00/17] cifs.ko fixes Paulo Alcantara
                   ` (6 preceding siblings ...)
  2023-08-17 15:34 ` [PATCH 07/17] smb: client: get rid of dfs code dep in namespace.c Paulo Alcantara
@ 2023-08-17 15:34 ` Paulo Alcantara
  2023-08-17 15:34 ` [PATCH 09/17] smb: client: do not query reparse points twice on symlinks Paulo Alcantara
                   ` (9 subsequent siblings)
  17 siblings, 0 replies; 21+ messages in thread
From: Paulo Alcantara @ 2023-08-17 15:34 UTC (permalink / raw)
  To: smfrench; +Cc: linux-cifs, Paulo Alcantara

Check for reparse point flag on query info calls as specified in
MS-SMB2 2.2.14.

Signed-off-by: Paulo Alcantara (SUSE) <pc@manguebit.com>
---
 fs/smb/client/cifsglob.h  |   4 ++
 fs/smb/client/cifsproto.h |   3 +
 fs/smb/client/inode.c     | 121 ++++++++++++++++++++++++++------------
 fs/smb/client/readdir.c   |  22 ++-----
 fs/smb/client/smb2inode.c | 115 ++++++++++++++++++++++++------------
 5 files changed, 172 insertions(+), 93 deletions(-)

diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
index 4792de20a447..95e62502cb01 100644
--- a/fs/smb/client/cifsglob.h
+++ b/fs/smb/client/cifsglob.h
@@ -199,6 +199,10 @@ struct cifs_open_info_data {
 	};
 };
 
+#define cifs_open_data_reparse(d) \
+	((d)->reparse_point || \
+	 (le32_to_cpu((d)->fi.Attributes) & ATTR_REPARSE))
+
 static inline void cifs_free_open_info(struct cifs_open_info_data *data)
 {
 	kfree(data->symlink_target);
diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h
index 694d16acdf61..7d8035846680 100644
--- a/fs/smb/client/cifsproto.h
+++ b/fs/smb/client/cifsproto.h
@@ -207,6 +207,9 @@ extern struct inode *cifs_iget(struct super_block *sb,
 int cifs_get_inode_info(struct inode **inode, const char *full_path,
 			struct cifs_open_info_data *data, struct super_block *sb, int xid,
 			const struct cifs_fid *fid);
+bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb,
+				 struct cifs_fattr *fattr,
+				 u32 tag);
 extern int smb311_posix_get_inode_info(struct inode **pinode, const char *search_path,
 			struct super_block *sb, unsigned int xid);
 extern int cifs_get_inode_info_unix(struct inode **pinode,
diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c
index da2ec48dc0f6..51e2916730cf 100644
--- a/fs/smb/client/inode.c
+++ b/fs/smb/client/inode.c
@@ -687,6 +687,43 @@ static void smb311_posix_info_to_fattr(struct cifs_fattr *fattr,
 		fattr->cf_mode, fattr->cf_uniqueid, fattr->cf_nlink);
 }
 
+bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb,
+				 struct cifs_fattr *fattr,
+				 u32 tag)
+{
+	switch (tag) {
+	case IO_REPARSE_TAG_LX_SYMLINK:
+		fattr->cf_mode |= S_IFLNK | cifs_sb->ctx->file_mode;
+		fattr->cf_dtype = DT_LNK;
+		break;
+	case IO_REPARSE_TAG_LX_FIFO:
+		fattr->cf_mode |= S_IFIFO | cifs_sb->ctx->file_mode;
+		fattr->cf_dtype = DT_FIFO;
+		break;
+	case IO_REPARSE_TAG_AF_UNIX:
+		fattr->cf_mode |= S_IFSOCK | cifs_sb->ctx->file_mode;
+		fattr->cf_dtype = DT_SOCK;
+		break;
+	case IO_REPARSE_TAG_LX_CHR:
+		fattr->cf_mode |= S_IFCHR | cifs_sb->ctx->file_mode;
+		fattr->cf_dtype = DT_CHR;
+		break;
+	case IO_REPARSE_TAG_LX_BLK:
+		fattr->cf_mode |= S_IFBLK | cifs_sb->ctx->file_mode;
+		fattr->cf_dtype = DT_BLK;
+		break;
+	case 0: /* SMB1 symlink */
+	case IO_REPARSE_TAG_SYMLINK:
+	case IO_REPARSE_TAG_NFS:
+		fattr->cf_mode = S_IFLNK;
+		fattr->cf_dtype = DT_LNK;
+		break;
+	default:
+		return false;
+	}
+	return true;
+}
+
 static void cifs_open_info_to_fattr(struct cifs_fattr *fattr,
 				    struct cifs_open_info_data *data,
 				    struct super_block *sb)
@@ -694,7 +731,6 @@ static void cifs_open_info_to_fattr(struct cifs_fattr *fattr,
 	struct smb2_file_all_info *info = &data->fi;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
 	struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
-	u32 reparse_tag = data->reparse_tag;
 
 	memset(fattr, 0, sizeof(*fattr));
 	fattr->cf_cifsattrs = le32_to_cpu(info->Attributes);
@@ -717,28 +753,13 @@ static void cifs_open_info_to_fattr(struct cifs_fattr *fattr,
 	fattr->cf_eof = le64_to_cpu(info->EndOfFile);
 	fattr->cf_bytes = le64_to_cpu(info->AllocationSize);
 	fattr->cf_createtime = le64_to_cpu(info->CreationTime);
-
 	fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks);
-	if (reparse_tag == IO_REPARSE_TAG_LX_SYMLINK) {
-		fattr->cf_mode |= S_IFLNK | cifs_sb->ctx->file_mode;
-		fattr->cf_dtype = DT_LNK;
-	} else if (reparse_tag == IO_REPARSE_TAG_LX_FIFO) {
-		fattr->cf_mode |= S_IFIFO | cifs_sb->ctx->file_mode;
-		fattr->cf_dtype = DT_FIFO;
-	} else if (reparse_tag == IO_REPARSE_TAG_AF_UNIX) {
-		fattr->cf_mode |= S_IFSOCK | cifs_sb->ctx->file_mode;
-		fattr->cf_dtype = DT_SOCK;
-	} else if (reparse_tag == IO_REPARSE_TAG_LX_CHR) {
-		fattr->cf_mode |= S_IFCHR | cifs_sb->ctx->file_mode;
-		fattr->cf_dtype = DT_CHR;
-	} else if (reparse_tag == IO_REPARSE_TAG_LX_BLK) {
-		fattr->cf_mode |= S_IFBLK | cifs_sb->ctx->file_mode;
-		fattr->cf_dtype = DT_BLK;
-	} else if (data->symlink || reparse_tag == IO_REPARSE_TAG_SYMLINK ||
-		   reparse_tag == IO_REPARSE_TAG_NFS) {
-		fattr->cf_mode = S_IFLNK;
-		fattr->cf_dtype = DT_LNK;
-	} else if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
+
+	if (cifs_open_data_reparse(data) &&
+	    cifs_reparse_point_to_fattr(cifs_sb, fattr, data->reparse_tag))
+		goto out_reparse;
+
+	if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
 		fattr->cf_mode = S_IFDIR | cifs_sb->ctx->dir_mode;
 		fattr->cf_dtype = DT_DIR;
 		/*
@@ -767,6 +788,7 @@ static void cifs_open_info_to_fattr(struct cifs_fattr *fattr,
 		}
 	}
 
+out_reparse:
 	if (S_ISLNK(fattr->cf_mode)) {
 		fattr->cf_symlink_target = data->symlink_target;
 		data->symlink_target = NULL;
@@ -957,6 +979,40 @@ static inline bool is_inode_cache_good(struct inode *ino)
 	return ino && CIFS_CACHE_READ(CIFS_I(ino)) && CIFS_I(ino)->time != 0;
 }
 
+static int query_reparse(struct cifs_open_info_data *data,
+			 struct super_block *sb,
+			 const unsigned int xid,
+			 struct cifs_tcon *tcon,
+			 const char *full_path,
+			 struct cifs_fattr *fattr)
+{
+	struct TCP_Server_Info *server = tcon->ses->server;
+	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
+	bool reparse_point = data->reparse_point;
+	u32 tag = data->reparse_tag;
+	int rc = 0;
+
+	if (!tag && server->ops->query_reparse_tag) {
+		server->ops->query_reparse_tag(xid, tcon, cifs_sb,
+					       full_path, &tag);
+	}
+	switch ((data->reparse_tag = tag)) {
+	case 0: /* SMB1 symlink */
+		reparse_point = false;
+		fallthrough;
+	case IO_REPARSE_TAG_NFS:
+	case IO_REPARSE_TAG_SYMLINK:
+		if (!data->symlink_target && server->ops->query_symlink) {
+			rc = server->ops->query_symlink(xid, tcon,
+							cifs_sb, full_path,
+							&data->symlink_target,
+							reparse_point);
+		}
+		break;
+	}
+	return rc;
+}
+
 int cifs_get_inode_info(struct inode **inode, const char *full_path,
 			struct cifs_open_info_data *data, struct super_block *sb, int xid,
 			const struct cifs_fid *fid)
@@ -1002,23 +1058,12 @@ int cifs_get_inode_info(struct inode **inode, const char *full_path,
 		 * since we have to check if its reparse tag matches a known
 		 * special file type e.g. symlink or fifo or char etc.
 		 */
-		if (data->reparse_point && data->symlink_target) {
-			data->reparse_tag = IO_REPARSE_TAG_SYMLINK;
-		} else if ((le32_to_cpu(data->fi.Attributes) & ATTR_REPARSE) &&
-			   server->ops->query_reparse_tag) {
-			tmprc = server->ops->query_reparse_tag(xid, tcon, cifs_sb, full_path,
-							       &data->reparse_tag);
-			cifs_dbg(FYI, "%s: query_reparse_tag: rc = %d\n", __func__, tmprc);
-			if (server->ops->query_symlink) {
-				tmprc = server->ops->query_symlink(xid, tcon, cifs_sb,
-								   full_path,
-								   &data->symlink_target,
-								   data->reparse_point);
-				cifs_dbg(FYI, "%s: query_symlink: rc = %d\n",
-					 __func__, tmprc);
-			}
+		if (cifs_open_data_reparse(data)) {
+			rc = query_reparse(data, sb, xid, tcon,
+					   full_path, &fattr);
 		}
-		cifs_open_info_to_fattr(&fattr, data, sb);
+		if (!rc)
+			cifs_open_info_to_fattr(&fattr, data, sb);
 		break;
 	case -EREMOTE:
 		/* DFS link, no metadata available on this server */
diff --git a/fs/smb/client/readdir.c b/fs/smb/client/readdir.c
index ef638086d734..59bf542d5211 100644
--- a/fs/smb/client/readdir.c
+++ b/fs/smb/client/readdir.c
@@ -163,29 +163,19 @@ cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb)
 	 * TODO: go through all documented  reparse tags to see if we can
 	 * reasonably map some of them to directories vs. files vs. symlinks
 	 */
+	if ((fattr->cf_cifsattrs & ATTR_REPARSE) &&
+	    cifs_reparse_point_to_fattr(cifs_sb, fattr, fattr->cf_cifstag))
+		goto out_reparse;
+
 	if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
 		fattr->cf_mode = S_IFDIR | cifs_sb->ctx->dir_mode;
 		fattr->cf_dtype = DT_DIR;
-	} else if (fattr->cf_cifstag == IO_REPARSE_TAG_LX_SYMLINK) {
-		fattr->cf_mode |= S_IFLNK | cifs_sb->ctx->file_mode;
-		fattr->cf_dtype = DT_LNK;
-	} else if (fattr->cf_cifstag == IO_REPARSE_TAG_LX_FIFO) {
-		fattr->cf_mode |= S_IFIFO | cifs_sb->ctx->file_mode;
-		fattr->cf_dtype = DT_FIFO;
-	} else if (fattr->cf_cifstag == IO_REPARSE_TAG_AF_UNIX) {
-		fattr->cf_mode |= S_IFSOCK | cifs_sb->ctx->file_mode;
-		fattr->cf_dtype = DT_SOCK;
-	} else if (fattr->cf_cifstag == IO_REPARSE_TAG_LX_CHR) {
-		fattr->cf_mode |= S_IFCHR | cifs_sb->ctx->file_mode;
-		fattr->cf_dtype = DT_CHR;
-	} else if (fattr->cf_cifstag == IO_REPARSE_TAG_LX_BLK) {
-		fattr->cf_mode |= S_IFBLK | cifs_sb->ctx->file_mode;
-		fattr->cf_dtype = DT_BLK;
-	} else { /* TODO: should we mark some other reparse points (like DFSR) as directories? */
+	} else {
 		fattr->cf_mode = S_IFREG | cifs_sb->ctx->file_mode;
 		fattr->cf_dtype = DT_REG;
 	}
 
+out_reparse:
 	/*
 	 * We need to revalidate it further to make a decision about whether it
 	 * is a symbolic link, DFS referral or a reparse point with a direct
diff --git a/fs/smb/client/smb2inode.c b/fs/smb/client/smb2inode.c
index 69a2969ecdf5..0999383c0284 100644
--- a/fs/smb/client/smb2inode.c
+++ b/fs/smb/client/smb2inode.c
@@ -542,6 +542,33 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
 	return rc;
 }
 
+static int parse_create_response(struct cifs_open_info_data *data,
+				 struct cifs_sb_info *cifs_sb,
+				 const struct kvec *iov)
+{
+	struct smb2_create_rsp *rsp = iov->iov_base;
+	bool reparse_point = false;
+	u32 tag = 0;
+	int rc = 0;
+
+	switch (rsp->hdr.Status) {
+	case STATUS_STOPPED_ON_SYMLINK:
+		rc = smb2_parse_symlink_response(cifs_sb, iov,
+						 &data->symlink_target);
+		if (rc)
+			return rc;
+		tag = IO_REPARSE_TAG_SYMLINK;
+		reparse_point = true;
+		break;
+	case STATUS_SUCCESS:
+		reparse_point = !!(rsp->Flags & SMB2_CREATE_FLAG_REPARSEPOINT);
+		break;
+	}
+	data->reparse_point = reparse_point;
+	data->reparse_tag = tag;
+	return rc;
+}
+
 int smb2_query_path_info(const unsigned int xid,
 			 struct cifs_tcon *tcon,
 			 struct cifs_sb_info *cifs_sb,
@@ -551,6 +578,7 @@ int smb2_query_path_info(const unsigned int xid,
 	__u32 create_options = 0;
 	struct cifsFileInfo *cfile;
 	struct cached_fid *cfid = NULL;
+	struct smb2_hdr *hdr;
 	struct kvec out_iov[3] = {};
 	int out_buftype[3] = {};
 	bool islink;
@@ -579,39 +607,43 @@ int smb2_query_path_info(const unsigned int xid,
 	rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, FILE_READ_ATTRIBUTES, FILE_OPEN,
 			      create_options, ACL_NO_MODE, data, SMB2_OP_QUERY_INFO, cfile,
 			      NULL, NULL, out_iov, out_buftype);
-	if (rc) {
-		struct smb2_hdr *hdr = out_iov[0].iov_base;
+	hdr = out_iov[0].iov_base;
+	/*
+	 * If first iov is unset, then SMB session was dropped or we've got a
+	 * cached open file (@cfile).
+	 */
+	if (!hdr || out_buftype[0] == CIFS_NO_BUFFER)
+		goto out;
 
-		if (unlikely(!hdr || out_buftype[0] == CIFS_NO_BUFFER))
+	switch (rc) {
+	case 0:
+	case -EOPNOTSUPP:
+		rc = parse_create_response(data, cifs_sb, &out_iov[0]);
+		if (rc || !data->reparse_point)
 			goto out;
-		if (rc == -EOPNOTSUPP && hdr->Command == SMB2_CREATE &&
-		    hdr->Status == STATUS_STOPPED_ON_SYMLINK) {
-			rc = smb2_parse_symlink_response(cifs_sb, out_iov,
-							 &data->symlink_target);
-			if (rc)
-				goto out;
 
-			data->reparse_point = true;
-			create_options |= OPEN_REPARSE_POINT;
-
-			/* Failed on a symbolic link - query a reparse point info */
-			cifs_get_readable_path(tcon, full_path, &cfile);
-			rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
-					      FILE_READ_ATTRIBUTES, FILE_OPEN,
-					      create_options, ACL_NO_MODE, data,
-					      SMB2_OP_QUERY_INFO, cfile, NULL, NULL,
-					      NULL, NULL);
+		create_options |= OPEN_REPARSE_POINT;
+		/* Failed on a symbolic link - query a reparse point info */
+		cifs_get_readable_path(tcon, full_path, &cfile);
+		rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
+				      FILE_READ_ATTRIBUTES, FILE_OPEN,
+				      create_options, ACL_NO_MODE, data,
+				      SMB2_OP_QUERY_INFO, cfile, NULL, NULL,
+				      NULL, NULL);
+		break;
+	case -EREMOTE:
+		break;
+	default:
+		if (hdr->Status != STATUS_OBJECT_NAME_INVALID)
+			break;
+		rc2 = cifs_inval_name_dfs_link_error(xid, tcon, cifs_sb,
+						     full_path, &islink);
+		if (rc2) {
+			rc = rc2;
 			goto out;
-		} else if (rc != -EREMOTE && hdr->Status == STATUS_OBJECT_NAME_INVALID) {
-			rc2 = cifs_inval_name_dfs_link_error(xid, tcon, cifs_sb,
-							     full_path, &islink);
-			if (rc2) {
-				rc = rc2;
-				goto out;
-			}
-			if (islink)
-				rc = -EREMOTE;
 		}
+		if (islink)
+			rc = -EREMOTE;
 	}
 
 out:
@@ -653,26 +685,32 @@ int smb311_posix_query_path_info(const unsigned int xid,
 	rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, FILE_READ_ATTRIBUTES, FILE_OPEN,
 			      create_options, ACL_NO_MODE, data, SMB2_OP_POSIX_QUERY_INFO, cfile,
 			      &sidsbuf, &sidsbuflen, out_iov, out_buftype);
-	if (rc == -EOPNOTSUPP) {
+	/*
+	 * If first iov is unset, then SMB session was dropped or we've got a
+	 * cached open file (@cfile).
+	 */
+	if (!out_iov[0].iov_base || out_buftype[0] == CIFS_NO_BUFFER)
+		goto out;
+
+	switch (rc) {
+	case 0:
+	case -EOPNOTSUPP:
 		/* BB TODO: When support for special files added to Samba re-verify this path */
-		if (out_iov[0].iov_base && out_buftype[0] != CIFS_NO_BUFFER &&
-		    ((struct smb2_hdr *)out_iov[0].iov_base)->Command == SMB2_CREATE &&
-		    ((struct smb2_hdr *)out_iov[0].iov_base)->Status == STATUS_STOPPED_ON_SYMLINK) {
-			rc = smb2_parse_symlink_response(cifs_sb, out_iov, &data->symlink_target);
-			if (rc)
-				goto out;
-		}
-		data->reparse_point = true;
-		create_options |= OPEN_REPARSE_POINT;
+		rc = parse_create_response(data, cifs_sb, &out_iov[0]);
+		if (rc || !data->reparse_point)
+			goto out;
 
+		create_options |= OPEN_REPARSE_POINT;
 		/* Failed on a symbolic link - query a reparse point info */
 		cifs_get_readable_path(tcon, full_path, &cfile);
 		rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, FILE_READ_ATTRIBUTES,
 				      FILE_OPEN, create_options, ACL_NO_MODE, data,
 				      SMB2_OP_POSIX_QUERY_INFO, cfile,
 				      &sidsbuf, &sidsbuflen, NULL, NULL);
+		break;
 	}
 
+out:
 	if (rc == 0) {
 		sidsbuf_end = sidsbuf + sidsbuflen;
 
@@ -692,7 +730,6 @@ int smb311_posix_query_path_info(const unsigned int xid,
 		memcpy(group, sidsbuf + owner_len, group_len);
 	}
 
-out:
 	kfree(sidsbuf);
 	free_rsp_buf(out_buftype[0], out_iov[0].iov_base);
 	free_rsp_buf(out_buftype[1], out_iov[1].iov_base);
-- 
2.41.0


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

* [PATCH 09/17] smb: client: do not query reparse points twice on symlinks
  2023-08-17 15:33 [PATCH 00/17] cifs.ko fixes Paulo Alcantara
                   ` (7 preceding siblings ...)
  2023-08-17 15:34 ` [PATCH 08/17] smb: client: parse reparse point flag in create response Paulo Alcantara
@ 2023-08-17 15:34 ` Paulo Alcantara
  2023-08-17 15:52   ` Fwd: " Steve French
  2023-08-17 15:34 ` [PATCH 10/17] smb: client: query reparse points in older dialects Paulo Alcantara
                   ` (8 subsequent siblings)
  17 siblings, 1 reply; 21+ messages in thread
From: Paulo Alcantara @ 2023-08-17 15:34 UTC (permalink / raw)
  To: smfrench; +Cc: linux-cifs, Paulo Alcantara

Save a roundtrip by getting the reparse point tag and buffer at once
in ->query_reparse_point() and then pass the buffer down to
->query_symlink().

Signed-off-by: Paulo Alcantara (SUSE) <pc@manguebit.com>
---
 fs/smb/client/cifsglob.h |  20 +++--
 fs/smb/client/inode.c    |  19 +++--
 fs/smb/client/smb1ops.c  |  11 ++-
 fs/smb/client/smb2ops.c  | 166 ++++++---------------------------------
 4 files changed, 55 insertions(+), 161 deletions(-)

diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
index 95e62502cb01..639a61417b08 100644
--- a/fs/smb/client/cifsglob.h
+++ b/fs/smb/client/cifsglob.h
@@ -336,10 +336,13 @@ struct smb_version_operations {
 	/* query file data from the server */
 	int (*query_file_info)(const unsigned int xid, struct cifs_tcon *tcon,
 			       struct cifsFileInfo *cfile, struct cifs_open_info_data *data);
-	/* query reparse tag from srv to determine which type of special file */
-	int (*query_reparse_tag)(const unsigned int xid, struct cifs_tcon *tcon,
-				struct cifs_sb_info *cifs_sb, const char *path,
-				__u32 *reparse_tag);
+	/* query reparse point to determine which type of special file */
+	int (*query_reparse_point)(const unsigned int xid,
+				   struct cifs_tcon *tcon,
+				   struct cifs_sb_info *cifs_sb,
+				   const char *full_path,
+				   u32 *tag, struct kvec *rsp,
+				   int *rsp_buftype);
 	/* get server index number */
 	int (*get_srv_inum)(const unsigned int xid, struct cifs_tcon *tcon,
 			    struct cifs_sb_info *cifs_sb, const char *full_path, u64 *uniqueid,
@@ -388,9 +391,12 @@ struct smb_version_operations {
 			       const char *, const char *,
 			       struct cifs_sb_info *);
 	/* query symlink target */
-	int (*query_symlink)(const unsigned int, struct cifs_tcon *,
-			     struct cifs_sb_info *, const char *,
-			     char **, bool);
+	int (*query_symlink)(const unsigned int xid,
+			     struct cifs_tcon *tcon,
+			     struct cifs_sb_info *cifs_sb,
+			     const char *full_path,
+			     char **target_path,
+			     struct kvec *rsp_iov);
 	/* open a file for non-posix mounts */
 	int (*open)(const unsigned int xid, struct cifs_open_parms *oparms, __u32 *oplock,
 		    void *buf);
diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c
index 51e2916730cf..96a09818aa5b 100644
--- a/fs/smb/client/inode.c
+++ b/fs/smb/client/inode.c
@@ -428,7 +428,7 @@ int cifs_get_inode_info_unix(struct inode **pinode,
 		if (!server->ops->query_symlink)
 			return -EOPNOTSUPP;
 		rc = server->ops->query_symlink(xid, tcon, cifs_sb, full_path,
-						&fattr.cf_symlink_target, false);
+						&fattr.cf_symlink_target, NULL);
 		if (rc) {
 			cifs_dbg(FYI, "%s: query_symlink: %d\n", __func__, rc);
 			goto cgiiu_exit;
@@ -988,17 +988,21 @@ static int query_reparse(struct cifs_open_info_data *data,
 {
 	struct TCP_Server_Info *server = tcon->ses->server;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
-	bool reparse_point = data->reparse_point;
+	struct kvec rsp_iov, *iov = NULL;
+	int rsp_buftype = CIFS_NO_BUFFER;
 	u32 tag = data->reparse_tag;
 	int rc = 0;
 
-	if (!tag && server->ops->query_reparse_tag) {
-		server->ops->query_reparse_tag(xid, tcon, cifs_sb,
-					       full_path, &tag);
+	if (!tag && server->ops->query_reparse_point) {
+		rc = server->ops->query_reparse_point(xid, tcon, cifs_sb,
+						      full_path, &tag,
+						      &rsp_iov, &rsp_buftype);
+		if (!rc)
+			iov = &rsp_iov;
 	}
 	switch ((data->reparse_tag = tag)) {
 	case 0: /* SMB1 symlink */
-		reparse_point = false;
+		iov = NULL;
 		fallthrough;
 	case IO_REPARSE_TAG_NFS:
 	case IO_REPARSE_TAG_SYMLINK:
@@ -1006,10 +1010,11 @@ static int query_reparse(struct cifs_open_info_data *data,
 			rc = server->ops->query_symlink(xid, tcon,
 							cifs_sb, full_path,
 							&data->symlink_target,
-							reparse_point);
+							iov);
 		}
 		break;
 	}
+	free_rsp_buf(rsp_buftype, rsp_iov.iov_base);
 	return rc;
 }
 
diff --git a/fs/smb/client/smb1ops.c b/fs/smb/client/smb1ops.c
index 094ef4fe2219..9bf8735cdd1e 100644
--- a/fs/smb/client/smb1ops.c
+++ b/fs/smb/client/smb1ops.c
@@ -972,13 +972,16 @@ cifs_unix_dfs_readlink(const unsigned int xid, struct cifs_tcon *tcon,
 #endif
 }
 
-static int
-cifs_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
-		   struct cifs_sb_info *cifs_sb, const char *full_path,
-		   char **target_path, bool is_reparse_point)
+static int cifs_query_symlink(const unsigned int xid,
+			      struct cifs_tcon *tcon,
+			      struct cifs_sb_info *cifs_sb,
+			      const char *full_path,
+			      char **target_path,
+			      struct kvec *rsp_iov)
 {
 	int rc;
 	int oplock = 0;
+	bool is_reparse_point = !!rsp_iov;
 	struct cifs_fid fid;
 	struct cifs_open_parms oparms;
 
diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
index 0f62bc373ad0..5eb2720f4aa7 100644
--- a/fs/smb/client/smb2ops.c
+++ b/fs/smb/client/smb2ops.c
@@ -2948,153 +2948,30 @@ parse_reparse_point(struct reparse_data_buffer *buf,
 	}
 }
 
-static int
-smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
-		   struct cifs_sb_info *cifs_sb, const char *full_path,
-		   char **target_path, bool is_reparse_point)
+static int smb2_query_symlink(const unsigned int xid,
+			      struct cifs_tcon *tcon,
+			      struct cifs_sb_info *cifs_sb,
+			      const char *full_path,
+			      char **target_path,
+			      struct kvec *rsp_iov)
 {
-	int rc;
-	__le16 *utf16_path = NULL;
-	__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
-	struct cifs_open_parms oparms;
-	struct cifs_fid fid;
-	struct kvec err_iov = {NULL, 0};
-	struct TCP_Server_Info *server = cifs_pick_channel(tcon->ses);
-	int flags = CIFS_CP_CREATE_CLOSE_OP;
-	struct smb_rqst rqst[3];
-	int resp_buftype[3];
-	struct kvec rsp_iov[3];
-	struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
-	struct kvec io_iov[SMB2_IOCTL_IOV_SIZE];
-	struct kvec close_iov[1];
-	struct smb2_create_rsp *create_rsp;
-	struct smb2_ioctl_rsp *ioctl_rsp;
-	struct reparse_data_buffer *reparse_buf;
-	int create_options = is_reparse_point ? OPEN_REPARSE_POINT : 0;
-	u32 plen;
+	struct reparse_data_buffer *buf;
+	struct smb2_ioctl_rsp *io = rsp_iov->iov_base;
+	u32 plen = le32_to_cpu(io->OutputCount);
 
 	cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path);
 
-	*target_path = NULL;
-
-	if (smb3_encryption_required(tcon))
-		flags |= CIFS_TRANSFORM_REQ;
-
-	memset(rqst, 0, sizeof(rqst));
-	resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
-	memset(rsp_iov, 0, sizeof(rsp_iov));
-
-	utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
-	if (!utf16_path)
-		return -ENOMEM;
-
-	/* Open */
-	memset(&open_iov, 0, sizeof(open_iov));
-	rqst[0].rq_iov = open_iov;
-	rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE;
-
-	oparms = (struct cifs_open_parms) {
-		.tcon = tcon,
-		.path = full_path,
-		.desired_access = FILE_READ_ATTRIBUTES,
-		.disposition = FILE_OPEN,
-		.create_options = cifs_create_options(cifs_sb, create_options),
-		.fid = &fid,
-	};
-
-	rc = SMB2_open_init(tcon, server,
-			    &rqst[0], &oplock, &oparms, utf16_path);
-	if (rc)
-		goto querty_exit;
-	smb2_set_next_command(tcon, &rqst[0]);
-
-
-	/* IOCTL */
-	memset(&io_iov, 0, sizeof(io_iov));
-	rqst[1].rq_iov = io_iov;
-	rqst[1].rq_nvec = SMB2_IOCTL_IOV_SIZE;
-
-	rc = SMB2_ioctl_init(tcon, server,
-			     &rqst[1], fid.persistent_fid,
-			     fid.volatile_fid, FSCTL_GET_REPARSE_POINT, NULL, 0,
-			     CIFSMaxBufSize -
-			     MAX_SMB2_CREATE_RESPONSE_SIZE -
-			     MAX_SMB2_CLOSE_RESPONSE_SIZE);
-	if (rc)
-		goto querty_exit;
-
-	smb2_set_next_command(tcon, &rqst[1]);
-	smb2_set_related(&rqst[1]);
-
-
-	/* Close */
-	memset(&close_iov, 0, sizeof(close_iov));
-	rqst[2].rq_iov = close_iov;
-	rqst[2].rq_nvec = 1;
-
-	rc = SMB2_close_init(tcon, server,
-			     &rqst[2], COMPOUND_FID, COMPOUND_FID, false);
-	if (rc)
-		goto querty_exit;
-
-	smb2_set_related(&rqst[2]);
-
-	rc = compound_send_recv(xid, tcon->ses, server,
-				flags, 3, rqst,
-				resp_buftype, rsp_iov);
-
-	create_rsp = rsp_iov[0].iov_base;
-	if (create_rsp && create_rsp->hdr.Status)
-		err_iov = rsp_iov[0];
-	ioctl_rsp = rsp_iov[1].iov_base;
-
-	/*
-	 * Open was successful and we got an ioctl response.
-	 */
-	if ((rc == 0) && (is_reparse_point)) {
-		/* See MS-FSCC 2.3.23 */
-
-		reparse_buf = (struct reparse_data_buffer *)
-			((char *)ioctl_rsp +
-			 le32_to_cpu(ioctl_rsp->OutputOffset));
-		plen = le32_to_cpu(ioctl_rsp->OutputCount);
-
-		if (plen + le32_to_cpu(ioctl_rsp->OutputOffset) >
-		    rsp_iov[1].iov_len) {
-			cifs_tcon_dbg(VFS, "srv returned invalid ioctl len: %d\n",
-				 plen);
-			rc = -EIO;
-			goto querty_exit;
-		}
-
-		rc = parse_reparse_point(reparse_buf, plen, target_path,
-					 cifs_sb);
-		goto querty_exit;
-	}
-
-	if (!rc || !err_iov.iov_base) {
-		rc = -ENOENT;
-		goto querty_exit;
-	}
-
-	rc = smb2_parse_symlink_response(cifs_sb, &err_iov, target_path);
-
- querty_exit:
-	cifs_dbg(FYI, "query symlink rc %d\n", rc);
-	kfree(utf16_path);
-	SMB2_open_free(&rqst[0]);
-	SMB2_ioctl_free(&rqst[1]);
-	SMB2_close_free(&rqst[2]);
-	free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
-	free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
-	free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base);
-	return rc;
+	buf = (struct reparse_data_buffer *)((u8 *)io +
+					     le32_to_cpu(io->OutputOffset));
+	return parse_reparse_point(buf, plen, target_path, cifs_sb);
 }
 
-int
-smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon,
-		   struct cifs_sb_info *cifs_sb, const char *full_path,
-		   __u32 *tag)
+static int smb2_query_reparse_point(const unsigned int xid,
+				    struct cifs_tcon *tcon,
+				    struct cifs_sb_info *cifs_sb,
+				    const char *full_path,
+				    u32 *tag, struct kvec *rsp,
+				    int *rsp_buftype)
 {
 	int rc;
 	__le16 *utf16_path = NULL;
@@ -3205,6 +3082,9 @@ smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon,
 			goto query_rp_exit;
 		}
 		*tag = le32_to_cpu(reparse_buf->ReparseTag);
+		*rsp = rsp_iov[1];
+		*rsp_buftype = resp_buftype[1];
+		resp_buftype[1] = CIFS_NO_BUFFER;
 	}
 
  query_rp_exit:
@@ -5503,7 +5383,7 @@ struct smb_version_operations smb30_operations = {
 	.echo = SMB2_echo,
 	.query_path_info = smb2_query_path_info,
 	/* WSL tags introduced long after smb2.1, enable for SMB3, 3.11 only */
-	.query_reparse_tag = smb2_query_reparse_tag,
+	.query_reparse_point = smb2_query_reparse_point,
 	.get_srv_inum = smb2_get_srv_inum,
 	.query_file_info = smb2_query_file_info,
 	.set_path_size = smb2_set_path_size,
@@ -5616,7 +5496,7 @@ struct smb_version_operations smb311_operations = {
 	.can_echo = smb2_can_echo,
 	.echo = SMB2_echo,
 	.query_path_info = smb2_query_path_info,
-	.query_reparse_tag = smb2_query_reparse_tag,
+	.query_reparse_point = smb2_query_reparse_point,
 	.get_srv_inum = smb2_get_srv_inum,
 	.query_file_info = smb2_query_file_info,
 	.set_path_size = smb2_set_path_size,
-- 
2.41.0


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

* [PATCH 10/17] smb: client: query reparse points in older dialects
  2023-08-17 15:33 [PATCH 00/17] cifs.ko fixes Paulo Alcantara
                   ` (8 preceding siblings ...)
  2023-08-17 15:34 ` [PATCH 09/17] smb: client: do not query reparse points twice on symlinks Paulo Alcantara
@ 2023-08-17 15:34 ` Paulo Alcantara
  2023-08-17 15:34 ` [PATCH 11/17] smb: cilent: set reparse mount points as automounts Paulo Alcantara
                   ` (7 subsequent siblings)
  17 siblings, 0 replies; 21+ messages in thread
From: Paulo Alcantara @ 2023-08-17 15:34 UTC (permalink / raw)
  To: smfrench; +Cc: linux-cifs, Paulo Alcantara

Enable the client to query reparse points in SMB2+.

Signed-off-by: Paulo Alcantara (SUSE) <pc@manguebit.com>
---
 fs/smb/client/smb2ops.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
index 5eb2720f4aa7..91c7b7e52a72 100644
--- a/fs/smb/client/smb2ops.c
+++ b/fs/smb/client/smb2ops.c
@@ -5178,6 +5178,7 @@ struct smb_version_operations smb20_operations = {
 	.can_echo = smb2_can_echo,
 	.echo = SMB2_echo,
 	.query_path_info = smb2_query_path_info,
+	.query_reparse_point = smb2_query_reparse_point,
 	.get_srv_inum = smb2_get_srv_inum,
 	.query_file_info = smb2_query_file_info,
 	.set_path_size = smb2_set_path_size,
@@ -5279,6 +5280,7 @@ struct smb_version_operations smb21_operations = {
 	.can_echo = smb2_can_echo,
 	.echo = SMB2_echo,
 	.query_path_info = smb2_query_path_info,
+	.query_reparse_point = smb2_query_reparse_point,
 	.get_srv_inum = smb2_get_srv_inum,
 	.query_file_info = smb2_query_file_info,
 	.set_path_size = smb2_set_path_size,
-- 
2.41.0


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

* [PATCH 11/17] smb: cilent: set reparse mount points as automounts
  2023-08-17 15:33 [PATCH 00/17] cifs.ko fixes Paulo Alcantara
                   ` (9 preceding siblings ...)
  2023-08-17 15:34 ` [PATCH 10/17] smb: client: query reparse points in older dialects Paulo Alcantara
@ 2023-08-17 15:34 ` Paulo Alcantara
  2023-08-17 15:34 ` [PATCH 12/17] smb: client: reduce stack usage in cifs_try_adding_channels() Paulo Alcantara
                   ` (6 subsequent siblings)
  17 siblings, 0 replies; 21+ messages in thread
From: Paulo Alcantara @ 2023-08-17 15:34 UTC (permalink / raw)
  To: smfrench; +Cc: linux-cifs, Paulo Alcantara

By doing so we can selectively mark those submounts as 'noserverino'
rather than whole mount and thus avoiding inode collisions in them.

Consider a "test" SMB share that has two mounted NTFS volumes
(vol0 & vol1) inside it.

* Before patch

$ mount.cifs //srv/test /mnt/1 -o ...,serverino
$ ls -li /mnt/1/vol0
total 1
281474976710693 drwxr-xr-x 2 root root 0 Jul 15 00:23 $RECYCLE.BIN
281474976710696 drwxr-xr-x 2 root root 0 Jul 18 18:23 System Volume...
281474976710699 -rwxr-xr-x 1 root root 0 Aug 14 21:53 f0
281474976710700 -rwxr-xr-x 1 root root 0 Aug 15 18:52 f2
281474976710698 drwxr-xr-x 2 root root 0 Aug 12 19:39 foo
281474976710692 -rwxr-xr-x 1 root root 5 Aug  4 21:18 vol0_f0.txt
$ ls -li /mnt/1/vol1
total 0
281474976710693 drwxr-xr-x 2 root root 0 Jul 15 00:23 $RECYCLE.BIN
281474976710696 drwxr-xr-x 2 root root 0 Jul 18 18:23 System Volume...
281474976710698 drwxr-xr-x 2 root root 0 Aug 12 19:39 bar
281474976710699 -rwxr-xr-x 1 root root 0 Aug 14 22:03 f0
281474976710700 -rwxr-xr-x 1 root root 0 Aug 14 22:52 f1
281474976710692 -rwxr-xr-x 1 root root 0 Jul 15 00:23 vol1_f0.txt

* After patch

$ mount.cifs //srv/test /mnt/1 -o ...,serverino
$ ls -li /mnt/1/vol0
total 1
590 drwxr-xr-x 2 root root 0 Jul 15 00:23 $RECYCLE.BIN
594 drwxr-xr-x 2 root root 0 Jul 18 18:23 System Volume Information
591 -rwxr-xr-x 1 root root 0 Aug 14 21:53 f0
592 -rwxr-xr-x 1 root root 0 Aug 15 18:52 f2
593 drwxr-xr-x 2 root root 0 Aug 12 19:39 foo
595 -rwxr-xr-x 1 root root 5 Aug  4 21:18 vol0_f0.txt
$ ls -li /mnt/1/vol1
total 0
596 drwxr-xr-x 2 root root 0 Jul 15 00:23 $RECYCLE.BIN
600 drwxr-xr-x 2 root root 0 Jul 18 18:23 System Volume Information
597 drwxr-xr-x 2 root root 0 Aug 12 19:39 bar
598 -rwxr-xr-x 1 root root 0 Aug 14 22:03 f0
599 -rwxr-xr-x 1 root root 0 Aug 14 22:52 f1
601 -rwxr-xr-x 1 root root 0 Jul 15 00:23 vol1_f0.txt

Signed-off-by: Paulo Alcantara (SUSE) <pc@manguebit.com>
---
 fs/smb/client/cifsglob.h  |   2 +-
 fs/smb/client/inode.c     | 352 +++++++++++++++++++++-----------------
 fs/smb/client/namespace.c |  19 +-
 fs/smb/client/readdir.c   |   1 +
 4 files changed, 198 insertions(+), 176 deletions(-)

diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
index 639a61417b08..6d5fa0351dce 100644
--- a/fs/smb/client/cifsglob.h
+++ b/fs/smb/client/cifsglob.h
@@ -1094,7 +1094,7 @@ cap_unix(struct cifs_ses *ses)
  * inode with new info
  */
 
-#define CIFS_FATTR_DFS_REFERRAL		0x1
+#define CIFS_FATTR_JUNCTION		0x1
 #define CIFS_FATTR_DELETE_PENDING	0x2
 #define CIFS_FATTR_NEED_REVAL		0x4
 #define CIFS_FATTR_INO_COLLISION	0x8
diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c
index 96a09818aa5b..ba17356aa7bb 100644
--- a/fs/smb/client/inode.c
+++ b/fs/smb/client/inode.c
@@ -214,7 +214,7 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
 	}
 	spin_unlock(&inode->i_lock);
 
-	if (fattr->cf_flags & CIFS_FATTR_DFS_REFERRAL)
+	if (fattr->cf_flags & CIFS_FATTR_JUNCTION)
 		inode->i_flags |= S_AUTOMOUNT;
 	if (inode->i_state & I_NEW)
 		cifs_set_ops(inode);
@@ -323,14 +323,14 @@ cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, FILE_UNIX_BASIC_INFO *info,
  *
  * Needed to setup cifs_fattr data for the directory which is the
  * junction to the new submount (ie to setup the fake directory
- * which represents a DFS referral).
+ * which represents a DFS referral or reparse mount point).
  */
-static void
-cifs_create_dfs_fattr(struct cifs_fattr *fattr, struct super_block *sb)
+static void cifs_create_junction_fattr(struct cifs_fattr *fattr,
+				       struct super_block *sb)
 {
 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
 
-	cifs_dbg(FYI, "creating fake fattr for DFS referral\n");
+	cifs_dbg(FYI, "%s: creating fake fattr\n", __func__);
 
 	memset(fattr, 0, sizeof(*fattr));
 	fattr->cf_mode = S_IFDIR | S_IXUGO | S_IRWXU;
@@ -339,7 +339,33 @@ cifs_create_dfs_fattr(struct cifs_fattr *fattr, struct super_block *sb)
 	ktime_get_coarse_real_ts64(&fattr->cf_mtime);
 	fattr->cf_atime = fattr->cf_ctime = fattr->cf_mtime;
 	fattr->cf_nlink = 2;
-	fattr->cf_flags = CIFS_FATTR_DFS_REFERRAL;
+	fattr->cf_flags = CIFS_FATTR_JUNCTION;
+}
+
+/* Update inode with final fattr data */
+static int update_inode_info(struct super_block *sb,
+			     struct cifs_fattr *fattr,
+			     struct inode **inode)
+{
+	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
+	int rc = 0;
+
+	if (!*inode) {
+		*inode = cifs_iget(sb, fattr);
+		if (!*inode)
+			rc = -ENOMEM;
+		return rc;
+	}
+	/* We already have inode, update it.
+	 *
+	 * If file type or uniqueid is different, return error.
+	 */
+	if (unlikely((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) &&
+		     CIFS_I(*inode)->uniqueid != fattr->cf_uniqueid)) {
+		CIFS_I(*inode)->time = 0; /* force reval */
+		return -ESTALE;
+	}
+	return cifs_fattr_to_inode(*inode, fattr);
 }
 
 #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
@@ -369,7 +395,7 @@ cifs_get_file_info_unix(struct file *filp)
 	if (!rc) {
 		cifs_unix_basic_to_fattr(&fattr, &find_data, cifs_sb);
 	} else if (rc == -EREMOTE) {
-		cifs_create_dfs_fattr(&fattr, inode->i_sb);
+		cifs_create_junction_fattr(&fattr, inode->i_sb);
 		rc = 0;
 	} else
 		goto cifs_gfiunix_out;
@@ -381,17 +407,18 @@ cifs_get_file_info_unix(struct file *filp)
 	return rc;
 }
 
-int cifs_get_inode_info_unix(struct inode **pinode,
-			     const unsigned char *full_path,
-			     struct super_block *sb, unsigned int xid)
+static int cifs_get_unix_fattr(const unsigned char *full_path,
+			       struct super_block *sb,
+			       struct cifs_fattr *fattr,
+			       struct inode **pinode,
+			       const unsigned int xid)
 {
-	int rc;
+	struct TCP_Server_Info *server;
+	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
 	FILE_UNIX_BASIC_INFO find_data;
-	struct cifs_fattr fattr;
 	struct cifs_tcon *tcon;
-	struct TCP_Server_Info *server;
 	struct tcon_link *tlink;
-	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
+	int rc, tmprc;
 
 	cifs_dbg(FYI, "Getting info on %s\n", full_path);
 
@@ -408,59 +435,61 @@ int cifs_get_inode_info_unix(struct inode **pinode,
 	cifs_put_tlink(tlink);
 
 	if (!rc) {
-		cifs_unix_basic_to_fattr(&fattr, &find_data, cifs_sb);
+		cifs_unix_basic_to_fattr(fattr, &find_data, cifs_sb);
 	} else if (rc == -EREMOTE) {
-		cifs_create_dfs_fattr(&fattr, sb);
+		cifs_create_junction_fattr(fattr, sb);
 		rc = 0;
 	} else {
 		return rc;
 	}
 
+	if (!*pinode)
+		cifs_fill_uniqueid(sb, fattr);
+
 	/* check for Minshall+French symlinks */
 	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
-		int tmprc = check_mf_symlink(xid, tcon, cifs_sb, &fattr,
-					     full_path);
-		if (tmprc)
-			cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc);
+		tmprc = check_mf_symlink(xid, tcon, cifs_sb, fattr, full_path);
+		cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc);
 	}
 
-	if (S_ISLNK(fattr.cf_mode) && !fattr.cf_symlink_target) {
+	if (S_ISLNK(fattr->cf_mode) && !fattr->cf_symlink_target) {
 		if (!server->ops->query_symlink)
 			return -EOPNOTSUPP;
-		rc = server->ops->query_symlink(xid, tcon, cifs_sb, full_path,
-						&fattr.cf_symlink_target, NULL);
-		if (rc) {
-			cifs_dbg(FYI, "%s: query_symlink: %d\n", __func__, rc);
-			goto cgiiu_exit;
-		}
+		rc = server->ops->query_symlink(xid, tcon,
+						cifs_sb, full_path,
+						&fattr->cf_symlink_target,
+						NULL);
+		cifs_dbg(FYI, "%s: query_symlink: %d\n", __func__, rc);
 	}
+	return rc;
+}
 
-	if (*pinode == NULL) {
-		/* get new inode */
-		cifs_fill_uniqueid(sb, &fattr);
-		*pinode = cifs_iget(sb, &fattr);
-		if (!*pinode)
-			rc = -ENOMEM;
-	} else {
-		/* we already have inode, update it */
+int cifs_get_inode_info_unix(struct inode **pinode,
+			     const unsigned char *full_path,
+			     struct super_block *sb, unsigned int xid)
+{
+	struct cifs_fattr fattr = {};
+	int rc;
 
-		/* if uniqueid is different, return error */
-		if (unlikely(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM &&
-		    CIFS_I(*pinode)->uniqueid != fattr.cf_uniqueid)) {
-			CIFS_I(*pinode)->time = 0; /* force reval */
-			rc = -ESTALE;
-			goto cgiiu_exit;
-		}
+	rc = cifs_get_unix_fattr(full_path, sb, &fattr, pinode, xid);
+	if (rc)
+		goto out;
 
-		/* if filetype is different, return error */
-		rc = cifs_fattr_to_inode(*pinode, &fattr);
-	}
-
-cgiiu_exit:
+	rc = update_inode_info(sb, &fattr, pinode);
+out:
 	kfree(fattr.cf_symlink_target);
 	return rc;
 }
 #else
+static inline int cifs_get_unix_fattr(const unsigned char *full_path,
+				      struct super_block *sb,
+				      struct cifs_fattr *fattr,
+				      struct inode **pinode,
+				      const unsigned int xid)
+{
+	return -EOPNOTSUPP;
+}
+
 int cifs_get_inode_info_unix(struct inode **pinode,
 			     const unsigned char *full_path,
 			     struct super_block *sb, unsigned int xid)
@@ -826,7 +855,7 @@ cifs_get_file_info(struct file *filp)
 		cifs_open_info_to_fattr(&fattr, &data, inode->i_sb);
 		break;
 	case -EREMOTE:
-		cifs_create_dfs_fattr(&fattr, inode->i_sb);
+		cifs_create_junction_fattr(&fattr, inode->i_sb);
 		rc = 0;
 		break;
 	case -EOPNOTSUPP:
@@ -979,12 +1008,12 @@ static inline bool is_inode_cache_good(struct inode *ino)
 	return ino && CIFS_CACHE_READ(CIFS_I(ino)) && CIFS_I(ino)->time != 0;
 }
 
-static int query_reparse(struct cifs_open_info_data *data,
-			 struct super_block *sb,
-			 const unsigned int xid,
-			 struct cifs_tcon *tcon,
-			 const char *full_path,
-			 struct cifs_fattr *fattr)
+static int reparse_info_to_fattr(struct cifs_open_info_data *data,
+				 struct super_block *sb,
+				 const unsigned int xid,
+				 struct cifs_tcon *tcon,
+				 const char *full_path,
+				 struct cifs_fattr *fattr)
 {
 	struct TCP_Server_Info *server = tcon->ses->server;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
@@ -1013,21 +1042,29 @@ static int query_reparse(struct cifs_open_info_data *data,
 							iov);
 		}
 		break;
+	case IO_REPARSE_TAG_MOUNT_POINT:
+		cifs_create_junction_fattr(fattr, sb);
+		goto out;
 	}
+
+	cifs_open_info_to_fattr(fattr, data, sb);
+out:
 	free_rsp_buf(rsp_buftype, rsp_iov.iov_base);
 	return rc;
 }
 
-int cifs_get_inode_info(struct inode **inode, const char *full_path,
-			struct cifs_open_info_data *data, struct super_block *sb, int xid,
-			const struct cifs_fid *fid)
+static int cifs_get_fattr(struct cifs_open_info_data *data,
+			  struct super_block *sb, int xid,
+			  const struct cifs_fid *fid,
+			  struct cifs_fattr *fattr,
+			  struct inode **inode,
+			  const char *full_path)
 {
-	struct cifs_tcon *tcon;
-	struct TCP_Server_Info *server;
-	struct tcon_link *tlink;
-	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
-	struct cifs_fattr fattr = {0};
 	struct cifs_open_info_data tmp_data = {};
+	struct cifs_tcon *tcon;
+	struct TCP_Server_Info *server;
+	struct tcon_link *tlink;
+	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
 	void *smb1_backup_rsp_buf = NULL;
 	int rc = 0;
 	int tmprc = 0;
@@ -1043,10 +1080,6 @@ int cifs_get_inode_info(struct inode **inode, const char *full_path,
 	 */
 
 	if (!data) {
-		if (is_inode_cache_good(*inode)) {
-			cifs_dbg(FYI, "No need to revalidate cached inode sizes\n");
-			goto out;
-		}
 		rc = server->ops->query_path_info(xid, tcon, cifs_sb,
 						  full_path, &tmp_data);
 		data = &tmp_data;
@@ -1064,15 +1097,15 @@ int cifs_get_inode_info(struct inode **inode, const char *full_path,
 		 * special file type e.g. symlink or fifo or char etc.
 		 */
 		if (cifs_open_data_reparse(data)) {
-			rc = query_reparse(data, sb, xid, tcon,
-					   full_path, &fattr);
+			rc = reparse_info_to_fattr(data, sb, xid, tcon,
+						   full_path, fattr);
+		} else {
+			cifs_open_info_to_fattr(fattr, data, sb);
 		}
-		if (!rc)
-			cifs_open_info_to_fattr(&fattr, data, sb);
 		break;
 	case -EREMOTE:
 		/* DFS link, no metadata available on this server */
-		cifs_create_dfs_fattr(&fattr, sb);
+		cifs_create_junction_fattr(fattr, sb);
 		rc = 0;
 		break;
 	case -EACCES:
@@ -1102,8 +1135,8 @@ int cifs_get_inode_info(struct inode **inode, const char *full_path,
 			fdi = (FILE_DIRECTORY_INFO *)fi;
 			si = (SEARCH_ID_FULL_DIR_INFO *)fi;
 
-			cifs_dir_info_to_fattr(&fattr, fdi, cifs_sb);
-			fattr.cf_uniqueid = le64_to_cpu(si->UniqueId);
+			cifs_dir_info_to_fattr(fattr, fdi, cifs_sb);
+			fattr->cf_uniqueid = le64_to_cpu(si->UniqueId);
 			/* uniqueid set, skip get inum step */
 			goto handle_mnt_opt;
 		} else {
@@ -1120,10 +1153,10 @@ int cifs_get_inode_info(struct inode **inode, const char *full_path,
 	}
 
 	/*
-	 * 3. Get or update inode number (fattr.cf_uniqueid)
+	 * 3. Get or update inode number (fattr->cf_uniqueid)
 	 */
 
-	cifs_set_fattr_ino(xid, tcon, sb, inode, full_path, data, &fattr);
+	cifs_set_fattr_ino(xid, tcon, sb, inode, full_path, data, fattr);
 
 	/*
 	 * 4. Tweak fattr based on mount options
@@ -1132,17 +1165,17 @@ int cifs_get_inode_info(struct inode **inode, const char *full_path,
 handle_mnt_opt:
 #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
 	/* query for SFU type info if supported and needed */
-	if (fattr.cf_cifsattrs & ATTR_SYSTEM &&
-	    cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
-		tmprc = cifs_sfu_type(&fattr, full_path, cifs_sb, xid);
+	if ((fattr->cf_cifsattrs & ATTR_SYSTEM) &&
+	    (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) {
+		tmprc = cifs_sfu_type(fattr, full_path, cifs_sb, xid);
 		if (tmprc)
 			cifs_dbg(FYI, "cifs_sfu_type failed: %d\n", tmprc);
 	}
 
 	/* fill in 0777 bits from ACL */
 	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID) {
-		rc = cifs_acl_to_fattr(cifs_sb, &fattr, *inode, true,
-				       full_path, fid);
+		rc = cifs_acl_to_fattr(cifs_sb, fattr, *inode,
+				       true, full_path, fid);
 		if (rc == -EREMOTE)
 			rc = 0;
 		if (rc) {
@@ -1151,8 +1184,8 @@ int cifs_get_inode_info(struct inode **inode, const char *full_path,
 			goto out;
 		}
 	} else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
-		rc = cifs_acl_to_fattr(cifs_sb, &fattr, *inode, false,
-				       full_path, fid);
+		rc = cifs_acl_to_fattr(cifs_sb, fattr, *inode,
+				       false, full_path, fid);
 		if (rc == -EREMOTE)
 			rc = 0;
 		if (rc) {
@@ -1164,58 +1197,57 @@ int cifs_get_inode_info(struct inode **inode, const char *full_path,
 
 	/* fill in remaining high mode bits e.g. SUID, VTX */
 	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)
-		cifs_sfu_mode(&fattr, full_path, cifs_sb, xid);
+		cifs_sfu_mode(fattr, full_path, cifs_sb, xid);
 
 	/* check for Minshall+French symlinks */
 	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
-		tmprc = check_mf_symlink(xid, tcon, cifs_sb, &fattr,
-					 full_path);
-		if (tmprc)
-			cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc);
+		tmprc = check_mf_symlink(xid, tcon, cifs_sb, fattr, full_path);
+		cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc);
 	}
 
-	/*
-	 * 5. Update inode with final fattr data
-	 */
-
-	if (!*inode) {
-		*inode = cifs_iget(sb, &fattr);
-		if (!*inode)
-			rc = -ENOMEM;
-	} else {
-		/* we already have inode, update it */
-
-		/* if uniqueid is different, return error */
-		if (unlikely(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM &&
-		    CIFS_I(*inode)->uniqueid != fattr.cf_uniqueid)) {
-			CIFS_I(*inode)->time = 0; /* force reval */
-			rc = -ESTALE;
-			goto out;
-		}
-		/* if filetype is different, return error */
-		rc = cifs_fattr_to_inode(*inode, &fattr);
-	}
 out:
 	cifs_buf_release(smb1_backup_rsp_buf);
 	cifs_put_tlink(tlink);
 	cifs_free_open_info(&tmp_data);
+	return rc;
+}
+
+int cifs_get_inode_info(struct inode **inode,
+			const char *full_path,
+			struct cifs_open_info_data *data,
+			struct super_block *sb, int xid,
+			const struct cifs_fid *fid)
+{
+	struct cifs_fattr fattr = {};
+	int rc;
+
+	if (is_inode_cache_good(*inode)) {
+		cifs_dbg(FYI, "No need to revalidate cached inode sizes\n");
+		return 0;
+	}
+
+	rc = cifs_get_fattr(data, sb, xid, fid, &fattr, inode, full_path);
+	if (rc)
+		goto out;
+
+	rc = update_inode_info(sb, &fattr, inode);
+out:
 	kfree(fattr.cf_symlink_target);
 	return rc;
 }
 
-int
-smb311_posix_get_inode_info(struct inode **inode,
-		    const char *full_path,
-		    struct super_block *sb, unsigned int xid)
+static int smb311_posix_get_fattr(struct cifs_fattr *fattr,
+				  const char *full_path,
+				  struct super_block *sb,
+				  const unsigned int xid)
 {
+	struct cifs_open_info_data data = {};
+	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
 	struct cifs_tcon *tcon;
 	struct tcon_link *tlink;
-	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
-	struct cifs_fattr fattr = {0};
-	struct cifs_open_info_data data = {};
 	struct cifs_sid owner, group;
-	int rc = 0;
-	int tmprc = 0;
+	int tmprc;
+	int rc;
 
 	tlink = cifs_sb_tlink(cifs_sb);
 	if (IS_ERR(tlink))
@@ -1226,11 +1258,6 @@ smb311_posix_get_inode_info(struct inode **inode,
 	 * 1. Fetch file metadata
 	 */
 
-	if (is_inode_cache_good(*inode)) {
-		cifs_dbg(FYI, "No need to revalidate cached inode sizes\n");
-		goto out;
-	}
-
 	rc = smb311_posix_query_path_info(xid, tcon, cifs_sb,
 					  full_path, &data,
 					  &owner, &group);
@@ -1241,11 +1268,11 @@ smb311_posix_get_inode_info(struct inode **inode,
 
 	switch (rc) {
 	case 0:
-		smb311_posix_info_to_fattr(&fattr, &data, &owner, &group, sb);
+		smb311_posix_info_to_fattr(fattr, &data, &owner, &group, sb);
 		break;
 	case -EREMOTE:
 		/* DFS link, no metadata available on this server */
-		cifs_create_dfs_fattr(&fattr, sb);
+		cifs_create_junction_fattr(fattr, sb);
 		rc = 0;
 		break;
 	case -EACCES:
@@ -1261,49 +1288,42 @@ smb311_posix_get_inode_info(struct inode **inode,
 		goto out;
 	}
 
-
 	/*
 	 * 3. Tweak fattr based on mount options
 	 */
-
 	/* check for Minshall+French symlinks */
 	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
-		tmprc = check_mf_symlink(xid, tcon, cifs_sb, &fattr,
-					 full_path);
-		if (tmprc)
-			cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc);
+		tmprc = check_mf_symlink(xid, tcon, cifs_sb, fattr, full_path);
+		cifs_dbg(FYI, "check_mf_symlink: %d\n", tmprc);
 	}
 
-	/*
-	 * 4. Update inode with final fattr data
-	 */
-
-	if (!*inode) {
-		*inode = cifs_iget(sb, &fattr);
-		if (!*inode)
-			rc = -ENOMEM;
-	} else {
-		/* we already have inode, update it */
-
-		/* if uniqueid is different, return error */
-		if (unlikely(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM &&
-		    CIFS_I(*inode)->uniqueid != fattr.cf_uniqueid)) {
-			CIFS_I(*inode)->time = 0; /* force reval */
-			rc = -ESTALE;
-			goto out;
-		}
-
-		/* if filetype is different, return error */
-		rc = cifs_fattr_to_inode(*inode, &fattr);
-	}
 out:
 	cifs_put_tlink(tlink);
 	cifs_free_open_info(&data);
+	return rc;
+}
+
+int smb311_posix_get_inode_info(struct inode **inode, const char *full_path,
+				struct super_block *sb, const unsigned int xid)
+{
+	struct cifs_fattr fattr = {};
+	int rc;
+
+	if (is_inode_cache_good(*inode)) {
+		cifs_dbg(FYI, "No need to revalidate cached inode sizes\n");
+		return 0;
+	}
+
+	rc = smb311_posix_get_fattr(&fattr, full_path, sb, xid);
+	if (rc)
+		goto out;
+
+	rc = update_inode_info(sb, &fattr, inode);
+out:
 	kfree(fattr.cf_symlink_target);
 	return rc;
 }
 
-
 static const struct inode_operations cifs_ipc_inode_ops = {
 	.lookup = cifs_lookup,
 };
@@ -1407,13 +1427,14 @@ cifs_iget(struct super_block *sb, struct cifs_fattr *fattr)
 /* gets root inode */
 struct inode *cifs_root_iget(struct super_block *sb)
 {
-	unsigned int xid;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
-	struct inode *inode = NULL;
-	long rc;
+	struct cifs_fattr fattr = {};
 	struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
+	struct inode *inode = NULL;
+	unsigned int xid;
 	char *path = NULL;
 	int len;
+	int rc;
 
 	if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH)
 	    && cifs_sb->prepath) {
@@ -1431,21 +1452,29 @@ struct inode *cifs_root_iget(struct super_block *sb)
 
 	xid = get_xid();
 	if (tcon->unix_ext) {
-		rc = cifs_get_inode_info_unix(&inode, path, sb, xid);
+		rc = cifs_get_unix_fattr(path, sb, &fattr, &inode, xid);
 		/* some servers mistakenly claim POSIX support */
 		if (rc != -EOPNOTSUPP)
-			goto iget_no_retry;
+			goto iget_root;
 		cifs_dbg(VFS, "server does not support POSIX extensions\n");
 		tcon->unix_ext = false;
 	}
 
 	convert_delimiter(path, CIFS_DIR_SEP(cifs_sb));
 	if (tcon->posix_extensions)
-		rc = smb311_posix_get_inode_info(&inode, path, sb, xid);
+		rc = smb311_posix_get_fattr(&fattr, path, sb, xid);
 	else
-		rc = cifs_get_inode_info(&inode, path, NULL, sb, xid, NULL);
+		rc = cifs_get_fattr(NULL, sb, xid, NULL, &fattr, &inode, path);
+
+iget_root:
+	if (!rc) {
+		if (fattr.cf_flags & CIFS_FATTR_JUNCTION) {
+			fattr.cf_flags &= ~CIFS_FATTR_JUNCTION;
+			cifs_autodisable_serverino(cifs_sb);
+		}
+		inode = cifs_iget(sb, &fattr);
+	}
 
-iget_no_retry:
 	if (!inode) {
 		inode = ERR_PTR(rc);
 		goto out;
@@ -1469,6 +1498,7 @@ struct inode *cifs_root_iget(struct super_block *sb)
 out:
 	kfree(path);
 	free_xid(xid);
+	kfree(fattr.cf_symlink_target);
 	return inode;
 }
 
diff --git a/fs/smb/client/namespace.c b/fs/smb/client/namespace.c
index 3252fe33f7a3..c8f5ed8a69f1 100644
--- a/fs/smb/client/namespace.c
+++ b/fs/smb/client/namespace.c
@@ -126,9 +126,11 @@ static char *automount_fullpath(struct dentry *dentry, void *page)
 	char *s;
 
 	spin_lock(&tcon->tc_lock);
-	if (unlikely(!tcon->origin_fullpath)) {
+	if (!tcon->origin_fullpath) {
 		spin_unlock(&tcon->tc_lock);
-		return ERR_PTR(-EREMOTE);
+		return build_path_from_dentry_optional_prefix(dentry,
+							      page,
+							      true);
 	}
 	spin_unlock(&tcon->tc_lock);
 
@@ -162,7 +164,6 @@ static struct vfsmount *cifs_do_automount(struct path *path)
 	int rc;
 	struct dentry *mntpt = path->dentry;
 	struct fs_context *fc;
-	struct cifs_sb_info *cifs_sb;
 	void *page = NULL;
 	struct smb3_fs_context *ctx, *cur_ctx;
 	struct smb3_fs_context tmp;
@@ -172,17 +173,7 @@ static struct vfsmount *cifs_do_automount(struct path *path)
 	if (IS_ROOT(mntpt))
 		return ERR_PTR(-ESTALE);
 
-	/*
-	 * The MSDFS spec states that paths in DFS referral requests and
-	 * responses must be prefixed by a single '\' character instead of
-	 * the double backslashes usually used in the UNC. This function
-	 * gives us the latter, so we must adjust the result.
-	 */
-	cifs_sb = CIFS_SB(mntpt->d_sb);
-	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS)
-		return ERR_PTR(-EREMOTE);
-
-	cur_ctx = cifs_sb->ctx;
+	cur_ctx = CIFS_SB(mntpt->d_sb)->ctx;
 
 	fc = fs_context_for_submount(path->mnt->mnt_sb->s_type, mntpt);
 	if (IS_ERR(fc))
diff --git a/fs/smb/client/readdir.c b/fs/smb/client/readdir.c
index 59bf542d5211..47fc22de8d20 100644
--- a/fs/smb/client/readdir.c
+++ b/fs/smb/client/readdir.c
@@ -143,6 +143,7 @@ static bool reparse_file_needs_reval(const struct cifs_fattr *fattr)
 	case IO_REPARSE_TAG_DFSR:
 	case IO_REPARSE_TAG_SYMLINK:
 	case IO_REPARSE_TAG_NFS:
+	case IO_REPARSE_TAG_MOUNT_POINT:
 	case 0:
 		return true;
 	}
-- 
2.41.0


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

* [PATCH 12/17] smb: client: reduce stack usage in cifs_try_adding_channels()
  2023-08-17 15:33 [PATCH 00/17] cifs.ko fixes Paulo Alcantara
                   ` (10 preceding siblings ...)
  2023-08-17 15:34 ` [PATCH 11/17] smb: cilent: set reparse mount points as automounts Paulo Alcantara
@ 2023-08-17 15:34 ` Paulo Alcantara
  2023-08-17 15:34 ` [PATCH 13/17] smb: client: reduce stack usage in cifs_demultiplex_thread() Paulo Alcantara
                   ` (5 subsequent siblings)
  17 siblings, 0 replies; 21+ messages in thread
From: Paulo Alcantara @ 2023-08-17 15:34 UTC (permalink / raw)
  To: smfrench; +Cc: linux-cifs, Paulo Alcantara, kernel test robot

Clang warns about exceeded stack frame size

  fs/smb/client/sess.c:160:5: warning: stack frame size (1368) exceeds
  limit (1024) in 'cifs_try_adding_channels' [-Wframe-larger-than]

It turns out that cifs_ses_add_channel() got inlined into
cifs_try_adding_channels() which had a stack-allocated variable @ctx
of 624 bytes in size.  Fix this by making it heap-allocated.

Reported-by: kernel test robot <lkp@intel.com>
Closes: https://lore.kernel.org/oe-kbuild-all/202307270640.5ODmPwDl-lkp@intel.com/
Signed-off-by: Paulo Alcantara (SUSE) <pc@manguebit.com>
---
 fs/smb/client/sess.c | 68 ++++++++++++++++++++++++++------------------
 1 file changed, 41 insertions(+), 27 deletions(-)

diff --git a/fs/smb/client/sess.c b/fs/smb/client/sess.c
index c57ca2050b73..5292216d9947 100644
--- a/fs/smb/client/sess.c
+++ b/fs/smb/client/sess.c
@@ -360,11 +360,11 @@ cifs_ses_add_channel(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses,
 {
 	struct TCP_Server_Info *chan_server;
 	struct cifs_chan *chan;
-	struct smb3_fs_context ctx = {NULL};
+	struct smb3_fs_context *ctx;
 	static const char unc_fmt[] = "\\%s\\foo";
-	char unc[sizeof(unc_fmt)+SERVER_NAME_LEN_WITH_NULL] = {0};
 	struct sockaddr_in *ipv4 = (struct sockaddr_in *)&iface->sockaddr;
 	struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)&iface->sockaddr;
+	size_t len;
 	int rc;
 	unsigned int xid = get_xid();
 
@@ -388,54 +388,64 @@ cifs_ses_add_channel(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses,
 	 * the session and server without caring about memory
 	 * management.
 	 */
+	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+	if (!ctx) {
+		rc = -ENOMEM;
+		goto out_free_xid;
+	}
 
 	/* Always make new connection for now (TODO?) */
-	ctx.nosharesock = true;
+	ctx->nosharesock = true;
 
 	/* Auth */
-	ctx.domainauto = ses->domainAuto;
-	ctx.domainname = ses->domainName;
+	ctx->domainauto = ses->domainAuto;
+	ctx->domainname = ses->domainName;
 
 	/* no hostname for extra channels */
-	ctx.server_hostname = "";
+	ctx->server_hostname = "";
 
-	ctx.username = ses->user_name;
-	ctx.password = ses->password;
-	ctx.sectype = ses->sectype;
-	ctx.sign = ses->sign;
+	ctx->username = ses->user_name;
+	ctx->password = ses->password;
+	ctx->sectype = ses->sectype;
+	ctx->sign = ses->sign;
 
 	/* UNC and paths */
 	/* XXX: Use ses->server->hostname? */
-	sprintf(unc, unc_fmt, ses->ip_addr);
-	ctx.UNC = unc;
-	ctx.prepath = "";
+	len = sizeof(unc_fmt) + SERVER_NAME_LEN_WITH_NULL;
+	ctx->UNC = kzalloc(len, GFP_KERNEL);
+	if (!ctx->UNC) {
+		rc = -ENOMEM;
+		goto out_free_ctx;
+	}
+	scnprintf(ctx->UNC, len, unc_fmt, ses->ip_addr);
+	ctx->prepath = "";
 
 	/* Reuse same version as master connection */
-	ctx.vals = ses->server->vals;
-	ctx.ops = ses->server->ops;
+	ctx->vals = ses->server->vals;
+	ctx->ops = ses->server->ops;
 
-	ctx.noblocksnd = ses->server->noblocksnd;
-	ctx.noautotune = ses->server->noautotune;
-	ctx.sockopt_tcp_nodelay = ses->server->tcp_nodelay;
-	ctx.echo_interval = ses->server->echo_interval / HZ;
-	ctx.max_credits = ses->server->max_credits;
+	ctx->noblocksnd = ses->server->noblocksnd;
+	ctx->noautotune = ses->server->noautotune;
+	ctx->sockopt_tcp_nodelay = ses->server->tcp_nodelay;
+	ctx->echo_interval = ses->server->echo_interval / HZ;
+	ctx->max_credits = ses->server->max_credits;
 
 	/*
 	 * This will be used for encoding/decoding user/domain/pw
 	 * during sess setup auth.
 	 */
-	ctx.local_nls = cifs_sb->local_nls;
+	ctx->local_nls = cifs_sb->local_nls;
 
 	/* Use RDMA if possible */
-	ctx.rdma = iface->rdma_capable;
-	memcpy(&ctx.dstaddr, &iface->sockaddr, sizeof(struct sockaddr_storage));
+	ctx->rdma = iface->rdma_capable;
+	memcpy(&ctx->dstaddr, &iface->sockaddr, sizeof(ctx->dstaddr));
 
 	/* reuse master con client guid */
-	memcpy(&ctx.client_guid, ses->server->client_guid,
-	       SMB2_CLIENT_GUID_SIZE);
-	ctx.use_client_guid = true;
+	memcpy(&ctx->client_guid, ses->server->client_guid,
+	       sizeof(ctx->client_guid));
+	ctx->use_client_guid = true;
 
-	chan_server = cifs_get_tcp_session(&ctx, ses->server);
+	chan_server = cifs_get_tcp_session(ctx, ses->server);
 
 	spin_lock(&ses->chan_lock);
 	chan = &ses->chans[ses->chan_count];
@@ -497,6 +507,10 @@ cifs_ses_add_channel(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses,
 		cifs_put_tcp_session(chan->server, 0);
 	}
 
+	kfree(ctx->UNC);
+out_free_ctx:
+	kfree(ctx);
+out_free_xid:
 	free_xid(xid);
 	return rc;
 }
-- 
2.41.0


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

* [PATCH 13/17] smb: client: reduce stack usage in cifs_demultiplex_thread()
  2023-08-17 15:33 [PATCH 00/17] cifs.ko fixes Paulo Alcantara
                   ` (11 preceding siblings ...)
  2023-08-17 15:34 ` [PATCH 12/17] smb: client: reduce stack usage in cifs_try_adding_channels() Paulo Alcantara
@ 2023-08-17 15:34 ` Paulo Alcantara
  2023-08-17 15:34 ` [PATCH 14/17] smb: client: reduce stack usage in smb_send_rqst() Paulo Alcantara
                   ` (4 subsequent siblings)
  17 siblings, 0 replies; 21+ messages in thread
From: Paulo Alcantara @ 2023-08-17 15:34 UTC (permalink / raw)
  To: smfrench; +Cc: linux-cifs, Paulo Alcantara

Clang warns about exceeded stack frame size

  fs/smb/client/connect.c:1109:1: warning: stack frame size (1048)
  exceeds limit (1024) in 'cifs_demultiplex_thread'
  [-Wframe-larger-than]

It turns out that clean_demultiplex_info() got inlined into
cifs_demultiplex_thread(), so mark it as noinline_for_stack to save
some stack space.

Signed-off-by: Paulo Alcantara (SUSE) <pc@manguebit.com>
---
 fs/smb/client/connect.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c
index b3461d5d0f7d..e19a9c81a5fa 100644
--- a/fs/smb/client/connect.c
+++ b/fs/smb/client/connect.c
@@ -911,8 +911,8 @@ cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required)
 	return 0;
 }
 
-
-static void clean_demultiplex_info(struct TCP_Server_Info *server)
+static noinline_for_stack void
+clean_demultiplex_info(struct TCP_Server_Info *server)
 {
 	int length;
 
-- 
2.41.0


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

* [PATCH 14/17] smb: client: reduce stack usage in smb_send_rqst()
  2023-08-17 15:33 [PATCH 00/17] cifs.ko fixes Paulo Alcantara
                   ` (12 preceding siblings ...)
  2023-08-17 15:34 ` [PATCH 13/17] smb: client: reduce stack usage in cifs_demultiplex_thread() Paulo Alcantara
@ 2023-08-17 15:34 ` Paulo Alcantara
  2023-08-17 15:34 ` [PATCH 15/17] smb: client: reduce stack usage in smb2_set_ea() Paulo Alcantara
                   ` (3 subsequent siblings)
  17 siblings, 0 replies; 21+ messages in thread
From: Paulo Alcantara @ 2023-08-17 15:34 UTC (permalink / raw)
  To: smfrench; +Cc: linux-cifs, Paulo Alcantara

Clang warns about exceeded stack frame size

  fs/smb/client/transport.c:420:1: warning: stack frame size (1048)
  exceeds limit (1024) in 'smb_send_rqst' [-Wframe-larger-than]

Fix this by allocating a structure that will hold transform header and
compound requests.

Signed-off-by: Paulo Alcantara (SUSE) <pc@manguebit.com>
---
 fs/smb/client/transport.c | 29 +++++++++++++++++------------
 1 file changed, 17 insertions(+), 12 deletions(-)

diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c
index f280502a2aee..1b5d9794ed5b 100644
--- a/fs/smb/client/transport.c
+++ b/fs/smb/client/transport.c
@@ -416,13 +416,19 @@ __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
 	return rc;
 }
 
+struct send_req_vars {
+	struct smb2_transform_hdr tr_hdr;
+	struct smb_rqst rqst[MAX_COMPOUND];
+	struct kvec iov;
+};
+
 static int
 smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
 	      struct smb_rqst *rqst, int flags)
 {
-	struct kvec iov;
-	struct smb2_transform_hdr *tr_hdr;
-	struct smb_rqst cur_rqst[MAX_COMPOUND];
+	struct send_req_vars *vars;
+	struct smb_rqst *cur_rqst;
+	struct kvec *iov;
 	int rc;
 
 	if (!(flags & CIFS_TRANSFORM_REQ))
@@ -436,16 +442,15 @@ smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
 		return -EIO;
 	}
 
-	tr_hdr = kzalloc(sizeof(*tr_hdr), GFP_NOFS);
-	if (!tr_hdr)
+	vars = kzalloc(sizeof(*vars), GFP_NOFS);
+	if (!vars)
 		return -ENOMEM;
+	cur_rqst = vars->rqst;
+	iov = &vars->iov;
 
-	memset(&cur_rqst[0], 0, sizeof(cur_rqst));
-	memset(&iov, 0, sizeof(iov));
-
-	iov.iov_base = tr_hdr;
-	iov.iov_len = sizeof(*tr_hdr);
-	cur_rqst[0].rq_iov = &iov;
+	iov->iov_base = &vars->tr_hdr;
+	iov->iov_len = sizeof(vars->tr_hdr);
+	cur_rqst[0].rq_iov = iov;
 	cur_rqst[0].rq_nvec = 1;
 
 	rc = server->ops->init_transform_rq(server, num_rqst + 1,
@@ -456,7 +461,7 @@ smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
 	rc = __smb_send_rqst(server, num_rqst + 1, &cur_rqst[0]);
 	smb3_free_compound_rqst(num_rqst, &cur_rqst[1]);
 out:
-	kfree(tr_hdr);
+	kfree(vars);
 	return rc;
 }
 
-- 
2.41.0


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

* [PATCH 15/17] smb: client: reduce stack usage in smb2_set_ea()
  2023-08-17 15:33 [PATCH 00/17] cifs.ko fixes Paulo Alcantara
                   ` (13 preceding siblings ...)
  2023-08-17 15:34 ` [PATCH 14/17] smb: client: reduce stack usage in smb_send_rqst() Paulo Alcantara
@ 2023-08-17 15:34 ` Paulo Alcantara
  2023-08-17 15:34 ` [PATCH 16/17] smb: client: reduce stack usage in smb2_query_info_compound() Paulo Alcantara
                   ` (2 subsequent siblings)
  17 siblings, 0 replies; 21+ messages in thread
From: Paulo Alcantara @ 2023-08-17 15:34 UTC (permalink / raw)
  To: smfrench; +Cc: linux-cifs, Paulo Alcantara

Clang warns about exceeded stack frame size

  fs/smb/client/smb2ops.c:1080:1: warning: stack frame size (1432)
  exceeds limit (1024) in 'smb2_set_ea' [-Wframe-larger-than]

Fix this by allocating a structure that will hold most of the large
variables.

Signed-off-by: Paulo Alcantara (SUSE) <pc@manguebit.com>
---
 fs/smb/client/cifsglob.h  | 13 ++++++++++
 fs/smb/client/smb2inode.c | 21 ++++------------
 fs/smb/client/smb2ops.c   | 50 ++++++++++++++++-----------------------
 3 files changed, 37 insertions(+), 47 deletions(-)

diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
index 6d5fa0351dce..1588f98660aa 100644
--- a/fs/smb/client/cifsglob.h
+++ b/fs/smb/client/cifsglob.h
@@ -2214,4 +2214,17 @@ static inline void cifs_sg_set_buf(struct sg_table *sgtable,
 	}
 }
 
+struct smb2_compound_vars {
+	struct cifs_open_parms oparms;
+	struct kvec rsp_iov[3];
+	struct smb_rqst rqst[3];
+	struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
+	struct kvec qi_iov;
+	struct kvec io_iov[SMB2_IOCTL_IOV_SIZE];
+	struct kvec si_iov[SMB2_SET_INFO_IOV_SIZE];
+	struct kvec close_iov;
+	struct smb2_file_rename_info rename_info;
+	struct smb2_file_link_info link_info;
+};
+
 #endif	/* _CIFS_GLOB_H */
diff --git a/fs/smb/client/smb2inode.c b/fs/smb/client/smb2inode.c
index 0999383c0284..b41e2e872b22 100644
--- a/fs/smb/client/smb2inode.c
+++ b/fs/smb/client/smb2inode.c
@@ -35,19 +35,6 @@ free_set_inf_compound(struct smb_rqst *rqst)
 		SMB2_close_free(&rqst[2]);
 }
 
-
-struct cop_vars {
-	struct cifs_open_parms oparms;
-	struct kvec rsp_iov[3];
-	struct smb_rqst rqst[3];
-	struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
-	struct kvec qi_iov[1];
-	struct kvec si_iov[SMB2_SET_INFO_IOV_SIZE];
-	struct kvec close_iov[1];
-	struct smb2_file_rename_info rename_info;
-	struct smb2_file_link_info link_info;
-};
-
 /*
  * note: If cfile is passed, the reference to it is dropped here.
  * So make sure that you do not reuse cfile after return from this func.
@@ -63,7 +50,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
 			    __u8 **extbuf, size_t *extbuflen,
 			    struct kvec *out_iov, int *out_buftype)
 {
-	struct cop_vars *vars = NULL;
+	struct smb2_compound_vars *vars = NULL;
 	struct kvec *rsp_iov;
 	struct smb_rqst *rqst;
 	int rc;
@@ -134,7 +121,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
 	/* Operation */
 	switch (command) {
 	case SMB2_OP_QUERY_INFO:
-		rqst[num_rqst].rq_iov = &vars->qi_iov[0];
+		rqst[num_rqst].rq_iov = &vars->qi_iov;
 		rqst[num_rqst].rq_nvec = 1;
 
 		if (cfile)
@@ -168,7 +155,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
 						     full_path);
 		break;
 	case SMB2_OP_POSIX_QUERY_INFO:
-		rqst[num_rqst].rq_iov = &vars->qi_iov[0];
+		rqst[num_rqst].rq_iov = &vars->qi_iov;
 		rqst[num_rqst].rq_nvec = 1;
 
 		if (cfile)
@@ -376,7 +363,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
 		goto after_close;
 	/* Close */
 	flags |= CIFS_CP_CREATE_CLOSE_OP;
-	rqst[num_rqst].rq_iov = &vars->close_iov[0];
+	rqst[num_rqst].rq_iov = &vars->close_iov;
 	rqst[num_rqst].rq_nvec = 1;
 	rc = SMB2_close_init(tcon, server,
 			     &rqst[num_rqst], COMPOUND_FID,
diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
index 91c7b7e52a72..d31ea7e7fd84 100644
--- a/fs/smb/client/smb2ops.c
+++ b/fs/smb/client/smb2ops.c
@@ -1075,31 +1075,28 @@ smb2_query_eas(const unsigned int xid, struct cifs_tcon *tcon,
 	return rc;
 }
 
-
 static int
 smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
 	    const char *path, const char *ea_name, const void *ea_value,
 	    const __u16 ea_value_len, const struct nls_table *nls_codepage,
 	    struct cifs_sb_info *cifs_sb)
 {
+	struct smb2_compound_vars *vars;
 	struct cifs_ses *ses = tcon->ses;
 	struct TCP_Server_Info *server = cifs_pick_channel(ses);
+	struct smb_rqst *rqst;
+	struct kvec *rsp_iov;
 	__le16 *utf16_path = NULL;
 	int ea_name_len = strlen(ea_name);
 	int flags = CIFS_CP_CREATE_CLOSE_OP;
 	int len;
-	struct smb_rqst rqst[3];
 	int resp_buftype[3];
-	struct kvec rsp_iov[3];
-	struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
 	struct cifs_open_parms oparms;
 	__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
 	struct cifs_fid fid;
-	struct kvec si_iov[SMB2_SET_INFO_IOV_SIZE];
 	unsigned int size[1];
 	void *data[1];
 	struct smb2_file_full_ea_info *ea = NULL;
-	struct kvec close_iov[1];
 	struct smb2_query_info_rsp *rsp;
 	int rc, used_len = 0;
 
@@ -1113,9 +1110,14 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
 	if (!utf16_path)
 		return -ENOMEM;
 
-	memset(rqst, 0, sizeof(rqst));
 	resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
-	memset(rsp_iov, 0, sizeof(rsp_iov));
+	vars = kzalloc(sizeof(*vars), GFP_KERNEL);
+	if (!vars) {
+		rc = -ENOMEM;
+		goto out_free_path;
+	}
+	rqst = vars->rqst;
+	rsp_iov = vars->rsp_iov;
 
 	if (ses->server->ops->query_all_EAs) {
 		if (!ea_value) {
@@ -1160,8 +1162,7 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
 	}
 
 	/* Open */
-	memset(&open_iov, 0, sizeof(open_iov));
-	rqst[0].rq_iov = open_iov;
+	rqst[0].rq_iov = vars->open_iov;
 	rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE;
 
 	oparms = (struct cifs_open_parms) {
@@ -1181,8 +1182,7 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
 
 
 	/* Set Info */
-	memset(&si_iov, 0, sizeof(si_iov));
-	rqst[1].rq_iov = si_iov;
+	rqst[1].rq_iov = vars->si_iov;
 	rqst[1].rq_nvec = 1;
 
 	len = sizeof(*ea) + ea_name_len + ea_value_len + 1;
@@ -1210,10 +1210,8 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
 	smb2_set_next_command(tcon, &rqst[1]);
 	smb2_set_related(&rqst[1]);
 
-
 	/* Close */
-	memset(&close_iov, 0, sizeof(close_iov));
-	rqst[2].rq_iov = close_iov;
+	rqst[2].rq_iov = &vars->close_iov;
 	rqst[2].rq_nvec = 1;
 	rc = SMB2_close_init(tcon, server,
 			     &rqst[2], COMPOUND_FID, COMPOUND_FID, false);
@@ -1228,13 +1226,15 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
 
  sea_exit:
 	kfree(ea);
-	kfree(utf16_path);
 	SMB2_open_free(&rqst[0]);
 	SMB2_set_info_free(&rqst[1]);
 	SMB2_close_free(&rqst[2]);
 	free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
 	free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
 	free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base);
+	kfree(vars);
+out_free_path:
+	kfree(utf16_path);
 	return rc;
 }
 #endif
@@ -1445,16 +1445,6 @@ SMB2_request_res_key(const unsigned int xid, struct cifs_tcon *tcon,
 	return rc;
 }
 
-struct iqi_vars {
-	struct smb_rqst rqst[3];
-	struct kvec rsp_iov[3];
-	struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
-	struct kvec qi_iov[1];
-	struct kvec io_iov[SMB2_IOCTL_IOV_SIZE];
-	struct kvec si_iov[SMB2_SET_INFO_IOV_SIZE];
-	struct kvec close_iov[1];
-};
-
 static int
 smb2_ioctl_query_info(const unsigned int xid,
 		      struct cifs_tcon *tcon,
@@ -1462,7 +1452,7 @@ smb2_ioctl_query_info(const unsigned int xid,
 		      __le16 *path, int is_dir,
 		      unsigned long p)
 {
-	struct iqi_vars *vars;
+	struct smb2_compound_vars *vars;
 	struct smb_rqst *rqst;
 	struct kvec *rsp_iov;
 	struct cifs_ses *ses = tcon->ses;
@@ -1580,7 +1570,7 @@ smb2_ioctl_query_info(const unsigned int xid,
 			rc = -EINVAL;
 			goto free_open_req;
 		}
-		rqst[1].rq_iov = &vars->si_iov[0];
+		rqst[1].rq_iov = vars->si_iov;
 		rqst[1].rq_nvec = 1;
 
 		/* MS-FSCC 2.4.13 FileEndOfFileInformation */
@@ -1592,7 +1582,7 @@ smb2_ioctl_query_info(const unsigned int xid,
 					SMB2_O_INFO_FILE, 0, data, size);
 		free_req1_func = SMB2_set_info_free;
 	} else if (qi.flags == PASSTHRU_QUERY_INFO) {
-		rqst[1].rq_iov = &vars->qi_iov[0];
+		rqst[1].rq_iov = &vars->qi_iov;
 		rqst[1].rq_nvec = 1;
 
 		rc = SMB2_query_info_init(tcon, server,
@@ -1614,7 +1604,7 @@ smb2_ioctl_query_info(const unsigned int xid,
 	smb2_set_related(&rqst[1]);
 
 	/* Close */
-	rqst[2].rq_iov = &vars->close_iov[0];
+	rqst[2].rq_iov = &vars->close_iov;
 	rqst[2].rq_nvec = 1;
 
 	rc = SMB2_close_init(tcon, server,
-- 
2.41.0


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

* [PATCH 16/17] smb: client: reduce stack usage in smb2_query_info_compound()
  2023-08-17 15:33 [PATCH 00/17] cifs.ko fixes Paulo Alcantara
                   ` (14 preceding siblings ...)
  2023-08-17 15:34 ` [PATCH 15/17] smb: client: reduce stack usage in smb2_set_ea() Paulo Alcantara
@ 2023-08-17 15:34 ` Paulo Alcantara
  2023-08-17 15:34 ` [PATCH 17/17] smb: client: reduce stack usage in smb2_query_reparse_point() Paulo Alcantara
  2023-08-19  3:37 ` [PATCH 00/17] cifs.ko fixes Steve French
  17 siblings, 0 replies; 21+ messages in thread
From: Paulo Alcantara @ 2023-08-17 15:34 UTC (permalink / raw)
  To: smfrench; +Cc: linux-cifs, Paulo Alcantara

Clang warns about exceeded stack frame size

  fs/smb/client/smb2ops.c:2521:1: warning: stack frame size (1336)
  exceeds limit (1024) in 'smb2_query_info_compound'
  [-Wframe-larger-than]

Fix this by allocating a structure that will hold most of the large
variables.

Signed-off-by: Paulo Alcantara (SUSE) <pc@manguebit.com>
---
 fs/smb/client/smb2ops.c | 30 ++++++++++++++++--------------
 1 file changed, 16 insertions(+), 14 deletions(-)

diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
index d31ea7e7fd84..015d13d9054d 100644
--- a/fs/smb/client/smb2ops.c
+++ b/fs/smb/client/smb2ops.c
@@ -2513,15 +2513,13 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
 			 struct kvec *rsp, int *buftype,
 			 struct cifs_sb_info *cifs_sb)
 {
+	struct smb2_compound_vars *vars;
 	struct cifs_ses *ses = tcon->ses;
 	struct TCP_Server_Info *server = cifs_pick_channel(ses);
 	int flags = CIFS_CP_CREATE_CLOSE_OP;
-	struct smb_rqst rqst[3];
+	struct smb_rqst *rqst;
 	int resp_buftype[3];
-	struct kvec rsp_iov[3];
-	struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
-	struct kvec qi_iov[1];
-	struct kvec close_iov[1];
+	struct kvec *rsp_iov;
 	u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
 	struct cifs_open_parms oparms;
 	struct cifs_fid fid;
@@ -2538,9 +2536,14 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
 	if (smb3_encryption_required(tcon))
 		flags |= CIFS_TRANSFORM_REQ;
 
-	memset(rqst, 0, sizeof(rqst));
 	resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
-	memset(rsp_iov, 0, sizeof(rsp_iov));
+	vars = kzalloc(sizeof(*vars), GFP_KERNEL);
+	if (!vars) {
+		rc = -ENOMEM;
+		goto out_free_path;
+	}
+	rqst = vars->rqst;
+	rsp_iov = vars->rsp_iov;
 
 	/*
 	 * We can only call this for things we know are directories.
@@ -2549,8 +2552,7 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
 		open_cached_dir(xid, tcon, path, cifs_sb, false,
 				&cfid); /* cfid null if open dir failed */
 
-	memset(&open_iov, 0, sizeof(open_iov));
-	rqst[0].rq_iov = open_iov;
+	rqst[0].rq_iov = vars->open_iov;
 	rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE;
 
 	oparms = (struct cifs_open_parms) {
@@ -2568,8 +2570,7 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
 		goto qic_exit;
 	smb2_set_next_command(tcon, &rqst[0]);
 
-	memset(&qi_iov, 0, sizeof(qi_iov));
-	rqst[1].rq_iov = qi_iov;
+	rqst[1].rq_iov = &vars->qi_iov;
 	rqst[1].rq_nvec = 1;
 
 	if (cfid) {
@@ -2596,8 +2597,7 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
 		smb2_set_related(&rqst[1]);
 	}
 
-	memset(&close_iov, 0, sizeof(close_iov));
-	rqst[2].rq_iov = close_iov;
+	rqst[2].rq_iov = &vars->close_iov;
 	rqst[2].rq_nvec = 1;
 
 	rc = SMB2_close_init(tcon, server,
@@ -2628,7 +2628,6 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
 	*buftype = resp_buftype[1];
 
  qic_exit:
-	kfree(utf16_path);
 	SMB2_open_free(&rqst[0]);
 	SMB2_query_info_free(&rqst[1]);
 	SMB2_close_free(&rqst[2]);
@@ -2636,6 +2635,9 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
 	free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base);
 	if (cfid)
 		close_cached_dir(cfid);
+	kfree(vars);
+out_free_path:
+	kfree(utf16_path);
 	return rc;
 }
 
-- 
2.41.0


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

* [PATCH 17/17] smb: client: reduce stack usage in smb2_query_reparse_point()
  2023-08-17 15:33 [PATCH 00/17] cifs.ko fixes Paulo Alcantara
                   ` (15 preceding siblings ...)
  2023-08-17 15:34 ` [PATCH 16/17] smb: client: reduce stack usage in smb2_query_info_compound() Paulo Alcantara
@ 2023-08-17 15:34 ` Paulo Alcantara
  2023-08-19  3:37 ` [PATCH 00/17] cifs.ko fixes Steve French
  17 siblings, 0 replies; 21+ messages in thread
From: Paulo Alcantara @ 2023-08-17 15:34 UTC (permalink / raw)
  To: smfrench; +Cc: linux-cifs, Paulo Alcantara

Clang warns about exceeded stack frame size

  fs/smb/client/smb2ops.c:2973:12: warning: stack frame size (1336)
  exceeds limit (1024) in 'smb2_query_reparse_point'
  [-Wframe-larger-than]

Fix this by allocating a structure that will hold most of the large
variables.

Signed-off-by: Paulo Alcantara (SUSE) <pc@manguebit.com>
---
 fs/smb/client/smb2ops.c | 35 ++++++++++++++++++-----------------
 1 file changed, 18 insertions(+), 17 deletions(-)

diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
index 015d13d9054d..38bc92371560 100644
--- a/fs/smb/client/smb2ops.c
+++ b/fs/smb/client/smb2ops.c
@@ -2965,6 +2965,7 @@ static int smb2_query_reparse_point(const unsigned int xid,
 				    u32 *tag, struct kvec *rsp,
 				    int *rsp_buftype)
 {
+	struct smb2_compound_vars *vars;
 	int rc;
 	__le16 *utf16_path = NULL;
 	__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
@@ -2972,12 +2973,9 @@ static int smb2_query_reparse_point(const unsigned int xid,
 	struct cifs_fid fid;
 	struct TCP_Server_Info *server = cifs_pick_channel(tcon->ses);
 	int flags = CIFS_CP_CREATE_CLOSE_OP;
-	struct smb_rqst rqst[3];
+	struct smb_rqst *rqst;
 	int resp_buftype[3];
-	struct kvec rsp_iov[3];
-	struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
-	struct kvec io_iov[SMB2_IOCTL_IOV_SIZE];
-	struct kvec close_iov[1];
+	struct kvec *rsp_iov;
 	struct smb2_ioctl_rsp *ioctl_rsp;
 	struct reparse_data_buffer *reparse_buf;
 	u32 plen;
@@ -2987,20 +2985,24 @@ static int smb2_query_reparse_point(const unsigned int xid,
 	if (smb3_encryption_required(tcon))
 		flags |= CIFS_TRANSFORM_REQ;
 
-	memset(rqst, 0, sizeof(rqst));
-	resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
-	memset(rsp_iov, 0, sizeof(rsp_iov));
-
 	utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
 	if (!utf16_path)
 		return -ENOMEM;
 
+	resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
+	vars = kzalloc(sizeof(*vars), GFP_KERNEL);
+	if (!vars) {
+		rc = -ENOMEM;
+		goto out_free_path;
+	}
+	rqst = vars->rqst;
+	rsp_iov = vars->rsp_iov;
+
 	/*
 	 * setup smb2open - TODO add optimization to call cifs_get_readable_path
 	 * to see if there is a handle already open that we can use
 	 */
-	memset(&open_iov, 0, sizeof(open_iov));
-	rqst[0].rq_iov = open_iov;
+	rqst[0].rq_iov = vars->open_iov;
 	rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE;
 
 	oparms = (struct cifs_open_parms) {
@@ -3020,8 +3022,7 @@ static int smb2_query_reparse_point(const unsigned int xid,
 
 
 	/* IOCTL */
-	memset(&io_iov, 0, sizeof(io_iov));
-	rqst[1].rq_iov = io_iov;
+	rqst[1].rq_iov = vars->io_iov;
 	rqst[1].rq_nvec = SMB2_IOCTL_IOV_SIZE;
 
 	rc = SMB2_ioctl_init(tcon, server,
@@ -3036,10 +3037,8 @@ static int smb2_query_reparse_point(const unsigned int xid,
 	smb2_set_next_command(tcon, &rqst[1]);
 	smb2_set_related(&rqst[1]);
 
-
 	/* Close */
-	memset(&close_iov, 0, sizeof(close_iov));
-	rqst[2].rq_iov = close_iov;
+	rqst[2].rq_iov = &vars->close_iov;
 	rqst[2].rq_nvec = 1;
 
 	rc = SMB2_close_init(tcon, server,
@@ -3080,13 +3079,15 @@ static int smb2_query_reparse_point(const unsigned int xid,
 	}
 
  query_rp_exit:
-	kfree(utf16_path);
 	SMB2_open_free(&rqst[0]);
 	SMB2_ioctl_free(&rqst[1]);
 	SMB2_close_free(&rqst[2]);
 	free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
 	free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
 	free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base);
+	kfree(vars);
+out_free_path:
+	kfree(utf16_path);
 	return rc;
 }
 
-- 
2.41.0


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

* Fwd: [PATCH 09/17] smb: client: do not query reparse points twice on symlinks
  2023-08-17 15:34 ` [PATCH 09/17] smb: client: do not query reparse points twice on symlinks Paulo Alcantara
@ 2023-08-17 15:52   ` Steve French
  2023-08-17 16:19     ` Paulo Alcantara
  0 siblings, 1 reply; 21+ messages in thread
From: Steve French @ 2023-08-17 15:52 UTC (permalink / raw)
  To: Paulo Alcantara, CIFS

Am also curious about the problem where we do an extra query on
mfsymlinks with ls -l

---------- Forwarded message ---------
From: Paulo Alcantara <pc@manguebit.com>
Date: Thu, Aug 17, 2023 at 10:35 AM
Subject: [PATCH 09/17] smb: client: do not query reparse points twice
on symlinks
To: <smfrench@gmail.com>
Cc: <linux-cifs@vger.kernel.org>, Paulo Alcantara <pc@manguebit.com>


Save a roundtrip by getting the reparse point tag and buffer at once
in ->query_reparse_point() and then pass the buffer down to
->query_symlink().

Signed-off-by: Paulo Alcantara (SUSE) <pc@manguebit.com>
---
 fs/smb/client/cifsglob.h |  20 +++--
 fs/smb/client/inode.c    |  19 +++--
 fs/smb/client/smb1ops.c  |  11 ++-
 fs/smb/client/smb2ops.c  | 166 ++++++---------------------------------
 4 files changed, 55 insertions(+), 161 deletions(-)

diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
index 95e62502cb01..639a61417b08 100644
--- a/fs/smb/client/cifsglob.h
+++ b/fs/smb/client/cifsglob.h
@@ -336,10 +336,13 @@ struct smb_version_operations {
        /* query file data from the server */
        int (*query_file_info)(const unsigned int xid, struct cifs_tcon *tcon,
                               struct cifsFileInfo *cfile, struct
cifs_open_info_data *data);
-       /* query reparse tag from srv to determine which type of special file */
-       int (*query_reparse_tag)(const unsigned int xid, struct cifs_tcon *tcon,
-                               struct cifs_sb_info *cifs_sb, const char *path,
-                               __u32 *reparse_tag);
+       /* query reparse point to determine which type of special file */
+       int (*query_reparse_point)(const unsigned int xid,
+                                  struct cifs_tcon *tcon,
+                                  struct cifs_sb_info *cifs_sb,
+                                  const char *full_path,
+                                  u32 *tag, struct kvec *rsp,
+                                  int *rsp_buftype);
        /* get server index number */
        int (*get_srv_inum)(const unsigned int xid, struct cifs_tcon *tcon,
                            struct cifs_sb_info *cifs_sb, const char
*full_path, u64 *uniqueid,
@@ -388,9 +391,12 @@ struct smb_version_operations {
                               const char *, const char *,
                               struct cifs_sb_info *);
        /* query symlink target */
-       int (*query_symlink)(const unsigned int, struct cifs_tcon *,
-                            struct cifs_sb_info *, const char *,
-                            char **, bool);
+       int (*query_symlink)(const unsigned int xid,
+                            struct cifs_tcon *tcon,
+                            struct cifs_sb_info *cifs_sb,
+                            const char *full_path,
+                            char **target_path,
+                            struct kvec *rsp_iov);
        /* open a file for non-posix mounts */
        int (*open)(const unsigned int xid, struct cifs_open_parms
*oparms, __u32 *oplock,
                    void *buf);
diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c
index 51e2916730cf..96a09818aa5b 100644
--- a/fs/smb/client/inode.c
+++ b/fs/smb/client/inode.c
@@ -428,7 +428,7 @@ int cifs_get_inode_info_unix(struct inode **pinode,
                if (!server->ops->query_symlink)
                        return -EOPNOTSUPP;
                rc = server->ops->query_symlink(xid, tcon, cifs_sb, full_path,
-
&fattr.cf_symlink_target, false);
+                                               &fattr.cf_symlink_target, NULL);
                if (rc) {
                        cifs_dbg(FYI, "%s: query_symlink: %d\n", __func__, rc);
                        goto cgiiu_exit;
@@ -988,17 +988,21 @@ static int query_reparse(struct cifs_open_info_data *data,
 {
        struct TCP_Server_Info *server = tcon->ses->server;
        struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
-       bool reparse_point = data->reparse_point;
+       struct kvec rsp_iov, *iov = NULL;
+       int rsp_buftype = CIFS_NO_BUFFER;
        u32 tag = data->reparse_tag;
        int rc = 0;

-       if (!tag && server->ops->query_reparse_tag) {
-               server->ops->query_reparse_tag(xid, tcon, cifs_sb,
-                                              full_path, &tag);
+       if (!tag && server->ops->query_reparse_point) {
+               rc = server->ops->query_reparse_point(xid, tcon, cifs_sb,
+                                                     full_path, &tag,
+                                                     &rsp_iov, &rsp_buftype);
+               if (!rc)
+                       iov = &rsp_iov;
        }
        switch ((data->reparse_tag = tag)) {
        case 0: /* SMB1 symlink */
-               reparse_point = false;
+               iov = NULL;
                fallthrough;
        case IO_REPARSE_TAG_NFS:
        case IO_REPARSE_TAG_SYMLINK:
@@ -1006,10 +1010,11 @@ static int query_reparse(struct
cifs_open_info_data *data,
                        rc = server->ops->query_symlink(xid, tcon,
                                                        cifs_sb, full_path,
                                                        &data->symlink_target,
-                                                       reparse_point);
+                                                       iov);
                }
                break;
        }
+       free_rsp_buf(rsp_buftype, rsp_iov.iov_base);
        return rc;
 }

diff --git a/fs/smb/client/smb1ops.c b/fs/smb/client/smb1ops.c
index 094ef4fe2219..9bf8735cdd1e 100644
--- a/fs/smb/client/smb1ops.c
+++ b/fs/smb/client/smb1ops.c
@@ -972,13 +972,16 @@ cifs_unix_dfs_readlink(const unsigned int xid,
struct cifs_tcon *tcon,
 #endif
 }

-static int
-cifs_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
-                  struct cifs_sb_info *cifs_sb, const char *full_path,
-                  char **target_path, bool is_reparse_point)
+static int cifs_query_symlink(const unsigned int xid,
+                             struct cifs_tcon *tcon,
+                             struct cifs_sb_info *cifs_sb,
+                             const char *full_path,
+                             char **target_path,
+                             struct kvec *rsp_iov)
 {
        int rc;
        int oplock = 0;
+       bool is_reparse_point = !!rsp_iov;
        struct cifs_fid fid;
        struct cifs_open_parms oparms;

diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
index 0f62bc373ad0..5eb2720f4aa7 100644
--- a/fs/smb/client/smb2ops.c
+++ b/fs/smb/client/smb2ops.c
@@ -2948,153 +2948,30 @@ parse_reparse_point(struct reparse_data_buffer *buf,
        }
 }

-static int
-smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
-                  struct cifs_sb_info *cifs_sb, const char *full_path,
-                  char **target_path, bool is_reparse_point)
+static int smb2_query_symlink(const unsigned int xid,
+                             struct cifs_tcon *tcon,
+                             struct cifs_sb_info *cifs_sb,
+                             const char *full_path,
+                             char **target_path,
+                             struct kvec *rsp_iov)
 {
-       int rc;
-       __le16 *utf16_path = NULL;
-       __u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
-       struct cifs_open_parms oparms;
-       struct cifs_fid fid;
-       struct kvec err_iov = {NULL, 0};
-       struct TCP_Server_Info *server = cifs_pick_channel(tcon->ses);
-       int flags = CIFS_CP_CREATE_CLOSE_OP;
-       struct smb_rqst rqst[3];
-       int resp_buftype[3];
-       struct kvec rsp_iov[3];
-       struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
-       struct kvec io_iov[SMB2_IOCTL_IOV_SIZE];
-       struct kvec close_iov[1];
-       struct smb2_create_rsp *create_rsp;
-       struct smb2_ioctl_rsp *ioctl_rsp;
-       struct reparse_data_buffer *reparse_buf;
-       int create_options = is_reparse_point ? OPEN_REPARSE_POINT : 0;
-       u32 plen;
+       struct reparse_data_buffer *buf;
+       struct smb2_ioctl_rsp *io = rsp_iov->iov_base;
+       u32 plen = le32_to_cpu(io->OutputCount);

        cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path);

-       *target_path = NULL;
-
-       if (smb3_encryption_required(tcon))
-               flags |= CIFS_TRANSFORM_REQ;
-
-       memset(rqst, 0, sizeof(rqst));
-       resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
-       memset(rsp_iov, 0, sizeof(rsp_iov));
-
-       utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
-       if (!utf16_path)
-               return -ENOMEM;
-
-       /* Open */
-       memset(&open_iov, 0, sizeof(open_iov));
-       rqst[0].rq_iov = open_iov;
-       rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE;
-
-       oparms = (struct cifs_open_parms) {
-               .tcon = tcon,
-               .path = full_path,
-               .desired_access = FILE_READ_ATTRIBUTES,
-               .disposition = FILE_OPEN,
-               .create_options = cifs_create_options(cifs_sb, create_options),
-               .fid = &fid,
-       };
-
-       rc = SMB2_open_init(tcon, server,
-                           &rqst[0], &oplock, &oparms, utf16_path);
-       if (rc)
-               goto querty_exit;
-       smb2_set_next_command(tcon, &rqst[0]);
-
-
-       /* IOCTL */
-       memset(&io_iov, 0, sizeof(io_iov));
-       rqst[1].rq_iov = io_iov;
-       rqst[1].rq_nvec = SMB2_IOCTL_IOV_SIZE;
-
-       rc = SMB2_ioctl_init(tcon, server,
-                            &rqst[1], fid.persistent_fid,
-                            fid.volatile_fid, FSCTL_GET_REPARSE_POINT, NULL, 0,
-                            CIFSMaxBufSize -
-                            MAX_SMB2_CREATE_RESPONSE_SIZE -
-                            MAX_SMB2_CLOSE_RESPONSE_SIZE);
-       if (rc)
-               goto querty_exit;
-
-       smb2_set_next_command(tcon, &rqst[1]);
-       smb2_set_related(&rqst[1]);
-
-
-       /* Close */
-       memset(&close_iov, 0, sizeof(close_iov));
-       rqst[2].rq_iov = close_iov;
-       rqst[2].rq_nvec = 1;
-
-       rc = SMB2_close_init(tcon, server,
-                            &rqst[2], COMPOUND_FID, COMPOUND_FID, false);
-       if (rc)
-               goto querty_exit;
-
-       smb2_set_related(&rqst[2]);
-
-       rc = compound_send_recv(xid, tcon->ses, server,
-                               flags, 3, rqst,
-                               resp_buftype, rsp_iov);
-
-       create_rsp = rsp_iov[0].iov_base;
-       if (create_rsp && create_rsp->hdr.Status)
-               err_iov = rsp_iov[0];
-       ioctl_rsp = rsp_iov[1].iov_base;
-
-       /*
-        * Open was successful and we got an ioctl response.
-        */
-       if ((rc == 0) && (is_reparse_point)) {
-               /* See MS-FSCC 2.3.23 */
-
-               reparse_buf = (struct reparse_data_buffer *)
-                       ((char *)ioctl_rsp +
-                        le32_to_cpu(ioctl_rsp->OutputOffset));
-               plen = le32_to_cpu(ioctl_rsp->OutputCount);
-
-               if (plen + le32_to_cpu(ioctl_rsp->OutputOffset) >
-                   rsp_iov[1].iov_len) {
-                       cifs_tcon_dbg(VFS, "srv returned invalid ioctl
len: %d\n",
-                                plen);
-                       rc = -EIO;
-                       goto querty_exit;
-               }
-
-               rc = parse_reparse_point(reparse_buf, plen, target_path,
-                                        cifs_sb);
-               goto querty_exit;
-       }
-
-       if (!rc || !err_iov.iov_base) {
-               rc = -ENOENT;
-               goto querty_exit;
-       }
-
-       rc = smb2_parse_symlink_response(cifs_sb, &err_iov, target_path);
-
- querty_exit:
-       cifs_dbg(FYI, "query symlink rc %d\n", rc);
-       kfree(utf16_path);
-       SMB2_open_free(&rqst[0]);
-       SMB2_ioctl_free(&rqst[1]);
-       SMB2_close_free(&rqst[2]);
-       free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
-       free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
-       free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base);
-       return rc;
+       buf = (struct reparse_data_buffer *)((u8 *)io +
+                                            le32_to_cpu(io->OutputOffset));
+       return parse_reparse_point(buf, plen, target_path, cifs_sb);
 }

-int
-smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon,
-                  struct cifs_sb_info *cifs_sb, const char *full_path,
-                  __u32 *tag)
+static int smb2_query_reparse_point(const unsigned int xid,
+                                   struct cifs_tcon *tcon,
+                                   struct cifs_sb_info *cifs_sb,
+                                   const char *full_path,
+                                   u32 *tag, struct kvec *rsp,
+                                   int *rsp_buftype)
 {
        int rc;
        __le16 *utf16_path = NULL;
@@ -3205,6 +3082,9 @@ smb2_query_reparse_tag(const unsigned int xid,
struct cifs_tcon *tcon,
                        goto query_rp_exit;
                }
                *tag = le32_to_cpu(reparse_buf->ReparseTag);
+               *rsp = rsp_iov[1];
+               *rsp_buftype = resp_buftype[1];
+               resp_buftype[1] = CIFS_NO_BUFFER;
        }

  query_rp_exit:
@@ -5503,7 +5383,7 @@ struct smb_version_operations smb30_operations = {
        .echo = SMB2_echo,
        .query_path_info = smb2_query_path_info,
        /* WSL tags introduced long after smb2.1, enable for SMB3, 3.11 only */
-       .query_reparse_tag = smb2_query_reparse_tag,
+       .query_reparse_point = smb2_query_reparse_point,
        .get_srv_inum = smb2_get_srv_inum,
        .query_file_info = smb2_query_file_info,
        .set_path_size = smb2_set_path_size,
@@ -5616,7 +5496,7 @@ struct smb_version_operations smb311_operations = {
        .can_echo = smb2_can_echo,
        .echo = SMB2_echo,
        .query_path_info = smb2_query_path_info,
-       .query_reparse_tag = smb2_query_reparse_tag,
+       .query_reparse_point = smb2_query_reparse_point,
        .get_srv_inum = smb2_get_srv_inum,
        .query_file_info = smb2_query_file_info,
        .set_path_size = smb2_set_path_size,
--
2.41.0



-- 
Thanks,

Steve

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

* Re: Fwd: [PATCH 09/17] smb: client: do not query reparse points twice on symlinks
  2023-08-17 15:52   ` Fwd: " Steve French
@ 2023-08-17 16:19     ` Paulo Alcantara
  0 siblings, 0 replies; 21+ messages in thread
From: Paulo Alcantara @ 2023-08-17 16:19 UTC (permalink / raw)
  To: Steve French, CIFS

Steve French <smfrench@gmail.com> writes:

> Am also curious about the problem where we do an extra query on
> mfsymlinks with ls -l

When we find regular files in QUERY_DIRECTORY response that could be a
potential mfsymlink, we always mark those dentries for revalidation so
we can read its target when it is an actual mfsymlink.

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

* Re: [PATCH 00/17] cifs.ko fixes
  2023-08-17 15:33 [PATCH 00/17] cifs.ko fixes Paulo Alcantara
                   ` (16 preceding siblings ...)
  2023-08-17 15:34 ` [PATCH 17/17] smb: client: reduce stack usage in smb2_query_reparse_point() Paulo Alcantara
@ 2023-08-19  3:37 ` Steve French
  17 siblings, 0 replies; 21+ messages in thread
From: Steve French @ 2023-08-19  3:37 UTC (permalink / raw)
  To: Paulo Alcantara; +Cc: linux-cifs

Tentatively added to cifs-2.6.git for-next pending testing.

Opinions on whether any should be cc:stable?

Also let me know if anyone wants to add RB or Acked-by

On Thu, Aug 17, 2023 at 10:35 AM Paulo Alcantara <pc@manguebit.com> wrote:
>
> Hi Steve,
>
> Follow patchset with DFS, reparse point and -Wframe-larger-than fixes
> for v6.6.
>
> Please review & test.
>
> Paulo Alcantara (17):
>   smb: client: introduce DFS_CACHE_TGT_LIST()
>   smb: client: ensure to try all targets when finding nested links
>   smb: client: move some params to cifs_open_info_data
>   smb: client: make smb2_compound_op() return resp buffer on success
>   smb: client: rename cifs_dfs_ref.c to namespace.c
>   smb: client: get rid of dfs naming in automount code
>   smb: client: get rid of dfs code dep in namespace.c
>   smb: client: parse reparse point flag in create response
>   smb: client: do not query reparse points twice on symlinks
>   smb: client: query reparse points in older dialects
>   smb: cilent: set reparse mount points as automounts
>   smb: client: reduce stack usage in cifs_try_adding_channels()
>   smb: client: reduce stack usage in cifs_demultiplex_thread()
>   smb: client: reduce stack usage in smb_send_rqst()
>   smb: client: reduce stack usage in smb2_set_ea()
>   smb: client: reduce stack usage in smb2_query_info_compound()
>   smb: client: reduce stack usage in smb2_query_reparse_point()
>
>  fs/smb/client/Makefile                        |   5 +-
>  fs/smb/client/cifsfs.c                        |   2 +-
>  fs/smb/client/cifsfs.h                        |  11 +-
>  fs/smb/client/cifsglob.h                      |  69 ++-
>  fs/smb/client/cifsproto.h                     |   9 +-
>  fs/smb/client/connect.c                       |   8 +-
>  fs/smb/client/dfs.c                           | 291 +++++-----
>  fs/smb/client/dfs.h                           | 141 +++--
>  fs/smb/client/dfs_cache.c                     |  10 +-
>  fs/smb/client/dfs_cache.h                     |  12 +-
>  fs/smb/client/dir.c                           |   4 +-
>  fs/smb/client/inode.c                         | 530 ++++++++++--------
>  fs/smb/client/{cifs_dfs_ref.c => namespace.c} | 113 ++--
>  fs/smb/client/readdir.c                       |  23 +-
>  fs/smb/client/sess.c                          |  68 ++-
>  fs/smb/client/smb1ops.c                       |  26 +-
>  fs/smb/client/smb2inode.c                     | 199 ++++---
>  fs/smb/client/smb2ops.c                       | 283 +++-------
>  fs/smb/client/smb2proto.h                     |  17 +-
>  fs/smb/client/transport.c                     |  29 +-
>  20 files changed, 993 insertions(+), 857 deletions(-)
>  rename fs/smb/client/{cifs_dfs_ref.c => namespace.c} (62%)
>
> --
> 2.41.0
>


-- 
Thanks,

Steve

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

end of thread, other threads:[~2023-08-19  3:38 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-08-17 15:33 [PATCH 00/17] cifs.ko fixes Paulo Alcantara
2023-08-17 15:33 ` [PATCH 01/17] smb: client: introduce DFS_CACHE_TGT_LIST() Paulo Alcantara
2023-08-17 15:34 ` [PATCH 02/17] smb: client: ensure to try all targets when finding nested links Paulo Alcantara
2023-08-17 15:34 ` [PATCH 03/17] smb: client: move some params to cifs_open_info_data Paulo Alcantara
2023-08-17 15:34 ` [PATCH 04/17] smb: client: make smb2_compound_op() return resp buffer on success Paulo Alcantara
2023-08-17 15:34 ` [PATCH 05/17] smb: client: rename cifs_dfs_ref.c to namespace.c Paulo Alcantara
2023-08-17 15:34 ` [PATCH 06/17] smb: client: get rid of dfs naming in automount code Paulo Alcantara
2023-08-17 15:34 ` [PATCH 07/17] smb: client: get rid of dfs code dep in namespace.c Paulo Alcantara
2023-08-17 15:34 ` [PATCH 08/17] smb: client: parse reparse point flag in create response Paulo Alcantara
2023-08-17 15:34 ` [PATCH 09/17] smb: client: do not query reparse points twice on symlinks Paulo Alcantara
2023-08-17 15:52   ` Fwd: " Steve French
2023-08-17 16:19     ` Paulo Alcantara
2023-08-17 15:34 ` [PATCH 10/17] smb: client: query reparse points in older dialects Paulo Alcantara
2023-08-17 15:34 ` [PATCH 11/17] smb: cilent: set reparse mount points as automounts Paulo Alcantara
2023-08-17 15:34 ` [PATCH 12/17] smb: client: reduce stack usage in cifs_try_adding_channels() Paulo Alcantara
2023-08-17 15:34 ` [PATCH 13/17] smb: client: reduce stack usage in cifs_demultiplex_thread() Paulo Alcantara
2023-08-17 15:34 ` [PATCH 14/17] smb: client: reduce stack usage in smb_send_rqst() Paulo Alcantara
2023-08-17 15:34 ` [PATCH 15/17] smb: client: reduce stack usage in smb2_set_ea() Paulo Alcantara
2023-08-17 15:34 ` [PATCH 16/17] smb: client: reduce stack usage in smb2_query_info_compound() Paulo Alcantara
2023-08-17 15:34 ` [PATCH 17/17] smb: client: reduce stack usage in smb2_query_reparse_point() Paulo Alcantara
2023-08-19  3:37 ` [PATCH 00/17] cifs.ko fixes 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).