LCOV - code coverage report
Current view: top level - module/bdev/zone_block - vbdev_zone_block.c (source / functions) Hit Total Coverage
Test: ut_cov_unit.info Lines: 329 456 72.1 %
Date: 2024-07-12 14:42:41 Functions: 28 37 75.7 %

          Line data    Source code
       1             : /*   SPDX-License-Identifier: BSD-3-Clause
       2             :  *   Copyright (C) 2019 Intel Corporation.
       3             :  *   Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES.
       4             :  *   All rights reserved.
       5             :  */
       6             : 
       7             : #include "spdk/stdinc.h"
       8             : 
       9             : #include "vbdev_zone_block.h"
      10             : 
      11             : #include "spdk/config.h"
      12             : #include "spdk/nvme.h"
      13             : #include "spdk/bdev_zone.h"
      14             : 
      15             : #include "spdk/log.h"
      16             : 
      17             : /* This namespace UUID was generated using uuid_generate() method. */
      18             : #define BDEV_ZONE_BLOCK_NAMESPACE_UUID "5f3f485a-d6bb-4443-9de7-023683b77389"
      19             : 
      20             : static int zone_block_init(void);
      21             : static int zone_block_get_ctx_size(void);
      22             : static void zone_block_finish(void);
      23             : static int zone_block_config_json(struct spdk_json_write_ctx *w);
      24             : static void zone_block_examine(struct spdk_bdev *bdev);
      25             : 
      26             : static struct spdk_bdev_module bdev_zoned_if = {
      27             :         .name = "bdev_zoned_block",
      28             :         .module_init = zone_block_init,
      29             :         .module_fini = zone_block_finish,
      30             :         .config_json = zone_block_config_json,
      31             :         .examine_config = zone_block_examine,
      32             :         .get_ctx_size = zone_block_get_ctx_size,
      33             : };
      34             : 
      35           1 : SPDK_BDEV_MODULE_REGISTER(bdev_zoned_block, &bdev_zoned_if)
      36             : 
      37             : /* List of block vbdev names and their base bdevs via configuration file.
      38             :  * Used so we can parse the conf once at init and use this list in examine().
      39             :  */
      40             : struct bdev_zone_block_config {
      41             :         char                                    *vbdev_name;
      42             :         char                                    *bdev_name;
      43             :         uint64_t                                zone_capacity;
      44             :         uint64_t                                optimal_open_zones;
      45             :         TAILQ_ENTRY(bdev_zone_block_config)     link;
      46             : };
      47             : static TAILQ_HEAD(, bdev_zone_block_config) g_bdev_configs = TAILQ_HEAD_INITIALIZER(g_bdev_configs);
      48             : 
      49             : struct block_zone {
      50             :         struct spdk_bdev_zone_info zone_info;
      51             :         pthread_spinlock_t lock;
      52             : };
      53             : 
      54             : /* List of block vbdevs and associated info for each. */
      55             : struct bdev_zone_block {
      56             :         struct spdk_bdev                bdev;    /* the block zoned bdev */
      57             :         struct spdk_bdev_desc           *base_desc; /* its descriptor we get from open */
      58             :         struct block_zone               *zones; /* array of zones */
      59             :         uint64_t                        num_zones; /* number of zones */
      60             :         uint64_t                        zone_capacity; /* zone capacity */
      61             :         uint64_t                        zone_shift; /* log2 of zone_size */
      62             :         TAILQ_ENTRY(bdev_zone_block)    link;
      63             :         struct spdk_thread              *thread; /* thread where base device is opened */
      64             : };
      65             : static TAILQ_HEAD(, bdev_zone_block) g_bdev_nodes = TAILQ_HEAD_INITIALIZER(g_bdev_nodes);
      66             : 
      67             : struct zone_block_io_channel {
      68             :         struct spdk_io_channel  *base_ch; /* IO channel of base device */
      69             : };
      70             : 
      71             : struct zone_block_io {
      72             :         /* vbdev to which IO was issued */
      73             :         struct bdev_zone_block *bdev_zone_block;
      74             : };
      75             : 
      76             : static int
      77          11 : zone_block_init(void)
      78             : {
      79          11 :         return 0;
      80             : }
      81             : 
      82             : static void
      83          13 : zone_block_remove_config(struct bdev_zone_block_config *name)
      84             : {
      85          13 :         TAILQ_REMOVE(&g_bdev_configs, name, link);
      86          13 :         free(name->bdev_name);
      87          13 :         free(name->vbdev_name);
      88          13 :         free(name);
      89          13 : }
      90             : 
      91             : static void
      92          11 : zone_block_finish(void)
      93             : {
      94             :         struct bdev_zone_block_config *name;
      95             : 
      96          11 :         while ((name = TAILQ_FIRST(&g_bdev_configs))) {
      97           0 :                 zone_block_remove_config(name);
      98             :         }
      99          11 : }
     100             : 
     101             : static int
     102           0 : zone_block_get_ctx_size(void)
     103             : {
     104           0 :         return sizeof(struct zone_block_io);
     105             : }
     106             : 
     107             : static int
     108           0 : zone_block_config_json(struct spdk_json_write_ctx *w)
     109             : {
     110             :         struct bdev_zone_block *bdev_node;
     111           0 :         struct spdk_bdev *base_bdev = NULL;
     112             : 
     113           0 :         TAILQ_FOREACH(bdev_node, &g_bdev_nodes, link) {
     114           0 :                 base_bdev = spdk_bdev_desc_get_bdev(bdev_node->base_desc);
     115           0 :                 spdk_json_write_object_begin(w);
     116           0 :                 spdk_json_write_named_string(w, "method", "bdev_zone_block_create");
     117           0 :                 spdk_json_write_named_object_begin(w, "params");
     118           0 :                 spdk_json_write_named_string(w, "base_bdev", spdk_bdev_get_name(base_bdev));
     119           0 :                 spdk_json_write_named_string(w, "name", spdk_bdev_get_name(&bdev_node->bdev));
     120           0 :                 spdk_json_write_named_uint64(w, "zone_capacity", bdev_node->zone_capacity);
     121           0 :                 spdk_json_write_named_uint64(w, "optimal_open_zones", bdev_node->bdev.optimal_open_zones);
     122           0 :                 spdk_json_write_object_end(w);
     123           0 :                 spdk_json_write_object_end(w);
     124             :         }
     125             : 
     126           0 :         return 0;
     127             : }
     128             : 
     129             : /* Callback for unregistering the IO device. */
     130             : static void
     131          12 : _device_unregister_cb(void *io_device)
     132             : {
     133          12 :         struct bdev_zone_block *bdev_node = io_device;
     134             :         uint64_t i;
     135             : 
     136          12 :         free(bdev_node->bdev.name);
     137         200 :         for (i = 0; i < bdev_node->num_zones; i++) {
     138         188 :                 pthread_spin_destroy(&bdev_node->zones[i].lock);
     139             :         }
     140          12 :         free(bdev_node->zones);
     141          12 :         free(bdev_node);
     142          12 : }
     143             : 
     144             : static void
     145           0 : _zone_block_destruct(void *ctx)
     146             : {
     147           0 :         struct spdk_bdev_desc *desc = ctx;
     148             : 
     149           0 :         spdk_bdev_close(desc);
     150           0 : }
     151             : 
     152             : static int
     153          12 : zone_block_destruct(void *ctx)
     154             : {
     155          12 :         struct bdev_zone_block *bdev_node = (struct bdev_zone_block *)ctx;
     156             : 
     157          12 :         TAILQ_REMOVE(&g_bdev_nodes, bdev_node, link);
     158             : 
     159             :         /* Unclaim the underlying bdev. */
     160          12 :         spdk_bdev_module_release_bdev(spdk_bdev_desc_get_bdev(bdev_node->base_desc));
     161             : 
     162             :         /* Close the underlying bdev on its same opened thread. */
     163          12 :         if (bdev_node->thread && bdev_node->thread != spdk_get_thread()) {
     164           0 :                 spdk_thread_send_msg(bdev_node->thread, _zone_block_destruct, bdev_node->base_desc);
     165             :         } else {
     166          12 :                 spdk_bdev_close(bdev_node->base_desc);
     167             :         }
     168             : 
     169             :         /* Unregister the io_device. */
     170          12 :         spdk_io_device_unregister(bdev_node, _device_unregister_cb);
     171             : 
     172          12 :         return 0;
     173             : }
     174             : 
     175             : static struct block_zone *
     176         503 : zone_block_get_zone_containing_lba(struct bdev_zone_block *bdev_node, uint64_t lba)
     177             : {
     178         503 :         size_t index = lba >> bdev_node->zone_shift;
     179             : 
     180         503 :         if (index >= bdev_node->num_zones) {
     181           9 :                 return NULL;
     182             :         }
     183             : 
     184         494 :         return &bdev_node->zones[index];
     185             : }
     186             : 
     187             : static struct block_zone *
     188         359 : zone_block_get_zone_by_slba(struct bdev_zone_block *bdev_node, uint64_t start_lba)
     189             : {
     190         359 :         struct block_zone *zone = zone_block_get_zone_containing_lba(bdev_node, start_lba);
     191             : 
     192         359 :         if (zone && zone->zone_info.zone_id == start_lba) {
     193         347 :                 return zone;
     194             :         } else {
     195          12 :                 return NULL;
     196             :         }
     197             : }
     198             : 
     199             : static int
     200         105 : zone_block_get_zone_info(struct bdev_zone_block *bdev_node, struct spdk_bdev_io *bdev_io)
     201             : {
     202             :         struct block_zone *zone;
     203         105 :         struct spdk_bdev_zone_info *zone_info = bdev_io->u.zone_mgmt.buf;
     204         105 :         uint64_t zone_id = bdev_io->u.zone_mgmt.zone_id;
     205             :         size_t i;
     206             : 
     207             :         /* User can request info for more zones than exist, need to check both internal and user
     208             :          * boundaries
     209             :          */
     210         221 :         for (i = 0; i < bdev_io->u.zone_mgmt.num_zones; i++, zone_id += bdev_node->bdev.zone_size) {
     211         119 :                 zone = zone_block_get_zone_by_slba(bdev_node, zone_id);
     212         119 :                 if (!zone) {
     213           3 :                         return -EINVAL;
     214             :                 }
     215         116 :                 memcpy(&zone_info[i], &zone->zone_info, sizeof(*zone_info));
     216             :         }
     217             : 
     218         102 :         spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_SUCCESS);
     219         102 :         return 0;
     220             : }
     221             : 
     222             : static int
     223          21 : zone_block_open_zone(struct block_zone *zone, struct spdk_bdev_io *bdev_io)
     224             : {
     225          21 :         pthread_spin_lock(&zone->lock);
     226             : 
     227          21 :         switch (zone->zone_info.state) {
     228          20 :         case SPDK_BDEV_ZONE_STATE_EMPTY:
     229             :         case SPDK_BDEV_ZONE_STATE_OPEN:
     230             :         case SPDK_BDEV_ZONE_STATE_CLOSED:
     231          20 :                 zone->zone_info.state = SPDK_BDEV_ZONE_STATE_OPEN;
     232          20 :                 pthread_spin_unlock(&zone->lock);
     233          20 :                 spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_SUCCESS);
     234          20 :                 return 0;
     235           1 :         default:
     236           1 :                 pthread_spin_unlock(&zone->lock);
     237           1 :                 return -EINVAL;
     238             :         }
     239             : }
     240             : 
     241             : static void
     242          70 : _zone_block_complete_unmap(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
     243             : {
     244          70 :         struct spdk_bdev_io *orig_io = cb_arg;
     245          70 :         int status = success ? SPDK_BDEV_IO_STATUS_SUCCESS : SPDK_BDEV_IO_STATUS_FAILED;
     246             : 
     247             :         /* Complete the original IO and then free the one that we created here
     248             :          * as a result of issuing an IO via submit_request.
     249             :          */
     250          70 :         spdk_bdev_io_complete(orig_io, status);
     251          70 :         spdk_bdev_free_io(bdev_io);
     252          70 : }
     253             : 
     254             : static int
     255          71 : zone_block_reset_zone(struct bdev_zone_block *bdev_node, struct zone_block_io_channel *ch,
     256             :                       struct block_zone *zone, struct spdk_bdev_io *bdev_io)
     257             : {
     258          71 :         pthread_spin_lock(&zone->lock);
     259             : 
     260          71 :         switch (zone->zone_info.state) {
     261           1 :         case SPDK_BDEV_ZONE_STATE_EMPTY:
     262           1 :                 pthread_spin_unlock(&zone->lock);
     263           1 :                 spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_SUCCESS);
     264           1 :                 return 0;
     265          70 :         case SPDK_BDEV_ZONE_STATE_OPEN:
     266             :         case SPDK_BDEV_ZONE_STATE_FULL:
     267             :         case SPDK_BDEV_ZONE_STATE_CLOSED:
     268          70 :                 zone->zone_info.state = SPDK_BDEV_ZONE_STATE_EMPTY;
     269          70 :                 zone->zone_info.write_pointer = zone->zone_info.zone_id;
     270          70 :                 pthread_spin_unlock(&zone->lock);
     271             : 
     272             :                 /* The unmap isn't necessary, so if the base bdev doesn't support it, we're done */
     273          70 :                 if (!spdk_bdev_io_type_supported(spdk_bdev_desc_get_bdev(bdev_node->base_desc),
     274             :                                                  SPDK_BDEV_IO_TYPE_UNMAP)) {
     275           0 :                         spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_SUCCESS);
     276           0 :                         return 0;
     277             :                 }
     278             : 
     279          70 :                 return spdk_bdev_unmap_blocks(bdev_node->base_desc, ch->base_ch,
     280             :                                               zone->zone_info.zone_id, zone->zone_info.capacity,
     281             :                                               _zone_block_complete_unmap, bdev_io);
     282           0 :         default:
     283           0 :                 pthread_spin_unlock(&zone->lock);
     284           0 :                 return -EINVAL;
     285             :         }
     286             : }
     287             : 
     288             : static int
     289           5 : zone_block_close_zone(struct block_zone *zone, struct spdk_bdev_io *bdev_io)
     290             : {
     291           5 :         pthread_spin_lock(&zone->lock);
     292             : 
     293           5 :         switch (zone->zone_info.state) {
     294           3 :         case SPDK_BDEV_ZONE_STATE_OPEN:
     295             :         case SPDK_BDEV_ZONE_STATE_CLOSED:
     296           3 :                 zone->zone_info.state = SPDK_BDEV_ZONE_STATE_CLOSED;
     297           3 :                 pthread_spin_unlock(&zone->lock);
     298           3 :                 spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_SUCCESS);
     299           3 :                 return 0;
     300           2 :         default:
     301           2 :                 pthread_spin_unlock(&zone->lock);
     302           2 :                 return -EINVAL;
     303             :         }
     304             : }
     305             : 
     306             : static int
     307           3 : zone_block_finish_zone(struct block_zone *zone, struct spdk_bdev_io *bdev_io)
     308             : {
     309           3 :         pthread_spin_lock(&zone->lock);
     310             : 
     311           3 :         zone->zone_info.write_pointer = zone->zone_info.zone_id + zone->zone_info.capacity;
     312           3 :         zone->zone_info.state = SPDK_BDEV_ZONE_STATE_FULL;
     313             : 
     314           3 :         pthread_spin_unlock(&zone->lock);
     315           3 :         spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_SUCCESS);
     316           3 :         return 0;
     317             : }
     318             : 
     319             : static int
     320         108 : zone_block_zone_management(struct bdev_zone_block *bdev_node, struct zone_block_io_channel *ch,
     321             :                            struct spdk_bdev_io *bdev_io)
     322             : {
     323             :         struct block_zone *zone;
     324             : 
     325         108 :         zone = zone_block_get_zone_by_slba(bdev_node, bdev_io->u.zone_mgmt.zone_id);
     326         108 :         if (!zone) {
     327           8 :                 return -EINVAL;
     328             :         }
     329             : 
     330         100 :         switch (bdev_io->u.zone_mgmt.zone_action) {
     331          71 :         case SPDK_BDEV_ZONE_RESET:
     332          71 :                 return zone_block_reset_zone(bdev_node, ch, zone, bdev_io);
     333          21 :         case SPDK_BDEV_ZONE_OPEN:
     334          21 :                 return zone_block_open_zone(zone, bdev_io);
     335           5 :         case SPDK_BDEV_ZONE_CLOSE:
     336           5 :                 return zone_block_close_zone(zone, bdev_io);
     337           3 :         case SPDK_BDEV_ZONE_FINISH:
     338           3 :                 return zone_block_finish_zone(zone, bdev_io);
     339           0 :         default:
     340           0 :                 return -EINVAL;
     341             :         }
     342             : }
     343             : 
     344             : static void
     345         260 : _zone_block_complete_write(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
     346             : {
     347         260 :         struct spdk_bdev_io *orig_io = cb_arg;
     348         260 :         int status = success ? SPDK_BDEV_IO_STATUS_SUCCESS : SPDK_BDEV_IO_STATUS_FAILED;
     349             : 
     350         260 :         if (success && orig_io->type == SPDK_BDEV_IO_TYPE_ZONE_APPEND) {
     351         129 :                 orig_io->u.bdev.offset_blocks = bdev_io->u.bdev.offset_blocks;
     352             :         }
     353             : 
     354             :         /* Complete the original IO and then free the one that we created here
     355             :          * as a result of issuing an IO via submit_request.
     356             :          */
     357         260 :         spdk_bdev_io_complete(orig_io, status);
     358         260 :         spdk_bdev_free_io(bdev_io);
     359         260 : }
     360             : 
     361             : static int
     362         268 : zone_block_write(struct bdev_zone_block *bdev_node, struct zone_block_io_channel *ch,
     363             :                  struct spdk_bdev_io *bdev_io)
     364             : {
     365             :         struct block_zone *zone;
     366         268 :         uint64_t len = bdev_io->u.bdev.num_blocks;
     367         268 :         uint64_t lba = bdev_io->u.bdev.offset_blocks;
     368             :         uint64_t num_blocks_left, wp;
     369         268 :         int rc = 0;
     370         268 :         bool is_append = bdev_io->type == SPDK_BDEV_IO_TYPE_ZONE_APPEND;
     371             : 
     372         268 :         if (is_append) {
     373         132 :                 zone = zone_block_get_zone_by_slba(bdev_node, lba);
     374             :         } else {
     375         136 :                 zone = zone_block_get_zone_containing_lba(bdev_node, lba);
     376             :         }
     377         268 :         if (!zone) {
     378           2 :                 SPDK_ERRLOG("Trying to write to invalid zone (lba 0x%" PRIx64 ")\n", lba);
     379           2 :                 return -EINVAL;
     380             :         }
     381             : 
     382         266 :         pthread_spin_lock(&zone->lock);
     383             : 
     384         266 :         switch (zone->zone_info.state) {
     385         264 :         case SPDK_BDEV_ZONE_STATE_OPEN:
     386             :         case SPDK_BDEV_ZONE_STATE_EMPTY:
     387             :         case SPDK_BDEV_ZONE_STATE_CLOSED:
     388         264 :                 zone->zone_info.state = SPDK_BDEV_ZONE_STATE_OPEN;
     389         264 :                 break;
     390           2 :         default:
     391           2 :                 SPDK_ERRLOG("Trying to write to zone in invalid state %u\n", zone->zone_info.state);
     392           2 :                 rc = -EINVAL;
     393           2 :                 goto write_fail;
     394             :         }
     395             : 
     396         264 :         wp = zone->zone_info.write_pointer;
     397         264 :         if (is_append) {
     398         130 :                 lba = wp;
     399             :         } else {
     400         134 :                 if (lba != wp) {
     401           2 :                         SPDK_ERRLOG("Trying to write to zone with invalid address (lba 0x%" PRIx64 ", wp 0x%" PRIx64 ")\n",
     402             :                                     lba, wp);
     403           2 :                         rc = -EINVAL;
     404           2 :                         goto write_fail;
     405             :                 }
     406             :         }
     407             : 
     408         262 :         num_blocks_left = zone->zone_info.zone_id + zone->zone_info.capacity - wp;
     409         262 :         if (len > num_blocks_left) {
     410           2 :                 SPDK_ERRLOG("Write exceeds zone capacity (lba 0x%" PRIx64 ", len 0x%" PRIx64 ", wp 0x%" PRIx64
     411             :                             ")\n", lba, len, wp);
     412           2 :                 rc = -EINVAL;
     413           2 :                 goto write_fail;
     414             :         }
     415             : 
     416         260 :         zone->zone_info.write_pointer += bdev_io->u.bdev.num_blocks;
     417         260 :         assert(zone->zone_info.write_pointer <= zone->zone_info.zone_id + zone->zone_info.capacity);
     418         260 :         if (zone->zone_info.write_pointer == zone->zone_info.zone_id + zone->zone_info.capacity) {
     419           2 :                 zone->zone_info.state = SPDK_BDEV_ZONE_STATE_FULL;
     420             :         }
     421         260 :         pthread_spin_unlock(&zone->lock);
     422             : 
     423         260 :         rc = spdk_bdev_writev_blocks_with_md(bdev_node->base_desc, ch->base_ch,
     424             :                                              bdev_io->u.bdev.iovs, bdev_io->u.bdev.iovcnt,
     425             :                                              bdev_io->u.bdev.md_buf,
     426             :                                              lba, bdev_io->u.bdev.num_blocks,
     427             :                                              _zone_block_complete_write, bdev_io);
     428             : 
     429         260 :         return rc;
     430             : 
     431           6 : write_fail:
     432           6 :         pthread_spin_unlock(&zone->lock);
     433           6 :         return rc;
     434             : }
     435             : 
     436             : static void
     437           5 : _zone_block_complete_read(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
     438             : {
     439           5 :         struct spdk_bdev_io *orig_io = cb_arg;
     440           5 :         int status = success ? SPDK_BDEV_IO_STATUS_SUCCESS : SPDK_BDEV_IO_STATUS_FAILED;
     441             : 
     442             :         /* Complete the original IO and then free the one that we created here
     443             :          * as a result of issuing an IO via submit_request.
     444             :          */
     445           5 :         spdk_bdev_io_complete(orig_io, status);
     446           5 :         spdk_bdev_free_io(bdev_io);
     447           5 : }
     448             : 
     449             : static int
     450           8 : zone_block_read(struct bdev_zone_block *bdev_node, struct zone_block_io_channel *ch,
     451             :                 struct spdk_bdev_io *bdev_io)
     452             : {
     453             :         struct block_zone *zone;
     454           8 :         uint64_t len = bdev_io->u.bdev.num_blocks;
     455           8 :         uint64_t lba = bdev_io->u.bdev.offset_blocks;
     456             :         int rc;
     457             : 
     458           8 :         zone = zone_block_get_zone_containing_lba(bdev_node, lba);
     459           8 :         if (!zone) {
     460           1 :                 SPDK_ERRLOG("Trying to read from invalid zone (lba 0x%" PRIx64 ")\n", lba);
     461           1 :                 return -EINVAL;
     462             :         }
     463             : 
     464           7 :         if ((lba + len) > (zone->zone_info.zone_id + zone->zone_info.capacity)) {
     465           2 :                 SPDK_ERRLOG("Read exceeds zone capacity (lba 0x%" PRIx64 ", len 0x%" PRIx64 ")\n", lba, len);
     466           2 :                 return -EINVAL;
     467             :         }
     468             : 
     469           5 :         rc = spdk_bdev_readv_blocks_with_md(bdev_node->base_desc, ch->base_ch,
     470             :                                             bdev_io->u.bdev.iovs, bdev_io->u.bdev.iovcnt,
     471             :                                             bdev_io->u.bdev.md_buf,
     472             :                                             lba, len,
     473             :                                             _zone_block_complete_read, bdev_io);
     474             : 
     475           5 :         return rc;
     476             : }
     477             : 
     478             : static void
     479         489 : zone_block_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
     480             : {
     481         489 :         struct bdev_zone_block *bdev_node = SPDK_CONTAINEROF(bdev_io->bdev, struct bdev_zone_block, bdev);
     482         489 :         struct zone_block_io_channel *dev_ch = spdk_io_channel_get_ctx(ch);
     483         489 :         int rc = 0;
     484             : 
     485         489 :         switch (bdev_io->type) {
     486         105 :         case SPDK_BDEV_IO_TYPE_GET_ZONE_INFO:
     487         105 :                 rc = zone_block_get_zone_info(bdev_node, bdev_io);
     488         105 :                 break;
     489         108 :         case SPDK_BDEV_IO_TYPE_ZONE_MANAGEMENT:
     490         108 :                 rc = zone_block_zone_management(bdev_node, dev_ch, bdev_io);
     491         108 :                 break;
     492         268 :         case SPDK_BDEV_IO_TYPE_WRITE:
     493             :         case SPDK_BDEV_IO_TYPE_ZONE_APPEND:
     494         268 :                 rc = zone_block_write(bdev_node, dev_ch, bdev_io);
     495         268 :                 break;
     496           8 :         case SPDK_BDEV_IO_TYPE_READ:
     497           8 :                 rc = zone_block_read(bdev_node, dev_ch, bdev_io);
     498           8 :                 break;
     499           0 :         default:
     500           0 :                 SPDK_ERRLOG("vbdev_block: unknown I/O type %u\n", bdev_io->type);
     501           0 :                 rc = -ENOTSUP;
     502           0 :                 break;
     503             :         }
     504             : 
     505         489 :         if (rc != 0) {
     506          25 :                 if (rc == -ENOMEM) {
     507           0 :                         SPDK_WARNLOG("ENOMEM, start to queue io for vbdev.\n");
     508           0 :                         spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_NOMEM);
     509             :                 } else {
     510          25 :                         SPDK_ERRLOG("ERROR on bdev_io submission!\n");
     511          25 :                         spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
     512             :                 }
     513             :         }
     514         489 : }
     515             : 
     516             : static bool
     517          12 : zone_block_io_type_supported(void *ctx, enum spdk_bdev_io_type io_type)
     518             : {
     519          12 :         switch (io_type) {
     520           4 :         case SPDK_BDEV_IO_TYPE_ZONE_MANAGEMENT:
     521             :         case SPDK_BDEV_IO_TYPE_WRITE:
     522             :         case SPDK_BDEV_IO_TYPE_READ:
     523             :         case SPDK_BDEV_IO_TYPE_ZONE_APPEND:
     524           4 :                 return true;
     525           8 :         default:
     526           8 :                 return false;
     527             :         }
     528             : }
     529             : 
     530             : static struct spdk_io_channel *
     531           0 : zone_block_get_io_channel(void *ctx)
     532             : {
     533           0 :         struct bdev_zone_block *bdev_node = (struct bdev_zone_block *)ctx;
     534             : 
     535           0 :         return spdk_get_io_channel(bdev_node);
     536             : }
     537             : 
     538             : static int
     539           0 : zone_block_dump_info_json(void *ctx, struct spdk_json_write_ctx *w)
     540             : {
     541           0 :         struct bdev_zone_block *bdev_node = (struct bdev_zone_block *)ctx;
     542           0 :         struct spdk_bdev *base_bdev = spdk_bdev_desc_get_bdev(bdev_node->base_desc);
     543             : 
     544           0 :         spdk_json_write_name(w, "zoned_block");
     545           0 :         spdk_json_write_object_begin(w);
     546           0 :         spdk_json_write_named_string(w, "name", spdk_bdev_get_name(&bdev_node->bdev));
     547           0 :         spdk_json_write_named_string(w, "base_bdev", spdk_bdev_get_name(base_bdev));
     548           0 :         spdk_json_write_named_uint64(w, "zone_capacity", bdev_node->zone_capacity);
     549           0 :         spdk_json_write_named_uint64(w, "optimal_open_zones", bdev_node->bdev.optimal_open_zones);
     550           0 :         spdk_json_write_object_end(w);
     551             : 
     552           0 :         return 0;
     553             : }
     554             : 
     555             : /* When we register our vbdev this is how we specify our entry points. */
     556             : static const struct spdk_bdev_fn_table zone_block_fn_table = {
     557             :         .destruct               = zone_block_destruct,
     558             :         .submit_request         = zone_block_submit_request,
     559             :         .io_type_supported      = zone_block_io_type_supported,
     560             :         .get_io_channel         = zone_block_get_io_channel,
     561             :         .dump_info_json         = zone_block_dump_info_json,
     562             : };
     563             : 
     564             : static void
     565           0 : zone_block_base_bdev_hotremove_cb(struct spdk_bdev *bdev_find)
     566             : {
     567             :         struct bdev_zone_block *bdev_node, *tmp;
     568             : 
     569           0 :         TAILQ_FOREACH_SAFE(bdev_node, &g_bdev_nodes, link, tmp) {
     570           0 :                 if (bdev_find == spdk_bdev_desc_get_bdev(bdev_node->base_desc)) {
     571           0 :                         spdk_bdev_unregister(&bdev_node->bdev, NULL, NULL);
     572             :                 }
     573             :         }
     574           0 : }
     575             : 
     576             : static void
     577           0 : zone_block_base_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev,
     578             :                               void *event_ctx)
     579             : {
     580           0 :         switch (type) {
     581           0 :         case SPDK_BDEV_EVENT_REMOVE:
     582           0 :                 zone_block_base_bdev_hotremove_cb(bdev);
     583           0 :                 break;
     584           0 :         default:
     585           0 :                 SPDK_NOTICELOG("Unsupported bdev event: type %d\n", type);
     586           0 :                 break;
     587             :         }
     588           0 : }
     589             : 
     590             : static int
     591           0 : _zone_block_ch_create_cb(void *io_device, void *ctx_buf)
     592             : {
     593           0 :         struct zone_block_io_channel *bdev_ch = ctx_buf;
     594           0 :         struct bdev_zone_block *bdev_node = io_device;
     595             : 
     596           0 :         bdev_ch->base_ch = spdk_bdev_get_io_channel(bdev_node->base_desc);
     597           0 :         if (!bdev_ch->base_ch) {
     598           0 :                 return -ENOMEM;
     599             :         }
     600             : 
     601           0 :         return 0;
     602             : }
     603             : 
     604             : static void
     605           0 : _zone_block_ch_destroy_cb(void *io_device, void *ctx_buf)
     606             : {
     607           0 :         struct zone_block_io_channel *bdev_ch = ctx_buf;
     608             : 
     609           0 :         spdk_put_io_channel(bdev_ch->base_ch);
     610           0 : }
     611             : 
     612             : static int
     613          14 : zone_block_insert_name(const char *bdev_name, const char *vbdev_name, uint64_t zone_capacity,
     614             :                        uint64_t optimal_open_zones)
     615             : {
     616             :         struct bdev_zone_block_config *name;
     617             : 
     618          15 :         TAILQ_FOREACH(name, &g_bdev_configs, link) {
     619           2 :                 if (strcmp(vbdev_name, name->vbdev_name) == 0) {
     620           0 :                         SPDK_ERRLOG("block zoned bdev %s already exists\n", vbdev_name);
     621           0 :                         return -EEXIST;
     622             :                 }
     623           2 :                 if (strcmp(bdev_name, name->bdev_name) == 0) {
     624           1 :                         SPDK_ERRLOG("base bdev %s already claimed\n", bdev_name);
     625           1 :                         return -EEXIST;
     626             :                 }
     627             :         }
     628             : 
     629          13 :         name = calloc(1, sizeof(*name));
     630          13 :         if (!name) {
     631           0 :                 SPDK_ERRLOG("could not allocate bdev_names\n");
     632           0 :                 return -ENOMEM;
     633             :         }
     634             : 
     635          13 :         name->bdev_name = strdup(bdev_name);
     636          13 :         if (!name->bdev_name) {
     637           0 :                 SPDK_ERRLOG("could not allocate name->bdev_name\n");
     638           0 :                 free(name);
     639           0 :                 return -ENOMEM;
     640             :         }
     641             : 
     642          13 :         name->vbdev_name = strdup(vbdev_name);
     643          13 :         if (!name->vbdev_name) {
     644           0 :                 SPDK_ERRLOG("could not allocate name->vbdev_name\n");
     645           0 :                 free(name->bdev_name);
     646           0 :                 free(name);
     647           0 :                 return -ENOMEM;
     648             :         }
     649             : 
     650          13 :         name->zone_capacity = zone_capacity;
     651          13 :         name->optimal_open_zones = optimal_open_zones;
     652             : 
     653          13 :         TAILQ_INSERT_TAIL(&g_bdev_configs, name, link);
     654             : 
     655          13 :         return 0;
     656             : }
     657             : 
     658             : static int
     659          12 : zone_block_init_zone_info(struct bdev_zone_block *bdev_node)
     660             : {
     661             :         size_t i;
     662             :         struct block_zone *zone;
     663          12 :         int rc = 0;
     664             : 
     665         200 :         for (i = 0; i < bdev_node->num_zones; i++) {
     666         188 :                 zone = &bdev_node->zones[i];
     667         188 :                 zone->zone_info.zone_id = bdev_node->bdev.zone_size * i;
     668         188 :                 zone->zone_info.capacity = bdev_node->zone_capacity;
     669         188 :                 zone->zone_info.write_pointer = zone->zone_info.zone_id + zone->zone_info.capacity;
     670         188 :                 zone->zone_info.state = SPDK_BDEV_ZONE_STATE_FULL;
     671         188 :                 zone->zone_info.type = SPDK_BDEV_ZONE_TYPE_SEQWR;
     672         188 :                 if (pthread_spin_init(&zone->lock, PTHREAD_PROCESS_PRIVATE)) {
     673           0 :                         SPDK_ERRLOG("pthread_spin_init() failed\n");
     674           0 :                         rc = -ENOMEM;
     675           0 :                         break;
     676             :                 }
     677             :         }
     678             : 
     679          12 :         if (rc) {
     680           0 :                 for (; i > 0; i--) {
     681           0 :                         pthread_spin_destroy(&bdev_node->zones[i - 1].lock);
     682             :                 }
     683             :         }
     684             : 
     685          12 :         return rc;
     686             : }
     687             : 
     688             : static int
     689          14 : zone_block_register(const char *base_bdev_name)
     690             : {
     691          14 :         struct spdk_bdev_desc *base_desc;
     692             :         struct spdk_bdev *base_bdev;
     693             :         struct bdev_zone_block_config *name, *tmp;
     694             :         struct bdev_zone_block *bdev_node;
     695          14 :         struct spdk_uuid ns_uuid;
     696             :         uint64_t zone_size;
     697          14 :         int rc = 0;
     698             : 
     699          14 :         spdk_uuid_parse(&ns_uuid, BDEV_ZONE_BLOCK_NAMESPACE_UUID);
     700             : 
     701             :         /* Check our list of names from config versus this bdev and if
     702             :          * there's a match, create the bdev_node & bdev accordingly.
     703             :          */
     704          27 :         TAILQ_FOREACH_SAFE(name, &g_bdev_configs, link, tmp) {
     705          15 :                 if (strcmp(name->bdev_name, base_bdev_name) != 0) {
     706           1 :                         continue;
     707             :                 }
     708             : 
     709          14 :                 rc = spdk_bdev_open_ext(base_bdev_name, true, zone_block_base_bdev_event_cb,
     710             :                                         NULL, &base_desc);
     711          14 :                 if (rc == -ENODEV) {
     712           1 :                         return -ENODEV;
     713          13 :                 } else if (rc) {
     714           0 :                         SPDK_ERRLOG("could not open bdev %s\n", base_bdev_name);
     715           0 :                         goto free_config;
     716             :                 }
     717             : 
     718          13 :                 base_bdev = spdk_bdev_desc_get_bdev(base_desc);
     719             : 
     720          13 :                 if (spdk_bdev_is_zoned(base_bdev)) {
     721           1 :                         SPDK_ERRLOG("Base bdev %s is already a zoned bdev\n", base_bdev_name);
     722           1 :                         rc = -EEXIST;
     723           1 :                         goto zone_exist;
     724             :                 }
     725             : 
     726          12 :                 bdev_node = calloc(1, sizeof(struct bdev_zone_block));
     727          12 :                 if (!bdev_node) {
     728           0 :                         rc = -ENOMEM;
     729           0 :                         SPDK_ERRLOG("could not allocate bdev_node\n");
     730           0 :                         goto zone_exist;
     731             :                 }
     732             : 
     733          12 :                 bdev_node->base_desc = base_desc;
     734             : 
     735             :                 /* The base bdev that we're attaching to. */
     736          12 :                 bdev_node->bdev.name = strdup(name->vbdev_name);
     737          12 :                 if (!bdev_node->bdev.name) {
     738           0 :                         rc = -ENOMEM;
     739           0 :                         SPDK_ERRLOG("could not allocate bdev_node name\n");
     740           0 :                         goto strdup_failed;
     741             :                 }
     742             : 
     743          12 :                 zone_size = spdk_align64pow2(name->zone_capacity);
     744          12 :                 if (zone_size == 0) {
     745           0 :                         rc = -EINVAL;
     746           0 :                         SPDK_ERRLOG("invalid zone size\n");
     747           0 :                         goto roundup_failed;
     748             :                 }
     749             : 
     750          12 :                 bdev_node->zone_shift = spdk_u64log2(zone_size);
     751          12 :                 bdev_node->num_zones = base_bdev->blockcnt / zone_size;
     752             : 
     753          12 :                 bdev_node->zones = calloc(bdev_node->num_zones, sizeof(struct block_zone));
     754          12 :                 if (!bdev_node->zones) {
     755           0 :                         rc = -ENOMEM;
     756           0 :                         SPDK_ERRLOG("could not allocate zones\n");
     757           0 :                         goto calloc_failed;
     758             :                 }
     759             : 
     760          12 :                 bdev_node->bdev.product_name = "zone_block";
     761             : 
     762             :                 /* Copy some properties from the underlying base bdev. */
     763          12 :                 bdev_node->bdev.write_cache = base_bdev->write_cache;
     764          12 :                 bdev_node->bdev.required_alignment = base_bdev->required_alignment;
     765          12 :                 bdev_node->bdev.optimal_io_boundary = base_bdev->optimal_io_boundary;
     766             : 
     767          12 :                 bdev_node->bdev.blocklen = base_bdev->blocklen;
     768          12 :                 bdev_node->bdev.blockcnt = bdev_node->num_zones * zone_size;
     769             : 
     770          12 :                 if (bdev_node->num_zones * name->zone_capacity != base_bdev->blockcnt) {
     771           0 :                         SPDK_DEBUGLOG(vbdev_zone_block,
     772             :                                       "Lost %" PRIu64 " blocks due to zone capacity and base bdev size misalignment\n",
     773             :                                       base_bdev->blockcnt - bdev_node->num_zones * name->zone_capacity);
     774             :                 }
     775             : 
     776          12 :                 bdev_node->bdev.write_unit_size = base_bdev->write_unit_size;
     777             : 
     778          12 :                 bdev_node->bdev.md_interleave = base_bdev->md_interleave;
     779          12 :                 bdev_node->bdev.md_len = base_bdev->md_len;
     780          12 :                 bdev_node->bdev.dif_type = base_bdev->dif_type;
     781          12 :                 bdev_node->bdev.dif_is_head_of_md = base_bdev->dif_is_head_of_md;
     782          12 :                 bdev_node->bdev.dif_check_flags = base_bdev->dif_check_flags;
     783             : 
     784          12 :                 bdev_node->bdev.zoned = true;
     785          12 :                 bdev_node->bdev.ctxt = bdev_node;
     786          12 :                 bdev_node->bdev.fn_table = &zone_block_fn_table;
     787          12 :                 bdev_node->bdev.module = &bdev_zoned_if;
     788             : 
     789             :                 /* Generate UUID based on namespace UUID + base bdev UUID. */
     790          12 :                 rc = spdk_uuid_generate_sha1(&bdev_node->bdev.uuid, &ns_uuid,
     791          12 :                                              (const char *)&base_bdev->uuid, sizeof(struct spdk_uuid));
     792          12 :                 if (rc) {
     793           0 :                         SPDK_ERRLOG("Unable to generate new UUID for zone block bdev\n");
     794           0 :                         goto uuid_generation_failed;
     795             :                 }
     796             : 
     797             :                 /* bdev specific info */
     798          12 :                 bdev_node->bdev.zone_size = zone_size;
     799             : 
     800          12 :                 bdev_node->zone_capacity = name->zone_capacity;
     801          12 :                 bdev_node->bdev.optimal_open_zones = name->optimal_open_zones;
     802          12 :                 bdev_node->bdev.max_open_zones = 0;
     803          12 :                 rc = zone_block_init_zone_info(bdev_node);
     804          12 :                 if (rc) {
     805           0 :                         SPDK_ERRLOG("could not init zone info\n");
     806           0 :                         goto zone_info_failed;
     807             :                 }
     808             : 
     809          12 :                 TAILQ_INSERT_TAIL(&g_bdev_nodes, bdev_node, link);
     810             : 
     811          12 :                 spdk_io_device_register(bdev_node, _zone_block_ch_create_cb, _zone_block_ch_destroy_cb,
     812             :                                         sizeof(struct zone_block_io_channel),
     813          12 :                                         name->vbdev_name);
     814             : 
     815             :                 /* Save the thread where the base device is opened */
     816          12 :                 bdev_node->thread = spdk_get_thread();
     817             : 
     818          12 :                 rc = spdk_bdev_module_claim_bdev(base_bdev, base_desc, bdev_node->bdev.module);
     819          12 :                 if (rc) {
     820           0 :                         SPDK_ERRLOG("could not claim bdev %s\n", base_bdev_name);
     821           0 :                         goto claim_failed;
     822             :                 }
     823             : 
     824          12 :                 rc = spdk_bdev_register(&bdev_node->bdev);
     825          12 :                 if (rc) {
     826           0 :                         SPDK_ERRLOG("could not register zoned bdev\n");
     827           0 :                         goto register_failed;
     828             :                 }
     829             :         }
     830             : 
     831          12 :         return rc;
     832             : 
     833           0 : register_failed:
     834           0 :         spdk_bdev_module_release_bdev(&bdev_node->bdev);
     835           0 : claim_failed:
     836           0 :         TAILQ_REMOVE(&g_bdev_nodes, bdev_node, link);
     837           0 :         spdk_io_device_unregister(bdev_node, NULL);
     838           0 : zone_info_failed:
     839           0 : uuid_generation_failed:
     840           0 :         free(bdev_node->zones);
     841           0 : calloc_failed:
     842           0 : roundup_failed:
     843           0 :         free(bdev_node->bdev.name);
     844           0 : strdup_failed:
     845           0 :         free(bdev_node);
     846           1 : zone_exist:
     847           1 :         spdk_bdev_close(base_desc);
     848           1 : free_config:
     849           1 :         zone_block_remove_config(name);
     850           1 :         return rc;
     851             : }
     852             : 
     853             : int
     854          16 : vbdev_zone_block_create(const char *bdev_name, const char *vbdev_name, uint64_t zone_capacity,
     855             :                         uint64_t optimal_open_zones)
     856             : {
     857          16 :         int rc = 0;
     858             : 
     859          16 :         if (zone_capacity == 0) {
     860           1 :                 SPDK_ERRLOG("Zone capacity can't be 0\n");
     861           1 :                 return -EINVAL;
     862             :         }
     863             : 
     864          15 :         if (optimal_open_zones == 0) {
     865           1 :                 SPDK_ERRLOG("Optimal open zones can't be 0\n");
     866           1 :                 return -EINVAL;
     867             :         }
     868             : 
     869             :         /* Insert the bdev into our global name list even if it doesn't exist yet,
     870             :          * it may show up soon...
     871             :          */
     872          14 :         rc = zone_block_insert_name(bdev_name, vbdev_name, zone_capacity, optimal_open_zones);
     873          14 :         if (rc) {
     874           1 :                 return rc;
     875             :         }
     876             : 
     877          13 :         rc = zone_block_register(bdev_name);
     878          13 :         if (rc == -ENODEV) {
     879             :                 /* This is not an error, even though the bdev is not present at this time it may
     880             :                  * still show up later.
     881             :                  */
     882           1 :                 rc = 0;
     883             :         }
     884          13 :         return rc;
     885             : }
     886             : 
     887             : void
     888          12 : vbdev_zone_block_delete(const char *name, spdk_bdev_unregister_cb cb_fn, void *cb_arg)
     889             : {
     890             :         struct bdev_zone_block_config *name_node;
     891             :         int rc;
     892             : 
     893          12 :         rc = spdk_bdev_unregister_by_name(name, &bdev_zoned_if, cb_fn, cb_arg);
     894          12 :         if (rc == 0) {
     895          12 :                 TAILQ_FOREACH(name_node, &g_bdev_configs, link) {
     896          12 :                         if (strcmp(name_node->vbdev_name, name) == 0) {
     897          12 :                                 zone_block_remove_config(name_node);
     898          12 :                                 break;
     899             :                         }
     900             :                 }
     901             :         } else {
     902           0 :                 cb_fn(cb_arg, rc);
     903             :         }
     904          12 : }
     905             : 
     906             : static void
     907           1 : zone_block_examine(struct spdk_bdev *bdev)
     908             : {
     909           1 :         zone_block_register(bdev->name);
     910             : 
     911           1 :         spdk_bdev_module_examine_done(&bdev_zoned_if);
     912           1 : }
     913             : 
     914           1 : SPDK_LOG_REGISTER_COMPONENT(vbdev_zone_block)

Generated by: LCOV version 1.15