LCOV - code coverage report
Current view: top level - module/bdev/raid - bdev_raid_sb.c (source / functions) Hit Total Coverage
Test: ut_cov_unit.info Lines: 186 223 83.4 %
Date: 2024-07-15 19:28:51 Functions: 16 16 100.0 %

          Line data    Source code
       1             : /*   SPDX-License-Identifier: BSD-3-Clause
       2             :  *   Copyright (C) 2022 Intel Corporation.
       3             :  *   All rights reserved.
       4             :  */
       5             : 
       6             : #include "spdk/bdev_module.h"
       7             : #include "spdk/crc32.h"
       8             : #include "spdk/env.h"
       9             : #include "spdk/log.h"
      10             : #include "spdk/string.h"
      11             : #include "spdk/util.h"
      12             : 
      13             : #include "bdev_raid.h"
      14             : 
      15             : struct raid_bdev_write_sb_ctx {
      16             :         struct raid_bdev *raid_bdev;
      17             :         int status;
      18             :         uint8_t submitted;
      19             :         uint8_t remaining;
      20             :         raid_bdev_write_sb_cb cb;
      21             :         void *cb_ctx;
      22             :         struct spdk_bdev_io_wait_entry wait_entry;
      23             : };
      24             : 
      25             : struct raid_bdev_read_sb_ctx {
      26             :         struct spdk_bdev_desc *desc;
      27             :         struct spdk_io_channel *ch;
      28             :         raid_bdev_load_sb_cb cb;
      29             :         void *cb_ctx;
      30             :         void *buf;
      31             :         uint32_t buf_size;
      32             : };
      33             : 
      34             : int
      35           3 : raid_bdev_alloc_superblock(struct raid_bdev *raid_bdev, uint32_t block_size)
      36             : {
      37             :         struct raid_bdev_superblock *sb;
      38             : 
      39           3 :         assert(raid_bdev->sb == NULL);
      40             : 
      41           3 :         sb = spdk_dma_zmalloc(SPDK_ALIGN_CEIL(RAID_BDEV_SB_MAX_LENGTH, block_size), 0x1000, NULL);
      42           3 :         if (!sb) {
      43           0 :                 SPDK_ERRLOG("Failed to allocate raid bdev sb buffer\n");
      44           0 :                 return -ENOMEM;
      45             :         }
      46             : 
      47           3 :         raid_bdev->sb = sb;
      48             : 
      49           3 :         return 0;
      50             : }
      51             : 
      52             : void
      53           3 : raid_bdev_free_superblock(struct raid_bdev *raid_bdev)
      54             : {
      55           3 :         if (raid_bdev->sb_io_buf != NULL && raid_bdev->sb_io_buf != raid_bdev->sb) {
      56           1 :                 assert(spdk_bdev_is_md_interleaved(&raid_bdev->bdev));
      57           1 :                 spdk_dma_free(raid_bdev->sb_io_buf);
      58           1 :                 raid_bdev->sb_io_buf = NULL;
      59             :         }
      60           3 :         spdk_dma_free(raid_bdev->sb);
      61           3 :         raid_bdev->sb = NULL;
      62           3 : }
      63             : 
      64             : void
      65           3 : raid_bdev_init_superblock(struct raid_bdev *raid_bdev)
      66             : {
      67           3 :         struct raid_bdev_superblock *sb = raid_bdev->sb;
      68             :         struct raid_base_bdev_info *base_info;
      69             :         struct raid_bdev_sb_base_bdev *sb_base_bdev;
      70             : 
      71           3 :         memcpy(&sb->signature, RAID_BDEV_SB_SIG, sizeof(sb->signature));
      72           3 :         sb->version.major = RAID_BDEV_SB_VERSION_MAJOR;
      73           3 :         sb->version.minor = RAID_BDEV_SB_VERSION_MINOR;
      74           3 :         spdk_uuid_copy(&sb->uuid, &raid_bdev->bdev.uuid);
      75           3 :         snprintf(sb->name, RAID_BDEV_SB_NAME_SIZE, "%s", raid_bdev->bdev.name);
      76           3 :         sb->raid_size = raid_bdev->bdev.blockcnt;
      77           3 :         sb->block_size = spdk_bdev_get_data_block_size(&raid_bdev->bdev);
      78           3 :         sb->level = raid_bdev->level;
      79           3 :         sb->strip_size = raid_bdev->strip_size;
      80             :         /* TODO: sb->state */
      81           3 :         sb->num_base_bdevs = sb->base_bdevs_size = raid_bdev->num_base_bdevs;
      82           3 :         sb->length = sizeof(*sb) + sizeof(*sb_base_bdev) * sb->base_bdevs_size;
      83             : 
      84           3 :         sb_base_bdev = &sb->base_bdevs[0];
      85          12 :         RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) {
      86           9 :                 spdk_uuid_copy(&sb_base_bdev->uuid, &base_info->uuid);
      87           9 :                 sb_base_bdev->data_offset = base_info->data_offset;
      88           9 :                 sb_base_bdev->data_size = base_info->data_size;
      89           9 :                 sb_base_bdev->state = RAID_SB_BASE_BDEV_CONFIGURED;
      90           9 :                 sb_base_bdev->slot = raid_bdev_base_bdev_slot(base_info);
      91           9 :                 sb_base_bdev++;
      92             :         }
      93           3 : }
      94             : 
      95             : static int
      96           6 : raid_bdev_alloc_sb_io_buf(struct raid_bdev *raid_bdev)
      97             : {
      98           6 :         struct raid_bdev_superblock *sb = raid_bdev->sb;
      99             : 
     100           6 :         if (spdk_bdev_is_md_interleaved(&raid_bdev->bdev)) {
     101           4 :                 raid_bdev->sb_io_buf_size = spdk_divide_round_up(sb->length,
     102           2 :                                             sb->block_size) * raid_bdev->bdev.blocklen;
     103           2 :                 raid_bdev->sb_io_buf = spdk_dma_zmalloc(raid_bdev->sb_io_buf_size, 0x1000, NULL);
     104           2 :                 if (!raid_bdev->sb_io_buf) {
     105           0 :                         SPDK_ERRLOG("Failed to allocate raid bdev sb io buffer\n");
     106           0 :                         return -ENOMEM;
     107             :                 }
     108             :         } else {
     109           4 :                 raid_bdev->sb_io_buf_size = SPDK_ALIGN_CEIL(sb->length, raid_bdev->bdev.blocklen);
     110           4 :                 raid_bdev->sb_io_buf = raid_bdev->sb;
     111             :         }
     112             : 
     113           6 :         return 0;
     114             : }
     115             : 
     116             : static void
     117          57 : raid_bdev_sb_update_crc(struct raid_bdev_superblock *sb)
     118             : {
     119          57 :         sb->crc = 0;
     120          57 :         sb->crc = spdk_crc32c_update(sb, sb->length, 0);
     121          57 : }
     122             : 
     123             : static bool
     124          27 : raid_bdev_sb_check_crc(struct raid_bdev_superblock *sb)
     125             : {
     126          27 :         uint32_t crc, prev = sb->crc;
     127             : 
     128          27 :         raid_bdev_sb_update_crc(sb);
     129          27 :         crc = sb->crc;
     130          27 :         sb->crc = prev;
     131             : 
     132          27 :         return crc == prev;
     133             : }
     134             : 
     135             : static int
     136          45 : raid_bdev_parse_superblock(struct raid_bdev_read_sb_ctx *ctx)
     137             : {
     138          45 :         struct raid_bdev_superblock *sb = ctx->buf;
     139          45 :         struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(ctx->desc);
     140             :         struct raid_bdev_sb_base_bdev *sb_base_bdev;
     141             :         uint8_t i;
     142             : 
     143          45 :         if (memcmp(sb->signature, RAID_BDEV_SB_SIG, sizeof(sb->signature))) {
     144           9 :                 SPDK_DEBUGLOG(bdev_raid_sb, "invalid signature\n");
     145           9 :                 return -EINVAL;
     146             :         }
     147             : 
     148          72 :         if (spdk_divide_round_up(sb->length, spdk_bdev_get_data_block_size(bdev)) >
     149          36 :             spdk_divide_round_up(ctx->buf_size, bdev->blocklen)) {
     150           9 :                 if (sb->length > RAID_BDEV_SB_MAX_LENGTH) {
     151           0 :                         SPDK_WARNLOG("Incorrect superblock length on bdev %s\n",
     152             :                                      spdk_bdev_get_name(bdev));
     153           0 :                         return -EINVAL;
     154             :                 }
     155             : 
     156           9 :                 return -EAGAIN;
     157             :         }
     158             : 
     159          27 :         if (!raid_bdev_sb_check_crc(sb)) {
     160           9 :                 SPDK_WARNLOG("Incorrect superblock crc on bdev %s\n", spdk_bdev_get_name(bdev));
     161           9 :                 return -EINVAL;
     162             :         }
     163             : 
     164          18 :         if (sb->version.major != RAID_BDEV_SB_VERSION_MAJOR) {
     165           3 :                 SPDK_ERRLOG("Not supported superblock major version %d on bdev %s\n",
     166             :                             sb->version.major, spdk_bdev_get_name(bdev));
     167           3 :                 return -EINVAL;
     168             :         }
     169             : 
     170          15 :         if (sb->version.minor > RAID_BDEV_SB_VERSION_MINOR) {
     171           0 :                 SPDK_WARNLOG("Superblock minor version %d on bdev %s is higher than the currently supported: %d\n",
     172             :                              sb->version.minor, spdk_bdev_get_name(bdev), RAID_BDEV_SB_VERSION_MINOR);
     173             :         }
     174             : 
     175          15 :         for (i = 0; i < sb->base_bdevs_size; i++) {
     176           3 :                 sb_base_bdev = &sb->base_bdevs[i];
     177           3 :                 if (sb_base_bdev->slot >= sb->num_base_bdevs) {
     178           3 :                         SPDK_WARNLOG("Invalid superblock base bdev slot number %u on bdev %s\n",
     179             :                                      sb_base_bdev->slot, spdk_bdev_get_name(bdev));
     180           3 :                         return -EINVAL;
     181             :                 }
     182             :         }
     183             : 
     184          12 :         return 0;
     185             : }
     186             : 
     187             : static void
     188          15 : raid_bdev_read_sb_ctx_free(struct raid_bdev_read_sb_ctx *ctx)
     189             : {
     190          15 :         spdk_dma_free(ctx->buf);
     191             : 
     192          15 :         free(ctx);
     193          15 : }
     194             : 
     195             : static void raid_bdev_read_sb_cb(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg);
     196             : 
     197             : static int
     198           6 : raid_bdev_read_sb_remainder(struct raid_bdev_read_sb_ctx *ctx)
     199             : {
     200           6 :         struct raid_bdev_superblock *sb = ctx->buf;
     201           6 :         struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(ctx->desc);
     202             :         uint32_t buf_size_prev;
     203             :         void *buf;
     204             :         int rc;
     205             : 
     206           6 :         buf_size_prev = ctx->buf_size;
     207           6 :         ctx->buf_size = spdk_divide_round_up(spdk_min(sb->length, RAID_BDEV_SB_MAX_LENGTH),
     208           6 :                                              spdk_bdev_get_data_block_size(bdev)) * bdev->blocklen;
     209           6 :         buf = spdk_dma_realloc(ctx->buf, ctx->buf_size, spdk_bdev_get_buf_align(bdev), NULL);
     210           6 :         if (buf == NULL) {
     211           0 :                 SPDK_ERRLOG("Failed to reallocate buffer\n");
     212           0 :                 return -ENOMEM;
     213             :         }
     214           6 :         ctx->buf = buf;
     215             : 
     216           6 :         rc = spdk_bdev_read(ctx->desc, ctx->ch, ctx->buf + buf_size_prev, buf_size_prev,
     217           6 :                             ctx->buf_size - buf_size_prev, raid_bdev_read_sb_cb, ctx);
     218           6 :         if (rc != 0) {
     219           0 :                 SPDK_ERRLOG("Failed to read bdev %s superblock remainder: %s\n",
     220             :                             spdk_bdev_get_name(bdev), spdk_strerror(-rc));
     221           0 :                 return rc;
     222             :         }
     223             : 
     224           6 :         return 0;
     225             : }
     226             : 
     227             : static void
     228          21 : raid_bdev_read_sb_cb(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
     229             : {
     230          21 :         struct spdk_bdev *bdev = bdev_io->bdev;
     231          21 :         struct raid_bdev_read_sb_ctx *ctx = cb_arg;
     232          21 :         struct raid_bdev_superblock *sb = NULL;
     233             :         int status;
     234             : 
     235          21 :         if (spdk_bdev_is_md_interleaved(bdev_io->bdev) && ctx->buf_size > bdev->blocklen) {
     236           2 :                 const uint32_t data_block_size = spdk_bdev_get_data_block_size(bdev);
     237             :                 uint32_t i;
     238             : 
     239           6 :                 for (i = 1; i < ctx->buf_size / bdev->blocklen; i++) {
     240           4 :                         memmove(ctx->buf + (i * data_block_size),
     241           4 :                                 ctx->buf + (i * bdev->blocklen),
     242             :                                 data_block_size);
     243             :                 }
     244             :         }
     245             : 
     246          21 :         spdk_bdev_free_io(bdev_io);
     247             : 
     248          21 :         if (!success) {
     249           0 :                 status = -EIO;
     250           0 :                 goto out;
     251             :         }
     252             : 
     253          21 :         status = raid_bdev_parse_superblock(ctx);
     254          21 :         if (status == -EAGAIN) {
     255           6 :                 status = raid_bdev_read_sb_remainder(ctx);
     256           6 :                 if (status == 0) {
     257           6 :                         return;
     258             :                 }
     259          15 :         } else if (status != 0) {
     260           9 :                 SPDK_DEBUGLOG(bdev_raid_sb, "failed to parse bdev %s superblock\n",
     261             :                               spdk_bdev_get_name(spdk_bdev_desc_get_bdev(ctx->desc)));
     262             :         } else {
     263           6 :                 sb = ctx->buf;
     264             :         }
     265          15 : out:
     266          15 :         ctx->cb(sb, status, ctx->cb_ctx);
     267             : 
     268          15 :         raid_bdev_read_sb_ctx_free(ctx);
     269             : }
     270             : 
     271             : int
     272          15 : raid_bdev_load_base_bdev_superblock(struct spdk_bdev_desc *desc, struct spdk_io_channel *ch,
     273             :                                     raid_bdev_load_sb_cb cb, void *cb_ctx)
     274             : {
     275          15 :         struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(desc);
     276             :         struct raid_bdev_read_sb_ctx *ctx;
     277             :         int rc;
     278             : 
     279          15 :         assert(cb != NULL);
     280             : 
     281          15 :         ctx = calloc(1, sizeof(*ctx));
     282          15 :         if (!ctx) {
     283           0 :                 return -ENOMEM;
     284             :         }
     285             : 
     286          15 :         ctx->desc = desc;
     287          15 :         ctx->ch = ch;
     288          15 :         ctx->cb = cb;
     289          15 :         ctx->cb_ctx = cb_ctx;
     290          15 :         ctx->buf_size = spdk_divide_round_up(sizeof(struct raid_bdev_superblock),
     291          15 :                                              spdk_bdev_get_data_block_size(bdev)) * bdev->blocklen;
     292          15 :         ctx->buf = spdk_dma_malloc(ctx->buf_size, spdk_bdev_get_buf_align(bdev), NULL);
     293          15 :         if (!ctx->buf) {
     294           0 :                 rc = -ENOMEM;
     295           0 :                 goto err;
     296             :         }
     297             : 
     298          15 :         rc = spdk_bdev_read(desc, ch, ctx->buf, 0, ctx->buf_size, raid_bdev_read_sb_cb, ctx);
     299          15 :         if (rc) {
     300           0 :                 goto err;
     301             :         }
     302             : 
     303          15 :         return 0;
     304           0 : err:
     305           0 :         raid_bdev_read_sb_ctx_free(ctx);
     306             : 
     307           0 :         return rc;
     308             : }
     309             : 
     310             : static void
     311          24 : raid_bdev_write_sb_base_bdev_done(int status, struct raid_bdev_write_sb_ctx *ctx)
     312             : {
     313          24 :         if (status != 0) {
     314           0 :                 ctx->status = status;
     315             :         }
     316             : 
     317          24 :         if (--ctx->remaining == 0) {
     318           6 :                 ctx->cb(ctx->status, ctx->raid_bdev, ctx->cb_ctx);
     319           6 :                 free(ctx);
     320             :         }
     321          24 : }
     322             : 
     323             : static void
     324          12 : raid_bdev_write_superblock_cb(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
     325             : {
     326          12 :         struct raid_bdev_write_sb_ctx *ctx = cb_arg;
     327          12 :         int status = 0;
     328             : 
     329          12 :         if (!success) {
     330           0 :                 SPDK_ERRLOG("Failed to save superblock on bdev %s\n", bdev_io->bdev->name);
     331           0 :                 status = -EIO;
     332             :         }
     333             : 
     334          12 :         spdk_bdev_free_io(bdev_io);
     335             : 
     336          12 :         raid_bdev_write_sb_base_bdev_done(status, ctx);
     337          12 : }
     338             : 
     339             : static void
     340           6 : _raid_bdev_write_superblock(void *_ctx)
     341             : {
     342           6 :         struct raid_bdev_write_sb_ctx *ctx = _ctx;
     343           6 :         struct raid_bdev *raid_bdev = ctx->raid_bdev;
     344             :         struct raid_base_bdev_info *base_info;
     345             :         uint8_t i;
     346             :         int rc;
     347             : 
     348          24 :         for (i = ctx->submitted; i < raid_bdev->num_base_bdevs; i++) {
     349          18 :                 base_info = &raid_bdev->base_bdev_info[i];
     350             : 
     351          18 :                 if (!base_info->is_configured || base_info->remove_scheduled) {
     352           6 :                         assert(ctx->remaining > 1);
     353           6 :                         raid_bdev_write_sb_base_bdev_done(0, ctx);
     354           6 :                         ctx->submitted++;
     355           6 :                         continue;
     356             :                 }
     357             : 
     358          12 :                 rc = spdk_bdev_write(base_info->desc, base_info->app_thread_ch,
     359          12 :                                      raid_bdev->sb_io_buf, 0, raid_bdev->sb_io_buf_size,
     360             :                                      raid_bdev_write_superblock_cb, ctx);
     361          12 :                 if (rc != 0) {
     362           0 :                         struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(base_info->desc);
     363             : 
     364           0 :                         if (rc == -ENOMEM) {
     365           0 :                                 ctx->wait_entry.bdev = bdev;
     366           0 :                                 ctx->wait_entry.cb_fn = _raid_bdev_write_superblock;
     367           0 :                                 ctx->wait_entry.cb_arg = ctx;
     368           0 :                                 spdk_bdev_queue_io_wait(bdev, base_info->app_thread_ch, &ctx->wait_entry);
     369           0 :                                 return;
     370             :                         }
     371             : 
     372           0 :                         assert(ctx->remaining > 1);
     373           0 :                         raid_bdev_write_sb_base_bdev_done(rc, ctx);
     374             :                 }
     375             : 
     376          12 :                 ctx->submitted++;
     377             :         }
     378             : 
     379           6 :         raid_bdev_write_sb_base_bdev_done(0, ctx);
     380             : }
     381             : 
     382             : void
     383           6 : raid_bdev_write_superblock(struct raid_bdev *raid_bdev, raid_bdev_write_sb_cb cb, void *cb_ctx)
     384             : {
     385             :         struct raid_bdev_write_sb_ctx *ctx;
     386           6 :         struct raid_bdev_superblock *sb = raid_bdev->sb;
     387             :         int rc;
     388             : 
     389           6 :         assert(spdk_get_thread() == spdk_thread_get_app_thread());
     390           6 :         assert(sb != NULL);
     391           6 :         assert(cb != NULL);
     392             : 
     393           6 :         if (raid_bdev->sb_io_buf == NULL) {
     394           6 :                 rc = raid_bdev_alloc_sb_io_buf(raid_bdev);
     395           6 :                 if (rc != 0) {
     396           0 :                         goto err;
     397             :                 }
     398             :         }
     399             : 
     400           6 :         ctx = calloc(1, sizeof(*ctx));
     401           6 :         if (!ctx) {
     402           0 :                 rc = -ENOMEM;
     403           0 :                 goto err;
     404             :         }
     405             : 
     406           6 :         ctx->raid_bdev = raid_bdev;
     407           6 :         ctx->remaining = raid_bdev->num_base_bdevs + 1;
     408           6 :         ctx->cb = cb;
     409           6 :         ctx->cb_ctx = cb_ctx;
     410             : 
     411           6 :         sb->seq_number++;
     412           6 :         raid_bdev_sb_update_crc(sb);
     413             : 
     414           6 :         if (spdk_bdev_is_md_interleaved(&raid_bdev->bdev)) {
     415           2 :                 void *sb_buf = sb;
     416             :                 uint32_t i;
     417             : 
     418          36 :                 for (i = 0; i < raid_bdev->sb_io_buf_size / raid_bdev->bdev.blocklen; i++) {
     419          34 :                         memcpy(raid_bdev->sb_io_buf + (i * raid_bdev->bdev.blocklen),
     420          34 :                                sb_buf + (i * sb->block_size), sb->block_size);
     421             :                 }
     422             :         }
     423             : 
     424           6 :         _raid_bdev_write_superblock(ctx);
     425           6 :         return;
     426           0 : err:
     427           0 :         cb(rc, raid_bdev, cb_ctx);
     428             : }
     429             : 
     430           1 : SPDK_LOG_REGISTER_COMPONENT(bdev_raid_sb)

Generated by: LCOV version 1.15