All of lore.kernel.org
 help / color / mirror / Atom feed
From: Paulo Alcantara <pc@manguebit.com>
To: "Steinbeißer, Sebastian" <Sebastian.Steinbeisser@lrz.de>,
	"tom@talpey.com" <tom@talpey.com>,
	"gregkh@linuxfoundation.org" <gregkh@linuxfoundation.org>
Cc: "smfrench@gmail.com" <smfrench@gmail.com>,
	"regressions@lists.linux.dev" <regressions@lists.linux.dev>
Subject: Re: Potential smb/dfs regression introduced in kernel 6.6
Date: Wed, 24 Jul 2024 22:28:37 -0300	[thread overview]
Message-ID: <6db3dbb8a7a6f4f5ed0f63d0e0c784c7@manguebit.com> (raw)
In-Reply-To: <2849de0676a015619b922708005a243595f9f56b.camel@lrz.de>

Tom, thank you very much for looking into this!

Steinbeißer, Sebastian	<Sebastian.Steinbeisser@lrz.de> writes:

> I've forwarded the question to our technical NetApp rep.
> Hopefully they will directly reply to the list - if not, I'll forward
> any replies once we get them.

Any news from NetApp?

In the meantime, could you try below changes on top of v6.10?  Thanks.

diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
index a865941724c0..c405ffb59b55 100644
--- a/fs/smb/client/cifsglob.h
+++ b/fs/smb/client/cifsglob.h
@@ -2322,4 +2322,10 @@ static inline bool cifs_ses_exiting(struct cifs_ses *ses)
 	return ret;
 }
 
+/*
+ * Used only by the client to ignore reparse points from files when the server
+ * doesn't support FSCTL_GET_REPARSE_POINT.
+ */
+#define IO_REPARSE_TAG_INTERNAL	0xffffffff
+
 #endif	/* _CIFS_GLOB_H */
diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c
index 4a8aa1de9522..3a39933f6fc1 100644
--- a/fs/smb/client/inode.c
+++ b/fs/smb/client/inode.c
@@ -1042,14 +1042,26 @@ static int reparse_info_to_fattr(struct cifs_open_info_data *data,
 	}
 
 	rc = -EOPNOTSUPP;
