s3:smb2_server: make use of unlikely()
[metze/samba/wip.git] / source3 / smbd / smb2_server.c
index becbbed66472d7c07aac6115025d3bd61a26a079..21519c8f2832fe748f4b6adb446d156b6a6dc741 100644 (file)
@@ -149,7 +149,7 @@ static const struct smbd_smb2_dispatch_table {
 
 const char *smb2_opcode_name(uint16_t opcode)
 {
-       if (opcode >= ARRAY_SIZE(smbd_smb2_table)) {
+       if (unlikely(opcode >= ARRAY_SIZE(smbd_smb2_table))) {
                return "Bad SMB2 opcode";
        }
        return smbd_smb2_table[opcode].name;
@@ -159,7 +159,7 @@ static const struct smbd_smb2_dispatch_table *smbd_smb2_call(uint16_t opcode)
 {
        const struct smbd_smb2_dispatch_table *ret = NULL;
 
-       if (opcode >= ARRAY_SIZE(smbd_smb2_table)) {
+       if (unlikely(opcode >= ARRAY_SIZE(smbd_smb2_table))) {
                return NULL;
        }
 
@@ -188,11 +188,11 @@ static void print_req_vectors(const struct smbd_smb2_request *req)
 
 bool smbd_is_smb2_header(const uint8_t *inbuf, size_t size)
 {
-       if (size < (4 + SMB2_HDR_BODY)) {
+       if (unlikely(size < (4 + SMB2_HDR_BODY))) {
                return false;
        }
 
-       if (IVAL(inbuf, 4) != SMB2_MAGIC) {
+       if (unlikely(IVAL(inbuf, 4) != SMB2_MAGIC)) {
                return false;
        }
 
@@ -211,7 +211,7 @@ static NTSTATUS smbd_initialize_smb2(struct smbd_server_connection *sconn)
        sconn->smb2.max_credits = lp_smb2_max_credits();
        sconn->smb2.credits_bitmap = bitmap_talloc(sconn,
                                                   sconn->smb2.max_credits);
-       if (sconn->smb2.credits_bitmap == NULL) {
+       if (unlikely(sconn->smb2.credits_bitmap == NULL)) {
                return NT_STATUS_NO_MEMORY;
        }
 
@@ -221,7 +221,7 @@ static NTSTATUS smbd_initialize_smb2(struct smbd_server_connection *sconn)
                                        TEVENT_FD_READ,
                                        smbd_smb2_connection_handler,
                                        sconn);
-       if (sconn->smb2.fde == NULL) {
+       if (unlikely(sconn->smb2.fde == NULL)) {
                return NT_STATUS_NO_MEMORY;
        }
 
@@ -270,15 +270,15 @@ static struct smbd_smb2_request *smbd_smb2_request_allocate(TALLOC_CTX *mem_ctx)
 #if 0
        /* Enable this to find subtle valgrind errors. */
        mem_pool = talloc_init("smbd_smb2_request_allocate");
-#else
-       mem_pool = talloc_tos();
-#endif
        if (mem_pool == NULL) {
                return NULL;
        }
+#else
+       mem_pool = talloc_tos();
+#endif
 
        req = talloc_zero(mem_pool, struct smbd_smb2_request);
-       if (req == NULL) {
+       if (unlikely(req == NULL)) {
                talloc_free(mem_pool);
                return NULL;
        }
@@ -335,19 +335,19 @@ static NTSTATUS smbd_smb2_inbuf_parse_compound(struct smbXsrv_connection *conn,
                        tf_len = 0;
                }
 
-               if (len < 4) {
+               if (unlikely(len < 4)) {
                        DEBUG(10, ("%d bytes left, expected at least %d\n",
                                   (int)len, 4));
                        goto inval;
                }
-               if (IVAL(hdr, 0) == SMB2_TF_MAGIC) {
+               if (unlikely(IVAL(hdr, 0) == SMB2_TF_MAGIC)) {
                        struct smbXsrv_session *s = NULL;
                        uint64_t uid;
                        struct iovec tf_iov[2];
                        NTSTATUS status;
                        size_t enc_len;
 
-                       if (conn->protocol < PROTOCOL_SMB2_24) {
+                       if (unlikely(conn->protocol < PROTOCOL_SMB2_24)) {
                                DEBUG(10, ("Got SMB2_TRANSFORM header, "
                                           "but dialect[0x%04X] is used\n",
                                           conn->smb2.server.dialect));
@@ -363,7 +363,7 @@ static NTSTATUS smbd_smb2_inbuf_parse_compound(struct smbXsrv_connection *conn,
                                goto inval;
                        }
 
-                       if (len < SMB2_TF_HDR_SIZE) {
+                       if (unlikely(len < SMB2_TF_HDR_SIZE)) {
                                DEBUG(1, ("%d bytes left, expected at least %d\n",
                                           (int)len, SMB2_TF_HDR_SIZE));
                                goto inval;
@@ -376,7 +376,7 @@ static NTSTATUS smbd_smb2_inbuf_parse_compound(struct smbXsrv_connection *conn,
                        enc_len = IVAL(tf, SMB2_TF_MSG_SIZE);
                        uid = BVAL(tf, SMB2_TF_SESSION_ID);
 
-                       if (len < SMB2_TF_HDR_SIZE + enc_len) {
+                       if (unlikely(len < SMB2_TF_HDR_SIZE + enc_len)) {
                                DEBUG(1, ("%d bytes left, expected at least %d\n",
                                           (int)len,
                                           (int)(SMB2_TF_HDR_SIZE + enc_len)));
@@ -384,7 +384,7 @@ static NTSTATUS smbd_smb2_inbuf_parse_compound(struct smbXsrv_connection *conn,
                        }
 
                        status = smb2srv_session_lookup(conn, uid, now, &s);
-                       if (s == NULL) {
+                       if (unlikely(s == NULL)) {
                                DEBUG(1, ("invalid session[%llu] in "
                                          "SMB2_TRANSFORM header\n",
                                           (unsigned long long)uid));
@@ -400,7 +400,7 @@ static NTSTATUS smbd_smb2_inbuf_parse_compound(struct smbXsrv_connection *conn,
                        status = smb2_signing_decrypt_pdu(s->global->decryption_key,
                                                          conn->protocol,
                                                          tf_iov, 2);
-                       if (!NT_STATUS_IS_OK(status)) {
+                       if (unlikely(!NT_STATUS_IS_OK(status))) {
                                TALLOC_FREE(iov);
                                return status;
                        }
@@ -413,17 +413,17 @@ static NTSTATUS smbd_smb2_inbuf_parse_compound(struct smbXsrv_connection *conn,
                 * We need the header plus the body length field
                 */
 
-               if (len < SMB2_HDR_BODY + 2) {
+               if (unlikely(len < SMB2_HDR_BODY + 2)) {
                        DEBUG(10, ("%d bytes left, expected at least %d\n",
                                   (int)len, SMB2_HDR_BODY));
                        goto inval;
                }
-               if (IVAL(hdr, 0) != SMB2_MAGIC) {
+               if (unlikely(IVAL(hdr, 0) != SMB2_MAGIC)) {
                        DEBUG(10, ("Got non-SMB2 PDU: %x\n",
                                   IVAL(hdr, 0)));
                        goto inval;
                }
-               if (SVAL(hdr, 4) != SMB2_HDR_BODY) {
+               if (unlikely(SVAL(hdr, 4) != SMB2_HDR_BODY)) {
                        DEBUG(10, ("Got HDR len %d, expected %d\n",
                                   SVAL(hdr, 4), SMB2_HDR_BODY));
                        goto inval;
@@ -434,20 +434,20 @@ static NTSTATUS smbd_smb2_inbuf_parse_compound(struct smbXsrv_connection *conn,
                body_size = SVAL(hdr, SMB2_HDR_BODY);
 
                if (next_command_ofs != 0) {
-                       if (next_command_ofs < (SMB2_HDR_BODY + 2)) {
+                       if (unlikely(next_command_ofs < (SMB2_HDR_BODY + 2))) {
                                goto inval;
                        }
-                       if (next_command_ofs > full_size) {
+                       if (unlikely(next_command_ofs > full_size)) {
                                goto inval;
                        }
                        full_size = next_command_ofs;
                }
-               if (body_size < 2) {
+               if (unlikely(body_size < 2)) {
                        goto inval;
                }
                body_size &= 0xfffe;
 
-               if (body_size > (full_size - SMB2_HDR_BODY)) {
+               if (unlikely(body_size > (full_size - SMB2_HDR_BODY))) {
                        /*
                         * let the caller handle the error
                         */
@@ -469,7 +469,7 @@ static NTSTATUS smbd_smb2_inbuf_parse_compound(struct smbXsrv_connection *conn,
                                                 struct iovec,
                                                 num_iov +
                                                 SMBD_SMB2_NUM_IOV_PER_REQ);
-                       if (iov_tmp == NULL) {
+                       if (unlikely(iov_tmp == NULL)) {
                                TALLOC_FREE(iov_alloc);
                                return NT_STATUS_NO_MEMORY;
                        }
@@ -520,7 +520,7 @@ static NTSTATUS smbd_smb2_request_create(struct smbd_server_connection *sconn,
        NTSTATUS status;
        NTTIME now;
 
-       if (size < (4 + SMB2_HDR_BODY + 2)) {
+       if (unlikely(size < (4 + SMB2_HDR_BODY + 2))) {
                DEBUG(0,("Invalid SMB2 packet length count %ld\n", (long)size));
                return NT_STATUS_INVALID_PARAMETER;
        }
@@ -528,28 +528,28 @@ static NTSTATUS smbd_smb2_request_create(struct smbd_server_connection *sconn,
        inhdr = inbuf + 4;
 
        protocol_version = IVAL(inhdr, SMB2_HDR_PROTOCOL_ID);
-       if (protocol_version != SMB2_MAGIC) {
+       if (unlikely(protocol_version != SMB2_MAGIC)) {
                DEBUG(0,("Invalid SMB packet: protocol prefix: 0x%08X\n",
                         protocol_version));
                return NT_STATUS_INVALID_PARAMETER;
        }
 
        cmd = SVAL(inhdr, SMB2_HDR_OPCODE);
-       if (cmd != SMB2_OP_NEGPROT) {
+       if (unlikely(cmd != SMB2_OP_NEGPROT)) {
                DEBUG(0,("Invalid SMB packet: first request: 0x%04X\n",
                         cmd));
                return NT_STATUS_INVALID_PARAMETER;
        }
 
        next_command_ofs = IVAL(inhdr, SMB2_HDR_NEXT_COMMAND);
-       if (next_command_ofs != 0) {
+       if (unlikely(next_command_ofs != 0)) {
                DEBUG(0,("Invalid SMB packet: next_command: 0x%08X\n",
                         next_command_ofs));
                return NT_STATUS_INVALID_PARAMETER;
        }
 
        req = smbd_smb2_request_allocate(sconn);
-       if (req == NULL) {
+       if (unlikely(req == NULL)) {
                return NT_STATUS_NO_MEMORY;
        }
        req->sconn = sconn;
@@ -565,7 +565,7 @@ static NTSTATUS smbd_smb2_request_create(struct smbd_server_connection *sconn,
                                                size - NBT_HDR_SIZE,
                                                req, &req->in.vector,
                                                &req->in.vector_count);
-       if (!NT_STATUS_IS_OK(status)) {
+       if (unlikely(!NT_STATUS_IS_OK(status))) {
                TALLOC_FREE(req);
                return status;
        }
@@ -582,7 +582,7 @@ static bool smb2_validate_sequence_number(struct smbd_server_connection *sconn,
        struct bitmap *credits_bm = sconn->smb2.credits_bitmap;
        unsigned int offset;
 
-       if (seq_id < sconn->smb2.seqnum_low) {
+       if (unlikely(seq_id < sconn->smb2.seqnum_low)) {
                DEBUG(0,("smb2_validate_sequence_number: bad message_id "
                        "%llu (sequence id %llu) "
                        "(granted = %u, low = %llu, range = %u)\n",
@@ -594,7 +594,7 @@ static bool smb2_validate_sequence_number(struct smbd_server_connection *sconn,
                return false;
        }
 
-       if (seq_id >= sconn->smb2.seqnum_low + sconn->smb2.seqnum_range) {
+       if (unlikely(seq_id >= sconn->smb2.seqnum_low + sconn->smb2.seqnum_range)) {
                DEBUG(0,("smb2_validate_sequence_number: bad message_id "
                        "%llu (sequence id %llu) "
                        "(granted = %u, low = %llu, range = %u)\n",
@@ -608,7 +608,7 @@ static bool smb2_validate_sequence_number(struct smbd_server_connection *sconn,
 
        offset = seq_id % sconn->smb2.max_credits;
 
-       if (bitmap_query(credits_bm, offset)) {
+       if (unlikely(bitmap_query(credits_bm, offset))) {
                DEBUG(0,("smb2_validate_sequence_number: duplicate message_id "
                        "%llu (sequence id %llu) "
                        "(granted = %u, low = %llu, range = %u) "
@@ -656,7 +656,7 @@ static bool smb2_validate_message_id(struct smbd_server_connection *sconn,
        uint16_t credit_charge = 1;
        uint64_t i;
 
-       if (opcode == SMB2_OP_CANCEL) {
+       if (unlikely(opcode == SMB2_OP_CANCEL)) {
                /* SMB2_CANCEL requests by definition resend messageids. */
                return true;
        }
@@ -675,7 +675,7 @@ static bool smb2_validate_message_id(struct smbd_server_connection *sconn,
                   (unsigned long long) sconn->smb2.seqnum_low,
                   (unsigned long long) sconn->smb2.seqnum_range));
 
-       if (sconn->smb2.credits_granted < credit_charge) {
+       if (unlikely(sconn->smb2.credits_granted < credit_charge)) {
                DEBUG(0, ("smb2_validate_message_id: client used more "
                          "credits than granted, mid %llu, charge %llu, "
                          "credits_granted %llu, "
@@ -706,7 +706,7 @@ static bool smb2_validate_message_id(struct smbd_server_connection *sconn,
                           (unsigned long long)id));
 
                ok = smb2_validate_sequence_number(sconn, message_id, id);
-               if (!ok) {
+               if (unlikely(!ok)) {
                        return false;
                }
        }
@@ -724,7 +724,7 @@ static NTSTATUS smbd_smb2_request_validate(struct smbd_smb2_request *req)
 
        count = req->in.vector_count;
 
-       if (count < 1 + SMBD_SMB2_NUM_IOV_PER_REQ) {
+       if (unlikely(count < 1 + SMBD_SMB2_NUM_IOV_PER_REQ)) {
                /* It's not a SMB2 request */
                return NT_STATUS_INVALID_PARAMETER;
        }
@@ -733,23 +733,25 @@ static NTSTATUS smbd_smb2_request_validate(struct smbd_smb2_request *req)
                struct iovec *hdr = SMBD_SMB2_IDX_HDR_IOV(req,in,idx);
                struct iovec *body = SMBD_SMB2_IDX_BODY_IOV(req,in,idx);
                const uint8_t *inhdr = NULL;
+               bool ok;
 
-               if (hdr->iov_len != SMB2_HDR_BODY) {
+               if (unlikely(hdr->iov_len != SMB2_HDR_BODY)) {
                        return NT_STATUS_INVALID_PARAMETER;
                }
 
-               if (body->iov_len < 2) {
+               if (unlikely(body->iov_len < 2)) {
                        return NT_STATUS_INVALID_PARAMETER;
                }
 
                inhdr = (const uint8_t *)hdr->iov_base;
 
                /* Check the SMB2 header */
-               if (IVAL(inhdr, SMB2_HDR_PROTOCOL_ID) != SMB2_MAGIC) {
+               if (unlikely(IVAL(inhdr, SMB2_HDR_PROTOCOL_ID) != SMB2_MAGIC)) {
                        return NT_STATUS_INVALID_PARAMETER;
                }
 
-               if (!smb2_validate_message_id(req->sconn, inhdr)) {
+               ok = smb2_validate_message_id(req->sconn, inhdr);
+               if (unlikely(!ok)) {
                        return NT_STATUS_INVALID_PARAMETER;
                }
        }
@@ -801,7 +803,7 @@ static void smb2_set_operation_credit(struct smbd_server_connection *sconn,
 
        SMB_ASSERT(sconn->smb2.max_credits >= sconn->smb2.credits_granted);
 
-       if (sconn->smb2.max_credits < credit_charge) {
+       if (unlikely(sconn->smb2.max_credits < credit_charge)) {
                smbd_server_connection_terminate(sconn,
                        "client error: credit charge > max credits\n");
                return;
@@ -926,21 +928,29 @@ DATA_BLOB smbd_smb2_generate_outbody(struct smbd_smb2_request *req, size_t size)
                if (size <= sizeof(req->out._body)) {
                        return data_blob_const(req->out._body, size);
                }
+               smb_panic(__location__);
        }
 
-       return data_blob_talloc(req->out.vector, NULL, size);
+       return data_blob_talloc(req, NULL, size);
 }
 
 static NTSTATUS smbd_smb2_request_setup_out(struct smbd_smb2_request *req)
 {
+       TALLOC_CTX *mem_ctx;
        struct iovec *vector;
        int count;
        int idx;
 
        count = req->in.vector_count;
-       vector = talloc_zero_array(req, struct iovec, count);
-       if (vector == NULL) {
-               return NT_STATUS_NO_MEMORY;
+       if (count <= ARRAY_SIZE(req->out._vector)) {
+               mem_ctx = req;
+               vector = req->out._vector;
+       } else {
+               vector = talloc_zero_array(req, struct iovec, count);
+               if (unlikely(vector == NULL)) {
+                       return NT_STATUS_NO_MEMORY;
+               }
+               mem_ctx = vector;
        }
 
        vector[0].iov_base      = req->out.nbt_hdr;
@@ -964,7 +974,7 @@ static NTSTATUS smbd_smb2_request_setup_out(struct smbd_smb2_request *req)
                if (idx == 1) {
                        outhdr = req->out._hdr;
                } else {
-                       outhdr = talloc_zero_array(vector, uint8_t,
+                       outhdr = talloc_zero_array(mem_ctx, uint8_t,
                                                   OUTVEC_ALLOC_SIZE);
                        if (outhdr == NULL) {
                                return NT_STATUS_NO_MEMORY;
@@ -1222,7 +1232,7 @@ static NTSTATUS smb2_send_async_interim_response(const struct smbd_smb2_request
        /* Calculate outgoing credits */
        smb2_calculate_credits(req, nreq);
 
-       if (DEBUGLEVEL >= 10) {
+       if (unlikely(DEBUGLEVEL >= 10)) {
                dbgtext("smb2_send_async_interim_response: nreq->current_idx = %u\n",
                        (unsigned int)nreq->current_idx );
                dbgtext("smb2_send_async_interim_response: returning %u vectors\n",
@@ -1259,7 +1269,7 @@ static NTSTATUS smb2_send_async_interim_response(const struct smbd_smb2_request
        nreq->sconn->smb2.send_queue_len++;
 
        status = smbd_smb2_io_handler(sconn, TEVENT_FD_WRITE);
-       if (!NT_STATUS_IS_OK(status)) {
+       if (unlikely(!NT_STATUS_IS_OK(status))) {
                return status;
        }
 
@@ -1338,7 +1348,7 @@ NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req,
                }
        }
 
-       if (DEBUGLEVEL >= 10) {
+       if (unlikely(DEBUGLEVEL >= 10)) {
                dbgtext("smbd_smb2_request_pending_queue: req->current_idx = %u\n",
                        (unsigned int)req->current_idx );
                print_req_vectors(req);
@@ -1400,7 +1410,7 @@ NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req,
                                         req, defer_endtime,
                                         smbd_smb2_request_pending_timer,
                                         req);
-       if (req->async_te == NULL) {
+       if (unlikely(req->async_te == NULL)) {
                return NT_STATUS_NO_MEMORY;
        }
 
@@ -1458,7 +1468,7 @@ static void smbd_smb2_request_pending_timer(struct tevent_context *ev,
         */
 
        state = talloc_zero(req->sconn, struct smbd_smb2_request_pending_state);
-       if (state == NULL) {
+       if (unlikely(state == NULL)) {
                smbd_server_connection_terminate(req->sconn,
                                                 nt_errstr(NT_STATUS_NO_MEMORY));
                return;
@@ -1592,7 +1602,7 @@ static void smbd_smb2_request_pending_timer(struct tevent_context *ev,
        sconn->smb2.send_queue_len++;
 
        status = smbd_smb2_io_handler(sconn, TEVENT_FD_WRITE);
-       if (!NT_STATUS_IS_OK(status)) {
+       if (unlikely(!NT_STATUS_IS_OK(status))) {
                smbd_server_connection_terminate(sconn,
                                                 nt_errstr(status));
                return;
@@ -1817,7 +1827,7 @@ NTSTATUS smbd_smb2_request_verify_creditcharge(struct smbd_smb2_request *req,
                   (unsigned long long) BVAL(inhdr, SMB2_HDR_MESSAGE_ID),
                   credit_charge, needed_charge));
 
-       if (needed_charge > credit_charge) {
+       if (unlikely(needed_charge > credit_charge)) {
                DEBUG(2, ("CreditCharge too low, given %d, needed %d\n",
                          credit_charge, needed_charge));
                return NT_STATUS_INVALID_PARAMETER;
@@ -1840,18 +1850,18 @@ NTSTATUS smbd_smb2_request_verify_sizes(struct smbd_smb2_request *req,
        /*
         * The following should be checked already.
         */
-       if (req->in.vector_count < SMBD_SMB2_NUM_IOV_PER_REQ) {
+       if (unlikely(req->in.vector_count < SMBD_SMB2_NUM_IOV_PER_REQ)) {
                return NT_STATUS_INTERNAL_ERROR;
        }
-       if (req->current_idx > max_idx) {
+       if (unlikely(req->current_idx > max_idx)) {
                return NT_STATUS_INTERNAL_ERROR;
        }
 
        inhdr_v = SMBD_SMB2_IN_HDR_IOV(req);
-       if (inhdr_v->iov_len != SMB2_HDR_BODY) {
+       if (unlikely(inhdr_v->iov_len != SMB2_HDR_BODY)) {
                return NT_STATUS_INTERNAL_ERROR;
        }
-       if (SMBD_SMB2_IN_BODY_LEN(req) < 2) {
+       if (unlikely(SMBD_SMB2_IN_BODY_LEN(req) < 2)) {
                return NT_STATUS_INTERNAL_ERROR;
        }
 
@@ -1863,6 +1873,15 @@ NTSTATUS smbd_smb2_request_verify_sizes(struct smbd_smb2_request *req,
        case SMB2_OP_GETINFO:
                min_dyn_size = 0;
                break;
+       case SMB2_OP_WRITE:
+               if (req->smb1req != NULL && req->smb1req->unread_bytes > 0) {
+                       if (unlikely(req->smb1req->unread_bytes < min_dyn_size)) {
+                               return NT_STATUS_INVALID_PARAMETER;
+                       }
+
+                       min_dyn_size = 0;
+               }
+               break;
        }
 
        /*
@@ -1870,17 +1889,17 @@ NTSTATUS smbd_smb2_request_verify_sizes(struct smbd_smb2_request *req,
         * where the last byte might be in the
         * dynamic section..
         */
-       if (SMBD_SMB2_IN_BODY_LEN(req) != (expected_body_size & 0xFFFFFFFE)) {
+       if (unlikely(SMBD_SMB2_IN_BODY_LEN(req) != (expected_body_size & 0xFFFFFFFE))) {
                return NT_STATUS_INVALID_PARAMETER;
        }
-       if (SMBD_SMB2_IN_DYN_LEN(req) < min_dyn_size) {
+       if (unlikely(SMBD_SMB2_IN_DYN_LEN(req) < min_dyn_size)) {
                return NT_STATUS_INVALID_PARAMETER;
        }
 
        inbody = SMBD_SMB2_IN_BODY_PTR(req);
 
        body_size = SVAL(inbody, 0x00);
-       if (body_size != expected_body_size) {
+       if (unlikely(body_size != expected_body_size)) {
                return NT_STATUS_INVALID_PARAMETER;
        }
 
@@ -1920,7 +1939,7 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
                 * once the protocol is negotiated
                 * SMB2_OP_NEGPROT is not allowed anymore
                 */
-               if (opcode == SMB2_OP_NEGPROT) {
+               if (unlikely(opcode == SMB2_OP_NEGPROT)) {
                        /* drop the connection */
                        return NT_STATUS_INVALID_PARAMETER;
                }
@@ -1987,17 +2006,17 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
        }
 
        call = smbd_smb2_call(opcode);
-       if (call == NULL) {
+       if (unlikely(call == NULL)) {
                return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
        }
 
        allowed_flags = SMB2_HDR_FLAG_CHAINED |
                        SMB2_HDR_FLAG_SIGNED |
                        SMB2_HDR_FLAG_DFS;
-       if (opcode == SMB2_OP_CANCEL) {
+       if (unlikely(opcode == SMB2_OP_CANCEL)) {
                allowed_flags |= SMB2_HDR_FLAG_ASYNC;
        }
-       if ((flags & ~allowed_flags) != 0) {
+       if (unlikely((flags & ~allowed_flags) != 0)) {
                return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
        }
 
@@ -2050,7 +2069,7 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
                if (!NT_STATUS_IS_OK(session_status)) {
                        return smbd_smb2_request_error(req, session_status);
                }
-       } else if (opcode == SMB2_OP_CANCEL) {
+       } else if (unlikely(opcode == SMB2_OP_CANCEL)) {
                /* Cancel requests are allowed to skip the signing */
        } else if (signing_required) {
                /*
@@ -2081,7 +2100,7 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
                 * calls change_to_user() on success.
                 */
                status = smbd_smb2_request_check_tcon(req);
-               if (!NT_STATUS_IS_OK(status)) {
+               if (unlikely(!NT_STATUS_IS_OK(status))) {
                        return smbd_smb2_request_error(req, status);
                }
                if (req->tcon->global->encryption_required) {
@@ -2103,7 +2122,7 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
 
                SMB_ASSERT(call->need_tcon);
 
-               if (needed > body_size) {
+               if (unlikely(needed > body_size)) {
                        return smbd_smb2_request_error(req,
                                        NT_STATUS_INVALID_PARAMETER);
                }
@@ -2112,7 +2131,7 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
                file_id_volatile        = BVAL(body, call->fileid_ofs + 8);
 
                fsp = file_fsp_smb2(req, file_id_persistent, file_id_volatile);
-               if (fsp == NULL) {
+               if (unlikely(fsp == NULL)) {
                        if (!call->allow_invalid_fileid) {
                                return smbd_smb2_request_error(req,
                                                NT_STATUS_FILE_CLOSED);
@@ -2348,7 +2367,7 @@ static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req)
                        return NT_STATUS_NO_MEMORY;
                }
 
-               tf = talloc_zero_array(req->out.vector, uint8_t,
+               tf = talloc_zero_array(req, uint8_t,
                                       SMB2_TF_HDR_SIZE);
                if (tf == NULL) {
                        return NT_STATUS_NO_MEMORY;
@@ -2399,7 +2418,7 @@ static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req)
                 * yet.
                 */
                struct tevent_immediate *im = tevent_create_immediate(req);
-               if (!im) {
+               if (unlikely(!im)) {
                        return NT_STATUS_NO_MEMORY;
                }
 
@@ -2484,7 +2503,7 @@ static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req)
        req->sconn->smb2.send_queue_len++;
 
        status = smbd_smb2_io_handler(sconn, TEVENT_FD_WRITE);
-       if (!NT_STATUS_IS_OK(status)) {
+       if (unlikely(!NT_STATUS_IS_OK(status))) {
                return status;
        }
 
@@ -2504,20 +2523,20 @@ void smbd_smb2_request_dispatch_immediate(struct tevent_context *ctx,
 
        TALLOC_FREE(im);
 
-       if (DEBUGLEVEL >= 10) {
+       if (unlikely(DEBUGLEVEL >= 10)) {
                DEBUG(10,("smbd_smb2_request_dispatch_immediate: idx[%d] of %d vectors\n",
                        req->current_idx, req->in.vector_count));
                print_req_vectors(req);
        }
 
        status = smbd_smb2_request_dispatch(req);
-       if (!NT_STATUS_IS_OK(status)) {
+       if (unlikely(!NT_STATUS_IS_OK(status))) {
                smbd_server_connection_terminate(sconn, nt_errstr(status));
                return;
        }
 
        status = smbd_smb2_request_next_incoming(sconn);
-       if (!NT_STATUS_IS_OK(status)) {
+       if (unlikely(!NT_STATUS_IS_OK(status))) {
                smbd_server_connection_terminate(sconn, nt_errstr(status));
                return;
        }
@@ -2540,11 +2559,11 @@ NTSTATUS smbd_smb2_request_done_ex(struct smbd_smb2_request *req,
                  (unsigned int)(dyn ? dyn->length : 0),
                  location));
 
-       if (body.length < 2) {
+       if (unlikely(body.length < 2)) {
                return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
        }
 
-       if ((body.length % 2) != 0) {
+       if (unlikely((body.length % 2) != 0)) {
                return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
        }
 
@@ -2582,7 +2601,7 @@ NTSTATUS smbd_smb2_request_done_ex(struct smbd_smb2_request *req,
                         */
                        uint8_t *pad;
 
-                       pad = talloc_zero_array(req->out.vector,
+                       pad = talloc_zero_array(req,
                                                uint8_t, pad_size);
                        if (pad == NULL) {
                                return smbd_smb2_request_error(req,
@@ -2605,9 +2624,9 @@ NTSTATUS smbd_smb2_request_done_ex(struct smbd_smb2_request *req,
                        old_dyn = SMBD_SMB2_OUT_DYN_PTR(req);
 
                        new_size = old_size + pad_size;
-                       new_dyn = talloc_zero_array(req->out.vector,
+                       new_dyn = talloc_zero_array(req,
                                               uint8_t, new_size);
-                       if (new_dyn == NULL) {
+                       if (unlikely(new_dyn == NULL)) {
                                return smbd_smb2_request_error(req,
                                                NT_STATUS_NO_MEMORY);
                        }
@@ -2632,6 +2651,7 @@ NTSTATUS smbd_smb2_request_error_ex(struct smbd_smb2_request *req,
                                    const char *location)
 {
        DATA_BLOB body;
+       DATA_BLOB _dyn;
        uint8_t *outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
        size_t unread_bytes = smbd_smb2_unread_bytes(req);
 
@@ -2639,7 +2659,7 @@ NTSTATUS smbd_smb2_request_error_ex(struct smbd_smb2_request *req,
                  req->current_idx, nt_errstr(status), info ? " +info" : "",
                  location));
 
-       if (unread_bytes) {
+       if (unlikely(unread_bytes)) {
                /* Recvfile error. Drain incoming socket. */
                size_t ret;
 
@@ -2673,12 +2693,7 @@ NTSTATUS smbd_smb2_request_error_ex(struct smbd_smb2_request *req,
                 * *MUST BE* OUTVEC_ALLOC_SIZE. So we have room for
                 * 1 byte without having to do an alloc.
                 */
-               info = talloc_zero_array(req->out.vector,
-                                       DATA_BLOB,
-                                       1);
-               if (!info) {
-                       return NT_STATUS_NO_MEMORY;
-               }
+               info = &_dyn;
                info->data = ((uint8_t *)outhdr) +
                        OUTVEC_ALLOC_SIZE - 1;
                info->length = 1;
@@ -2726,7 +2741,7 @@ NTSTATUS smbd_smb2_send_oplock_break(struct smbd_server_connection *sconn,
        }
 
        state = talloc_zero(sconn, struct smbd_smb2_send_oplock_break_state);
-       if (state == NULL) {
+       if (unlikely(state == NULL)) {
                return NT_STATUS_NO_MEMORY;
        }
        state->sconn = sconn;
@@ -2818,7 +2833,7 @@ NTSTATUS smbd_smb2_send_oplock_break(struct smbd_server_connection *sconn,
        state->sconn->smb2.send_queue_len++;
 
        status = smbd_smb2_io_handler(sconn, TEVENT_FD_WRITE);
-       if (!NT_STATUS_IS_OK(status)) {
+       if (unlikely(!NT_STATUS_IS_OK(status))) {
                return status;
        }
 
@@ -2871,8 +2886,7 @@ static bool is_smb2_recvfile_write(struct smbd_smb2_request_read_state *state)
        }
 
        DEBUG(10,("Doing recvfile write len = %u\n",
-               (unsigned int)(state->pktlen -
-               SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN)));
+               (unsigned int)(state->pktfull - state->pktlen)));
 
        return true;
 }
@@ -2913,7 +2927,7 @@ static NTSTATUS smbd_smb2_request_next_incoming(struct smbd_server_connection *s
        /* ask for the next request */
        ZERO_STRUCTP(state);
        state->req = smbd_smb2_request_allocate(sconn);
-       if (state->req == NULL) {
+       if (unlikely(state->req == NULL)) {
                return NT_STATUS_NO_MEMORY;
        }
        state->req->sconn = sconn;
@@ -2934,37 +2948,37 @@ void smbd_smb2_first_negprot(struct smbd_server_connection *sconn,
                 (unsigned int)size));
 
        status = smbd_initialize_smb2(sconn);
-       if (!NT_STATUS_IS_OK(status)) {
+       if (unlikely(!NT_STATUS_IS_OK(status))) {
                smbd_server_connection_terminate(sconn, nt_errstr(status));
                return;
        }
 
        status = smbd_smb2_request_create(sconn, inbuf, size, &req);
-       if (!NT_STATUS_IS_OK(status)) {
+       if (unlikely(!NT_STATUS_IS_OK(status))) {
                smbd_server_connection_terminate(sconn, nt_errstr(status));
                return;
        }
 
        status = smbd_smb2_request_validate(req);
-       if (!NT_STATUS_IS_OK(status)) {
+       if (unlikely(!NT_STATUS_IS_OK(status))) {
                smbd_server_connection_terminate(sconn, nt_errstr(status));
                return;
        }
 
        status = smbd_smb2_request_setup_out(req);
-       if (!NT_STATUS_IS_OK(status)) {
+       if (unlikely(!NT_STATUS_IS_OK(status))) {
                smbd_server_connection_terminate(sconn, nt_errstr(status));
                return;
        }
 
        status = smbd_smb2_request_dispatch(req);
-       if (!NT_STATUS_IS_OK(status)) {
+       if (unlikely(!NT_STATUS_IS_OK(status))) {
                smbd_server_connection_terminate(sconn, nt_errstr(status));
                return;
        }
 
        status = smbd_smb2_request_next_incoming(sconn);
-       if (!NT_STATUS_IS_OK(status)) {
+       if (unlikely(!NT_STATUS_IS_OK(status))) {
                smbd_server_connection_terminate(sconn, nt_errstr(status));
                return;
        }
@@ -3049,6 +3063,7 @@ static NTSTATUS smbd_smb2_flush_send_queue(struct smbd_server_connection *sconn)
                        if (size <= e->sendfile_header->length) {
                                buf = e->sendfile_header->data;
                        } else {
+                               smb_panic(__location__);
                                buf = talloc_array(e->mem_ctx, uint8_t, size);
                                if (buf == NULL) {
                                        return NT_STATUS_NO_MEMORY;
@@ -3210,10 +3225,21 @@ again:
                         * Read the rest of the data.
                         */
                        state->doing_receivefile = false;
+
+                       state->pktbuf = talloc_realloc(state->req,
+                                                      state->pktbuf,
+                                                      uint8_t,
+                                                      state->pktfull);
+                       if (unlikely(state->pktbuf == NULL)) {
+                               return NT_STATUS_NO_MEMORY;
+                       }
+
                        state->vector.iov_base = (void *)(state->pktbuf +
-                               SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN);
-                       state->vector.iov_len = (state->pktlen -
-                               SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN);
+                               state->pktlen);
+                       state->vector.iov_len = (state->pktfull -
+                               state->pktlen);
+
+                       state->pktlen = state->pktfull;
                        goto again;
                }
 
@@ -3227,24 +3253,17 @@ again:
        /*
         * Now we analyze the NBT header
         */
-       state->pktlen = smb2_len(state->hdr.nbt);
-       if (state->pktlen == 0) {
+       state->pktfull = smb2_len(state->hdr.nbt);
+       if (unlikely(state->pktfull == 0)) {
                goto got_full;
        }
 
-       state->pktbuf = talloc_array(state->req, uint8_t, state->pktlen);
-       if (state->pktbuf == NULL) {
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       state->vector.iov_base = (void *)state->pktbuf;
-
        if (state->min_recv_size != 0) {
                min_recvfile_size = SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN;
                min_recvfile_size += state->min_recv_size;
        }
 
-       if (state->pktlen > min_recvfile_size) {
+       if (state->pktfull > min_recvfile_size) {
                /*
                 * Might be a receivefile write. Read the SMB2 HEADER +
                 * SMB2_WRITE header first. Set 'doing_receivefile'
@@ -3253,17 +3272,25 @@ again:
                 * not suitable then we'll just read the rest of the data
                 * the next time this function is called.
                 */
-               state->vector.iov_len = SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN;
+               state->pktlen = SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN;
                state->doing_receivefile = true;
        } else {
-               state->vector.iov_len = state->pktlen;
+               state->pktlen = state->pktfull;
        }
 
+       state->pktbuf = talloc_array(state->req, uint8_t, state->pktlen);
+       if (unlikely(state->pktbuf == NULL)) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       state->vector.iov_base = (void *)state->pktbuf;
+       state->vector.iov_len = state->pktlen;
+
        goto again;
 
 got_full:
 
-       if (state->hdr.nbt[0] != 0x00) {
+       if (unlikely(state->hdr.nbt[0] != 0x00)) {
                DEBUG(1,("ignore NBT[0x%02X] msg\n",
                         state->hdr.nbt[0]));
 
@@ -3288,17 +3315,16 @@ got_full:
                                                req,
                                                &req->in.vector,
                                                &req->in.vector_count);
-       if (!NT_STATUS_IS_OK(status)) {
+       if (unlikely(!NT_STATUS_IS_OK(status))) {
                return status;
        }
 
        if (state->doing_receivefile) {
                req->smb1req = talloc_zero(req, struct smb_request);
-               if (req->smb1req == NULL) {
+               if (unlikely(req->smb1req == NULL)) {
                        return NT_STATUS_NO_MEMORY;
                }
-               req->smb1req->unread_bytes =
-                       state->pktlen - SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN;
+               req->smb1req->unread_bytes = state->pktfull - state->pktlen;
        }
 
        ZERO_STRUCTP(state);
@@ -3309,17 +3335,17 @@ got_full:
                 req->current_idx, req->in.vector_count));
 
        status = smbd_smb2_request_validate(req);
-       if (!NT_STATUS_IS_OK(status)) {
+       if (unlikely(!NT_STATUS_IS_OK(status))) {
                return status;
        }
 
        status = smbd_smb2_request_setup_out(req);
-       if (!NT_STATUS_IS_OK(status)) {
+       if (unlikely(!NT_STATUS_IS_OK(status))) {
                return status;
        }
 
        status = smbd_smb2_request_dispatch(req);
-       if (!NT_STATUS_IS_OK(status)) {
+       if (unlikely(!NT_STATUS_IS_OK(status))) {
                return status;
        }
 
@@ -3339,7 +3365,7 @@ got_full:
        }
 
        status = smbd_smb2_request_next_incoming(sconn);
-       if (!NT_STATUS_IS_OK(status)) {
+       if (unlikely(!NT_STATUS_IS_OK(status))) {
                return status;
        }
 
@@ -3357,7 +3383,7 @@ static void smbd_smb2_connection_handler(struct tevent_context *ev,
        NTSTATUS status;
 
        status = smbd_smb2_io_handler(sconn, flags);
-       if (!NT_STATUS_IS_OK(status)) {
+       if (unlikely(!NT_STATUS_IS_OK(status))) {
                smbd_server_connection_terminate(sconn, nt_errstr(status));
                return;
        }