Commit c10037f8 authored by Linus Torvalds's avatar Linus Torvalds

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
......@@ -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 */
......@@ -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 *,
......
......@@ -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))
......@@ -938,8 +954,8 @@ cifs_get_inode_info(struct inode **inode,
goto out;
}
rc = server->ops->query_path_info(xid, tcon, cifs_sb,
full_path, tmp_data,
&adjust_tz, &symlink);
full_path, tmp_data,
&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 */
......
......@@ -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 @@ 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,
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 */
......
......@@ -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,
......
......@@ -999,6 +999,31 @@ struct copychunk_ioctl_rsp {
__le32 TotalBytesWritten;
} __packed;
/* See MS-FSCC 2.3.29 and 2.3.30 */
struct get_retrieval_pointer_count_req {
__le64 StartingVcn; /* virtual cluster number (signed) */
} __packed;
struct get_retrieval_pointer_count_rsp {
__le32 ExtentCount;
} __packed;
/*
* See MS-FSCC 2.3.33 and 2.3.34
* request is the same as get_retrieval_point_count_req struct above
*/
struct smb3_extents {
__le64 NextVcn;
__le64 Lcn; /* logical cluster number */
} __packed;
struct get_retrieval_pointers_refcount_rsp {
__le32 ExtentCount;
__u32 Reserved;
__le64 StartingVcn;
struct smb3_extents extents[];
} __packed;
struct fsctl_set_integrity_information_req {
__le16 ChecksumAlgorithm;
__le16 Reserved;
......@@ -1640,6 +1665,7 @@ struct smb2_file_rename_info { /* encoding of request for level 10 */
__u64 RootDirectory; /* MBZ for network operations (why says spec?) */
__le32 FileNameLength;
char FileName[]; /* New name to be assigned */
/* padding - overall struct size must be >= 24 so filename + pad >= 6 */
} __packed; /* level 10 Set */
struct smb2_file_link_info { /* encoding of request for level 11 */
......@@ -1691,6 +1717,11 @@ struct smb2_file_eof_info { /* encoding of request for level 10 */
__le64 EndOfFile; /* new end of file value */
} __packed; /* level 20 Set */
struct smb2_file_reparse_point_info {
__le64 IndexNumber;
__le32 Tag;
} __packed;
struct smb2_file_network_open_info {
__le64 CreationTime;
__le64 LastAccessTime;
......
......@@ -77,6 +77,9 @@ extern void close_shroot_lease(struct cached_fid *cfid);
extern void close_shroot_lease_locked(struct cached_fid *cfid);
extern void move_smb2_info_to_cifs(FILE_ALL_INFO *dst,
struct smb2_file_all_info *src);
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);
extern 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,
......
......@@ -103,6 +103,8 @@
#define FSCTL_SET_ZERO_ON_DEALLOC 0x00090194 /* BB add struct */
#define FSCTL_SET_SHORT_NAME_BEHAVIOR 0x000901B4 /* BB add struct */
#define FSCTL_GET_INTEGRITY_INFORMATION 0x0009027C
#define FSCTL_GET_RETRIEVAL_POINTERS_AND_REFCOUNT 0x000903d3
#define FSCTL_GET_RETRIEVAL_POINTER_COUNT 0x0009042b
#define FSCTL_QUERY_ALLOCATED_RANGES 0x000940CF
#define FSCTL_SET_DEFECT_MANAGEMENT 0x00098134 /* BB add struct */
#define FSCTL_FILE_LEVEL_TRIM 0x00098208 /* BB add struct */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment