LCOV - code coverage report
Current view: top level - spdk/test/unit/lib/thread/iobuf.c - iobuf_ut.c (source / functions) Hit Total Coverage
Test: Combined Lines: 391 391 100.0 %
Date: 2024-07-15 16:11:34 Functions: 6 6 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 14 14 100.0 %

           Branch data     Line data    Source code
       1                 :            : /*   SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  *   Copyright (C) 2023 Intel Corporation. All rights reserved.
       3                 :            :  */
       4                 :            : 
       5                 :            : #include "spdk_internal/cunit.h"
       6                 :            : 
       7                 :            : #include "common/lib/ut_multithread.c"
       8                 :            : #include "unit/lib/json_mock.c"
       9                 :            : 
      10                 :            : #include "spdk/config.h"
      11                 :            : #include "spdk/thread.h"
      12                 :            : 
      13                 :            : #include "thread/iobuf.c"
      14                 :            : 
      15                 :            : struct ut_iobuf_entry {
      16                 :            :         struct spdk_iobuf_channel       *ioch;
      17                 :            :         struct spdk_iobuf_entry         iobuf;
      18                 :            :         void                            *buf;
      19                 :            :         uint32_t                        thread_id;
      20                 :            :         const char                      *module;
      21                 :            : };
      22                 :            : 
      23                 :            : static void
      24                 :          6 : ut_iobuf_finish_cb(void *ctx)
      25                 :            : {
      26                 :          6 :         *(int *)ctx = 1;
      27                 :          6 : }
      28                 :            : 
      29                 :            : static void
      30                 :         36 : ut_iobuf_get_buf_cb(struct spdk_iobuf_entry *entry, void *buf)
      31                 :            : {
      32                 :         36 :         struct ut_iobuf_entry *ut_entry = SPDK_CONTAINEROF(entry, struct ut_iobuf_entry, iobuf);
      33                 :            : 
      34                 :         36 :         ut_entry->buf = buf;
      35                 :         36 : }
      36                 :            : 
      37                 :            : static int
      38                 :         24 : ut_iobuf_foreach_cb(struct spdk_iobuf_channel *ch, struct spdk_iobuf_entry *entry, void *cb_arg)
      39                 :            : {
      40                 :         24 :         struct ut_iobuf_entry *ut_entry = SPDK_CONTAINEROF(entry, struct ut_iobuf_entry, iobuf);
      41                 :            : 
      42                 :         24 :         ut_entry->buf = cb_arg;
      43                 :            : 
      44                 :         24 :         return 0;
      45                 :            : }
      46                 :            : 
      47                 :            : #define SMALL_BUFSIZE 4096
      48                 :            : #define LARGE_BUFSIZE 8192
      49                 :            : 
      50                 :            : static void
      51                 :          3 : iobuf(void)
      52                 :            : {
      53                 :          3 :         struct spdk_iobuf_opts opts = {
      54                 :            :                 .small_pool_count = 2,
      55                 :            :                 .large_pool_count = 2,
      56                 :            :                 .small_bufsize = SMALL_BUFSIZE,
      57                 :            :                 .large_bufsize = LARGE_BUFSIZE,
      58                 :            :         };
      59                 :            :         struct ut_iobuf_entry *entry;
      60                 :          3 :         struct spdk_iobuf_channel mod0_ch[2], mod1_ch[2];
      61                 :          3 :         struct ut_iobuf_entry mod0_entries[] = {
      62                 :            :                 { .thread_id = 0, .module = "ut_module0", },
      63                 :            :                 { .thread_id = 0, .module = "ut_module0", },
      64                 :            :                 { .thread_id = 0, .module = "ut_module0", },
      65                 :            :                 { .thread_id = 0, .module = "ut_module0", },
      66                 :            :                 { .thread_id = 1, .module = "ut_module0", },
      67                 :            :                 { .thread_id = 1, .module = "ut_module0", },
      68                 :            :                 { .thread_id = 1, .module = "ut_module0", },
      69                 :            :                 { .thread_id = 1, .module = "ut_module0", },
      70                 :            :         };
      71                 :          3 :         struct ut_iobuf_entry mod1_entries[] = {
      72                 :            :                 { .thread_id = 0, .module = "ut_module1", },
      73                 :            :                 { .thread_id = 0, .module = "ut_module1", },
      74                 :            :                 { .thread_id = 0, .module = "ut_module1", },
      75                 :            :                 { .thread_id = 0, .module = "ut_module1", },
      76                 :            :                 { .thread_id = 1, .module = "ut_module1", },
      77                 :            :                 { .thread_id = 1, .module = "ut_module1", },
      78                 :            :                 { .thread_id = 1, .module = "ut_module1", },
      79                 :            :                 { .thread_id = 1, .module = "ut_module1", },
      80                 :            :         };
      81                 :          3 :         int rc, finish = 0;
      82                 :            :         uint32_t i;
      83                 :            : 
      84                 :          3 :         allocate_cores(2);
      85                 :          3 :         allocate_threads(2);
      86                 :            : 
      87                 :          3 :         set_thread(0);
      88                 :            : 
      89                 :            :         /* We cannot use spdk_iobuf_set_opts(), as it won't allow us to use such small pools */
      90                 :          3 :         g_iobuf.opts = opts;
      91                 :          3 :         rc = spdk_iobuf_initialize();
      92                 :          3 :         CU_ASSERT_EQUAL(rc, 0);
      93                 :            : 
      94                 :          3 :         rc = spdk_iobuf_register_module("ut_module0");
      95                 :          3 :         CU_ASSERT_EQUAL(rc, 0);
      96                 :            : 
      97                 :          3 :         rc = spdk_iobuf_register_module("ut_module1");
      98                 :          3 :         CU_ASSERT_EQUAL(rc, 0);
      99                 :            : 
     100                 :          3 :         set_thread(0);
     101                 :          3 :         rc = spdk_iobuf_channel_init(&mod0_ch[0], "ut_module0", 0, 0);
     102                 :          3 :         CU_ASSERT_EQUAL(rc, 0);
     103                 :          3 :         set_thread(1);
     104                 :          3 :         rc = spdk_iobuf_channel_init(&mod0_ch[1], "ut_module0", 0, 0);
     105                 :          3 :         CU_ASSERT_EQUAL(rc, 0);
     106         [ +  + ]:         27 :         for (i = 0; i < SPDK_COUNTOF(mod0_entries); ++i) {
     107                 :         24 :                 mod0_entries[i].ioch = &mod0_ch[mod0_entries[i].thread_id];
     108                 :            :         }
     109                 :          3 :         set_thread(0);
     110                 :          3 :         rc = spdk_iobuf_channel_init(&mod1_ch[0], "ut_module1", 0, 0);
     111                 :          3 :         CU_ASSERT_EQUAL(rc, 0);
     112                 :          3 :         set_thread(1);
     113                 :          3 :         rc = spdk_iobuf_channel_init(&mod1_ch[1], "ut_module1", 0, 0);
     114                 :          3 :         CU_ASSERT_EQUAL(rc, 0);
     115         [ +  + ]:         27 :         for (i = 0; i < SPDK_COUNTOF(mod1_entries); ++i) {
     116                 :         24 :                 mod1_entries[i].ioch = &mod1_ch[mod1_entries[i].thread_id];
     117                 :            :         }
     118                 :            : 
     119                 :            :         /* First check that it's possible to retrieve the whole pools from a single module */
     120                 :          3 :         set_thread(0);
     121                 :          3 :         entry = &mod0_entries[0];
     122                 :          3 :         entry->buf = spdk_iobuf_get(entry->ioch, LARGE_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
     123                 :          3 :         CU_ASSERT_PTR_NOT_NULL(entry->buf);
     124                 :          3 :         entry = &mod0_entries[1];
     125                 :          3 :         entry->buf = spdk_iobuf_get(entry->ioch, LARGE_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
     126                 :          3 :         CU_ASSERT_PTR_NOT_NULL(entry->buf);
     127                 :            :         /* The next two should be put onto the large buf wait queue */
     128                 :          3 :         entry = &mod0_entries[2];
     129                 :          3 :         entry->buf = spdk_iobuf_get(entry->ioch, LARGE_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
     130                 :          3 :         CU_ASSERT_PTR_NULL(entry->buf);
     131                 :          3 :         entry = &mod0_entries[3];
     132                 :          3 :         entry->buf = spdk_iobuf_get(entry->ioch, LARGE_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
     133                 :          3 :         CU_ASSERT_PTR_NULL(entry->buf);
     134                 :            :         /* Pick the two next buffers from the small pool */
     135                 :          3 :         set_thread(1);
     136                 :          3 :         entry = &mod0_entries[4];
     137                 :          3 :         entry->buf = spdk_iobuf_get(entry->ioch, SMALL_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
     138                 :          3 :         CU_ASSERT_PTR_NOT_NULL(entry->buf);
     139                 :          3 :         entry = &mod0_entries[5];
     140                 :          3 :         entry->buf = spdk_iobuf_get(entry->ioch, SMALL_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
     141                 :          3 :         CU_ASSERT_PTR_NOT_NULL(entry->buf);
     142                 :            :         /* The next two should be put onto the small buf wait queue */
     143                 :          3 :         entry = &mod0_entries[6];
     144                 :          3 :         entry->buf = spdk_iobuf_get(entry->ioch, SMALL_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
     145                 :          3 :         CU_ASSERT_PTR_NULL(entry->buf);
     146                 :          3 :         entry = &mod0_entries[7];
     147                 :          3 :         entry->buf = spdk_iobuf_get(entry->ioch, SMALL_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
     148                 :          3 :         CU_ASSERT_PTR_NULL(entry->buf);
     149                 :            : 
     150                 :            :         /* Now return one of the large buffers to the pool and verify that the first request's
     151                 :            :          * (entry 2) callback was executed and it was removed from the wait queue.
     152                 :            :          */
     153                 :          3 :         set_thread(0);
     154                 :          3 :         entry = &mod0_entries[0];
     155                 :          3 :         spdk_iobuf_put(entry->ioch, entry->buf, LARGE_BUFSIZE);
     156                 :          3 :         entry = &mod0_entries[2];
     157                 :          3 :         CU_ASSERT_PTR_NOT_NULL(entry->buf);
     158                 :          3 :         entry = &mod0_entries[3];
     159                 :          3 :         CU_ASSERT_PTR_NULL(entry->buf);
     160                 :            : 
     161                 :            :         /* Return the second buffer and check that the other request is satisfied */
     162                 :          3 :         entry = &mod0_entries[1];
     163                 :          3 :         spdk_iobuf_put(entry->ioch, entry->buf, LARGE_BUFSIZE);
     164                 :          3 :         entry = &mod0_entries[3];
     165                 :          3 :         CU_ASSERT_PTR_NOT_NULL(entry->buf);
     166                 :            : 
     167                 :            :         /* Return the remaining two buffers */
     168                 :          3 :         entry = &mod0_entries[2];
     169                 :          3 :         spdk_iobuf_put(entry->ioch, entry->buf, LARGE_BUFSIZE);
     170                 :          3 :         entry = &mod0_entries[3];
     171                 :          3 :         spdk_iobuf_put(entry->ioch, entry->buf, LARGE_BUFSIZE);
     172                 :            : 
     173                 :            :         /* Check that it didn't change the requests waiting for the small buffers */
     174                 :          3 :         entry = &mod0_entries[6];
     175                 :          3 :         CU_ASSERT_PTR_NULL(entry->buf);
     176                 :          3 :         entry = &mod0_entries[7];
     177                 :          3 :         CU_ASSERT_PTR_NULL(entry->buf);
     178                 :            : 
     179                 :            :         /* Do the same test as above, this time using the small pool */
     180                 :          3 :         set_thread(1);
     181                 :          3 :         entry = &mod0_entries[4];
     182                 :          3 :         spdk_iobuf_put(entry->ioch, entry->buf, SMALL_BUFSIZE);
     183                 :          3 :         entry = &mod0_entries[6];
     184                 :          3 :         CU_ASSERT_PTR_NOT_NULL(entry->buf);
     185                 :          3 :         entry = &mod0_entries[7];
     186                 :          3 :         CU_ASSERT_PTR_NULL(entry->buf);
     187                 :            : 
     188                 :            :         /* Return the second buffer and check that the other request is satisfied */
     189                 :          3 :         entry = &mod0_entries[5];
     190                 :          3 :         spdk_iobuf_put(entry->ioch, entry->buf, SMALL_BUFSIZE);
     191                 :          3 :         entry = &mod0_entries[7];
     192                 :          3 :         CU_ASSERT_PTR_NOT_NULL(entry->buf);
     193                 :            : 
     194                 :            :         /* Return the remaining two buffers */
     195                 :          3 :         entry = &mod0_entries[6];
     196                 :          3 :         spdk_iobuf_put(entry->ioch, entry->buf, SMALL_BUFSIZE);
     197                 :          3 :         entry = &mod0_entries[7];
     198                 :          3 :         spdk_iobuf_put(entry->ioch, entry->buf, SMALL_BUFSIZE);
     199                 :            : 
     200                 :            :         /* Now check requesting buffers from different modules - first request all of them from one
     201                 :            :          * module, starting from the large pool
     202                 :            :          */
     203                 :          3 :         set_thread(0);
     204                 :          3 :         entry = &mod0_entries[0];
     205                 :          3 :         entry->buf = spdk_iobuf_get(entry->ioch, LARGE_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
     206                 :          3 :         CU_ASSERT_PTR_NOT_NULL(entry->buf);
     207                 :          3 :         entry = &mod0_entries[1];
     208                 :          3 :         entry->buf = spdk_iobuf_get(entry->ioch, LARGE_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
     209                 :          3 :         CU_ASSERT_PTR_NOT_NULL(entry->buf);
     210                 :            :         /* Request all of them from the small one */
     211                 :          3 :         set_thread(1);
     212                 :          3 :         entry = &mod0_entries[4];
     213                 :          3 :         entry->buf = spdk_iobuf_get(entry->ioch, SMALL_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
     214                 :          3 :         CU_ASSERT_PTR_NOT_NULL(entry->buf);
     215                 :          3 :         entry = &mod0_entries[5];
     216                 :          3 :         entry->buf = spdk_iobuf_get(entry->ioch, SMALL_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
     217                 :          3 :         CU_ASSERT_PTR_NOT_NULL(entry->buf);
     218                 :            : 
     219                 :            :         /* Request one buffer per module from each pool  */
     220                 :          3 :         set_thread(0);
     221                 :          3 :         entry = &mod1_entries[0];
     222                 :          3 :         entry->buf = spdk_iobuf_get(entry->ioch, LARGE_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
     223                 :          3 :         CU_ASSERT_PTR_NULL(entry->buf);
     224                 :          3 :         entry = &mod0_entries[3];
     225                 :          3 :         entry->buf = spdk_iobuf_get(entry->ioch, LARGE_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
     226                 :          3 :         CU_ASSERT_PTR_NULL(entry->buf);
     227                 :            :         /* Change the order from the small pool and request a buffer from mod0 first */
     228                 :          3 :         set_thread(1);
     229                 :          3 :         entry = &mod0_entries[6];
     230                 :          3 :         entry->buf = spdk_iobuf_get(entry->ioch, SMALL_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
     231                 :          3 :         CU_ASSERT_PTR_NULL(entry->buf);
     232                 :          3 :         entry = &mod1_entries[4];
     233                 :          3 :         entry->buf = spdk_iobuf_get(entry->ioch, SMALL_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
     234                 :          3 :         CU_ASSERT_PTR_NULL(entry->buf);
     235                 :            : 
     236                 :            :         /* Now return one buffer to the large pool */
     237                 :          3 :         set_thread(0);
     238                 :          3 :         entry = &mod0_entries[0];
     239                 :          3 :         spdk_iobuf_put(entry->ioch, entry->buf, LARGE_BUFSIZE);
     240                 :            : 
     241                 :            :         /* Make sure the request from mod1 got the buffer, as it was the first to request it */
     242                 :          3 :         entry = &mod1_entries[0];
     243                 :          3 :         CU_ASSERT_PTR_NOT_NULL(entry->buf);
     244                 :          3 :         entry = &mod0_entries[3];
     245                 :          3 :         CU_ASSERT_PTR_NULL(entry->buf);
     246                 :            : 
     247                 :            :         /* Return second buffer to the large pool and check the outstanding mod0 request */
     248                 :          3 :         entry = &mod0_entries[1];
     249                 :          3 :         spdk_iobuf_put(entry->ioch, entry->buf, LARGE_BUFSIZE);
     250                 :          3 :         entry = &mod0_entries[3];
     251                 :          3 :         CU_ASSERT_PTR_NOT_NULL(entry->buf);
     252                 :            : 
     253                 :            :         /* Return the remaining two buffers */
     254                 :          3 :         entry = &mod1_entries[0];
     255                 :          3 :         spdk_iobuf_put(entry->ioch, entry->buf, LARGE_BUFSIZE);
     256                 :          3 :         entry = &mod0_entries[3];
     257                 :          3 :         spdk_iobuf_put(entry->ioch, entry->buf, LARGE_BUFSIZE);
     258                 :            : 
     259                 :            :         /* Check the same for the small pool, but this time the order of the request is reversed
     260                 :            :          * (mod0 before mod1)
     261                 :            :          */
     262                 :          3 :         set_thread(1);
     263                 :          3 :         entry = &mod0_entries[4];
     264                 :          3 :         spdk_iobuf_put(entry->ioch, entry->buf, SMALL_BUFSIZE);
     265                 :          3 :         entry = &mod0_entries[6];
     266                 :          3 :         CU_ASSERT_PTR_NOT_NULL(entry->buf);
     267                 :            :         /* mod1 request was second in this case, so it still needs to wait */
     268                 :          3 :         entry = &mod1_entries[4];
     269                 :          3 :         CU_ASSERT_PTR_NULL(entry->buf);
     270                 :            : 
     271                 :            :         /* Return the second requested buffer */
     272                 :          3 :         entry = &mod0_entries[5];
     273                 :          3 :         spdk_iobuf_put(entry->ioch, entry->buf, SMALL_BUFSIZE);
     274                 :          3 :         entry = &mod1_entries[4];
     275                 :          3 :         CU_ASSERT_PTR_NOT_NULL(entry->buf);
     276                 :            : 
     277                 :            :         /* Return the remaining two buffers */
     278                 :          3 :         entry = &mod0_entries[6];
     279                 :          3 :         spdk_iobuf_put(entry->ioch, entry->buf, SMALL_BUFSIZE);
     280                 :          3 :         entry = &mod1_entries[4];
     281                 :          3 :         spdk_iobuf_put(entry->ioch, entry->buf, SMALL_BUFSIZE);
     282                 :            : 
     283                 :            :         /* Request buffers to make the pools empty */
     284                 :          3 :         set_thread(0);
     285                 :          3 :         entry = &mod0_entries[0];
     286                 :          3 :         entry->buf = spdk_iobuf_get(entry->ioch, LARGE_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
     287                 :          3 :         CU_ASSERT_PTR_NOT_NULL(entry->buf);
     288                 :          3 :         entry = &mod1_entries[0];
     289                 :          3 :         entry->buf = spdk_iobuf_get(entry->ioch, LARGE_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
     290                 :          3 :         CU_ASSERT_PTR_NOT_NULL(entry->buf);
     291                 :          3 :         entry = &mod0_entries[1];
     292                 :          3 :         entry->buf = spdk_iobuf_get(entry->ioch, SMALL_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
     293                 :          3 :         CU_ASSERT_PTR_NOT_NULL(entry->buf);
     294                 :          3 :         entry = &mod1_entries[1];
     295                 :          3 :         entry->buf = spdk_iobuf_get(entry->ioch, SMALL_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
     296                 :          3 :         CU_ASSERT_PTR_NOT_NULL(entry->buf);
     297                 :            : 
     298                 :            :         /* Queue more requests from both modules */
     299                 :          3 :         entry = &mod0_entries[2];
     300                 :          3 :         entry->buf = spdk_iobuf_get(entry->ioch, LARGE_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
     301                 :          3 :         CU_ASSERT_PTR_NULL(entry->buf);
     302                 :          3 :         entry = &mod1_entries[2];
     303                 :          3 :         entry->buf = spdk_iobuf_get(entry->ioch, LARGE_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
     304                 :          3 :         CU_ASSERT_PTR_NULL(entry->buf);
     305                 :          3 :         entry = &mod1_entries[3];
     306                 :          3 :         entry->buf = spdk_iobuf_get(entry->ioch, SMALL_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
     307                 :          3 :         CU_ASSERT_PTR_NULL(entry->buf);
     308                 :          3 :         entry = &mod0_entries[3];
     309                 :          3 :         entry->buf = spdk_iobuf_get(entry->ioch, SMALL_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
     310                 :          3 :         CU_ASSERT_PTR_NULL(entry->buf);
     311                 :            : 
     312                 :            :         /* Check that abort correctly remove an entry from the queue */
     313                 :          3 :         entry = &mod0_entries[2];
     314                 :          3 :         spdk_iobuf_entry_abort(entry->ioch, &entry->iobuf, LARGE_BUFSIZE);
     315                 :          3 :         entry = &mod1_entries[3];
     316                 :          3 :         spdk_iobuf_entry_abort(entry->ioch, &entry->iobuf, SMALL_BUFSIZE);
     317                 :            : 
     318                 :          3 :         entry = &mod0_entries[0];
     319                 :          3 :         spdk_iobuf_put(entry->ioch, entry->buf, LARGE_BUFSIZE);
     320                 :          3 :         CU_ASSERT_PTR_NOT_NULL(mod1_entries[2].buf);
     321                 :          3 :         entry = &mod0_entries[1];
     322                 :          3 :         spdk_iobuf_put(entry->ioch, entry->buf, SMALL_BUFSIZE);
     323                 :          3 :         CU_ASSERT_PTR_NOT_NULL(mod0_entries[3].buf);
     324                 :            : 
     325                 :            :         /* Clean up */
     326                 :          3 :         entry = &mod1_entries[0];
     327                 :          3 :         spdk_iobuf_put(entry->ioch, entry->buf, LARGE_BUFSIZE);
     328                 :          3 :         entry = &mod1_entries[2];
     329                 :          3 :         spdk_iobuf_put(entry->ioch, entry->buf, LARGE_BUFSIZE);
     330                 :          3 :         entry = &mod1_entries[1];
     331                 :          3 :         spdk_iobuf_put(entry->ioch, entry->buf, SMALL_BUFSIZE);
     332                 :          3 :         entry = &mod0_entries[3];
     333                 :          3 :         spdk_iobuf_put(entry->ioch, entry->buf, SMALL_BUFSIZE);
     334                 :            : 
     335                 :            :         /* Request buffers to make the pools empty */
     336                 :          3 :         set_thread(0);
     337                 :          3 :         entry = &mod0_entries[0];
     338                 :          3 :         entry->buf = spdk_iobuf_get(entry->ioch, LARGE_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
     339                 :          3 :         CU_ASSERT_PTR_NOT_NULL(entry->buf);
     340                 :          3 :         entry = &mod1_entries[0];
     341                 :          3 :         entry->buf = spdk_iobuf_get(entry->ioch, LARGE_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
     342                 :          3 :         CU_ASSERT_PTR_NOT_NULL(entry->buf);
     343                 :          3 :         entry = &mod0_entries[1];
     344                 :          3 :         entry->buf = spdk_iobuf_get(entry->ioch, SMALL_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
     345                 :          3 :         CU_ASSERT_PTR_NOT_NULL(entry->buf);
     346                 :          3 :         entry = &mod1_entries[1];
     347                 :          3 :         entry->buf = spdk_iobuf_get(entry->ioch, SMALL_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
     348                 :          3 :         CU_ASSERT_PTR_NOT_NULL(entry->buf);
     349                 :            : 
     350                 :            :         /* Request a buffer from each queue and each module on thread 0 */
     351                 :          3 :         set_thread(0);
     352                 :          3 :         entry = &mod0_entries[2];
     353                 :          3 :         entry->buf = spdk_iobuf_get(entry->ioch, LARGE_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
     354                 :          3 :         CU_ASSERT_PTR_NULL(entry->buf);
     355                 :          3 :         entry = &mod1_entries[2];
     356                 :          3 :         entry->buf = spdk_iobuf_get(entry->ioch, LARGE_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
     357                 :          3 :         CU_ASSERT_PTR_NULL(entry->buf);
     358                 :          3 :         entry = &mod0_entries[3];
     359                 :          3 :         entry->buf = spdk_iobuf_get(entry->ioch, SMALL_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
     360                 :          3 :         CU_ASSERT_PTR_NULL(entry->buf);
     361                 :          3 :         entry = &mod1_entries[3];
     362                 :          3 :         entry->buf = spdk_iobuf_get(entry->ioch, SMALL_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
     363                 :          3 :         CU_ASSERT_PTR_NULL(entry->buf);
     364                 :            : 
     365                 :            :         /* Do the same on thread 1 */
     366                 :          3 :         set_thread(1);
     367                 :          3 :         entry = &mod0_entries[6];
     368                 :          3 :         entry->buf = spdk_iobuf_get(entry->ioch, LARGE_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
     369                 :          3 :         CU_ASSERT_PTR_NULL(entry->buf);
     370                 :          3 :         entry = &mod1_entries[6];
     371                 :          3 :         entry->buf = spdk_iobuf_get(entry->ioch, LARGE_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
     372                 :          3 :         CU_ASSERT_PTR_NULL(entry->buf);
     373                 :          3 :         entry = &mod0_entries[7];
     374                 :          3 :         entry->buf = spdk_iobuf_get(entry->ioch, SMALL_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
     375                 :          3 :         CU_ASSERT_PTR_NULL(entry->buf);
     376                 :          3 :         entry = &mod1_entries[7];
     377                 :          3 :         entry->buf = spdk_iobuf_get(entry->ioch, SMALL_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
     378                 :          3 :         CU_ASSERT_PTR_NULL(entry->buf);
     379                 :            : 
     380                 :            :         /* Now do the foreach and check that correct entries are iterated over by assigning their
     381                 :            :          * ->buf pointers to different values.
     382                 :            :          */
     383                 :          3 :         set_thread(0);
     384                 :          3 :         rc = spdk_iobuf_for_each_entry(&mod0_ch[0], &mod0_ch[0].large,
     385                 :            :                                        ut_iobuf_foreach_cb, (void *)0xdeadbeef);
     386                 :          3 :         CU_ASSERT_EQUAL(rc, 0);
     387                 :          3 :         rc = spdk_iobuf_for_each_entry(&mod0_ch[0], &mod0_ch[0].small,
     388                 :            :                                        ut_iobuf_foreach_cb, (void *)0xbeefdead);
     389                 :          3 :         CU_ASSERT_EQUAL(rc, 0);
     390                 :          3 :         rc = spdk_iobuf_for_each_entry(&mod1_ch[0], &mod1_ch[0].large,
     391                 :            :                                        ut_iobuf_foreach_cb, (void *)0xfeedbeef);
     392                 :          3 :         CU_ASSERT_EQUAL(rc, 0);
     393                 :          3 :         rc = spdk_iobuf_for_each_entry(&mod1_ch[0], &mod1_ch[0].small,
     394                 :            :                                        ut_iobuf_foreach_cb, (void *)0xbeeffeed);
     395                 :          3 :         CU_ASSERT_EQUAL(rc, 0);
     396                 :          3 :         set_thread(1);
     397                 :          3 :         rc = spdk_iobuf_for_each_entry(&mod0_ch[1], &mod0_ch[1].large,
     398                 :            :                                        ut_iobuf_foreach_cb, (void *)0xcafebabe);
     399                 :          3 :         CU_ASSERT_EQUAL(rc, 0);
     400                 :          3 :         rc = spdk_iobuf_for_each_entry(&mod0_ch[1], &mod0_ch[1].small,
     401                 :            :                                        ut_iobuf_foreach_cb, (void *)0xbabecafe);
     402                 :          3 :         CU_ASSERT_EQUAL(rc, 0);
     403                 :          3 :         rc = spdk_iobuf_for_each_entry(&mod1_ch[1], &mod1_ch[1].large,
     404                 :            :                                        ut_iobuf_foreach_cb, (void *)0xbeefcafe);
     405                 :          3 :         CU_ASSERT_EQUAL(rc, 0);
     406                 :          3 :         rc = spdk_iobuf_for_each_entry(&mod1_ch[1], &mod1_ch[1].small,
     407                 :            :                                        ut_iobuf_foreach_cb, (void *)0xcafebeef);
     408                 :          3 :         CU_ASSERT_EQUAL(rc, 0);
     409                 :            : 
     410                 :            :         /* thread 0 */
     411                 :          3 :         CU_ASSERT_PTR_EQUAL(mod0_entries[2].buf, (void *)0xdeadbeef);
     412                 :          3 :         CU_ASSERT_PTR_EQUAL(mod0_entries[3].buf, (void *)0xbeefdead);
     413                 :          3 :         CU_ASSERT_PTR_EQUAL(mod1_entries[2].buf, (void *)0xfeedbeef);
     414                 :          3 :         CU_ASSERT_PTR_EQUAL(mod1_entries[3].buf, (void *)0xbeeffeed);
     415                 :            :         /* thread 1 */
     416                 :          3 :         CU_ASSERT_PTR_EQUAL(mod0_entries[6].buf, (void *)0xcafebabe);
     417                 :          3 :         CU_ASSERT_PTR_EQUAL(mod0_entries[7].buf, (void *)0xbabecafe);
     418                 :          3 :         CU_ASSERT_PTR_EQUAL(mod1_entries[6].buf, (void *)0xbeefcafe);
     419                 :          3 :         CU_ASSERT_PTR_EQUAL(mod1_entries[7].buf, (void *)0xcafebeef);
     420                 :            : 
     421                 :            :         /* Clean everything up */
     422                 :          3 :         set_thread(0);
     423                 :          3 :         entry = &mod0_entries[2];
     424                 :          3 :         spdk_iobuf_entry_abort(entry->ioch, &entry->iobuf, LARGE_BUFSIZE);
     425                 :          3 :         entry = &mod0_entries[3];
     426                 :          3 :         spdk_iobuf_entry_abort(entry->ioch, &entry->iobuf, SMALL_BUFSIZE);
     427                 :          3 :         entry = &mod1_entries[2];
     428                 :          3 :         spdk_iobuf_entry_abort(entry->ioch, &entry->iobuf, LARGE_BUFSIZE);
     429                 :          3 :         entry = &mod1_entries[3];
     430                 :          3 :         spdk_iobuf_entry_abort(entry->ioch, &entry->iobuf, SMALL_BUFSIZE);
     431                 :            : 
     432                 :          3 :         entry = &mod0_entries[0];
     433                 :          3 :         spdk_iobuf_put(entry->ioch, entry->buf, LARGE_BUFSIZE);
     434                 :          3 :         entry = &mod1_entries[0];
     435                 :          3 :         spdk_iobuf_put(entry->ioch, entry->buf, LARGE_BUFSIZE);
     436                 :          3 :         entry = &mod0_entries[1];
     437                 :          3 :         spdk_iobuf_put(entry->ioch, entry->buf, SMALL_BUFSIZE);
     438                 :          3 :         entry = &mod1_entries[1];
     439                 :          3 :         spdk_iobuf_put(entry->ioch, entry->buf, SMALL_BUFSIZE);
     440                 :            : 
     441                 :          3 :         set_thread(1);
     442                 :          3 :         entry = &mod0_entries[6];
     443                 :          3 :         spdk_iobuf_entry_abort(entry->ioch, &entry->iobuf, LARGE_BUFSIZE);
     444                 :          3 :         entry = &mod0_entries[7];
     445                 :          3 :         spdk_iobuf_entry_abort(entry->ioch, &entry->iobuf, SMALL_BUFSIZE);
     446                 :          3 :         entry = &mod1_entries[6];
     447                 :          3 :         spdk_iobuf_entry_abort(entry->ioch, &entry->iobuf, LARGE_BUFSIZE);
     448                 :          3 :         entry = &mod1_entries[7];
     449                 :          3 :         spdk_iobuf_entry_abort(entry->ioch, &entry->iobuf, SMALL_BUFSIZE);
     450                 :            : 
     451                 :          3 :         set_thread(0);
     452                 :          3 :         spdk_iobuf_channel_fini(&mod0_ch[0]);
     453                 :          3 :         poll_threads();
     454                 :          3 :         spdk_iobuf_channel_fini(&mod1_ch[0]);
     455                 :          3 :         poll_threads();
     456                 :          3 :         set_thread(1);
     457                 :          3 :         spdk_iobuf_channel_fini(&mod0_ch[1]);
     458                 :          3 :         poll_threads();
     459                 :          3 :         spdk_iobuf_channel_fini(&mod1_ch[1]);
     460                 :          3 :         poll_threads();
     461                 :            : 
     462                 :          3 :         spdk_iobuf_finish(ut_iobuf_finish_cb, &finish);
     463                 :          3 :         poll_threads();
     464                 :            : 
     465                 :          3 :         CU_ASSERT_EQUAL(finish, 1);
     466                 :            : 
     467                 :          3 :         free_threads();
     468                 :          3 :         free_cores();
     469                 :          3 : }
     470                 :            : 
     471                 :            : static void
     472                 :          3 : iobuf_cache(void)
     473                 :            : {
     474                 :          3 :         struct spdk_iobuf_opts opts = {
     475                 :            :                 .small_pool_count = 4,
     476                 :            :                 .large_pool_count = 4,
     477                 :            :                 .small_bufsize = SMALL_BUFSIZE,
     478                 :            :                 .large_bufsize = LARGE_BUFSIZE,
     479                 :            :         };
     480                 :          3 :         struct spdk_iobuf_channel iobuf_ch[2];
     481                 :            :         struct ut_iobuf_entry *entry;
     482                 :          3 :         struct ut_iobuf_entry mod0_entries[] = {
     483                 :            :                 { .thread_id = 0, .module = "ut_module0", },
     484                 :            :                 { .thread_id = 0, .module = "ut_module0", },
     485                 :            :                 { .thread_id = 0, .module = "ut_module0", },
     486                 :            :                 { .thread_id = 0, .module = "ut_module0", },
     487                 :            :         };
     488                 :          3 :         struct ut_iobuf_entry mod1_entries[] = {
     489                 :            :                 { .thread_id = 0, .module = "ut_module1", },
     490                 :            :                 { .thread_id = 0, .module = "ut_module1", },
     491                 :            :         };
     492                 :          3 :         int rc, finish = 0;
     493                 :            :         uint32_t i, j, bufsize;
     494                 :            : 
     495                 :          3 :         allocate_cores(1);
     496                 :          3 :         allocate_threads(1);
     497                 :            : 
     498                 :          3 :         set_thread(0);
     499                 :            : 
     500                 :            :         /* We cannot use spdk_iobuf_set_opts(), as it won't allow us to use such small pools */
     501                 :          3 :         g_iobuf.opts = opts;
     502                 :          3 :         rc = spdk_iobuf_initialize();
     503                 :          3 :         CU_ASSERT_EQUAL(rc, 0);
     504                 :            : 
     505                 :          3 :         rc = spdk_iobuf_register_module("ut_module0");
     506                 :          3 :         CU_ASSERT_EQUAL(rc, 0);
     507                 :            : 
     508                 :          3 :         rc = spdk_iobuf_register_module("ut_module1");
     509                 :          3 :         CU_ASSERT_EQUAL(rc, 0);
     510                 :            : 
     511                 :            :         /* First check that channel initialization fails when it's not possible to fill in the cache
     512                 :            :          * from the pool.
     513                 :            :          */
     514                 :          3 :         rc = spdk_iobuf_channel_init(&iobuf_ch[0], "ut_module0", 5, 1);
     515                 :          3 :         CU_ASSERT_EQUAL(rc, -ENOMEM);
     516                 :          3 :         rc = spdk_iobuf_channel_init(&iobuf_ch[0], "ut_module0", 1, 5);
     517                 :          3 :         CU_ASSERT_EQUAL(rc, -ENOMEM);
     518                 :            : 
     519                 :          3 :         rc = spdk_iobuf_channel_init(&iobuf_ch[0], "ut_module0", 4, 4);
     520                 :          3 :         CU_ASSERT_EQUAL(rc, 0);
     521                 :          3 :         rc = spdk_iobuf_channel_init(&iobuf_ch[1], "ut_module1", 4, 4);
     522                 :          3 :         CU_ASSERT_EQUAL(rc, -ENOMEM);
     523                 :            : 
     524                 :          3 :         spdk_iobuf_channel_fini(&iobuf_ch[0]);
     525                 :          3 :         poll_threads();
     526                 :            : 
     527                 :            :         /* Initialize one channel with cache, acquire buffers, and check that a second one can be
     528                 :            :          * created once the buffers acquired from the first one are returned to the pool
     529                 :            :          */
     530                 :          3 :         rc = spdk_iobuf_channel_init(&iobuf_ch[0], "ut_module0", 2, 2);
     531                 :          3 :         CU_ASSERT_EQUAL(rc, 0);
     532                 :            : 
     533         [ +  + ]:         12 :         for (i = 0; i < 3; ++i) {
     534                 :          9 :                 mod0_entries[i].buf = spdk_iobuf_get(&iobuf_ch[0], LARGE_BUFSIZE, &mod0_entries[i].iobuf,
     535                 :            :                                                      ut_iobuf_get_buf_cb);
     536                 :          9 :                 CU_ASSERT_PTR_NOT_NULL(mod0_entries[i].buf);
     537                 :            :         }
     538                 :            : 
     539                 :            :         /* The channels can be temporarily greedy, holding more buffers than their configured cache
     540                 :            :          * size. We can only guarantee that we can create a channel if all outstanding buffers
     541                 :            :          * have been returned. */
     542         [ +  + ]:         12 :         for (i = 0; i < 3; ++i) {
     543                 :          9 :                 spdk_iobuf_put(&iobuf_ch[0], mod0_entries[i].buf, LARGE_BUFSIZE);
     544                 :            :         }
     545                 :            : 
     546                 :            :         /* The last buffer should be released back to the pool, so we should be able to create a new
     547                 :            :          * channel
     548                 :            :          */
     549                 :          3 :         rc = spdk_iobuf_channel_init(&iobuf_ch[1], "ut_module1", 2, 2);
     550                 :          3 :         CU_ASSERT_EQUAL(rc, 0);
     551                 :            : 
     552                 :          3 :         spdk_iobuf_channel_fini(&iobuf_ch[0]);
     553                 :          3 :         spdk_iobuf_channel_fini(&iobuf_ch[1]);
     554                 :          3 :         poll_threads();
     555                 :            : 
     556                 :            :         /* Check that the pool is only used when the cache is empty and that the cache guarantees a
     557                 :            :          * certain set of buffers
     558                 :            :          */
     559                 :          3 :         rc = spdk_iobuf_channel_init(&iobuf_ch[0], "ut_module0", 2, 2);
     560                 :          3 :         CU_ASSERT_EQUAL(rc, 0);
     561                 :          3 :         rc = spdk_iobuf_channel_init(&iobuf_ch[1], "ut_module1", 1, 1);
     562                 :          3 :         CU_ASSERT_EQUAL(rc, 0);
     563                 :            : 
     564                 :          3 :         uint32_t buffer_sizes[] = { SMALL_BUFSIZE, LARGE_BUFSIZE };
     565         [ +  + ]:          9 :         for (i = 0; i < SPDK_COUNTOF(buffer_sizes); ++i) {
     566                 :          6 :                 bufsize = buffer_sizes[i];
     567                 :            : 
     568         [ +  + ]:         24 :                 for (j = 0; j < 3; ++j) {
     569                 :         18 :                         entry = &mod0_entries[j];
     570                 :         18 :                         entry->buf = spdk_iobuf_get(&iobuf_ch[0], bufsize, &entry->iobuf,
     571                 :            :                                                     ut_iobuf_get_buf_cb);
     572                 :         18 :                         CU_ASSERT_PTR_NOT_NULL(entry->buf);
     573                 :            :                 }
     574                 :            : 
     575                 :          6 :                 mod1_entries[0].buf = spdk_iobuf_get(&iobuf_ch[1], bufsize, &mod1_entries[0].iobuf,
     576                 :            :                                                      ut_iobuf_get_buf_cb);
     577                 :          6 :                 CU_ASSERT_PTR_NOT_NULL(mod1_entries[0].buf);
     578                 :            : 
     579                 :            :                 /* The whole pool is exhausted now */
     580                 :          6 :                 mod1_entries[1].buf = spdk_iobuf_get(&iobuf_ch[1], bufsize, &mod1_entries[1].iobuf,
     581                 :            :                                                      ut_iobuf_get_buf_cb);
     582                 :          6 :                 CU_ASSERT_PTR_NULL(mod1_entries[1].buf);
     583                 :          6 :                 mod0_entries[3].buf = spdk_iobuf_get(&iobuf_ch[0], bufsize, &mod0_entries[3].iobuf,
     584                 :            :                                                      ut_iobuf_get_buf_cb);
     585                 :          6 :                 CU_ASSERT_PTR_NULL(mod0_entries[3].buf);
     586                 :            : 
     587                 :            :                 /* If there are outstanding requests waiting for a buffer, they should have priority
     588                 :            :                  * over filling in the cache, even if they're from different modules.
     589                 :            :                  */
     590                 :          6 :                 spdk_iobuf_put(&iobuf_ch[0], mod0_entries[2].buf, bufsize);
     591                 :            :                 /* Also make sure the queue is FIFO and doesn't care about which module requested
     592                 :            :                  * and which module released the buffer.
     593                 :            :                  */
     594                 :          6 :                 CU_ASSERT_PTR_NOT_NULL(mod1_entries[1].buf);
     595                 :          6 :                 CU_ASSERT_PTR_NULL(mod0_entries[3].buf);
     596                 :            : 
     597                 :            :                 /* Return the buffers back */
     598                 :          6 :                 spdk_iobuf_entry_abort(&iobuf_ch[0], &mod0_entries[3].iobuf, bufsize);
     599         [ +  + ]:         18 :                 for (j = 0; j < 2; ++j) {
     600                 :         12 :                         spdk_iobuf_put(&iobuf_ch[0], mod0_entries[j].buf, bufsize);
     601                 :         12 :                         spdk_iobuf_put(&iobuf_ch[1], mod1_entries[j].buf, bufsize);
     602                 :            :                 }
     603                 :            :         }
     604                 :            : 
     605                 :          3 :         spdk_iobuf_channel_fini(&iobuf_ch[0]);
     606                 :          3 :         spdk_iobuf_channel_fini(&iobuf_ch[1]);
     607                 :          3 :         poll_threads();
     608                 :            : 
     609                 :          3 :         spdk_iobuf_finish(ut_iobuf_finish_cb, &finish);
     610                 :          3 :         poll_threads();
     611                 :            : 
     612                 :          3 :         CU_ASSERT_EQUAL(finish, 1);
     613                 :            : 
     614                 :          3 :         free_threads();
     615                 :          3 :         free_cores();
     616                 :          3 : }
     617                 :            : 
     618                 :            : int
     619                 :          3 : main(int argc, char **argv)
     620                 :            : {
     621                 :          3 :         CU_pSuite       suite = NULL;
     622                 :            :         unsigned int    num_failures;
     623                 :            : 
     624                 :          3 :         CU_initialize_registry();
     625                 :            : 
     626                 :          3 :         suite = CU_add_suite("io_channel", NULL, NULL);
     627                 :          3 :         CU_ADD_TEST(suite, iobuf);
     628                 :          3 :         CU_ADD_TEST(suite, iobuf_cache);
     629                 :            : 
     630                 :          3 :         num_failures = spdk_ut_run_tests(argc, argv, NULL);
     631                 :          3 :         CU_cleanup_registry();
     632                 :          3 :         return num_failures;
     633                 :            : }

Generated by: LCOV version 1.14