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_V(io_uring_queue_exit, (struct io_uring *ring)); 52 53 static void 54 _req_cb(void *cb_arg, int len) 55 { 56 *(bool *)cb_arg = true; 57 CU_ASSERT(len == 0); 58 } 59 60 static void 61 flush_client(void) 62 { 63 struct spdk_uring_sock_group_impl group = {}; 64 struct spdk_uring_sock usock = {}; 65 struct spdk_sock *sock = &usock.base; 66 struct spdk_sock_request *req1, *req2; 67 bool cb_arg1, cb_arg2; 68 int rc; 69 70 /* Set up data structures */ 71 TAILQ_INIT(&sock->queued_reqs); 72 TAILQ_INIT(&sock->pending_reqs); 73 sock->group_impl = &group.base; 74 75 req1 = calloc(1, sizeof(struct spdk_sock_request) + 3 * sizeof(struct iovec)); 76 SPDK_CU_ASSERT_FATAL(req1 != NULL); 77 SPDK_SOCK_REQUEST_IOV(req1, 0)->iov_base = (void *)100; 78 SPDK_SOCK_REQUEST_IOV(req1, 0)->iov_len = 64; 79 SPDK_SOCK_REQUEST_IOV(req1, 1)->iov_base = (void *)200; 80 SPDK_SOCK_REQUEST_IOV(req1, 1)->iov_len = 64; 81 SPDK_SOCK_REQUEST_IOV(req1, 2)->iov_base = (void *)300; 82 SPDK_SOCK_REQUEST_IOV(req1, 2)->iov_len = 64; 83 req1->iovcnt = 3; 84 req1->cb_fn = _req_cb; 85 req1->cb_arg = &cb_arg1; 86 87 req2 = calloc(1, sizeof(struct spdk_sock_request) + 2 * sizeof(struct iovec)); 88 SPDK_CU_ASSERT_FATAL(req2 != NULL); 89 SPDK_SOCK_REQUEST_IOV(req2, 0)->iov_base = (void *)100; 90 SPDK_SOCK_REQUEST_IOV(req2, 0)->iov_len = 32; 91 SPDK_SOCK_REQUEST_IOV(req2, 1)->iov_base = (void *)200; 92 SPDK_SOCK_REQUEST_IOV(req2, 1)->iov_len = 32; 93 req2->iovcnt = 2; 94 req2->cb_fn = _req_cb; 95 req2->cb_arg = &cb_arg2; 96 97 /* Simple test - a request with a 3 element iovec 98 * that gets submitted in a single sendmsg. */ 99 spdk_sock_request_queue(sock, req1); 100 MOCK_SET(sendmsg, 192); 101 cb_arg1 = false; 102 rc = _sock_flush_client(sock); 103 CU_ASSERT(rc == 0); 104 CU_ASSERT(cb_arg1 == true); 105 CU_ASSERT(TAILQ_EMPTY(&sock->queued_reqs)); 106 107 /* Two requests, where both can fully send. */ 108 spdk_sock_request_queue(sock, req1); 109 spdk_sock_request_queue(sock, req2); 110 MOCK_SET(sendmsg, 256); 111 cb_arg1 = false; 112 cb_arg2 = false; 113 rc = _sock_flush_client(sock); 114 CU_ASSERT(rc == 0); 115 CU_ASSERT(cb_arg1 == true); 116 CU_ASSERT(cb_arg2 == true); 117 CU_ASSERT(TAILQ_EMPTY(&sock->queued_reqs)); 118 119 /* Two requests. Only first one can send */ 120 spdk_sock_request_queue(sock, req1); 121 spdk_sock_request_queue(sock, req2); 122 MOCK_SET(sendmsg, 192); 123 cb_arg1 = false; 124 cb_arg2 = false; 125 rc = _sock_flush_client(sock); 126 CU_ASSERT(rc == 0); 127 CU_ASSERT(cb_arg1 == true); 128 CU_ASSERT(cb_arg2 == false); 129 CU_ASSERT(TAILQ_FIRST(&sock->queued_reqs) == req2); 130 TAILQ_REMOVE(&sock->queued_reqs, req2, internal.link); 131 CU_ASSERT(TAILQ_EMPTY(&sock->queued_reqs)); 132 133 /* One request. Partial send. */ 134 spdk_sock_request_queue(sock, req1); 135 MOCK_SET(sendmsg, 10); 136 cb_arg1 = false; 137 rc = _sock_flush_client(sock); 138 CU_ASSERT(rc == 0); 139 CU_ASSERT(cb_arg1 == false); 140 CU_ASSERT(TAILQ_FIRST(&sock->queued_reqs) == req1); 141 142 /* Do a second flush that partial sends again. */ 143 MOCK_SET(sendmsg, 52); 144 cb_arg1 = false; 145 rc = _sock_flush_client(sock); 146 CU_ASSERT(rc == 0); 147 CU_ASSERT(cb_arg1 == false); 148 CU_ASSERT(TAILQ_FIRST(&sock->queued_reqs) == req1); 149 150 /* Flush the rest of the data */ 151 MOCK_SET(sendmsg, 130); 152 cb_arg1 = false; 153 rc = _sock_flush_client(sock); 154 CU_ASSERT(rc == 0); 155 CU_ASSERT(cb_arg1 == true); 156 CU_ASSERT(TAILQ_EMPTY(&sock->queued_reqs)); 157 158 free(req1); 159 free(req2); 160 } 161 162 static void 163 flush_server(void) 164 { 165 struct spdk_uring_sock_group_impl group = {}; 166 struct spdk_uring_sock usock = {}; 167 struct spdk_sock *sock = &usock.base; 168 struct spdk_sock_request *req1, *req2; 169 bool cb_arg1, cb_arg2; 170 int rc; 171 172 /* Set up data structures */ 173 TAILQ_INIT(&sock->queued_reqs); 174 TAILQ_INIT(&sock->pending_reqs); 175 sock->group_impl = &group.base; 176 usock.write_task.sock = &usock; 177 usock.group = &group; 178 179 req1 = calloc(1, sizeof(struct spdk_sock_request) + 2 * sizeof(struct iovec)); 180 SPDK_CU_ASSERT_FATAL(req1 != NULL); 181 SPDK_SOCK_REQUEST_IOV(req1, 0)->iov_base = (void *)100; 182 SPDK_SOCK_REQUEST_IOV(req1, 0)->iov_len = 64; 183 SPDK_SOCK_REQUEST_IOV(req1, 1)->iov_base = (void *)200; 184 SPDK_SOCK_REQUEST_IOV(req1, 1)->iov_len = 64; 185 req1->iovcnt = 2; 186 req1->cb_fn = _req_cb; 187 req1->cb_arg = &cb_arg1; 188 189 req2 = calloc(1, sizeof(struct spdk_sock_request) + 2 * sizeof(struct iovec)); 190 SPDK_CU_ASSERT_FATAL(req2 != NULL); 191 SPDK_SOCK_REQUEST_IOV(req2, 0)->iov_base = (void *)100; 192 SPDK_SOCK_REQUEST_IOV(req2, 0)->iov_len = 32; 193 SPDK_SOCK_REQUEST_IOV(req2, 1)->iov_base = (void *)200; 194 SPDK_SOCK_REQUEST_IOV(req2, 1)->iov_len = 32; 195 req2->iovcnt = 2; 196 req2->cb_fn = _req_cb; 197 req2->cb_arg = &cb_arg2; 198 199 /* we should not call _sock_flush directly, since it will finally 200 * call liburing related funtions */ 201 202 /* Simple test - a request with a 2 element iovec 203 * that is fully completed. */ 204 spdk_sock_request_queue(sock, req1); 205 cb_arg1 = false; 206 rc = spdk_sock_prep_reqs(sock, usock.write_task.iovs, 0, NULL); 207 CU_ASSERT(rc == 2); 208 sock_complete_reqs(sock, 128); 209 CU_ASSERT(cb_arg1 == true); 210 CU_ASSERT(TAILQ_EMPTY(&sock->queued_reqs)); 211 212 /* Two requests, where both can be fully completed. */ 213 spdk_sock_request_queue(sock, req1); 214 spdk_sock_request_queue(sock, req2); 215 cb_arg1 = false; 216 cb_arg2 = false; 217 rc = spdk_sock_prep_reqs(sock, usock.write_task.iovs, 0, NULL); 218 CU_ASSERT(rc == 4); 219 sock_complete_reqs(sock, 192); 220 CU_ASSERT(cb_arg1 == true); 221 CU_ASSERT(cb_arg2 == true); 222 CU_ASSERT(TAILQ_EMPTY(&sock->queued_reqs)); 223 224 225 /* One request that is partially sent. */ 226 spdk_sock_request_queue(sock, req1); 227 cb_arg1 = false; 228 rc = spdk_sock_prep_reqs(sock, usock.write_task.iovs, 0, NULL); 229 CU_ASSERT(rc == 2); 230 sock_complete_reqs(sock, 92); 231 CU_ASSERT(rc == 2); 232 CU_ASSERT(cb_arg1 == false); 233 CU_ASSERT(TAILQ_FIRST(&sock->queued_reqs) == req1); 234 235 /* Get the second time partial sent result. */ 236 sock_complete_reqs(sock, 10); 237 CU_ASSERT(cb_arg1 == false); 238 CU_ASSERT(TAILQ_FIRST(&sock->queued_reqs) == req1); 239 240 /* Data is finally sent. */ 241 sock_complete_reqs(sock, 26); 242 CU_ASSERT(cb_arg1 == true); 243 CU_ASSERT(TAILQ_EMPTY(&sock->queued_reqs)); 244 245 free(req1); 246 free(req2); 247 } 248 249 int 250 main(int argc, char **argv) 251 { 252 CU_pSuite suite = NULL; 253 unsigned int num_failures; 254 255 CU_set_error_action(CUEA_ABORT); 256 CU_initialize_registry(); 257 258 suite = CU_add_suite("uring", NULL, NULL); 259 260 261 CU_ADD_TEST(suite, flush_client); 262 CU_ADD_TEST(suite, flush_server); 263 264 CU_basic_set_mode(CU_BRM_VERBOSE); 265 266 CU_basic_run_tests(); 267 268 num_failures = CU_get_number_of_failures(); 269 CU_cleanup_registry(); 270 271 return num_failures; 272 } 273