--- /dev/null
+From 7db09b0bddf57b0194eb3226abf04e08ee222b5a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 Dec 2024 14:50:38 +0100
+Subject: cifs: Remove symlink member from cifs_open_info_data union
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Pali Rohár <pali@kernel.org>
+
+[ Upstream commit 65c49767dd4fc058673f9259fda1772fd398eaa7 ]
+
+Member 'symlink' is part of the union in struct cifs_open_info_data. Its
+value is assigned on few places, but is always read through another union
+member 'reparse_point'. So to make code more readable, always use only
+'reparse_point' member and drop whole union structure. No function change.
+
+Signed-off-by: Pali Rohár <pali@kernel.org>
+Acked-by: Paulo Alcantara (Red Hat) <pc@manguebit.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Stable-dep-of: 9df23801c83d ("smb311: failure to open files of length 1040 when mounting with SMB3.1.1 POSIX extensions")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/client/cifsglob.h | 5 +----
+ fs/smb/client/inode.c | 2 +-
+ fs/smb/client/smb1ops.c | 4 ++--
+ 3 files changed, 4 insertions(+), 7 deletions(-)
+
+diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
+index 1e6085f2f78ee..3877b861529ea 100644
+--- a/fs/smb/client/cifsglob.h
++++ b/fs/smb/client/cifsglob.h
+@@ -215,10 +215,7 @@ struct cifs_cred {
+
+ struct cifs_open_info_data {
+ bool adjust_tz;
+- union {
+- bool reparse_point;
+- bool symlink;
+- };
++ bool reparse_point;
+ struct {
+ /* ioctl response buffer */
+ struct {
+diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c
+index 0d149b315a832..4d8effe78be57 100644
+--- a/fs/smb/client/inode.c
++++ b/fs/smb/client/inode.c
+@@ -990,7 +990,7 @@ cifs_get_file_info(struct file *filp)
+ /* TODO: add support to query reparse tag */
+ data.adjust_tz = false;
+ if (data.symlink_target) {
+- data.symlink = true;
++ data.reparse_point = true;
+ data.reparse.tag = IO_REPARSE_TAG_SYMLINK;
+ }
+ path = build_path_from_dentry(dentry, page);
+diff --git a/fs/smb/client/smb1ops.c b/fs/smb/client/smb1ops.c
+index c70f4961c4eb7..bd791aa54681f 100644
+--- a/fs/smb/client/smb1ops.c
++++ b/fs/smb/client/smb1ops.c
+@@ -551,7 +551,7 @@ static int cifs_query_path_info(const unsigned int xid,
+ int rc;
+ FILE_ALL_INFO fi = {};
+
+- data->symlink = false;
++ data->reparse_point = false;
+ data->adjust_tz = false;
+
+ /* could do find first instead but this returns more info */
+@@ -592,7 +592,7 @@ static int cifs_query_path_info(const unsigned int xid,
+ /* Need to check if this is a symbolic link or not */
+ tmprc = CIFS_open(xid, &oparms, &oplock, NULL);
+ if (tmprc == -EOPNOTSUPP)
+- data->symlink = true;
++ data->reparse_point = true;
+ else if (tmprc == 0)
+ CIFSSMBClose(xid, tcon, fid.netfid);
+ }
+--
+2.39.5
+
--- /dev/null
+From 8ce8e1b13fa4b829a13245289c3a4c329597e763 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 16 Feb 2025 22:17:54 -0600
+Subject: smb311: failure to open files of length 1040 when mounting with
+ SMB3.1.1 POSIX extensions
+
+From: Steve French <stfrench@microsoft.com>
+
+[ Upstream commit 9df23801c83d3e12b4c09be39d37d2be385e52f9 ]
+
+If a file size has bits 0x410 = ATTR_DIRECTORY | ATTR_REPARSE set
+then during queryinfo (stat) the file is regarded as a directory
+and subsequent opens can fail. A simple test example is trying
+to open any file 1040 bytes long when mounting with "posix"
+(SMB3.1.1 POSIX/Linux Extensions).
+
+The cause of this bug is that Attributes field in smb2_file_all_info
+struct occupies the same place that EndOfFile field in
+smb311_posix_qinfo, and sometimes the latter struct is incorrectly
+processed as if it was the first one.
+
+Reported-by: Oleh Nykyforchyn <oleh.nyk@gmail.com>
+Tested-by: Oleh Nykyforchyn <oleh.nyk@gmail.com>
+Acked-by: Paulo Alcantara (Red Hat) <pc@manguebit.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/client/cifsglob.h | 1 +
+ fs/smb/client/reparse.h | 28 ++++++++++++++++++++++------
+ fs/smb/client/smb2inode.c | 4 ++++
+ fs/smb/client/smb2ops.c | 3 ++-
+ 4 files changed, 29 insertions(+), 7 deletions(-)
+
+diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
+index 3877b861529ea..37b7d84e26913 100644
+--- a/fs/smb/client/cifsglob.h
++++ b/fs/smb/client/cifsglob.h
+@@ -216,6 +216,7 @@ struct cifs_cred {
+ struct cifs_open_info_data {
+ bool adjust_tz;
+ bool reparse_point;
++ bool contains_posix_file_info;
+ struct {
+ /* ioctl response buffer */
+ struct {
+diff --git a/fs/smb/client/reparse.h b/fs/smb/client/reparse.h
+index ff05b0e75c928..f080f92cb1e74 100644
+--- a/fs/smb/client/reparse.h
++++ b/fs/smb/client/reparse.h
+@@ -97,14 +97,30 @@ static inline bool reparse_inode_match(struct inode *inode,
+
+ static inline bool cifs_open_data_reparse(struct cifs_open_info_data *data)
+ {
+- struct smb2_file_all_info *fi = &data->fi;
+- u32 attrs = le32_to_cpu(fi->Attributes);
++ u32 attrs;
+ bool ret;
+
+- ret = data->reparse_point || (attrs & ATTR_REPARSE);
+- if (ret)
+- attrs |= ATTR_REPARSE;
+- fi->Attributes = cpu_to_le32(attrs);
++ if (data->contains_posix_file_info) {
++ struct smb311_posix_qinfo *fi = &data->posix_fi;
++
++ attrs = le32_to_cpu(fi->DosAttributes);
++ if (data->reparse_point) {
++ attrs |= ATTR_REPARSE;
++ fi->DosAttributes = cpu_to_le32(attrs);
++ }
++
++ } else {
++ struct smb2_file_all_info *fi = &data->fi;
++
++ attrs = le32_to_cpu(fi->Attributes);
++ if (data->reparse_point) {
++ attrs |= ATTR_REPARSE;
++ fi->Attributes = cpu_to_le32(attrs);
++ }
++ }
++
++ ret = attrs & ATTR_REPARSE;
++
+ return ret;
+ }
+
+diff --git a/fs/smb/client/smb2inode.c b/fs/smb/client/smb2inode.c
+index 7dfd3eb3847b3..6048b3fed3e78 100644
+--- a/fs/smb/client/smb2inode.c
++++ b/fs/smb/client/smb2inode.c
+@@ -648,6 +648,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
+ switch (cmds[i]) {
+ case SMB2_OP_QUERY_INFO:
+ idata = in_iov[i].iov_base;
++ idata->contains_posix_file_info = false;
+ if (rc == 0 && cfile && cfile->symlink_target) {
+ idata->symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL);
+ if (!idata->symlink_target)
+@@ -671,6 +672,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
+ break;
+ case SMB2_OP_POSIX_QUERY_INFO:
+ idata = in_iov[i].iov_base;
++ idata->contains_posix_file_info = true;
+ if (rc == 0 && cfile && cfile->symlink_target) {
+ idata->symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL);
+ if (!idata->symlink_target)
+@@ -768,6 +770,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
+ idata = in_iov[i].iov_base;
+ idata->reparse.io.iov = *iov;
+ idata->reparse.io.buftype = resp_buftype[i + 1];
++ idata->contains_posix_file_info = false; /* BB VERIFY */
+ rbuf = reparse_buf_ptr(iov);
+ if (IS_ERR(rbuf)) {
+ rc = PTR_ERR(rbuf);
+@@ -789,6 +792,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
+ case SMB2_OP_QUERY_WSL_EA:
+ if (!rc) {
+ idata = in_iov[i].iov_base;
++ idata->contains_posix_file_info = false;
+ qi_rsp = rsp_iov[i + 1].iov_base;
+ data[0] = (u8 *)qi_rsp + le16_to_cpu(qi_rsp->OutputBufferOffset);
+ size[0] = le32_to_cpu(qi_rsp->OutputBufferLength);
+diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
+index 793e9b2b79d6f..17c3063a9ca5b 100644
+--- a/fs/smb/client/smb2ops.c
++++ b/fs/smb/client/smb2ops.c
+@@ -1001,6 +1001,7 @@ static int smb2_query_file_info(const unsigned int xid, struct cifs_tcon *tcon,
+ if (!data->symlink_target)
+ return -ENOMEM;
+ }
++ data->contains_posix_file_info = false;
+ return SMB2_query_info(xid, tcon, fid->persistent_fid, fid->volatile_fid, &data->fi);
+ }
+
+@@ -5150,7 +5151,7 @@ int __cifs_sfu_make_node(unsigned int xid, struct inode *inode,
+ FILE_CREATE, CREATE_NOT_DIR |
+ CREATE_OPTION_SPECIAL, ACL_NO_MODE);
+ oparms.fid = &fid;
+-
++ idata.contains_posix_file_info = false;
+ rc = server->ops->open(xid, &oparms, &oplock, &idata);
+ if (rc)
+ goto out;
+--
+2.39.5
+