-	switch ((data->reparse.tag = tag)) {
-	case 0: /* SMB1 symlink */
+	data->reparse.tag = tag;
+	if (!data->reparse.tag) {
 		if (server->ops->query_symlink) {
 			rc = server->ops->query_symlink(xid, tcon,
 							cifs_sb, full_path,
 							&data->symlink_target);
+		} else {
+			data->reparse.tag = IO_REPARSE_TAG_INTERNAL;
 		}
+	}
+
+	switch (data->reparse.tag) {
+	case 0: /* SMB1 symlink */
 		break;
+	case IO_REPARSE_TAG_INTERNAL:
+		if (!(le32_to_cpu(data->fi.Attributes) & ATTR_DIRECTORY)) {
+			rc = 0;
+			break;
+		}
+		fallthrough;
 	case IO_REPARSE_TAG_MOUNT_POINT:
 		cifs_create_junction_fattr(fattr, sb);
 		rc = 0;
diff --git a/fs/smb/client/reparse.c b/fs/smb/client/reparse.c
index a0ffbda90733..689d8a506d45 100644
--- a/fs/smb/client/reparse.c
+++ b/fs/smb/client/reparse.c
@@ -505,6 +505,10 @@ bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb,
 	}
 
 	switch (tag) {
+	case IO_REPARSE_TAG_INTERNAL:
+		if (!(fattr->cf_cifsattrs & ATTR_DIRECTORY))
+			return false;
+		fallthrough;
 	case IO_REPARSE_TAG_DFS:
 	case IO_REPARSE_TAG_DFSR:
 	case IO_REPARSE_TAG_MOUNT_POINT:
diff --git a/fs/smb/client/reparse.h b/fs/smb/client/reparse.h
index 6b55d1df9e2f..4cf2fef9d988 100644
--- a/fs/smb/client/reparse.h
+++ b/fs/smb/client/reparse.h
@@ -78,10 +78,19 @@ static inline u32 reparse_mode_wsl_tag(mode_t mode)
 static inline bool reparse_inode_match(struct inode *inode,
 				       struct cifs_fattr *fattr)
 {
+	struct cifsInodeInfo *cinode = CIFS_I(inode);
 	struct timespec64 ctime = inode_get_ctime(inode);
 
-	return (CIFS_I(inode)->cifsAttrs & ATTR_REPARSE) &&
-		CIFS_I(inode)->reparse_tag == fattr->cf_cifstag &&
+	/*
+	 * Do not match reparse tags when the server doesn't support
+	 * FSCTL_GET_REPARSE_POINT.  @fattr->cf_cifstag should contain the
+	 * correct reparse tag but the client won't be able to parse the
+	 * reparse point data anyway.  This spares us a revalidation.
+	 */
+	if (cinode->reparse_tag != IO_REPARSE_TAG_INTERNAL &&
+	    cinode->reparse_tag != fattr->cf_cifstag)
+		return false;
+	return (cinode->cifsAttrs & ATTR_REPARSE) &&
 		timespec64_equal(&ctime, &fattr->cf_ctime);
 }
 
diff --git a/fs/smb/client/smb2inode.c b/fs/smb/client/smb2inode.c
index 5c02a12251c8..eceefe006d52 100644
--- a/fs/smb/client/smb2inode.c
+++ b/fs/smb/client/smb2inode.c
@@ -856,6 +856,43 @@ static int parse_create_response(struct cifs_open_info_data *data,
 	return rc;
 }
 
+static inline void free_qinfo_resp(struct kvec *rsp_iov,
+				   int *rsp_buftype, int num_resps)
+{
+	int i;
+
+	for (i = 0; i < num_resps; i++) {
+		free_rsp_buf(rsp_buftype[i], rsp_iov[i].iov_base);
+		rsp_buftype[i] = CIFS_NO_BUFFER;
+		memset(&rsp_iov[i], 0, sizeof(rsp_iov[i]));
+	}
+}
+
+/*
+ * If the server doesn't support FSCTL_GET_REPARSE_POINT, then just ignore the
+ * SMB2_IOCTL error.  See MS-FSA 2.1.5.10.14.
+ */
+static inline bool may_ignore_reparse_error(struct kvec *rsp_iov,
+					    int *rsp_buftype,
+					    int num_resps)
+{
+	struct smb2_hdr *hdr;
+	int i;
+
+	for (i = 0; i < num_resps; i++) {
+		hdr = (struct smb2_hdr *)rsp_iov[i].iov_base;
+		if (!hdr || rsp_buftype[i] == CIFS_NO_BUFFER)
+			return false;
+		if (hdr->Command == SMB2_IOCTL) {
+			if (hdr->Status != STATUS_INVALID_DEVICE_REQUEST)
+				return false;
+		} else if (hdr->Status != STATUS_SUCCESS) {
+			return false;
+		}
+	}
+	return true;
+}
+
 int smb2_query_path_info(const unsigned int xid,
 			 struct cifs_tcon *tcon,
 			 struct cifs_sb_info *cifs_sb,
@@ -867,11 +904,11 @@ int smb2_query_path_info(const unsigned int xid,
 	struct cifsFileInfo *cfile;
 	struct cached_fid *cfid = NULL;
 	struct smb2_hdr *hdr;
-	struct kvec in_iov[3], out_iov[3] = {};
-	int out_buftype[3] = {};
+	struct kvec in_iov[5], out_iov[5] = {};
+	int out_buftype[5] = {};
 	int cmds[3];
 	bool islink;
-	int i, num_cmds = 0;
+	int num_cmds = 0;
 	int rc, rc2;
 
 	data->adjust_tz = false;
@@ -952,9 +989,19 @@ int smb2_query_path_info(const unsigned int xid,
 				     FILE_OPEN, create_options |
 				     OPEN_REPARSE_POINT, ACL_NO_MODE);
 		cifs_get_readable_path(tcon, full_path, &cfile);
+		free_qinfo_resp(out_iov, out_buftype, ARRAY_SIZE(out_iov));
 		rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
 				      &oparms, in_iov, cmds, num_cmds,
-				      cfile, NULL, NULL, NULL);
+				      cfile, out_iov, out_buftype, NULL);
+		if (rc && cmds[num_cmds - 1] == SMB2_OP_GET_REPARSE &&
+		    may_ignore_reparse_error(out_iov, out_buftype,
+					     num_cmds + 1)) {
+			data->reparse.tag = IO_REPARSE_TAG_INTERNAL;
+			cifs_get_readable_path(tcon, full_path, &cfile);
+			rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
+					      &oparms, in_iov, cmds, num_cmds - 1,
+					      cfile, NULL, NULL, NULL);
+		}
 		break;
 	case -EREMOTE:
 		break;
@@ -972,8 +1019,7 @@ int smb2_query_path_info(const unsigned int xid,
 	}
 
 out:
-	for (i = 0; i < ARRAY_SIZE(out_buftype); i++)
-		free_rsp_buf(out_buftype[i], out_iov[i].iov_base);
+	free_qinfo_resp(out_iov, out_buftype, ARRAY_SIZE(out_iov));
 	return rc;
 }
 

  reply	other threads:[~2024-07-25  1:28 UTC|newest]

