Skip to content

Commit 67ec994

Browse files
Paulo Alcantarasmfrench
authored andcommitted
smb: client: optimise reparse point querying
Reduce number of roundtrips to server when querying reparse points in ->query_path_info() by sending a single compound request of create+get_reparse+get_info+close. Signed-off-by: Paulo Alcantara (SUSE) <pc@manguebit.com> Signed-off-by: Steve French <stfrench@microsoft.com>
1 parent 102466f commit 67ec994

6 files changed

Lines changed: 119 additions & 31 deletions

File tree

fs/smb/client/cifsglob.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,11 @@ struct cifs_open_info_data {
192192
bool symlink;
193193
};
194194
struct {
195+
/* ioctl response buffer */
196+
struct {
197+
int buftype;
198+
struct kvec iov;
199+
} io;
195200
__u32 tag;
196201
union {
197202
struct reparse_data_buffer *buf;
@@ -209,11 +214,6 @@ struct cifs_open_info_data {
209214
((d)->reparse_point || \
210215
(le32_to_cpu((d)->fi.Attributes) & ATTR_REPARSE))
211216

212-
static inline void cifs_free_open_info(struct cifs_open_info_data *data)
213-
{
214-
kfree(data->symlink_target);
215-
}
216-
217217
/*
218218
*****************************************************************
219219
* Except the CIFS PDUs themselves all the

fs/smb/client/cifsproto.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -764,4 +764,11 @@ static inline void release_mid(struct mid_q_entry *mid)
764764
kref_put(&mid->refcount, __release_mid);
765765
}
766766

767+
static inline void cifs_free_open_info(struct cifs_open_info_data *data)
768+
{
769+
kfree(data->symlink_target);
770+
free_rsp_buf(data->reparse.io.buftype, data->reparse.io.iov.iov_base);
771+
memset(data, 0, sizeof(*data));
772+
}
773+
767774
#endif /* _CIFSPROTO_H */

fs/smb/client/inode.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1078,6 +1078,9 @@ static int reparse_info_to_fattr(struct cifs_open_info_data *data,
10781078
&rsp_iov, &rsp_buftype);
10791079
if (!rc)
10801080
iov = &rsp_iov;
1081+
} else if (data->reparse.io.buftype != CIFS_NO_BUFFER &&
1082+
data->reparse.io.iov.iov_base) {
1083+
iov = &data->reparse.io.iov;
10811084
}
10821085

10831086
rc = -EOPNOTSUPP;
@@ -1097,7 +1100,7 @@ static int reparse_info_to_fattr(struct cifs_open_info_data *data,
10971100
/* Check for cached reparse point data */
10981101
if (data->symlink_target || data->reparse.buf) {
10991102
rc = 0;
1100-
} else if (server->ops->parse_reparse_point) {
1103+
} else if (iov && server->ops->parse_reparse_point) {
11011104
rc = server->ops->parse_reparse_point(cifs_sb,
11021105
iov, data);
11031106
}

fs/smb/client/smb2glob.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ enum smb2_compound_ops {
3535
SMB2_OP_SET_EOF,
3636
SMB2_OP_RMDIR,
3737
SMB2_OP_POSIX_QUERY_INFO,
38-
SMB2_OP_SET_REPARSE
38+
SMB2_OP_SET_REPARSE,
39+
SMB2_OP_GET_REPARSE
3940
};
4041

4142
/* Used when constructing chained read requests. */

fs/smb/client/smb2inode.c

Lines changed: 98 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,24 @@
2626
#include "cached_dir.h"
2727
#include "smb2status.h"
2828

29+
static struct reparse_data_buffer *reparse_buf_ptr(struct kvec *iov)
30+
{
31+
struct reparse_data_buffer *buf;
32+
struct smb2_ioctl_rsp *io = iov->iov_base;
33+
u32 off, count, len;
34+
35+
count = le32_to_cpu(io->OutputCount);
36+
off = le32_to_cpu(io->OutputOffset);
37+
if (check_add_overflow(off, count, &len) || len > iov->iov_len)
38+
return ERR_PTR(-EIO);
39+
40+
buf = (struct reparse_data_buffer *)((u8 *)io + off);
41+
len = sizeof(*buf);
42+
if (count < len || count < le16_to_cpu(buf->ReparseDataLength) + len)
43+
return ERR_PTR(-EIO);
44+
return buf;
45+
}
46+
2947
/*
3048
* note: If cfile is passed, the reference to it is dropped here.
3149
* So make sure that you do not reuse cfile after return from this func.
@@ -42,8 +60,10 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
4260
__u8 **extbuf, size_t *extbuflen,
4361
struct kvec *out_iov, int *out_buftype)
4462
{
63+
64+
struct reparse_data_buffer *rbuf;
4565
struct smb2_compound_vars *vars = NULL;
46-
struct kvec *rsp_iov;
66+
struct kvec *rsp_iov, *iov;
4767
struct smb_rqst *rqst;
4868
int rc;
4969
__le16 *utf16_path = NULL;
@@ -363,6 +383,21 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
363383
trace_smb3_set_reparse_compound_enter(xid, ses->Suid,
364384
tcon->tid, full_path);
365385
break;
386+
case SMB2_OP_GET_REPARSE:
387+
rqst[num_rqst].rq_iov = vars->io_iov;
388+
rqst[num_rqst].rq_nvec = ARRAY_SIZE(vars->io_iov);
389+
390+
rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],
391+
COMPOUND_FID, COMPOUND_FID,
392+
FSCTL_GET_REPARSE_POINT,
393+
NULL, 0, CIFSMaxBufSize);
394+
if (rc)
395+
goto finished;
396+
smb2_set_next_command(tcon, &rqst[num_rqst]);
397+
smb2_set_related(&rqst[num_rqst++]);
398+
trace_smb3_get_reparse_compound_enter(xid, ses->Suid,
399+
tcon->tid, full_path);
400+
break;
366401
default:
367402
cifs_dbg(VFS, "Invalid command\n");
368403
rc = -EINVAL;
@@ -529,6 +564,30 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
529564
}
530565
SMB2_ioctl_free(&rqst[num_rqst++]);
531566
break;
567+
case SMB2_OP_GET_REPARSE:
568+
if (!rc) {
569+
iov = &rsp_iov[i + 1];
570+
idata = in_iov[i].iov_base;
571+
idata->reparse.io.iov = *iov;
572+
idata->reparse.io.buftype = resp_buftype[i + 1];
573+
rbuf = reparse_buf_ptr(iov);
574+
if (IS_ERR(rbuf)) {
575+
rc = PTR_ERR(rbuf);
576+
trace_smb3_set_reparse_compound_err(xid, ses->Suid,
577+
tcon->tid, rc);
578+
} else {
579+
idata->reparse.tag = le32_to_cpu(rbuf->ReparseTag);
580+
trace_smb3_set_reparse_compound_done(xid, ses->Suid,
581+
tcon->tid);
582+
}
583+
memset(iov, 0, sizeof(*iov));
584+
resp_buftype[i + 1] = CIFS_NO_BUFFER;
585+
} else {
586+
trace_smb3_set_reparse_compound_err(xid, ses->Suid,
587+
tcon->tid, rc);
588+
}
589+
SMB2_ioctl_free(&rqst[num_rqst++]);
590+
break;
532591
}
533592
}
534593
SMB2_close_free(&rqst[num_rqst]);
@@ -589,10 +648,11 @@ int smb2_query_path_info(const unsigned int xid,
589648
struct cifsFileInfo *cfile;
590649
struct cached_fid *cfid = NULL;
591650
struct smb2_hdr *hdr;
592-
struct kvec in_iov, out_iov[3] = {};
651+
struct kvec in_iov[2], out_iov[3] = {};
593652
int out_buftype[3] = {};
653+
int cmds[2] = { SMB2_OP_QUERY_INFO, };
594654
bool islink;
595-
int cmd = SMB2_OP_QUERY_INFO;
655+
int i, num_cmds;
596656
int rc, rc2;
597657

598658
data->adjust_tz = false;
@@ -614,14 +674,16 @@ int smb2_query_path_info(const unsigned int xid,
614674
return rc;
615675
}
616676

617-
in_iov.iov_base = data;
618-
in_iov.iov_len = sizeof(*data);
677+
in_iov[0].iov_base = data;
678+
in_iov[0].iov_len = sizeof(*data);
679+
in_iov[1] = in_iov[0];
619680

620681
cifs_get_readable_path(tcon, full_path, &cfile);
621682
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
622683
FILE_READ_ATTRIBUTES, FILE_OPEN,
623-
create_options, ACL_NO_MODE, &in_iov,
624-
&cmd, 1, cfile, NULL, NULL, out_iov, out_buftype);
684+
create_options, ACL_NO_MODE,
685+
in_iov, cmds, 1, cfile,
686+
NULL, NULL, out_iov, out_buftype);
625687
hdr = out_iov[0].iov_base;
626688
/*
627689
* If first iov is unset, then SMB session was dropped or we've got a
@@ -637,13 +699,19 @@ int smb2_query_path_info(const unsigned int xid,
637699
if (rc || !data->reparse_point)
638700
goto out;
639701

702+
if (data->reparse.tag == IO_REPARSE_TAG_SYMLINK) {
703+
/* symlink already parsed in create response */
704+
num_cmds = 1;
705+
} else {
706+
cmds[1] = SMB2_OP_GET_REPARSE;
707+
num_cmds = 2;
708+
}
640709
create_options |= OPEN_REPARSE_POINT;
641-
/* Failed on a symbolic link - query a reparse point info */
642710
cifs_get_readable_path(tcon, full_path, &cfile);
643711
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
644712
FILE_READ_ATTRIBUTES, FILE_OPEN,
645-
create_options, ACL_NO_MODE, &in_iov,
646-
&cmd, 1, cfile, NULL, NULL, NULL, NULL);
713+
create_options, ACL_NO_MODE, in_iov, cmds,
714+
num_cmds, cfile, NULL, NULL, NULL, NULL);
647715
break;
648716
case -EREMOTE:
649717
break;
@@ -661,9 +729,8 @@ int smb2_query_path_info(const unsigned int xid,
661729
}
662730

