1 /*- 2 * BSD LICENSE 3 * 4 * Copyright (c) Intel Corporation. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include "spdk/stdinc.h" 35 #include "spdk/util.h" 36 37 #include "spdk_internal/mock.h" 38 39 #include "spdk_cunit.h" 40 41 #include "sock/uring/uring.c" 42 43 DEFINE_STUB_V(spdk_net_impl_register, (struct spdk_net_impl *impl, int priority)); 44 DEFINE_STUB(spdk_sock_close, int, (struct spdk_sock **s), 0); 45 DEFINE_STUB(__io_uring_get_cqe, int, (struct io_uring *ring, struct io_uring_cqe **cqe_ptr, 46 unsigned submit, 47 unsigned wait_nr, sigset_t *sigmask), 0); 48 DEFINE_STUB(io_uring_submit, int, (struct io_uring *ring), 0); 49 DEFINE_STUB(io_uring_get_sqe, struct io_uring_sqe *, (struct io_uring *ring), 0); 50 DEFINE_STUB(io_uring_queue_init, int, (unsigned entries, struct io_uring *ring, unsigned flags), 0); 51 DEFINE_STUB(io_uring_peek_batch_cqe, unsigned, (struct io_uring *ring, struct io_uring_cqe **cqes, 52 unsigned count), 0); 53 DEFINE_STUB_V(io_uring_queue_exit, (struct io_uring *ring)); 54 55 static void 56 _req_cb(void *cb_arg, int len) 57 { 58 *(bool *)cb_arg = true; 59 CU_ASSERT(len == 0); 60 } 61 62 static void 63 flush_client(void) 64 { 65 struct spdk_uring_sock_group_impl group = {}; 66 struct spdk_uring_sock usock = {}; 67 struct spdk_sock *sock = &usock.base; 68 struct spdk_sock_request *req1, *req2; 69 bool cb_arg1, cb_arg2; 70 int rc; 71 72 /* Set up data structures */ 73 TAILQ_INIT(&sock->queued_reqs); 74 TAILQ_INIT(&sock->pending_reqs); 75 sock->group_impl = &group.base; 76 77 req1 = calloc(1, sizeof(struct spdk_sock_request) + 3 * sizeof(struct iovec)); 78 SPDK_CU_ASSERT_FATAL(req1 != NULL); 79 SPDK_SOCK_REQUEST_IOV(req1, 0)->iov_base = (void *)100; 80 SPDK_SOCK_REQUEST_IOV(req1, 0)->iov_len = 64; 81 SPDK_SOCK_REQUEST_IOV(req1, 1)->iov_base = (void *)200; 82 SPDK_SOCK_REQUEST_IOV(req1, 1)->iov_len = 64; 83 SPDK_SOCK_REQUEST_IOV(req1, 2)->iov_base = (void *)300; 84 SPDK_SOCK_REQUEST_IOV(req1, 2)->iov_len = 64; 85 req1->iovcnt = 3; 86 req1->cb_fn = _req_cb; 87 req1->cb_arg = &cb_arg1; 88 89 req2 = calloc(1, sizeof(struct spdk_sock_request) + 2 * sizeof(struct iovec)); 90 SPDK_CU_ASSERT_FATAL(req2 != NULL); 91 SPDK_SOCK_REQUEST_IOV(req2, 0)->iov_base = (void *)100; 92 SPDK_SOCK_REQUEST_IOV(req2, 0)->iov_len = 32; 93 SPDK_SOCK_REQUEST_IOV(req2, 1)->iov_base = (void *)200; 94 SPDK_SOCK_REQUEST_IOV(req2, 1)->iov_len = 32; 95 req2->iovcnt = 2; 96 req2->cb_fn = _req_cb; 97 req2->cb_arg = &cb_arg2; 98 99 /* Simple test - a request with a 3 element iovec 100 * that gets submitted in a single sendmsg. */ 101 spdk_sock_request_queue(sock, req1); 102 MOCK_SET(sendmsg, 192); 103 cb_arg1 = false; 104 rc = _sock_flush_client(sock); 105 CU_ASSERT(rc == 0); 106 CU_ASSERT(cb_arg1 == true); 107 CU_ASSERT(TAILQ_EMPTY(&sock->queued_reqs)); 108 109 /* Two requests, where both can fully send. */ 110 spdk_sock_request_queue(sock, req1); 111 spdk_sock_request_queue(sock, req2); 112 MOCK_SET(sendmsg, 256); 113 cb_arg1 = false; 114 cb_arg2 = false; 115 rc = _sock_flush_client(sock); 116 CU_ASSERT(rc == 0); 117 CU_ASSERT(cb_arg1 == true); 118 CU_ASSERT(cb_arg2 == true); 119 CU_ASSERT(TAILQ_EMPTY(&sock->queued_reqs)); 120 121 /* Two requests. Only first one can send */ 122 spdk_sock_request_queue(sock, req1); 123 spdk_sock_request_queue(sock, req2); 124 MOCK_SET(sendmsg, 192); 125 cb_arg1 = false; 126 cb_arg2 = false; 127 rc = _sock_flush_client(sock); 128 CU_ASSERT(rc == 0); 129 CU_ASSERT(cb_arg1 == true); 130 CU_ASSERT(cb_arg2 == false); 131 CU_ASSERT(TAILQ_FIRST(&sock->queued_reqs) == req2); 132 TAILQ_REMOVE(&sock->queued_reqs, req2, internal.link); 133 CU_ASSERT(TAILQ_EMPTY(&sock->queued_reqs)); 134 135 /* One request. Partial send. */ 136 spdk_sock_request_queue(sock, req1); 137 MOCK_SET(sendmsg, 10); 138 cb_arg1 = false; 139 rc = _sock_flush_client(sock); 140 CU_ASSERT(rc == 0); 141 CU_ASSERT(cb_arg1 == false); 142 CU_ASSERT(TAILQ_FIRST(&sock->queued_reqs) == req1); 143 144 /* Do a second flush that partial sends again. */ 145 MOCK_SET(sendmsg, 52); 146 cb_arg1 = false; 147 rc = _sock_flush_client(sock); 148 CU_ASSERT(rc == 0); 149 CU_ASSERT(cb_arg1 == false); 150 CU_ASSERT(TAILQ_FIRST(&sock->queued_reqs) == req1); 151 152 /* Flush the rest of the data */ 153 MOCK_SET(sendmsg, 130); 154 cb_arg1 = false; 155 rc = _sock_flush_client(sock); 156 CU_ASSERT(rc == 0); 157 CU_ASSERT(cb_arg1 == true); 158 CU_ASSERT(TAILQ_EMPTY(&sock->queued_reqs)); 159 160 free(req1); 161 free(req2); 162 } 163 164 static void 165 flush_server(void) 166 { 167 struct spdk_uring_sock_group_impl group = {}; 168 struct spdk_uring_sock usock = {}; 169 struct spdk_sock *sock = &usock.base; 170 struct spdk_sock_request *req1, *req2; 171 bool cb_arg1, cb_arg2; 172 int rc; 173 174 /* Set up data structures */ 175 TAILQ_INIT(&sock->queued_reqs); 176 TAILQ_INIT(&sock->pending_reqs); 177 sock->group_impl = &group.base; 178 usock.write_task.sock = &usock; 179 usock.group = &group; 180 181 req1 = calloc(1, sizeof(struct spdk_sock_request) + 2 * sizeof(struct iovec)); 182 SPDK_CU_ASSERT_FATAL(req1 != NULL); 183 SPDK_SOCK_REQUEST_IOV(req1, 0)->iov_base = (void *)100; 184 SPDK_SOCK_REQUEST_IOV(req1, 0)->iov_len = 64; 185 SPDK_SOCK_REQUEST_IOV(req1, 1)->iov_base = (void *)200; 186 SPDK_SOCK_REQUEST_IOV(req1, 1)->iov_len = 64; 187 req1->iovcnt = 2; 188 req1->cb_fn = _req_cb; 189 req1->cb_arg = &cb_arg1; 190 191 req2 = calloc(1, sizeof(struct spdk_sock_request) + 2 * sizeof(struct iovec)); 192 SPDK_CU_ASSERT_FATAL(req2 != NULL); 193 SPDK_SOCK_REQUEST_IOV(req2, 0)->iov_base = (void *)100; 194 SPDK_SOCK_REQUEST_IOV(req2, 0)->iov_len = 32; 195 SPDK_SOCK_REQUEST_IOV(req2, 1)->iov_base = (void *)200; 196 SPDK_SOCK_REQUEST_IOV(req2, 1)->iov_len = 32; 197 req2->iovcnt = 2; 198 req2->cb_fn = _req_cb; 199 req2->cb_arg = &cb_arg2; 200 201 /* we should not call _sock_flush directly, since it will finally 202 * call liburing related funtions */ 203 204 /* Simple test - a request with a 2 element iovec 205 * that is fully completed. */ 206 spdk_sock_request_queue(sock, req1); 207 cb_arg1 = false; 208 rc = sock_prep_reqs(sock, usock.write_task.iovs, 0, NULL); 209 CU_ASSERT(rc == 2); 210 sock_complete_reqs(sock, 128); 211 CU_ASSERT(cb_arg1 == true); 212 CU_ASSERT(TAILQ_EMPTY(&sock->queued_reqs)); 213 214 /* Two requests, where both can be fully completed. */ 215 spdk_sock_request_queue(sock, req1); 216 spdk_sock_request_queue(sock, req2); 217 cb_arg1 = false; 218 cb_arg2 = false; 219 rc = sock_prep_reqs(sock, usock.write_task.iovs, 0, NULL); 220 CU_ASSERT(rc == 4); 221 sock_complete_reqs(sock, 192); 222 CU_ASSERT(cb_arg1 == true); 223 CU_ASSERT(cb_arg2 == true); 224 CU_ASSERT(TAILQ_EMPTY(&sock->queued_reqs)); 225 226 227 /* One request that is partially sent. */ 228 spdk_sock_request_queue(sock, req1); 229 cb_arg1 = false; 230 rc = sock_prep_reqs(sock, usock.write_task.iovs, 0, NULL); 231 CU_ASSERT(rc == 2); 232 sock_complete_reqs(sock, 92); 233 CU_ASSERT(rc == 2); 234 CU_ASSERT(cb_arg1 == false); 235 CU_ASSERT(TAILQ_FIRST(&sock->queued_reqs) == req1); 236 237 /* Get the second time partial sent result. */ 238 sock_complete_reqs(sock, 10); 239 CU_ASSERT(cb_arg1 == false); 240 CU_ASSERT(TAILQ_FIRST(&sock->queued_reqs) == req1); 241 242 /* Data is finally sent. */ 243 sock_complete_reqs(sock, 26); 244 CU_ASSERT(cb_arg1 == true); 245 CU_ASSERT(TAILQ_EMPTY(&sock->queued_reqs)); 246 247 free(req1); 248 free(req2); 249 } 250 251 int 252 main(int argc, char **argv) 253 { 254 CU_pSuite suite = NULL; 255 unsigned int num_failures; 256 257 CU_set_error_action(CUEA_ABORT); 258 CU_initialize_registry(); 259 260 suite = CU_add_suite("uring", NULL, NULL); 261 262 263 CU_ADD_TEST(suite, flush_client); 264 CU_ADD_TEST(suite, flush_server); 265 266 CU_basic_set_mode(CU_BRM_VERBOSE); 267 268 CU_basic_run_tests(); 269 270 num_failures = CU_get_number_of_failures(); 271 CU_cleanup_registry(); 272 273 return num_failures; 274 } 275