]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
cifs: add a smb2_compound_op and change QUERY_INFO to use it
authorRonnie Sahlberg <lsahlber@redhat.com>
Mon, 3 Sep 2018 03:33:41 +0000 (13:33 +1000)
committerSteve French <stfrench@microsoft.com>
Wed, 24 Oct 2018 02:16:04 +0000 (21:16 -0500)
This turns most open/query-info/close patterns in cifs.ko
to become compounds.

This changes stat from using 3 roundtrips to just a single one.

Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/cifs/smb2inode.c
fs/cifs/smb2ops.c
fs/cifs/smb2pdu.c
fs/cifs/smb2proto.h

index 1eef1791d0c4099403d5cb6089e18336a1108b9e..9d3ada937715eb68314d3c8de005da2654b0433e 100644 (file)
 #include "smb2pdu.h"
 #include "smb2proto.h"
 
+static int
+smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
+                struct cifs_sb_info *cifs_sb, const char *full_path,
+                __u32 desired_access, __u32 create_disposition,
+                __u32 create_options, void *data, int command)
+{
+       int rc;
+       __le16 *utf16_path = NULL;
+       __u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
+       struct cifs_open_parms oparms;
+       struct cifs_fid fid;
+       struct cifs_ses *ses = tcon->ses;
+       struct TCP_Server_Info *server = ses->server;
+       int num_rqst = 0;
+       struct smb_rqst rqst[3];
+       int resp_buftype[3];
+       struct kvec rsp_iov[3];
+       struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
+       struct kvec qi_iov[1];
+       struct kvec close_iov[1];
+       struct smb2_query_info_rsp *rsp = NULL;
+       int flags = 0;
+
+       if (smb3_encryption_required(tcon))
+               flags |= CIFS_TRANSFORM_REQ;
+
+       memset(rqst, 0, sizeof(rqst));
+       resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
+       memset(rsp_iov, 0, sizeof(rsp_iov));
+
+       /* Open */
+       utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
+       if (!utf16_path)
+               return -ENOMEM;
+
+       oparms.tcon = tcon;
+       oparms.desired_access = desired_access;
+       oparms.disposition = create_disposition;
+       oparms.create_options = create_options;
+       oparms.fid = &fid;
+       oparms.reconnect = false;
+
+       memset(&open_iov, 0, sizeof(open_iov));
+       rqst[num_rqst].rq_iov = open_iov;
+       rqst[num_rqst].rq_nvec = SMB2_CREATE_IOV_SIZE;
+       rc = SMB2_open_init(tcon, &rqst[num_rqst], &oplock, &oparms,
+                           utf16_path);
+       kfree(utf16_path);
+       if (rc)
+               goto finished;
+
+       smb2_set_next_command(server, &rqst[num_rqst++]);
+
+       /* Operation */
+       switch (command) {
+       case SMB2_OP_QUERY_INFO:
+               memset(&qi_iov, 0, sizeof(qi_iov));
+               rqst[num_rqst].rq_iov = qi_iov;
+               rqst[num_rqst].rq_nvec = 1;
+
+               rc = SMB2_query_info_init(tcon, &rqst[num_rqst], COMPOUND_FID,
+                               COMPOUND_FID, FILE_ALL_INFORMATION,
+                               SMB2_O_INFO_FILE, 0,
+                               sizeof(struct smb2_file_all_info) +
+                                         PATH_MAX * 2);
+               smb2_set_next_command(server, &rqst[num_rqst]);
+               smb2_set_related(&rqst[num_rqst++]);
+               break;
+       default:
+               cifs_dbg(VFS, "Invalid command\n");
+               rc = -EINVAL;
+       }
+       if (rc)
+               goto finished;
+
+       /* Close */
+       memset(&close_iov, 0, sizeof(close_iov));
+       rqst[num_rqst].rq_iov = close_iov;
+       rqst[num_rqst].rq_nvec = 1;
+       rc = SMB2_close_init(tcon, &rqst[num_rqst], COMPOUND_FID,
+                            COMPOUND_FID);
+       smb2_set_related(&rqst[num_rqst++]);
+       if (rc)
+               goto finished;
+
+       rc = compound_send_recv(xid, ses, flags, num_rqst, rqst,
+                               resp_buftype, rsp_iov);
+
+ finished:
+       SMB2_open_free(&rqst[0]);
+       switch (command) {
+       case SMB2_OP_QUERY_INFO:
+               if (rc == 0) {
+                       rsp = (struct smb2_query_info_rsp *)rsp_iov[1].iov_base;
+                       rc = smb2_validate_and_copy_iov(
+                               le16_to_cpu(rsp->OutputBufferOffset),
+                               le32_to_cpu(rsp->OutputBufferLength),
+                               &rsp_iov[1], sizeof(struct smb2_file_all_info),
+                               data);
+               }
+               if (rqst[1].rq_iov)
+                       SMB2_query_info_free(&rqst[1]);
+               if (rqst[2].rq_iov)
+                       SMB2_close_free(&rqst[2]);
+               break;
+       }
+       free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
+       free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
+       free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base);
+       return rc;
+}
+
 static int
 smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon,
                   struct cifs_sb_info *cifs_sb, const char *full_path,
