Commit c10037f8 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag '5.10-rc-smb3-fixes-part2' of git://git.samba.org/sfrench/cifs-2.6

Pull more cifs updates from Steve French:
 "Add support for stat of various special file types (WSL reparse points
  for char, block, fifo)"

* tag '5.10-rc-smb3-fixes-part2' of git://git.samba.org/sfrench/cifs-2.6:
  cifs: update internal module version number
  smb3: add some missing definitions from MS-FSCC
  smb3: remove two unused variables
  smb3: add support for stat of WSL reparse points for special file types
parents f9c25d98 aef0388a
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -156,5 +156,5 @@ extern int cifs_truncate_page(struct address_space *mapping, loff_t from);
extern const struct export_operations cifs_export_ops;
#endif /* CONFIG_CIFS_NFSD_EXPORT */

#define CIFS_VERSION   "2.28"
#define CIFS_VERSION   "2.29"
#endif				/* _CIFSFS_H */
+4 −0
Original line number Diff line number Diff line
@@ -298,6 +298,10 @@ struct smb_version_operations {
	/* query file data from the server */
	int (*query_file_info)(const unsigned int, struct cifs_tcon *,
			       struct cifs_fid *, FILE_ALL_INFO *);
	/* 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);
	/* get server index number */
	int (*get_srv_inum)(const unsigned int, struct cifs_tcon *,
			    struct cifs_sb_info *, const char *,
+36 −8
Original line number Diff line number Diff line
@@ -656,7 +656,7 @@ smb311_posix_info_to_fattr(struct cifs_fattr *fattr, struct smb311_posix_qinfo *
static void
cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
		       struct super_block *sb, bool adjust_tz,
		       bool symlink)
		       bool symlink, u32 reparse_tag)
{
	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
	struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
@@ -684,8 +684,22 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
	fattr->cf_createtime = le64_to_cpu(info->CreationTime);

	fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks);

	if (symlink) {
	if (reparse_tag == IO_REPARSE_TAG_LX_SYMLINK) {
		fattr->cf_mode |= S_IFLNK | cifs_sb->mnt_file_mode;
		fattr->cf_dtype = DT_LNK;
	} else if (reparse_tag == IO_REPARSE_TAG_LX_FIFO) {
		fattr->cf_mode |= S_IFIFO | cifs_sb->mnt_file_mode;
		fattr->cf_dtype = DT_FIFO;
	} else if (reparse_tag == IO_REPARSE_TAG_AF_UNIX) {
		fattr->cf_mode |= S_IFSOCK | cifs_sb->mnt_file_mode;
		fattr->cf_dtype = DT_SOCK;
	} else if (reparse_tag == IO_REPARSE_TAG_LX_CHR) {
		fattr->cf_mode |= S_IFCHR | cifs_sb->mnt_file_mode;
		fattr->cf_dtype = DT_CHR;
	} else if (reparse_tag == IO_REPARSE_TAG_LX_BLK) {
		fattr->cf_mode |= S_IFBLK | cifs_sb->mnt_file_mode;
		fattr->cf_dtype = DT_BLK;
	} else if (symlink) { /* TODO add more reparse tag checks */
		fattr->cf_mode = S_IFLNK;
		fattr->cf_dtype = DT_LNK;
	} else if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
@@ -740,8 +754,9 @@ cifs_get_file_info(struct file *filp)
	rc = server->ops->query_file_info(xid, tcon, &cfile->fid, &find_data);
	switch (rc) {
	case 0:
		/* TODO: add support to query reparse tag */
		cifs_all_info_to_fattr(&fattr, &find_data, inode->i_sb, false,
				       false);
				       false, 0 /* no reparse tag */);
		break;
	case -EREMOTE:
		cifs_create_dfs_fattr(&fattr, inode->i_sb);
@@ -910,12 +925,13 @@ cifs_get_inode_info(struct inode **inode,
	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
	bool adjust_tz = false;
	struct cifs_fattr fattr = {0};
	bool symlink = false;
	bool is_reparse_point = false;
	FILE_ALL_INFO *data = in_data;
	FILE_ALL_INFO *tmp_data = NULL;
	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))
@@ -939,7 +955,7 @@ cifs_get_inode_info(struct inode **inode,
		}
		rc = server->ops->query_path_info(xid, tcon, cifs_sb,
						 full_path, tmp_data,
						  &adjust_tz, &symlink);
						 &adjust_tz, &is_reparse_point);
		data = tmp_data;
	}