663731
out:
664-
free_rsp_buf(out_buftype[0], out_iov[0].iov_base);
665-
free_rsp_buf(out_buftype[1], out_iov[1].iov_base);
666-
free_rsp_buf(out_buftype[2], out_iov[2].iov_base);
732+
for (i = 0; i < ARRAY_SIZE(out_buftype); i++)
733+
free_rsp_buf(out_buftype[i], out_iov[i].iov_base);
667734
return rc;
668735
}
669736

@@ -678,13 +745,14 @@ int smb311_posix_query_path_info(const unsigned int xid,
678745
int rc;
679746
__u32 create_options = 0;
680747
struct cifsFileInfo *cfile;
681-
struct kvec in_iov, out_iov[3] = {};
748+
struct kvec in_iov[2], out_iov[3] = {};
682749
int out_buftype[3] = {};
683750
__u8 *sidsbuf = NULL;
684751
__u8 *sidsbuf_end = NULL;
685752
size_t sidsbuflen = 0;
686753
size_t owner_len, group_len;
687-
int cmd = SMB2_OP_POSIX_QUERY_INFO;
754+
int cmds[2] = { SMB2_OP_POSIX_QUERY_INFO, };
755+
int i, num_cmds;
688756

689757
data->adjust_tz = false;
690758
data->reparse_point = false;
@@ -695,13 +763,14 @@ int smb311_posix_query_path_info(const unsigned int xid,
695763
* when we already have an open file handle for this. For now this is fast enough
696764
* (always using the compounded version).
697765
*/
698-
in_iov.iov_base = data;
699-
in_iov.iov_len = sizeof(*data);
766+
in_iov[0].iov_base = data;
767+
in_iov[0].iov_len = sizeof(*data);
768+
in_iov[1] = in_iov[0];
700769

701770
cifs_get_readable_path(tcon, full_path, &cfile);
702771
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
703772
FILE_READ_ATTRIBUTES, FILE_OPEN,
704-
create_options, ACL_NO_MODE, &in_iov, &cmd, 1,
773+
create_options, ACL_NO_MODE, in_iov, cmds, 1,
705774
cfile, &sidsbuf, &sidsbuflen, out_iov, out_buftype);
706775
/*
707776
* If first iov is unset, then SMB session was dropped or we've got a
@@ -718,13 +787,19 @@ int smb311_posix_query_path_info(const unsigned int xid,
718787
if (rc || !data->reparse_point)
719788
goto out;
720789

790+
if (data->reparse.tag == IO_REPARSE_TAG_SYMLINK) {
791+
/* symlink already parsed in create response */
792+
num_cmds = 1;
793+
} else {
794+
cmds[1] = SMB2_OP_GET_REPARSE;
795+
num_cmds = 2;
796+
}
721797
create_options |= OPEN_REPARSE_POINT;
722-
/* Failed on a symbolic link - query a reparse point info */
723798
cifs_get_readable_path(tcon, full_path, &cfile);
724799
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
725800
FILE_READ_ATTRIBUTES, FILE_OPEN,
726-
create_options, ACL_NO_MODE, &in_iov, &cmd, 1,
727-
cfile, &sidsbuf, &sidsbuflen, NULL, NULL);
801+
create_options, ACL_NO_MODE, in_iov, cmds,
802+
num_cmds, cfile, &sidsbuf, &sidsbuflen, NULL, NULL);
728803
break;
729804
}
730805