@@ -82,11 +194,6 @@ smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon,
        switch (command) {
        case SMB2_OP_DELETE:
                break;
-       case SMB2_OP_QUERY_INFO:
-               tmprc = SMB2_query_info(xid, tcon, fid.persistent_fid,
-                                       fid.volatile_fid,
-                                       (struct smb2_file_all_info *)data);
-               break;
        case SMB2_OP_MKDIR:
                /*
                 * Directories are created through parameters in the
@@ -156,16 +263,16 @@ smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
        if (smb2_data == NULL)
                return -ENOMEM;
 
-       rc = smb2_open_op_close(xid, tcon, cifs_sb, full_path,
-                               FILE_READ_ATTRIBUTES, FILE_OPEN, 0,
-                               smb2_data, SMB2_OP_QUERY_INFO);
+       rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
+                             FILE_READ_ATTRIBUTES, FILE_OPEN, 0,
+                             smb2_data, SMB2_OP_QUERY_INFO);
        if (rc == -EOPNOTSUPP) {
                *symlink = true;
                /* Failed on a symbolic link - query a reparse point info */
-               rc = smb2_open_op_close(xid, tcon, cifs_sb, full_path,
-                                       FILE_READ_ATTRIBUTES, FILE_OPEN,
-                                       OPEN_REPARSE_POINT, smb2_data,
-                                       SMB2_OP_QUERY_INFO);
+               rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
+                                     FILE_READ_ATTRIBUTES, FILE_OPEN,
+                                     OPEN_REPARSE_POINT, smb2_data,
+                                     SMB2_OP_QUERY_INFO);
        }
        if (rc)
                goto out;
index 831fa60ef8866a862c821adef35cda17fa7930e6..55ae6918be25e4aef986db24f878e430a448888b 100644 (file)
@@ -1562,7 +1562,7 @@ smb2_oplock_response(struct cifs_tcon *tcon, struct cifs_fid *fid,
                                 CIFS_CACHE_READ(cinode) ? 1 : 0);
 }
 
-static void
+void
 smb2_set_related(struct smb_rqst *rqst)
 {
        struct smb2_sync_hdr *shdr;
@@ -1573,7 +1573,7 @@ smb2_set_related(struct smb_rqst *rqst)
 
 char smb2_padding[7] = {0, 0, 0, 0, 0, 0, 0};
 
-static void
+void
 smb2_set_next_command(struct TCP_Server_Info *server, struct smb_rqst *rqst)
 {
        struct smb2_sync_hdr *shdr;
@@ -1616,7 +1616,7 @@ smb2_queryfs(const unsigned int xid, struct cifs_tcon *tcon,
                flags |= CIFS_TRANSFORM_REQ;
 
        memset(rqst, 0, sizeof(rqst));
-       memset(resp_buftype, 0, sizeof(resp_buftype));
+       resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
        memset(rsp_iov, 0, sizeof(rsp_iov));
 
        memset(&open_iov, 0, sizeof(open_iov));
index d7a41141ed387101a0ada017432bdc25b0f91a09..181ada4f2bd6c5f910965957558b5c2d0d491a98 100644 (file)
@@ -2627,10 +2627,10 @@ smb2_validate_iov(unsigned int offset, unsigned int buffer_length,
  * If SMB buffer fields are valid, copy into temporary buffer to hold result.
  * Caller must free buffer.
  */
-static int
-validate_and_copy_iov(unsigned int offset, unsigned int buffer_length,
-                     struct kvec *iov, unsigned int minbufsize,
-                     char *data)
+int
+smb2_validate_and_copy_iov(unsigned int offset, unsigned int buffer_length,
+                          struct kvec *iov, unsigned int minbufsize,
+                          char *data)
 {
        char *begin_of_buf = offset + (char *)iov->iov_base;
        int rc;
@@ -2746,9 +2746,9 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
                }
        }
 
-       rc = validate_and_copy_iov(le16_to_cpu(rsp->OutputBufferOffset),
-                                  le32_to_cpu(rsp->OutputBufferLength),
-                                  &rsp_iov, min_len, *data);
+       rc = smb2_validate_and_copy_iov(le16_to_cpu(rsp->OutputBufferOffset),
+                                       le32_to_cpu(rsp->OutputBufferLength),
+                                       &rsp_iov, min_len, *data);
 
 qinf_exit:
        SMB2_query_info_free(&rqst);
index b4076577eeb73b4cb98632a6e82e48ddacc0d2f6..d27e23e6f6e969f38d54db2693c277ffb82ae7eb 100644 (file)
@@ -116,6 +116,9 @@ extern void smb2_reconnect_server(struct work_struct *work);
 extern int smb3_crypto_aead_allocate(struct TCP_Server_Info *server);
 extern unsigned long smb_rqst_len(struct TCP_Server_Info *server,
                                  struct smb_rqst *rqst);
+extern void smb2_set_next_command(struct TCP_Server_Info *server,
+                                 struct smb_rqst *rqst);
+extern void smb2_set_related(struct smb_rqst *rqst);
 
 /*
  * SMB2 Worker functions - most of protocol specific implementation details
@@ -232,6 +235,10 @@ extern enum securityEnum smb2_select_sectype(struct TCP_Server_Info *,
 extern int smb3_encryption_required(const struct cifs_tcon *tcon);
 extern int smb2_validate_iov(unsigned int offset, unsigned int buffer_length,
                             struct kvec *iov, unsigned int min_buf_size);
+extern int smb2_validate_and_copy_iov(unsigned int offset,
+                                     unsigned int buffer_length,
+                                     struct kvec *iov,
+                                     unsigned int minbufsize, char *data);
 extern void smb2_copy_fs_info_to_kstatfs(
         struct smb2_fs_full_size_info *pfs_inf,
         struct kstatfs *kst);