Skip to content

Commit

Permalink
Merge tag 'v6.14-rc3-smb3-client-fixes' of git://git.samba.org/sfrenc…
Browse files Browse the repository at this point in the history
…h/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
  • Loading branch information
torvalds committed Feb 20, 2025
2 parents bf0e5ed + b587fd1 commit e9a8cac
Show file tree
Hide file tree
Showing 8 changed files with 71 additions and 24 deletions.
5 changes: 3 additions & 2 deletions fs/smb/client/cifsglob.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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;
};

Expand Down
17 changes: 15 additions & 2 deletions fs/smb/client/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}
Expand Down
5 changes: 2 additions & 3 deletions fs/smb/client/reparse.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
28 changes: 22 additions & 6 deletions fs/smb/client/reparse.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
4 changes: 4 additions & 0 deletions fs/smb/client/smb2inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
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)
Expand All @@ -673,6 +674,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
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)
Expand Down Expand Up @@ -770,6 +772,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
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);
Expand All @@ -791,6 +794,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
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);
Expand Down
3 changes: 2 additions & 1 deletion fs/smb/client/smb2ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down Expand Up @@ -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;
Expand Down
30 changes: 20 additions & 10 deletions fs/smb/common/smb2pdu.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions fs/smb/common/smbfsctl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit e9a8cac

Please sign in to comment.