@@ -949,7 +965,19 @@ cifs_get_inode_info(struct inode **inode,

	switch (rc) {
	case 0:
		cifs_all_info_to_fattr(&fattr, data, sb, adjust_tz, symlink);
		/*
		 * If the file is a reparse point, it is more complicated
		 * since we have to check if its reparse tag matches a known
		 * special file type e.g. symlink or fifo or char etc.
		 */
		if ((le32_to_cpu(data->Attributes) & ATTR_REPARSE) &&
		    server->ops->query_reparse_tag) {
			rc = server->ops->query_reparse_tag(xid, tcon, cifs_sb,
						full_path, &reparse_tag);
			cifs_dbg(FYI, "reparse tag 0x%x\n", reparse_tag);
		}
		cifs_all_info_to_fattr(&fattr, data, sb, adjust_tz,
				       is_reparse_point, reparse_tag);
		break;
	case -EREMOTE:
		/* DFS link, no metadata available on this server */
+6 −6
Original line number Diff line number Diff line
@@ -506,7 +506,7 @@ move_smb2_info_to_cifs(FILE_ALL_INFO *dst, struct smb2_file_all_info *src)
int
smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
		     struct cifs_sb_info *cifs_sb, const char *full_path,
		     FILE_ALL_INFO *data, bool *adjust_tz, bool *symlink)
		     FILE_ALL_INFO *data, bool *adjust_tz, bool *reparse)
{
	int rc;
	struct smb2_file_all_info *smb2_data;
@@ -516,7 +516,7 @@ smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
	struct cached_fid *cfid = NULL;

	*adjust_tz = false;
	*symlink = false;
	*reparse = false;

	smb2_data = kzalloc(sizeof(struct smb2_file_all_info) + PATH_MAX * 2,
			    GFP_KERNEL);
@@ -548,7 +548,7 @@ smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
			      FILE_READ_ATTRIBUTES, FILE_OPEN, create_options,
			      ACL_NO_MODE, smb2_data, SMB2_OP_QUERY_INFO, cfile);
	if (rc == -EOPNOTSUPP) {
		*symlink = true;
		*reparse = true;
		create_options |= OPEN_REPARSE_POINT;

		/* Failed on a symbolic link - query a reparse point info */
@@ -570,7 +570,7 @@ out:
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 smb311_posix_qinfo *data, bool *adjust_tz, bool *symlink)
		     struct smb311_posix_qinfo *data, bool *adjust_tz, bool *reparse)
{
	int rc;
	__u32 create_options = 0;
@@ -578,7 +578,7 @@ smb311_posix_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
	struct smb311_posix_qinfo *smb2_data;

	*adjust_tz = false;
	*symlink = false;
	*reparse = false;

	/* BB TODO: Make struct larger when add support for parsing owner SIDs */
	smb2_data = kzalloc(sizeof(struct smb311_posix_qinfo),
@@ -599,7 +599,7 @@ smb311_posix_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
			      ACL_NO_MODE, smb2_data, SMB2_OP_POSIX_QUERY_INFO, cfile);
	if (rc == -EOPNOTSUPP) {
		/* BB TODO: When support for special files added to Samba re-verify this path */
		*symlink = true;
		*reparse = true;
		create_options |= OPEN_REPARSE_POINT;

		/* Failed on a symbolic link - query a reparse point info */
+130 −0
Original line number Diff line number Diff line
@@ -3034,6 +3034,133 @@ 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 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_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);

	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 +5113,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 +5226,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,
Loading