@@ -749,9 +824,8 @@ int smb311_posix_query_path_info(const unsigned int xid,
749824
}
750825

751826
kfree(sidsbuf);
752-
free_rsp_buf(out_buftype[0], out_iov[0].iov_base);
753-
free_rsp_buf(out_buftype[1], out_iov[1].iov_base);
754-
free_rsp_buf(out_buftype[2], out_iov[2].iov_base);
827+
for (i = 0; i < ARRAY_SIZE(out_buftype); i++)
828+
free_rsp_buf(out_buftype[i], out_iov[i].iov_base);
755829
return rc;
756830
}
757831

fs/smb/client/trace.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,7 @@ DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(rmdir_enter);
371371
DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(set_eof_enter);
372372
DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(set_info_compound_enter);
373373
DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(set_reparse_compound_enter);
374+
DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(get_reparse_compound_enter);
374375
DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(delete_enter);
375376
DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(mkdir_enter);
376377
DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(tdis_enter);
@@ -409,6 +410,7 @@ DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(rmdir_done);
409410
DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(set_eof_done);
410411
DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(set_info_compound_done);
411412
DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(set_reparse_compound_done);
413+
DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(get_reparse_compound_done);
412414
DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(delete_done);
413415
DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(mkdir_done);
414416
DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(tdis_done);
@@ -453,6 +455,7 @@ DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(rmdir_err);
453455
DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(set_eof_err);
454456
DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(set_info_compound_err);
455457
DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(set_reparse_compound_err);
458+
DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(get_reparse_compound_err);
456459
DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(mkdir_err);
457460
DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(delete_err);
458461
DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(tdis_err);

0 commit comments

Comments
 (0)