LCOV - code coverage report
Current view: top level - lib/ftl - ftl_writer.c (source / functions) Hit Total Coverage
Test: ut_cov_unit.info Lines: 0 122 0.0 %
Date: 2024-12-16 00:20:30 Functions: 0 11 0.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/likely.h"
       7             : 
       8             : #include "ftl_writer.h"
       9             : #include "ftl_band.h"
      10             : 
      11             : void
      12           0 : ftl_writer_init(struct spdk_ftl_dev *dev, struct ftl_writer *writer,
      13             :                 uint64_t limit, enum ftl_band_type type)
      14             : {
      15           0 :         memset(writer, 0, sizeof(*writer));
      16           0 :         writer->dev = dev;
      17           0 :         TAILQ_INIT(&writer->rq_queue);
      18           0 :         TAILQ_INIT(&writer->full_bands);
      19           0 :         writer->limit = limit;
      20           0 :         writer->halt = true;
      21           0 :         writer->writer_type = type;
      22           0 : }
      23             : 
      24             : static bool
      25           0 : can_write(struct ftl_writer *writer)
      26             : {
      27           0 :         if (spdk_unlikely(writer->halt)) {
      28           0 :                 return false;
      29             :         }
      30             : 
      31           0 :         return writer->band->md->state == FTL_BAND_STATE_OPEN;
      32             : }
      33             : 
      34             : void
      35           0 : ftl_writer_band_state_change(struct ftl_band *band)
      36             : {
      37           0 :         struct ftl_writer *writer = band->owner.priv;
      38             : 
      39           0 :         switch (band->md->state) {
      40           0 :         case FTL_BAND_STATE_FULL:
      41           0 :                 assert(writer->band == band);
      42           0 :                 TAILQ_INSERT_TAIL(&writer->full_bands, band, queue_entry);
      43           0 :                 writer->band = NULL;
      44           0 :                 break;
      45             : 
      46           0 :         case FTL_BAND_STATE_CLOSED:
      47           0 :                 assert(writer->num_bands > 0);
      48           0 :                 writer->num_bands--;
      49           0 :                 ftl_band_clear_owner(band, ftl_writer_band_state_change, writer);
      50           0 :                 writer->last_seq_id = band->md->close_seq_id;
      51           0 :                 break;
      52             : 
      53           0 :         default:
      54           0 :                 break;
      55             :         }
      56           0 : }
      57             : 
      58             : static void
      59           0 : close_full_bands(struct ftl_writer *writer)
      60             : {
      61             :         struct ftl_band *band, *next;
      62             : 
      63           0 :         TAILQ_FOREACH_SAFE(band, &writer->full_bands, queue_entry, next) {
      64           0 :                 if (band->queue_depth) {
      65           0 :                         continue;
      66             :                 }
      67             : 
      68           0 :                 TAILQ_REMOVE(&writer->full_bands, band, queue_entry);
      69           0 :                 ftl_band_close(band);
      70             :         }
      71           0 : }
      72             : 
      73             : static bool
      74           0 : is_active(struct ftl_writer *writer)
      75             : {
      76           0 :         if (writer->dev->limit < writer->limit) {
      77           0 :                 return false;
      78             :         }
      79             : 
      80           0 :         return true;
      81             : }
      82             : 
      83             : static struct ftl_band *
      84           0 : get_band(struct ftl_writer *writer)
      85             : {
      86           0 :         if (spdk_unlikely(!writer->band)) {
      87           0 :                 if (!is_active(writer)) {
      88           0 :                         return NULL;
      89             :                 }
      90             : 
      91           0 :                 if (spdk_unlikely(NULL != writer->next_band)) {
      92           0 :                         if (FTL_BAND_STATE_OPEN == writer->next_band->md->state) {
      93           0 :                                 writer->band = writer->next_band;
      94           0 :                                 writer->next_band = NULL;
      95             : 
      96           0 :                                 return writer->band;
      97             :                         } else {
      98           0 :                                 assert(FTL_BAND_STATE_OPEN == writer->next_band->md->state);
      99           0 :                                 ftl_abort();
     100             :                         }
     101             :                 }
     102             : 
     103           0 :                 if (writer->num_bands >= FTL_LAYOUT_REGION_TYPE_P2L_COUNT / 2) {
     104             :                         /* Maximum number of opened band exceed (we split this
     105             :                          * value between and compaction and GC writer
     106             :                          */
     107           0 :                         return NULL;
     108             :                 }
     109             : 
     110           0 :                 writer->band = ftl_band_get_next_free(writer->dev);
     111           0 :                 if (writer->band) {
     112           0 :                         writer->num_bands++;
     113           0 :                         ftl_band_set_owner(writer->band,
     114             :                                            ftl_writer_band_state_change, writer);
     115             : 
     116           0 :                         if (ftl_band_write_prep(writer->band)) {
     117             :                                 /*
     118             :                                  * This error might happen due to allocation failure. However number
     119             :                                  * of open bands is controlled and it should have enough resources
     120             :                                  * to do it. So here is better to perform a crash and recover from
     121             :                                  * shared memory to bring back stable state.
     122             :                                  *  */
     123           0 :                                 ftl_abort();
     124             :                         }
     125             :                 } else {
     126           0 :                         return NULL;
     127             :                 }
     128             :         }
     129             : 
     130           0 :         if (spdk_likely(writer->band->md->state == FTL_BAND_STATE_OPEN)) {
     131           0 :                 return writer->band;
     132             :         } else {
     133           0 :                 if (spdk_unlikely(writer->band->md->state == FTL_BAND_STATE_PREP)) {
     134           0 :                         ftl_band_open(writer->band, writer->writer_type);
     135             :                 }
     136           0 :                 return NULL;
     137             :         }
     138             : }
     139             : 
     140             : void
     141           0 : ftl_writer_run(struct ftl_writer *writer)
     142             : {
     143             :         struct ftl_band *band;
     144             :         struct ftl_rq *rq;
     145             : 
     146           0 :         close_full_bands(writer);
     147             : 
     148           0 :         if (!TAILQ_EMPTY(&writer->rq_queue)) {
     149           0 :                 band = get_band(writer);
     150           0 :                 if (spdk_unlikely(!band)) {
     151           0 :                         return;
     152             :                 }
     153             : 
     154           0 :                 if (!can_write(writer)) {
     155           0 :                         return;
     156             :                 }
     157             : 
     158             :                 /* Finally we can write to band */
     159           0 :                 rq = TAILQ_FIRST(&writer->rq_queue);
     160           0 :                 TAILQ_REMOVE(&writer->rq_queue, rq, qentry);
     161           0 :                 ftl_band_rq_write(writer->band, rq);
     162             :         }
     163             : }
     164             : 
     165             : static void
     166           0 : ftl_writer_pad_band_cb(struct ftl_rq *rq)
     167             : {
     168           0 :         assert(1 == rq->iter.qd);
     169           0 :         rq->iter.qd = 0;
     170           0 : }
     171             : 
     172             : static void
     173           0 : ftl_writer_pad_band(struct ftl_writer *writer)
     174             : {
     175           0 :         struct spdk_ftl_dev *dev = writer->dev;
     176             : 
     177           0 :         assert(dev->conf.prep_upgrade_on_shutdown);
     178           0 :         assert(writer->band);
     179           0 :         assert(0 == writer->band->queue_depth);
     180             : 
     181             :         /* First allocate the padding FTL request */
     182           0 :         if (!writer->pad) {
     183           0 :                 writer->pad = ftl_rq_new(dev, dev->md_size);
     184           0 :                 if (!writer->pad) {
     185           0 :                         FTL_ERRLOG(dev, "Cannot allocate FTL request to pad the band");
     186           0 :                         return;
     187             :                 }
     188           0 :                 writer->pad->owner.cb = ftl_writer_pad_band_cb;
     189             :         }
     190             : 
     191           0 :         if (writer->pad->iter.qd) {
     192             :                 /* The band is handling the pad request already */
     193           0 :                 return;
     194             :         }
     195             : 
     196           0 :         if (writer->band->md->state == FTL_BAND_STATE_OPEN) {
     197           0 :                 ftl_band_rq_write(writer->band, writer->pad);
     198           0 :                 writer->pad->iter.qd++;
     199             :         }
     200             : }
     201             : 
     202             : bool
     203           0 : ftl_writer_is_halted(struct ftl_writer *writer)
     204             : {
     205           0 :         if (spdk_unlikely(!TAILQ_EMPTY(&writer->full_bands))) {
     206           0 :                 return false;
     207             :         }
     208             : 
     209           0 :         if (writer->band) {
     210           0 :                 if (writer->band->md->state != FTL_BAND_STATE_OPEN) {
     211           0 :                         return false;
     212             :                 }
     213             : 
     214           0 :                 if (writer->band->queue_depth) {
     215           0 :                         return false;
     216             :                 }
     217             :         }
     218             : 
     219           0 :         if (writer->dev->conf.prep_upgrade_on_shutdown) {
     220           0 :                 if (writer->band) {
     221           0 :                         ftl_writer_pad_band(writer);
     222           0 :                 } else if (writer->num_bands) {
     223           0 :                         return false;
     224             :                 } else {
     225             :                         /* All bands closed, free padding request */
     226           0 :                         ftl_rq_del(writer->pad);
     227           0 :                         writer->pad = NULL;
     228             :                 }
     229             :         }
     230             : 
     231           0 :         return writer->halt;
     232             : }
     233             : 
     234             : uint64_t
     235           0 : ftl_writer_get_free_blocks(struct ftl_writer *writer)
     236             : {
     237           0 :         uint64_t free_blocks = 0;
     238             : 
     239           0 :         if (writer->band) {
     240           0 :                 free_blocks += ftl_band_user_blocks_left(writer->band,
     241           0 :                                 writer->band->md->iter.offset);
     242             :         }
     243             : 
     244           0 :         if (writer->next_band) {
     245           0 :                 free_blocks += ftl_band_user_blocks_left(writer->next_band,
     246           0 :                                 writer->next_band->md->iter.offset);
     247             :         }
     248             : 
     249           0 :         return free_blocks;
     250             : }

Generated by: LCOV version 1.15