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_cunit.h" 35 36 #include "lib/test_env.c" 37 #include "lib/ut_multithread.c" 38 39 /* HACK: disable VTune integration so the unit test doesn't need VTune headers and libs to build */ 40 #undef SPDK_CONFIG_VTUNE 41 42 #include "bdev.c" 43 44 #define BDEV_UT_NUM_THREADS 3 45 46 DEFINE_STUB_V(spdk_scsi_nvme_translate, (const struct spdk_bdev_io *bdev_io, 47 int *sc, int *sk, int *asc, int *ascq)); 48 49 struct ut_bdev { 50 struct spdk_bdev bdev; 51 int io_target; 52 }; 53 54 struct ut_bdev_channel { 55 TAILQ_HEAD(, spdk_bdev_io) outstanding_io; 56 }; 57 58 struct ut_bdev g_bdev; 59 struct spdk_bdev_desc *g_desc; 60 61 static int 62 stub_create_ch(void *io_device, void *ctx_buf) 63 { 64 struct ut_bdev_channel *ch = ctx_buf; 65 66 TAILQ_INIT(&ch->outstanding_io); 67 return 0; 68 } 69 70 static void 71 stub_destroy_ch(void *io_device, void *ctx_buf) 72 { 73 } 74 75 static struct spdk_io_channel * 76 stub_get_io_channel(void *ctx) 77 { 78 return spdk_get_io_channel(&g_bdev.io_target); 79 } 80 81 static int 82 stub_destruct(void *ctx) 83 { 84 return 0; 85 } 86 87 static void 88 stub_submit_request(struct spdk_io_channel *_ch, struct spdk_bdev_io *bdev_io) 89 { 90 struct ut_bdev_channel *ch = spdk_io_channel_get_ctx(_ch); 91 92 TAILQ_INSERT_TAIL(&ch->outstanding_io, bdev_io, module_link); 93 } 94 95 static void 96 stub_complete_io(void) 97 { 98 struct spdk_io_channel *_ch = spdk_get_io_channel(&g_bdev.io_target); 99 struct ut_bdev_channel *ch = spdk_io_channel_get_ctx(_ch); 100 struct spdk_bdev_io *io; 101 102 while (!TAILQ_EMPTY(&ch->outstanding_io)) { 103 io = TAILQ_FIRST(&ch->outstanding_io); 104 TAILQ_REMOVE(&ch->outstanding_io, io, module_link); 105 spdk_bdev_io_complete(io, SPDK_BDEV_IO_STATUS_SUCCESS); 106 } 107 108 spdk_put_io_channel(_ch); 109 } 110 111 static struct spdk_bdev_fn_table fn_table = { 112 .get_io_channel = stub_get_io_channel, 113 .destruct = stub_destruct, 114 .submit_request = stub_submit_request, 115 }; 116 117 static int 118 module_init(void) 119 { 120 return 0; 121 } 122 123 static void 124 module_fini(void) 125 { 126 } 127 128 SPDK_BDEV_MODULE_REGISTER(bdev_ut, module_init, module_fini, NULL, NULL, NULL) 129 130 static void 131 register_bdev(void) 132 { 133 g_bdev.bdev.name = "bdev_ut"; 134 g_bdev.bdev.fn_table = &fn_table; 135 g_bdev.bdev.module = SPDK_GET_BDEV_MODULE(bdev_ut); 136 137 spdk_io_device_register(&g_bdev.io_target, stub_create_ch, stub_destroy_ch, 138 sizeof(struct ut_bdev_channel)); 139 spdk_bdev_register(&g_bdev.bdev); 140 } 141 142 static void 143 unregister_bdev(void) 144 { 145 /* Handle any deferred messages. */ 146 poll_threads(); 147 spdk_bdev_unregister(&g_bdev.bdev); 148 spdk_io_device_unregister(&g_bdev.io_target, NULL); 149 memset(&g_bdev, 0, sizeof(g_bdev)); 150 } 151 152 static void 153 bdev_init_cb(void *done, int rc) 154 { 155 CU_ASSERT(rc == 0); 156 *(bool *)done = true; 157 } 158 159 static void 160 setup_test(void) 161 { 162 bool done = false; 163 164 allocate_threads(BDEV_UT_NUM_THREADS); 165 spdk_bdev_initialize(bdev_init_cb, &done, NULL, NULL); 166 register_bdev(); 167 spdk_bdev_open(&g_bdev.bdev, true, NULL, NULL, &g_desc); 168 } 169 170 static void 171 teardown_test(void) 172 { 173 spdk_bdev_close(g_desc); 174 g_desc = NULL; 175 unregister_bdev(); 176 spdk_bdev_finish(); 177 free_threads(); 178 } 179 180 static void 181 basic(void) 182 { 183 setup_test(); 184 185 set_thread(0); 186 187 g_ut_threads[0].ch = spdk_bdev_get_io_channel(g_desc); 188 spdk_put_io_channel(g_ut_threads[0].ch); 189 190 teardown_test(); 191 } 192 193 static void 194 reset_done(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg) 195 { 196 bool *done = cb_arg; 197 198 CU_ASSERT(success == true); 199 *done = true; 200 spdk_bdev_free_io(bdev_io); 201 } 202 203 static void 204 put_channel_during_reset(void) 205 { 206 struct spdk_io_channel *io_ch; 207 bool done = false; 208 209 setup_test(); 210 211 set_thread(0); 212 io_ch = spdk_bdev_get_io_channel(g_desc); 213 CU_ASSERT(io_ch != NULL); 214 215 /* 216 * Start a reset, but then put the I/O channel before 217 * the deferred messages for the reset get a chance to 218 * execute. 219 */ 220 spdk_bdev_reset(g_desc, io_ch, reset_done, &done); 221 spdk_put_io_channel(io_ch); 222 poll_threads(); 223 stub_complete_io(); 224 225 teardown_test(); 226 } 227 228 int 229 main(int argc, char **argv) 230 { 231 CU_pSuite suite = NULL; 232 unsigned int num_failures; 233 234 if (CU_initialize_registry() != CUE_SUCCESS) { 235 return CU_get_error(); 236 } 237 238 suite = CU_add_suite("bdev", NULL, NULL); 239 if (suite == NULL) { 240 CU_cleanup_registry(); 241 return CU_get_error(); 242 } 243 244 if ( 245 CU_add_test(suite, "basic", basic) == NULL || 246 CU_add_test(suite, "put_channel_during_reset", put_channel_during_reset) == NULL 247 ) { 248 CU_cleanup_registry(); 249 return CU_get_error(); 250 } 251 252 CU_basic_set_mode(CU_BRM_VERBOSE); 253 CU_basic_run_tests(); 254 num_failures = CU_get_number_of_failures(); 255 CU_cleanup_registry(); 256 return num_failures; 257 } 258