Skip to content

Commit 9a49e22

Browse files
Paulo Alcantarasmfrench
authored andcommitted
smb: client: do not query reparse points twice on symlinks
Save a roundtrip by getting the reparse point tag and buffer at once in ->query_reparse_point() and then pass the buffer down to ->query_symlink(). Signed-off-by: Paulo Alcantara (SUSE) <[email protected]> Signed-off-by: Steve French <[email protected]>
1 parent 5f71ebc commit 9a49e22

File tree

4 files changed

+55
-161
lines changed

4 files changed

+55
-161
lines changed

fs/smb/client/cifsglob.h

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -336,10 +336,13 @@ struct smb_version_operations {
336336
/* query file data from the server */
337337
int (*query_file_info)(const unsigned int xid, struct cifs_tcon *tcon,
338338
struct cifsFileInfo *cfile, struct cifs_open_info_data *data);
339-
/* query reparse tag from srv to determine which type of special file */
340-
int (*query_reparse_tag)(const unsigned int xid, struct cifs_tcon *tcon,
341-
struct cifs_sb_info *cifs_sb, const char *path,
342-
__u32 *reparse_tag);
339+
/* query reparse point to determine which type of special file */
340+
int (*query_reparse_point)(const unsigned int xid,
341+
struct cifs_tcon *tcon,
342+
struct cifs_sb_info *cifs_sb,
343+
const char *full_path,
344+
u32 *tag, struct kvec *rsp,
345+
int *rsp_buftype);
343346
/* get server index number */
344347
int (*get_srv_inum)(const unsigned int xid, struct cifs_tcon *tcon,
345348
struct cifs_sb_info *cifs_sb, const char *full_path, u64 *uniqueid,
@@ -388,9 +391,12 @@ struct smb_version_operations {
388391
const char *, const char *,
389392
struct cifs_sb_info *);
390393
/* query symlink target */
391-
int (*query_symlink)(const unsigned int, struct cifs_tcon *,
392-
struct cifs_sb_info *, const char *,
393-
char **, bool);
394+
int (*query_symlink)(const unsigned int xid,
395+
struct cifs_tcon *tcon,
396+
struct cifs_sb_info *cifs_sb,
397+
const char *full_path,
398+
char **target_path,
399+
struct kvec *rsp_iov);
394400
/* open a file for non-posix mounts */
395401
int (*open)(const unsigned int xid, struct cifs_open_parms *oparms, __u32 *oplock,
396402
void *buf);

fs/smb/client/inode.c

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -428,7 +428,7 @@ int cifs_get_inode_info_unix(struct inode **pinode,
428428
if (!server->ops->query_symlink)
429429
return -EOPNOTSUPP;
430430
rc = server->ops->query_symlink(xid, tcon, cifs_sb, full_path,
431-
&fattr.cf_symlink_target, false);
431+
&fattr.cf_symlink_target, NULL);
432432
if (rc) {
433433
cifs_dbg(FYI, "%s: query_symlink: %d\n", __func__, rc);
434434
goto cgiiu_exit;
@@ -988,28 +988,33 @@ static int query_reparse(struct cifs_open_info_data *data,
988988
{
989989
struct TCP_Server_Info *server = tcon->ses->server;
990990
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
991-
bool reparse_point = data->reparse_point;
991+
struct kvec rsp_iov, *iov = NULL;
992+
int rsp_buftype = CIFS_NO_BUFFER;
992993
u32 tag = data->reparse_tag;
993994
int rc = 0;
994995

995-
if (!tag && server->ops->query_reparse_tag) {
996-
server->ops->query_reparse_tag(xid, tcon, cifs_sb,
997-
full_path, &tag);
996+
if (!tag && server->ops->query_reparse_point) {
997+
rc = server->ops->query_reparse_point(xid, tcon, cifs_sb,
998+
full_path, &tag,
999+
&rsp_iov, &rsp_buftype);
1000+
if (!rc)
1001+
iov = &rsp_iov;
9981002
}
9991003
switch ((data->reparse_tag = tag)) {
10001004
case 0: /* SMB1 symlink */
1001-
reparse_point = false;
1005+
iov = NULL;
10021006
fallthrough;
10031007
case IO_REPARSE_TAG_NFS:
10041008
case IO_REPARSE_TAG_SYMLINK:
10051009
if (!data->symlink_target && server->ops->query_symlink) {
10061010
rc = server->ops->query_symlink(xid, tcon,
10071011
cifs_sb, full_path,
10081012
&data->symlink_target,
1009-
reparse_point);
1013+
iov);
10101014
}
10111015
break;
10121016
}
1017+
free_rsp_buf(rsp_buftype, rsp_iov.iov_base);
10131018
return rc;
10141019
}
10151020

fs/smb/client/smb1ops.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -972,13 +972,16 @@ cifs_unix_dfs_readlink(const unsigned int xid, struct cifs_tcon *tcon,
972972
#endif
973973
}
974974

975-
static int
976-
cifs_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
977-
struct cifs_sb_info *cifs_sb, const char *full_path,
978-
char **target_path, bool is_reparse_point)
975+
static int cifs_query_symlink(const unsigned int xid,
976+
struct cifs_tcon *tcon,
977+
struct cifs_sb_info *cifs_sb,
978+
const char *full_path,
979+
char **target_path,
980+
struct kvec *rsp_iov)
979981
{
980982
int rc;
981983
int oplock = 0;
984+
bool is_reparse_point = !!rsp_iov;
982985
struct cifs_fid fid;
983986
struct cifs_open_parms oparms;
984987

fs/smb/client/smb2ops.c

Lines changed: 23 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -2948,153 +2948,30 @@ parse_reparse_point(struct reparse_data_buffer *buf,
29482948
}
29492949
}
29502950

2951-
static int
2952-
smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
2953-
struct cifs_sb_info *cifs_sb, const char *full_path,
2954-
char **target_path, bool is_reparse_point)
2951+
static int smb2_query_symlink(const unsigned int xid,
2952+
struct cifs_tcon *tcon,
2953+
struct cifs_sb_info *cifs_sb,
2954+
const char *full_path,
2955+
char **target_path,
2956+
struct kvec *rsp_iov)
29552957
{
2956-
int rc;
2957-
__le16 *utf16_path = NULL;
2958-
__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
2959-
struct cifs_open_parms oparms;
2960-
struct cifs_fid fid;
2961-
struct kvec err_iov = {NULL, 0};
2962-
struct TCP_Server_Info *server = cifs_pick_channel(tcon->ses);
2963-
int flags = CIFS_CP_CREATE_CLOSE_OP;
2964-
struct smb_rqst rqst[3];
2965-
int resp_buftype[3];
2966-
struct kvec rsp_iov[3];
2967-
struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
2968-
struct kvec io_iov[SMB2_IOCTL_IOV_SIZE];
2969-
struct kvec close_iov[1];
2970-
struct smb2_create_rsp *create_rsp;
2971-
struct smb2_ioctl_rsp *ioctl_rsp;
2972-
struct reparse_data_buffer *reparse_buf;
2973-
int create_options = is_reparse_point ? OPEN_REPARSE_POINT : 0;
2974-
u32 plen;
2958+
struct reparse_data_buffer *buf;
2959+
struct smb2_ioctl_rsp *io = rsp_iov->iov_base;
2960+
u32 plen = le32_to_cpu(io->OutputCount);
29752961

29762962
cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path);
29772963

2978-
*target_path = NULL;
2979-
2980-
if (smb3_encryption_required(tcon))
2981-
flags |= CIFS_TRANSFORM_REQ;
2982-
2983-
memset(rqst, 0, sizeof(rqst));
2984-
resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
2985-
memset(rsp_iov, 0, sizeof(rsp_iov));
2986-
2987-
utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
2988-
if (!utf16_path)
2989-
return -ENOMEM;
2990-
2991-
/* Open */
2992-
memset(&open_iov, 0, sizeof(open_iov));
2993-
rqst[0].rq_iov = open_iov;
2994-
rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE;
2995-
2996-
oparms = (struct cifs_open_parms) {
2997-
.tcon = tcon,
2998-
.path = full_path,
2999-
.desired_access = FILE_READ_ATTRIBUTES,
3000-
.disposition = FILE_OPEN,
3001-
.create_options = cifs_create_options(cifs_sb, create_options),
3002-
.fid = &fid,
3003-
};
3004-
3005-
rc = SMB2_open_init(tcon, server,
3006-
&rqst[0], &oplock, &oparms, utf16_path);
3007-
if (rc)
3008-
goto querty_exit;
3009-
smb2_set_next_command(tcon, &rqst[0]);
3010-
3011-
3012-
/* IOCTL */
3013-
memset(&io_iov, 0, sizeof(io_iov));
3014-
rqst[1].rq_iov = io_iov;
3015-
rqst[1].rq_nvec = SMB2_IOCTL_IOV_SIZE;
3016-
3017-
rc = SMB2_ioctl_init(tcon, server,
3018-
&rqst[1], fid.persistent_fid,
3019-
fid.volatile_fid, FSCTL_GET_REPARSE_POINT, NULL, 0,
3020-
CIFSMaxBufSize -
3021-
MAX_SMB2_CREATE_RESPONSE_SIZE -
3022-
MAX_SMB2_CLOSE_RESPONSE_SIZE);
3023-
if (rc)
3024-
goto querty_exit;
3025-
3026-
smb2_set_next_command(tcon, &rqst[1]);
3027-
smb2_set_related(&rqst[1]);
3028-
3029-
3030-
/* Close */
3031-
memset(&close_iov, 0, sizeof(close_iov));
3032-
rqst[2].rq_iov = close_iov;
3033-
rqst[2].rq_nvec = 1;
3034-
3035-
rc = SMB2_close_init(tcon, server,
3036-
&rqst[2], COMPOUND_FID, COMPOUND_FID, false);
3037-
if (rc)
3038-
goto querty_exit;
3039-
3040-
smb2_set_related(&rqst[2]);
3041-
3042-
rc = compound_send_recv(xid, tcon->ses, server,
3043-
flags, 3, rqst,
3044-
resp_buftype, rsp_iov);
3045-
3046-
create_rsp = rsp_iov[0].iov_base;
3047-
if (create_rsp && create_rsp->hdr.Status)
3048-
err_iov = rsp_iov[0];
3049-
ioctl_rsp = rsp_iov[1].iov_base;
3050-
3051-
/*
3052-
* Open was successful and we got an ioctl response.
3053-
*/
3054-
if ((rc == 0) && (is_reparse_point)) {
3055-
/* See MS-FSCC 2.3.23 */
3056-
3057-
reparse_buf = (struct reparse_data_buffer *)
3058-
((char *)ioctl_rsp +
3059-
le32_to_cpu(ioctl_rsp->OutputOffset));
3060-
plen = le32_to_cpu(ioctl_rsp->OutputCount);
3061-
3062-
if (plen + le32_to_cpu(ioctl_rsp->OutputOffset) >
3063-
rsp_iov[1].iov_len) {
3064-
cifs_tcon_dbg(VFS, "srv returned invalid ioctl len: %d\n",
3065-
plen);
3066-
rc = -EIO;
3067-
goto querty_exit;
3068-
}
3069-
3070-
rc = parse_reparse_point(reparse_buf, plen, target_path,
3071-
cifs_sb);
3072-
goto querty_exit;
3073-
}
3074-
3075-
if (!rc || !err_iov.iov_base) {
3076-
rc = -ENOENT;
3077-
goto querty_exit;
3078-
}
3079-
3080-
rc = smb2_parse_symlink_response(cifs_sb, &err_iov, target_path);
3081-
3082-
querty_exit:
3083-
cifs_dbg(FYI, "query symlink rc %d\n", rc);
3084-
kfree(utf16_path);
3085-
SMB2_open_free(&rqst[0]);
3086-
SMB2_ioctl_free(&rqst[1]);
3087-
SMB2_close_free(&rqst[2]);
3088-
free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
3089-
free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
3090-
free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base);
3091-
return rc;
2964+
buf = (struct reparse_data_buffer *)((u8 *)io +
2965+
le32_to_cpu(io->OutputOffset));
2966+
return parse_reparse_point(buf, plen, target_path, cifs_sb);
30922967
}
30932968

