summaryrefslogtreecommitdiff
path: root/fs/cifs/smb2ops.c
diff options
context:
space:
mode:
authorSteve French <stfrench@microsoft.com>2020-10-22 22:03:14 -0500
committerSteve French <stfrench@microsoft.com>2020-10-23 15:38:10 -0500
commit2e4564b31b645f599d531e2c8bd0e47316e02223 (patch)
tree8327c6e83d7546e973f4cef68c670d4d2a6c204b /fs/cifs/smb2ops.c
parent0613ed91901b5f87afcd28b4560fb0aa37a0db13 (diff)
smb3: add support for stat of WSL reparse points for special file types
This is needed so when mounting to Windows we do not misinterpret various special files created by Linux (WSL) as symlinks. An earlier patch addressed readdir. This patch fixes stat (getattr). With this patch:   File: /mnt1/char   Size: 0          Blocks: 0          IO Block: 16384  character special file Device: 34h/52d Inode: 844424930132069  Links: 1     Device type: 0,0 Access: (0755/crwxr-xr-x)  Uid: (    0/    root)   Gid: (    0/    root) Access: 2020-10-21 17:46:51.839458900 -0500 Modify: 2020-10-21 17:46:51.839458900 -0500 Change: 2020-10-21 18:30:39.797358800 -0500  Birth: -   File: /mnt1/fifo   Size: 0          Blocks: 0          IO Block: 16384  fifo Device: 34h/52d Inode: 1125899906842722  Links: 1 Access: (0755/prwxr-xr-x)  Uid: (    0/    root)   Gid: (    0/    root) Access: 2020-10-21 16:21:37.259249700 -0500 Modify: 2020-10-21 16:21:37.259249700 -0500 Change: 2020-10-21 18:30:39.797358800 -0500  Birth: -   File: /mnt1/block   Size: 0          Blocks: 0          IO Block: 16384  block special file Device: 34h/52d Inode: 844424930132068  Links: 1     Device type: 0,0 Access: (0755/brwxr-xr-x)  Uid: (    0/    root)   Gid: (    0/    root) Access: 2020-10-21 17:10:47.913103200 -0500 Modify: 2020-10-21 17:10:47.913103200 -0500 Change: 2020-10-21 18:30:39.796725500 -0500  Birth: - without the patch all show up incorrectly as symlinks with annoying "operation not supported error also returned"   File: /mnt1/charstat: cannot read symbolic link '/mnt1/char': Operation not supported   Size: 0          Blocks: 0          IO Block: 16384  symbolic link Device: 34h/52d Inode: 844424930132069  Links: 1 Access: (0000/l---------)  Uid: (    0/    root)   Gid: (    0/    root) Access: 2020-10-21 17:46:51.839458900 -0500 Modify: 2020-10-21 17:46:51.839458900 -0500 Change: 2020-10-21 18:30:39.797358800 -0500  Birth: -   File: /mnt1/fifostat: cannot read symbolic link '/mnt1/fifo': Operation not supported   Size: 0          Blocks: 0          IO Block: 16384  symbolic link Device: 34h/52d Inode: 1125899906842722  Links: 1 Access: (0000/l---------)  Uid: (    0/    root)   Gid: (    0/    root) Access: 2020-10-21 16:21:37.259249700 -0500 Modify: 2020-10-21 16:21:37.259249700 -0500 Change: 2020-10-21 18:30:39.797358800 -0500  Birth: -   File: /mnt1/blockstat: cannot read symbolic link '/mnt1/block': Operation not supported   Size: 0          Blocks: 0          IO Block: 16384  symbolic link Device: 34h/52d Inode: 844424930132068  Links: 1 Access: (0000/l---------)  Uid: (    0/    root)   Gid: (    0/    root) Access: 2020-10-21 17:10:47.913103200 -0500 Modify: 2020-10-21 17:10:47.913103200 -0500 Change: 2020-10-21 18:30:39.796725500 -0500 Signed-off-by: Steve French <stfrench@microsoft.com> Reviewed-by: Ronnie Sahlberg <lsahlber@redhat.com>
Diffstat (limited to 'fs/cifs/smb2ops.c')
-rw-r--r--fs/cifs/smb2ops.c135
1 files changed, 135 insertions, 0 deletions
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 3cde719ec41b..0fe87f397ac5 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -3034,6 +3034,138 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
return rc;
}
+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)
+{
+ 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 = 0;
+ 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;
+ u32 plen;
+
+ cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path);
+
+ 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;
+
+ /*
+ * 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_nvec = SMB2_CREATE_IOV_SIZE;
+
+ memset(&oparms, 0, sizeof(oparms));
+ oparms.tcon = tcon;
+ oparms.desired_access = FILE_READ_ATTRIBUTES;
+ oparms.disposition = FILE_OPEN;
+ oparms.create_options = cifs_create_options(cifs_sb, OPEN_REPARSE_POINT);
+ oparms.fid = &fid;
+ oparms.reconnect = false;
+
+ rc = SMB2_open_init(tcon, server,
+ &rqst[0], &oplock, &oparms, utf16_path);
+ if (rc)
+ goto query_rp_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,
+ true /* is_fctl */, NULL, 0,
+ CIFSMaxBufSize -
+ MAX_SMB2_CREATE_RESPONSE_SIZE -
+ MAX_SMB2_CLOSE_RESPONSE_SIZE);
+ if (rc)
+ goto query_rp_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 query_rp_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->sync_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) {
+ /* 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(FYI, "srv returned invalid ioctl len: %d\n",
+ plen);
+ rc = -EIO;
+ goto query_rp_exit;
+ }
+ *tag = le32_to_cpu(reparse_buf->ReparseTag);
+ }
+
+ 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);
+ return rc;
+}
+
static struct cifs_ntsd *
get_smb2_acl_by_fid(struct cifs_sb_info *cifs_sb,
const struct cifs_fid *cifsfid, u32 *pacllen)
@@ -4986,6 +5118,8 @@ struct smb_version_operations smb30_operations = {
.can_echo = smb2_can_echo,
.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,
.get_srv_inum = smb2_get_srv_inum,
.query_file_info = smb2_query_file_info,
.set_path_size = smb2_set_path_size,
@@ -5097,6 +5231,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,
.get_srv_inum = smb2_get_srv_inum,
.query_file_info = smb2_query_file_info,
.set_path_size = smb2_set_path_size,