Skip to content

Commit e9a8cac

Browse files
committed
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
2 parents bf0e5ed + b587fd1 commit e9a8cac

File tree

8 files changed

+71
-24
lines changed

8 files changed

+71
-24
lines changed

fs/smb/client/cifsglob.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ struct cifs_cred {
253253
struct cifs_open_info_data {
254254
bool adjust_tz;
255255
bool reparse_point;
256+
bool contains_posix_file_info;
256257
struct {
257258
/* ioctl response buffer */
258259
struct {
@@ -2324,8 +2325,8 @@ struct smb2_compound_vars {
23242325
struct kvec io_iov[SMB2_IOCTL_IOV_SIZE];
23252326
struct kvec si_iov[SMB2_SET_INFO_IOV_SIZE];
23262327
struct kvec close_iov;
2327-
struct smb2_file_rename_info rename_info;
2328-
struct smb2_file_link_info link_info;
2328+
struct smb2_file_rename_info_hdr rename_info;
2329+
struct smb2_file_link_info_hdr link_info;
23292330
struct kvec ea_iov;
23302331
};
23312332

fs/smb/client/inode.c

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1215,6 +1215,19 @@ static int reparse_info_to_fattr(struct cifs_open_info_data *data,
12151215
rc = server->ops->parse_reparse_point(cifs_sb,
12161216
full_path,
12171217
iov, data);
1218+
/*
1219+
* If the reparse point was not handled but it is the
1220+
* name surrogate which points to directory, then treat
1221+
* is as a new mount point. Name surrogate reparse point
1222+
* represents another named entity in the system.
1223+
*/
1224+
if (rc == -EOPNOTSUPP &&
1225+
IS_REPARSE_TAG_NAME_SURROGATE(data->reparse.tag) &&
1226+
(le32_to_cpu(data->fi.Attributes) & ATTR_DIRECTORY)) {
1227+
rc = 0;
1228+
cifs_create_junction_fattr(fattr, sb);
1229+
goto out;
1230+
}
12181231
}
12191232

12201233
if (data->reparse.tag == IO_REPARSE_TAG_SYMLINK && !rc) {
@@ -1408,7 +1421,7 @@ int cifs_get_inode_info(struct inode **inode,
14081421
struct cifs_fattr fattr = {};
14091422
int rc;
14101423

1411-
if (is_inode_cache_good(*inode)) {
1424+
if (!data && is_inode_cache_good(*inode)) {
14121425
cifs_dbg(FYI, "No need to revalidate cached inode sizes\n");
14131426
return 0;
14141427
}
@@ -1507,7 +1520,7 @@ int smb311_posix_get_inode_info(struct inode **inode,
15071520
struct cifs_fattr fattr = {};
15081521
int rc;
15091522

1510-
if (is_inode_cache_good(*inode)) {
1523+
if (!data && is_inode_cache_good(*inode)) {
15111524
cifs_dbg(FYI, "No need to revalidate cached inode sizes\n");
15121525
return 0;
15131526
}

fs/smb/client/reparse.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1088,13 +1088,12 @@ int parse_reparse_point(struct reparse_data_buffer *buf,
10881088
le32_to_cpu(buf->ReparseTag));
10891089
return -EIO;
10901090
}
1091-
break;
1091+
return 0;
10921092
default:
10931093
cifs_tcon_dbg(VFS | ONCE, "unhandled reparse tag: 0x%08x\n",
10941094
le32_to_cpu(buf->ReparseTag));
1095-
break;
1095+
return -EOPNOTSUPP;
10961096
}
1097-
return 0;
10981097
}
10991098

11001099
int smb2_parse_reparse_point(struct cifs_sb_info *cifs_sb,

fs/smb/client/reparse.h

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -99,14 +99,30 @@ static inline bool reparse_inode_match(struct inode *inode,
9999

100100
static inline bool cifs_open_data_reparse(struct cifs_open_info_data *data)
101101
{
102-
struct smb2_file_all_info *fi = &data->fi;
103-
u32 attrs = le32_to_cpu(fi->Attributes);
102+
u32 attrs;
104103
bool ret;
105104

106-
ret = data->reparse_point || (attrs & ATTR_REPARSE);
107-
if (ret)
108-
attrs |= ATTR_REPARSE;
109-
fi->Attributes = cpu_to_le32(attrs);
105+
if (data->contains_posix_file_info) {
106+
struct smb311_posix_qinfo *fi = &data->posix_fi;
107+
108+
attrs = le32_to_cpu(fi->DosAttributes);
109+
if (data->reparse_point) {
110+
attrs |= ATTR_REPARSE;
111+
fi->DosAttributes = cpu_to_le32(attrs);
112+
}
113+
114+
} else {
115+
struct smb2_file_all_info *fi = &data->fi;
116+
117+
attrs = le32_to_cpu(fi->Attributes);
118+
if (data->reparse_point) {
119+
attrs |= ATTR_REPARSE;
120+
fi->Attributes = cpu_to_le32(attrs);
121+
}
122+
}
123+
124+
ret = attrs & ATTR_REPARSE;
125+
110126
return ret;
111127
}
112128

fs/smb/client/smb2inode.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -650,6 +650,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
650650
switch (cmds[i]) {
651651
case SMB2_OP_QUERY_INFO:
652652
idata = in_iov[i].iov_base;
653+
idata->contains_posix_file_info = false;
653654
if (rc == 0 && cfile && cfile->symlink_target) {
654655
idata->symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL);
655656
if (!idata->symlink_target)
@@ -673,6 +674,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
673674
break;
674675
case SMB2_OP_POSIX_QUERY_INFO:
675676
idata = in_iov[i].iov_base;
677+
idata->contains_posix_file_info = true;
676678
if (rc == 0 && cfile && cfile->symlink_target) {
677679
idata->symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL);
678680
if (!idata->symlink_target)
@@ -770,6 +772,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
770772
idata = in_iov[i].iov_base;
771773
idata->reparse.io.iov = *iov;
772774
idata->reparse.io.buftype = resp_buftype[i + 1];
775+
idata->contains_posix_file_info = false; /* BB VERIFY */
773776
rbuf = reparse_buf_ptr(iov);
774777
if (IS_ERR(rbuf)) {
775778
rc = PTR_ERR(rbuf);
@@ -791,6 +794,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
791794
case SMB2_OP_QUERY_WSL_EA:
792795
if (!rc) {
793796
idata = in_iov[i].iov_base;
797+
idata->contains_posix_file_info = false;
794798
qi_rsp = rsp_iov[i + 1].iov_base;
795799
data[0] = (u8 *)qi_rsp + le16_to_cpu(qi_rsp->OutputBufferOffset);
796800
size[0] = le32_to_cpu(qi_rsp->OutputBufferLength);

fs/smb/client/smb2ops.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1001,6 +1001,7 @@ static int smb2_query_file_info(const unsigned int xid, struct cifs_tcon *tcon,
10011001
if (!data->symlink_target)
10021002
return -ENOMEM;
10031003
}
1004+
data->contains_posix_file_info = false;
10041005
return SMB2_query_info(xid, tcon, fid->persistent_fid, fid->volatile_fid, &data->fi);
10051006
}
10061007

@@ -5146,7 +5147,7 @@ int __cifs_sfu_make_node(unsigned int xid, struct inode *inode,
51465147
FILE_CREATE, CREATE_NOT_DIR |
51475148
CREATE_OPTION_SPECIAL, ACL_NO_MODE);
51485149
oparms.fid = &fid;
5149-
5150+
idata.contains_posix_file_info = false;
51505151
rc = server->ops->open(xid, &oparms, &oplock, &idata);
51515152
if (rc)
51525153
goto out;

fs/smb/common/smb2pdu.h

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1707,23 +1707,33 @@ struct smb2_file_internal_info {
17071707
} __packed; /* level 6 Query */
17081708

17091709
struct smb2_file_rename_info { /* encoding of request for level 10 */
1710-
__u8 ReplaceIfExists; /* 1 = replace existing target with new */
1711-
/* 0 = fail if target already exists */
1712-
__u8 Reserved[7];
1713-
__u64 RootDirectory; /* MBZ for network operations (why says spec?) */
1714-
__le32 FileNameLength;
1710+
/* New members MUST be added within the struct_group() macro below. */
1711+
__struct_group(smb2_file_rename_info_hdr, __hdr, __packed,
1712+
__u8 ReplaceIfExists; /* 1 = replace existing target with new */
1713+
/* 0 = fail if target already exists */
1714+
__u8 Reserved[7];
1715+
__u64 RootDirectory; /* MBZ for network operations (why says spec?) */
1716+
__le32 FileNameLength;
1717+
);
17151718
char FileName[]; /* New name to be assigned */
17161719
/* padding - overall struct size must be >= 24 so filename + pad >= 6 */
17171720
} __packed; /* level 10 Set */
1721+
static_assert(offsetof(struct smb2_file_rename_info, FileName) == sizeof(struct smb2_file_rename_info_hdr),
1722+
"struct member likely outside of __struct_group()");
17181723

17191724
struct smb2_file_link_info { /* encoding of request for level 11 */
1720-
__u8 ReplaceIfExists; /* 1 = replace existing link with new */
1721-
/* 0 = fail if link already exists */
1722-
__u8 Reserved[7];
1723-
__u64 RootDirectory; /* MBZ for network operations (why says spec?) */
1724-
__le32 FileNameLength;
1725+
/* New members MUST be added within the struct_group() macro below. */
1726+
__struct_group(smb2_file_link_info_hdr, __hdr, __packed,
1727+
__u8 ReplaceIfExists; /* 1 = replace existing link with new */
1728+
/* 0 = fail if link already exists */
1729+
__u8 Reserved[7];
1730+
__u64 RootDirectory; /* MBZ for network operations (why says spec?) */
1731+
__le32 FileNameLength;
1732+
);
17251733
char FileName[]; /* Name to be assigned to new link */
17261734
} __packed; /* level 11 Set */
1735+
static_assert(offsetof(struct smb2_file_link_info, FileName) == sizeof(struct smb2_file_link_info_hdr),
1736+
"struct member likely outside of __struct_group()");
17271737

17281738
/*
17291739
* This level 18, although with struct with same name is different from cifs

fs/smb/common/smbfsctl.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,9 @@
159159
#define IO_REPARSE_TAG_LX_CHR 0x80000025
160160
#define IO_REPARSE_TAG_LX_BLK 0x80000026
161161

162+
/* If Name Surrogate Bit is set, the file or directory represents another named entity in the system. */
163+
#define IS_REPARSE_TAG_NAME_SURROGATE(tag) (!!((tag) & 0x20000000))
164+
162165
/* fsctl flags */
163166
/* If Flags is set to this value, the request is an FSCTL not ioctl request */
164167
#define SMB2_0_IOCTL_IS_FSCTL 0x00000001

0 commit comments

Comments
 (0)