forked from Minki/linux
add support for stat of various special file types (WSL reparse points for char, block, fifo)
-----BEGIN PGP SIGNATURE----- iQGzBAABCgAdFiEE6fsu8pdIjtWE/DpLiiy9cAdyT1EFAl+UkSkACgkQiiy9cAdy T1F3bgwApxA6MpakG30bXb+ed0PZPCE5g19qMjj9i+rGyGXn44jzSJAZ9FQzSs6E V95JjLiEKQ+7aaeqiy5Fy96PCHONvbG8RY6rXLgOD2F+wGrVeArXdY/QjotVZLZe Yyx0hHsBs8OeAsjmzYnkG65DVx/oKg3FKYOs22Fw+B5X6UzSY13p7iK3juW64oA/ RWJ0sFizJdn2PKTWGKZPoyncJabvjC8SDPq+GCyQ7uq2plh4I6R+DOXEUdfT7PV7 kyymgqt8MG2gSetxpbIgIEe4QqfNGxYsOxiGB0k/d5XsPHRPtbJkZYHWAiZR7W/f B7Iccgte6Rz5Uv9+FknWibOsEwvHgeh0kCJ+Ct3A53FEP/My6CzG6j2Vq4akTsn3 sPu7nur8ITErUE8ybfxNO08OcqV7Sk28RMTFaZZN5fu+Zb90Pc7rGk49KXKqEsvc GbIU4Lp4nI2eknjcp2+/CX0vUJhn1SmkhvTuh46XdwfIC3aN6yrUg7ZWsVQRHlDI HNX4gVjb =4LDZ -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
c10037f832
@ -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 @@ 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 */
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user