Five SMB client fixes
-----BEGIN PGP SIGNATURE----- iQGzBAABCgAdFiEE6fsu8pdIjtWE/DpLiiy9cAdyT1EFAme2g0oACgkQiiy9cAdy T1Ho0QwAqnmeBvEtAeRBoOO+iKNe3WJy4xKfZA4vJMRWcd99jt7j81q/hZDxPTNW 9x3HPivjMsCOrFSXP6EFRTwiaOXvx4GH+iMejVc7odhfD4Vs9hESvdH61ob1DoXi 3O7hMkA/X3bhy7j7+JS3ellHV6GLylOITnI+6RUBP12f5i+JVWndf4+umj+RcesL igdgveN748HSm6zN7aOQzvcDQhW+oamgq5GppPnjWbVeRStCvK51VuvpYM0PtbW6 7EEh5nQMGdeDe6L2JWVrJNZF4owVuxXzbdUv8zblDStTWeevBnDJgjv2NgW6msP/ r+8IqSu4C6XaDdriQO4rV0HBivR3Vt/VDZvRkSniBqJIj9uoedaiZaAZz8oYgXkF uCJbq+Z3pJojm5KcutcvSmYYbPS4Gzck6B4QQbz/3uIuTRXCvoRUZohnrUPm4Jdl Iv3ImO34Q0ScbriNQBmnBmzSvgmSSoTlNpsHPqd4bGNTCxJ+uZMChG1x3cK+AhhH g/XOMOOi =nwa3 -----END PGP SIGNATURE----- Merge tag 'v6.14-rc3-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6 Pull smb client fixes from Steve French: - Fix for chmod regression - Two reparse point related fixes - One minor cleanup (for GCC 14 compiles) - Fix for SMB3.1.1 POSIX Extensions reporting incorrect file type * tag 'v6.14-rc3-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6: cifs: Treat unhandled directory name surrogate reparse points as mount directory nodes cifs: Throw -EOPNOTSUPP error on unsupported reparse point type from parse_reparse_point() smb311: failure to open files of length 1040 when mounting with SMB3.1.1 POSIX extensions smb: client, common: Avoid multiple -Wflex-array-member-not-at-end warnings smb: client: fix chmod(2) regression with ATTR_READONLY
This commit is contained in:
commit
e9a8cac0bf
8 changed files with 71 additions and 24 deletions
|
@ -253,6 +253,7 @@ struct cifs_cred {
|
|||
struct cifs_open_info_data {
|
||||
bool adjust_tz;
|
||||
bool reparse_point;
|
||||
bool contains_posix_file_info;
|
||||
struct {
|
||||
/* ioctl response buffer */
|
||||
struct {
|
||||
|
@ -2324,8 +2325,8 @@ struct smb2_compound_vars {
|
|||
struct kvec io_iov[SMB2_IOCTL_IOV_SIZE];
|
||||
struct kvec si_iov[SMB2_SET_INFO_IOV_SIZE];
|
||||
struct kvec close_iov;
|
||||
struct smb2_file_rename_info rename_info;
|
||||
struct smb2_file_link_info link_info;
|
||||
struct smb2_file_rename_info_hdr rename_info;
|
||||
struct smb2_file_link_info_hdr link_info;
|
||||
struct kvec ea_iov;
|
||||
};
|
||||
|
||||
|
|
|
@ -1215,6 +1215,19 @@ static int reparse_info_to_fattr(struct cifs_open_info_data *data,
|
|||
rc = server->ops->parse_reparse_point(cifs_sb,
|
||||
full_path,
|
||||
iov, data);
|
||||
/*
|
||||
* If the reparse point was not handled but it is the
|
||||
* name surrogate which points to directory, then treat
|
||||
* is as a new mount point. Name surrogate reparse point
|
||||
* represents another named entity in the system.
|
||||
*/
|
||||
if (rc == -EOPNOTSUPP &&
|
||||
IS_REPARSE_TAG_NAME_SURROGATE(data->reparse.tag) &&
|
||||
(le32_to_cpu(data->fi.Attributes) & ATTR_DIRECTORY)) {
|
||||
rc = 0;
|
||||
cifs_create_junction_fattr(fattr, sb);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (data->reparse.tag == IO_REPARSE_TAG_SYMLINK && !rc) {
|
||||
|
@ -1408,7 +1421,7 @@ int cifs_get_inode_info(struct inode **inode,
|
|||
struct cifs_fattr fattr = {};
|
||||
int rc;
|
||||
|
||||
if (is_inode_cache_good(*inode)) {
|
||||
if (!data && is_inode_cache_good(*inode)) {
|
||||
cifs_dbg(FYI, "No need to revalidate cached inode sizes\n");
|
||||
return 0;
|
||||
}
|
||||
|
@ -1507,7 +1520,7 @@ int smb311_posix_get_inode_info(struct inode **inode,
|
|||
struct cifs_fattr fattr = {};
|
||||
int rc;
|
||||
|
||||
if (is_inode_cache_good(*inode)) {
|
||||
if (!data && is_inode_cache_good(*inode)) {
|
||||
cifs_dbg(FYI, "No need to revalidate cached inode sizes\n");
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1088,13 +1088,12 @@ int parse_reparse_point(struct reparse_data_buffer *buf,
|
|||
le32_to_cpu(buf->ReparseTag));
|
||||
return -EIO;
|
||||
}
|
||||
break;
|
||||
return 0;
|
||||
default:
|
||||
cifs_tcon_dbg(VFS | ONCE, "unhandled reparse tag: 0x%08x\n",
|
||||
le32_to_cpu(buf->ReparseTag));
|
||||
break;
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int smb2_parse_reparse_point(struct cifs_sb_info *cifs_sb,
|
||||
|
|
|
@ -99,14 +99,30 @@ static inline bool reparse_inode_match(struct inode *inode,
|
|||
|
||||
static inline bool cifs_open_data_reparse(struct cifs_open_info_data *data)
|
||||
{
|
||||
struct smb2_file_all_info *fi = &data->fi;
|
||||
u32 attrs = le32_to_cpu(fi->Attributes);
|
||||
u32 attrs;
|
||||
bool ret;
|
||||
|
||||
ret = data->reparse_point || (attrs & ATTR_REPARSE);
|
||||
if (ret)
|
||||
attrs |= ATTR_REPARSE;
|
||||
fi->Attributes = cpu_to_le32(attrs);
|
||||
if (data->contains_posix_file_info) {
|
||||
struct smb311_posix_qinfo *fi = &data->posix_fi;
|
||||
|
||||
attrs = le32_to_cpu(fi->DosAttributes);
|
||||
if (data->reparse_point) {
|
||||
attrs |= ATTR_REPARSE;
|
||||
fi->DosAttributes = cpu_to_le32(attrs);
|
||||
}
|
||||
|
||||
} else {
|
||||
struct smb2_file_all_info *fi = &data->fi;
|
||||
|
||||
attrs = le32_to_cpu(fi->Attributes);
|
||||
if (data->reparse_point) {
|
||||
attrs |= ATTR_REPARSE;
|
||||
fi->Attributes = cpu_to_le32(attrs);
|
||||
}
|
||||
}
|
||||
|
||||
ret = attrs & ATTR_REPARSE;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -650,6 +650,7 @@ finished:
|
|||
switch (cmds[i]) {
|
||||
case SMB2_OP_QUERY_INFO:
|
||||
idata = in_iov[i].iov_base;
|
||||
idata->contains_posix_file_info = false;
|
||||
if (rc == 0 && cfile && cfile->symlink_target) {
|
||||
idata->symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL);
|
||||
if (!idata->symlink_target)
|
||||
|
@ -673,6 +674,7 @@ finished:
|
|||
break;
|
||||
case SMB2_OP_POSIX_QUERY_INFO:
|
||||
idata = in_iov[i].iov_base;
|
||||
idata->contains_posix_file_info = true;
|
||||
if (rc == 0 && cfile && cfile->symlink_target) {
|
||||
idata->symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL);
|
||||
if (!idata->symlink_target)
|
||||
|
@ -770,6 +772,7 @@ finished:
|
|||
idata = in_iov[i].iov_base;
|
||||
idata->reparse.io.iov = *iov;
|
||||
idata->reparse.io.buftype = resp_buftype[i + 1];
|
||||
idata->contains_posix_file_info = false; /* BB VERIFY */
|
||||
rbuf = reparse_buf_ptr(iov);
|
||||
if (IS_ERR(rbuf)) {
|
||||
rc = PTR_ERR(rbuf);
|
||||
|
@ -791,6 +794,7 @@ finished:
|
|||
case SMB2_OP_QUERY_WSL_EA:
|
||||
if (!rc) {
|
||||
idata = in_iov[i].iov_base;
|
||||
idata->contains_posix_file_info = false;
|
||||
qi_rsp = rsp_iov[i + 1].iov_base;
|
||||
data[0] = (u8 *)qi_rsp + le16_to_cpu(qi_rsp->OutputBufferOffset);
|
||||
size[0] = le32_to_cpu(qi_rsp->OutputBufferLength);
|
||||
|
|
|
@ -1001,6 +1001,7 @@ static int smb2_query_file_info(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
if (!data->symlink_target)
|
||||
return -ENOMEM;
|
||||
}
|
||||
data->contains_posix_file_info = false;
|
||||
return SMB2_query_info(xid, tcon, fid->persistent_fid, fid->volatile_fid, &data->fi);
|
||||
}
|
||||
|
||||
|
@ -5146,7 +5147,7 @@ int __cifs_sfu_make_node(unsigned int xid, struct inode *inode,
|
|||
FILE_CREATE, CREATE_NOT_DIR |
|
||||
CREATE_OPTION_SPECIAL, ACL_NO_MODE);
|
||||
oparms.fid = &fid;
|
||||
|
||||
idata.contains_posix_file_info = false;
|
||||
rc = server->ops->open(xid, &oparms, &oplock, &idata);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
|
|
@ -1707,23 +1707,33 @@ struct smb2_file_internal_info {
|
|||
} __packed; /* level 6 Query */
|
||||
|
||||
struct smb2_file_rename_info { /* encoding of request for level 10 */
|
||||
__u8 ReplaceIfExists; /* 1 = replace existing target with new */
|
||||
/* 0 = fail if target already exists */
|
||||
__u8 Reserved[7];
|
||||
__u64 RootDirectory; /* MBZ for network operations (why says spec?) */
|
||||
__le32 FileNameLength;
|
||||
/* New members MUST be added within the struct_group() macro below. */
|
||||
__struct_group(smb2_file_rename_info_hdr, __hdr, __packed,
|
||||
__u8 ReplaceIfExists; /* 1 = replace existing target with new */
|
||||
/* 0 = fail if target already exists */
|
||||
__u8 Reserved[7];
|
||||
__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 */
|
||||
static_assert(offsetof(struct smb2_file_rename_info, FileName) == sizeof(struct smb2_file_rename_info_hdr),
|
||||
"struct member likely outside of __struct_group()");
|
||||
|
||||
struct smb2_file_link_info { /* encoding of request for level 11 */
|
||||
__u8 ReplaceIfExists; /* 1 = replace existing link with new */
|
||||
/* 0 = fail if link already exists */
|
||||
__u8 Reserved[7];
|
||||
__u64 RootDirectory; /* MBZ for network operations (why says spec?) */
|
||||
__le32 FileNameLength;
|
||||
/* New members MUST be added within the struct_group() macro below. */
|
||||
__struct_group(smb2_file_link_info_hdr, __hdr, __packed,
|
||||
__u8 ReplaceIfExists; /* 1 = replace existing link with new */
|
||||
/* 0 = fail if link already exists */
|
||||
__u8 Reserved[7];
|
||||
__u64 RootDirectory; /* MBZ for network operations (why says spec?) */
|
||||
__le32 FileNameLength;
|
||||
);
|
||||
char FileName[]; /* Name to be assigned to new link */
|
||||
} __packed; /* level 11 Set */
|
||||
static_assert(offsetof(struct smb2_file_link_info, FileName) == sizeof(struct smb2_file_link_info_hdr),
|
||||
"struct member likely outside of __struct_group()");
|
||||
|
||||
/*
|
||||
* This level 18, although with struct with same name is different from cifs
|
||||
|
|
|
@ -159,6 +159,9 @@
|
|||
#define IO_REPARSE_TAG_LX_CHR 0x80000025
|
||||
#define IO_REPARSE_TAG_LX_BLK 0x80000026
|
||||
|
||||
/* If Name Surrogate Bit is set, the file or directory represents another named entity in the system. */
|
||||
#define IS_REPARSE_TAG_NAME_SURROGATE(tag) (!!((tag) & 0x20000000))
|
||||
|
||||
/* fsctl flags */
|
||||
/* If Flags is set to this value, the request is an FSCTL not ioctl request */
|
||||
#define SMB2_0_IOCTL_IS_FSCTL 0x00000001
|
||||
|
|
Loading…
Add table
Reference in a new issue