mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-07 13:43:51 +00:00
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>
This commit is contained in:
parent
102466f303
commit
67ec9949b0
@ -192,6 +192,11 @@ struct cifs_open_info_data {
|
||||
bool symlink;
|
||||
};
|
||||
struct {
|
||||
/* ioctl response buffer */
|
||||
struct {
|
||||
int buftype;
|
||||
struct kvec iov;
|
||||
} io;
|
||||
__u32 tag;
|
||||
union {
|
||||
struct reparse_data_buffer *buf;
|
||||
@ -209,11 +214,6 @@ struct cifs_open_info_data {
|
||||
((d)->reparse_point || \
|
||||
(le32_to_cpu((d)->fi.Attributes) & ATTR_REPARSE))
|
||||
|
||||
static inline void cifs_free_open_info(struct cifs_open_info_data *data)
|
||||
{
|
||||
kfree(data->symlink_target);
|
||||
}
|
||||
|
||||
/*
|
||||
*****************************************************************
|
||||
* Except the CIFS PDUs themselves all the
|
||||
|
@ -764,4 +764,11 @@ static inline void release_mid(struct mid_q_entry *mid)
|
||||
kref_put(&mid->refcount, __release_mid);
|
||||
}
|
||||
|
||||
static inline void cifs_free_open_info(struct cifs_open_info_data *data)
|
||||
{
|
||||
kfree(data->symlink_target);
|
||||
free_rsp_buf(data->reparse.io.buftype, data->reparse.io.iov.iov_base);
|
||||
memset(data, 0, sizeof(*data));
|
||||
}
|
||||
|
||||
#endif /* _CIFSPROTO_H */
|
||||
|
@ -1078,6 +1078,9 @@ static int reparse_info_to_fattr(struct cifs_open_info_data *data,
|
||||
&rsp_iov, &rsp_buftype);
|
||||
if (!rc)
|
||||
iov = &rsp_iov;
|
||||
} else if (data->reparse.io.buftype != CIFS_NO_BUFFER &&
|
||||
data->reparse.io.iov.iov_base) {
|
||||
iov = &data->reparse.io.iov;
|
||||
}
|
||||
|
||||
rc = -EOPNOTSUPP;
|
||||
@ -1097,7 +1100,7 @@ static int reparse_info_to_fattr(struct cifs_open_info_data *data,
|
||||
/* Check for cached reparse point data */
|
||||
if (data->symlink_target || data->reparse.buf) {
|
||||
rc = 0;
|
||||
} else if (server->ops->parse_reparse_point) {
|
||||
} else if (iov && server->ops->parse_reparse_point) {
|
||||
rc = server->ops->parse_reparse_point(cifs_sb,
|
||||
iov, data);
|
||||
}
|
||||
|
@ -35,7 +35,8 @@ enum smb2_compound_ops {
|
||||
SMB2_OP_SET_EOF,
|
||||
SMB2_OP_RMDIR,
|
||||
SMB2_OP_POSIX_QUERY_INFO,
|
||||
SMB2_OP_SET_REPARSE
|
||||
SMB2_OP_SET_REPARSE,
|
||||
SMB2_OP_GET_REPARSE
|
||||
};
|
||||
|
||||
/* Used when constructing chained read requests. */
|
||||
|
@ -26,6 +26,24 @@
|
||||
#include "cached_dir.h"
|
||||
#include "smb2status.h"
|
||||
|
||||
static struct reparse_data_buffer *reparse_buf_ptr(struct kvec *iov)
|
||||
{
|
||||
struct reparse_data_buffer *buf;
|
||||
struct smb2_ioctl_rsp *io = iov->iov_base;
|
||||
u32 off, count, len;
|
||||
|
||||
count = le32_to_cpu(io->OutputCount);
|
||||
off = le32_to_cpu(io->OutputOffset);
|
||||
if (check_add_overflow(off, count, &len) || len > iov->iov_len)
|
||||
return ERR_PTR(-EIO);
|
||||
|
||||
buf = (struct reparse_data_buffer *)((u8 *)io + off);
|
||||
len = sizeof(*buf);
|
||||
if (count < len || count < le16_to_cpu(buf->ReparseDataLength) + len)
|
||||
return ERR_PTR(-EIO);
|
||||
return buf;
|
||||
}
|
||||
|
||||
/*
|
||||
* note: If cfile is passed, the reference to it is dropped here.
|
||||
* 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,
|
||||
__u8 **extbuf, size_t *extbuflen,
|
||||
struct kvec *out_iov, int *out_buftype)
|
||||
{
|
||||
|
||||
struct reparse_data_buffer *rbuf;
|
||||
struct smb2_compound_vars *vars = NULL;
|
||||
struct kvec *rsp_iov;
|
||||
struct kvec *rsp_iov, *iov;
|
||||
struct smb_rqst *rqst;
|
||||
int rc;
|
||||
__le16 *utf16_path = NULL;
|
||||
@ -363,6 +383,21 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
trace_smb3_set_reparse_compound_enter(xid, ses->Suid,
|
||||
tcon->tid, full_path);
|
||||
break;
|
||||
case SMB2_OP_GET_REPARSE:
|
||||
rqst[num_rqst].rq_iov = vars->io_iov;
|
||||
rqst[num_rqst].rq_nvec = ARRAY_SIZE(vars->io_iov);
|
||||
|
||||
rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],
|
||||
COMPOUND_FID, COMPOUND_FID,
|
||||
FSCTL_GET_REPARSE_POINT,
|
||||
NULL, 0, CIFSMaxBufSize);
|
||||
if (rc)
|
||||
goto finished;
|
||||
smb2_set_next_command(tcon, &rqst[num_rqst]);
|
||||
smb2_set_related(&rqst[num_rqst++]);
|
||||
trace_smb3_get_reparse_compound_enter(xid, ses->Suid,
|
||||
tcon->tid, full_path);
|
||||
break;
|
||||
default:
|
||||
cifs_dbg(VFS, "Invalid command\n");
|
||||
rc = -EINVAL;
|
||||
@ -529,6 +564,30 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
}
|
||||
SMB2_ioctl_free(&rqst[num_rqst++]);
|
||||
break;
|
||||
case SMB2_OP_GET_REPARSE:
|
||||
if (!rc) {
|
||||
iov = &rsp_iov[i + 1];
|
||||
idata = in_iov[i].iov_base;
|
||||
idata->reparse.io.iov = *iov;
|
||||
idata->reparse.io.buftype = resp_buftype[i + 1];
|
||||
rbuf = reparse_buf_ptr(iov);
|
||||
if (IS_ERR(rbuf)) {
|
||||
rc = PTR_ERR(rbuf);
|
||||
trace_smb3_set_reparse_compound_err(xid, ses->Suid,
|
||||
tcon->tid, rc);
|
||||
} else {
|
||||
idata->reparse.tag = le32_to_cpu(rbuf->ReparseTag);
|
||||
trace_smb3_set_reparse_compound_done(xid, ses->Suid,
|
||||
tcon->tid);
|
||||
}
|
||||
memset(iov, 0, sizeof(*iov));
|
||||
resp_buftype[i + 1] = CIFS_NO_BUFFER;
|
||||
} else {
|
||||
trace_smb3_set_reparse_compound_err(xid, ses->Suid,
|
||||
tcon->tid, rc);
|
||||
}
|
||||
SMB2_ioctl_free(&rqst[num_rqst++]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
SMB2_close_free(&rqst[num_rqst]);
|
||||
@ -589,10 +648,11 @@ int smb2_query_path_info(const unsigned int xid,
|
||||
struct cifsFileInfo *cfile;
|
||||
struct cached_fid *cfid = NULL;
|
||||
struct smb2_hdr *hdr;
|
||||
struct kvec in_iov, out_iov[3] = {};
|
||||
struct kvec in_iov[2], out_iov[3] = {};
|
||||
int out_buftype[3] = {};
|
||||
int cmds[2] = { SMB2_OP_QUERY_INFO, };
|
||||
bool islink;
|
||||
int cmd = SMB2_OP_QUERY_INFO;
|
||||
int i, num_cmds;
|
||||
int rc, rc2;
|
||||
|
||||
data->adjust_tz = false;
|
||||
@ -614,14 +674,16 @@ int smb2_query_path_info(const unsigned int xid,
|
||||
return rc;
|
||||
}
|
||||
|
||||
in_iov.iov_base = data;
|
||||
in_iov.iov_len = sizeof(*data);
|
||||
in_iov[0].iov_base = data;
|
||||
in_iov[0].iov_len = sizeof(*data);
|
||||
in_iov[1] = in_iov[0];
|
||||
|
||||
cifs_get_readable_path(tcon, full_path, &cfile);
|
||||
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
|
||||
FILE_READ_ATTRIBUTES, FILE_OPEN,
|
||||
create_options, ACL_NO_MODE, &in_iov,
|
||||
&cmd, 1, cfile, NULL, NULL, out_iov, out_buftype);
|
||||
create_options, ACL_NO_MODE,
|
||||
in_iov, cmds, 1, cfile,
|
||||
NULL, NULL, out_iov, out_buftype);
|
||||
hdr = out_iov[0].iov_base;
|
||||
/*
|
||||
* 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,
|
||||
if (rc || !data->reparse_point)
|
||||
goto out;
|
||||
|
||||
if (data->reparse.tag == IO_REPARSE_TAG_SYMLINK) {
|
||||
/* symlink already parsed in create response */
|
||||
num_cmds = 1;
|
||||
} else {
|
||||
cmds[1] = SMB2_OP_GET_REPARSE;
|
||||
num_cmds = 2;
|
||||
}
|
||||
create_options |= OPEN_REPARSE_POINT;
|
||||
/* Failed on a symbolic link - query a reparse point info */
|
||||
cifs_get_readable_path(tcon, full_path, &cfile);
|
||||
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
|
||||
FILE_READ_ATTRIBUTES, FILE_OPEN,
|
||||
create_options, ACL_NO_MODE, &in_iov,
|
||||
&cmd, 1, cfile, NULL, NULL, NULL, NULL);
|
||||
create_options, ACL_NO_MODE, in_iov, cmds,
|
||||
num_cmds, cfile, NULL, NULL, NULL, NULL);
|
||||
break;
|
||||
case -EREMOTE:
|
||||
break;
|
||||
@ -661,9 +729,8 @@ int smb2_query_path_info(const unsigned int xid,
|
||||
}
|
||||
|
||||
out:
|
||||
free_rsp_buf(out_buftype[0], out_iov[0].iov_base);
|
||||
free_rsp_buf(out_buftype[1], out_iov[1].iov_base);
|
||||
free_rsp_buf(out_buftype[2], out_iov[2].iov_base);
|
||||
for (i = 0; i < ARRAY_SIZE(out_buftype); i++)
|
||||
free_rsp_buf(out_buftype[i], out_iov[i].iov_base);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -678,13 +745,14 @@ int smb311_posix_query_path_info(const unsigned int xid,
|
||||
int rc;
|
||||
__u32 create_options = 0;
|
||||
struct cifsFileInfo *cfile;
|
||||
struct kvec in_iov, out_iov[3] = {};
|
||||
struct kvec in_iov[2], out_iov[3] = {};
|
||||
int out_buftype[3] = {};
|
||||
__u8 *sidsbuf = NULL;
|
||||
__u8 *sidsbuf_end = NULL;
|
||||
size_t sidsbuflen = 0;
|
||||
size_t owner_len, group_len;
|
||||
int cmd = SMB2_OP_POSIX_QUERY_INFO;
|
||||
int cmds[2] = { SMB2_OP_POSIX_QUERY_INFO, };
|
||||
int i, num_cmds;
|
||||
|
||||
data->adjust_tz = false;
|
||||
data->reparse_point = false;
|
||||
@ -695,13 +763,14 @@ int smb311_posix_query_path_info(const unsigned int xid,
|
||||
* when we already have an open file handle for this. For now this is fast enough
|
||||
* (always using the compounded version).
|
||||
*/
|
||||
in_iov.iov_base = data;
|
||||
in_iov.iov_len = sizeof(*data);
|
||||
in_iov[0].iov_base = data;
|
||||
in_iov[0].iov_len = sizeof(*data);
|
||||
in_iov[1] = in_iov[0];
|
||||
|
||||
cifs_get_readable_path(tcon, full_path, &cfile);
|
||||
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
|
||||
FILE_READ_ATTRIBUTES, FILE_OPEN,
|
||||
create_options, ACL_NO_MODE, &in_iov, &cmd, 1,
|
||||
create_options, ACL_NO_MODE, in_iov, cmds, 1,
|
||||
cfile, &sidsbuf, &sidsbuflen, out_iov, out_buftype);
|
||||
/*
|
||||
* 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,
|
||||
if (rc || !data->reparse_point)
|
||||
goto out;
|
||||
|
||||
if (data->reparse.tag == IO_REPARSE_TAG_SYMLINK) {
|
||||
/* symlink already parsed in create response */
|
||||
num_cmds = 1;
|
||||
} else {
|
||||
cmds[1] = SMB2_OP_GET_REPARSE;
|
||||
num_cmds = 2;
|
||||
}
|
||||
create_options |= OPEN_REPARSE_POINT;
|
||||
/* Failed on a symbolic link - query a reparse point info */
|
||||
cifs_get_readable_path(tcon, full_path, &cfile);
|
||||
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
|
||||
FILE_READ_ATTRIBUTES, FILE_OPEN,
|
||||
create_options, ACL_NO_MODE, &in_iov, &cmd, 1,
|
||||
cfile, &sidsbuf, &sidsbuflen, NULL, NULL);
|
||||
create_options, ACL_NO_MODE, in_iov, cmds,
|
||||
num_cmds, cfile, &sidsbuf, &sidsbuflen, NULL, NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -749,9 +824,8 @@ int smb311_posix_query_path_info(const unsigned int xid,
|
||||
}
|
||||
|
||||
kfree(sidsbuf);
|
||||
free_rsp_buf(out_buftype[0], out_iov[0].iov_base);
|
||||
free_rsp_buf(out_buftype[1], out_iov[1].iov_base);
|
||||
free_rsp_buf(out_buftype[2], out_iov[2].iov_base);
|
||||
for (i = 0; i < ARRAY_SIZE(out_buftype); i++)
|
||||
free_rsp_buf(out_buftype[i], out_iov[i].iov_base);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -371,6 +371,7 @@ DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(rmdir_enter);
|
||||
DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(set_eof_enter);
|
||||
DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(set_info_compound_enter);
|
||||
DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(set_reparse_compound_enter);
|
||||
DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(get_reparse_compound_enter);
|
||||
DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(delete_enter);
|
||||
DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(mkdir_enter);
|
||||
DEFINE_SMB3_INF_COMPOUND_ENTER_EVENT(tdis_enter);
|
||||
@ -409,6 +410,7 @@ DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(rmdir_done);
|
||||
DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(set_eof_done);
|
||||
DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(set_info_compound_done);
|
||||
DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(set_reparse_compound_done);
|
||||
DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(get_reparse_compound_done);
|
||||
DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(delete_done);
|
||||
DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(mkdir_done);
|
||||
DEFINE_SMB3_INF_COMPOUND_DONE_EVENT(tdis_done);
|
||||
@ -453,6 +455,7 @@ DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(rmdir_err);
|
||||
DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(set_eof_err);
|
||||
DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(set_info_compound_err);
|
||||
DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(set_reparse_compound_err);
|
||||
DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(get_reparse_compound_err);
|
||||
DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(mkdir_err);
|
||||
DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(delete_err);
|
||||
DEFINE_SMB3_INF_COMPOUND_ERR_EVENT(tdis_err);
|
||||
|
Loading…
Reference in New Issue
Block a user