3094-
int
3095-
smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon,
3096-
struct cifs_sb_info *cifs_sb, const char *full_path,
3097-
__u32 *tag)
2969+
static int smb2_query_reparse_point(const unsigned int xid,
2970+
struct cifs_tcon *tcon,
2971+
struct cifs_sb_info *cifs_sb,
2972+
const char *full_path,
2973+
u32 *tag, struct kvec *rsp,
2974+
int *rsp_buftype)
30982975
{
30992976
int rc;
31002977
__le16 *utf16_path = NULL;
@@ -3205,6 +3082,9 @@ smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon,
32053082
goto query_rp_exit;
32063083
}
32073084
*tag = le32_to_cpu(reparse_buf->ReparseTag);
3085+
*rsp = rsp_iov[1];
3086+
*rsp_buftype = resp_buftype[1];
3087+
resp_buftype[1] = CIFS_NO_BUFFER;
32083088
}
32093089

32103090
query_rp_exit:
@@ -5503,7 +5383,7 @@ struct smb_version_operations smb30_operations = {
55035383
.echo = SMB2_echo,
55045384
.query_path_info = smb2_query_path_info,
55055385
/* WSL tags introduced long after smb2.1, enable for SMB3, 3.11 only */
5506-
.query_reparse_tag = smb2_query_reparse_tag,
5386+
.query_reparse_point = smb2_query_reparse_point,
55075387
.get_srv_inum = smb2_get_srv_inum,
55085388
.query_file_info = smb2_query_file_info,
55095389
.set_path_size = smb2_set_path_size,
@@ -5616,7 +5496,7 @@ struct smb_version_operations smb311_operations = {
56165496
.can_echo = smb2_can_echo,
56175497
.echo = SMB2_echo,
56185498
.query_path_info = smb2_query_path_info,
5619-
.query_reparse_tag = smb2_query_reparse_tag,
5499+
.query_reparse_point = smb2_query_reparse_point,
56205500
.get_srv_inum = smb2_get_srv_inum,
56215501
.query_file_info = smb2_query_file_info,
56225502
.set_path_size = smb2_set_path_size,

0 commit comments

Comments
 (0)