Thread overview: 28+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-06-27 13:28 Potential smb/dfs regression introduced in kernel 6.6 Steinbeißer, Sebastian
2024-06-27 13:37 ` Greg KH
     [not found] ` <f3a02647b6fcb27a70da4c334930ad3c@manguebit.com>
2024-06-28  8:19   ` Steinbeißer, Sebastian
2024-07-11  6:20     ` Steinbeißer, Sebastian
2024-07-11  7:27       ` gregkh
2024-07-11 15:20       ` Christian Heusel
2024-07-14 19:12       ` Paulo Alcantara
2024-07-15  5:41         ` Steinbeißer, Sebastian
2024-07-15 12:21           ` Paulo Alcantara
2024-07-15 13:26             ` Steinbeißer, Sebastian
2024-07-15 14:24               ` Paulo Alcantara
2024-07-16  6:14         ` Steinbeißer, Sebastian
2024-07-17 18:24           ` Paulo Alcantara
2024-07-17 20:03             ` Tom Talpey
2024-07-18  5:43               ` Steinbeißer, Sebastian
2024-07-25  1:28                 ` Paulo Alcantara [this message]
2024-07-26  8:19                   ` Steinbeißer, Sebastian
2024-07-26 18:00                     ` Paulo Alcantara
2024-07-29  5:57                   ` Steinbeißer, Sebastian
2024-07-29 12:34                     ` Paulo Alcantara
2024-07-30  5:25                       ` Steinbeißer, Sebastian
2024-07-31  2:35                         ` Paulo Alcantara
2024-07-31  5:02                           ` Steinbeißer, Sebastian
2024-07-31  5:07                             ` Steinbeißer, Sebastian
2024-07-31 14:25                               ` Paulo Alcantara
2024-08-01 13:07                                 ` Steinbeißer, Sebastian
2024-08-01 16:25                                   ` Paulo Alcantara
2024-08-01 19:02                                     ` Tom Talpey

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=6db3dbb8a7a6f4f5ed0f63d0e0c784c7@manguebit.com \
    --to=pc@manguebit.com \
    --cc=Sebastian.Steinbeisser@lrz.de \
    --cc=gregkh@linuxfoundation.org \
    --cc=regressions@lists.linux.dev \
    --cc=smfrench@gmail.com \
    --cc=tom@talpey.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.