LCOV - code coverage report
Current view: top level - spdk/lib/ftl - ftl_writer.c (source / functions) Hit Total Coverage
Test: Combined Lines: 95 142 66.9 %
Date: 2024-12-13 03:18:31 Functions: 10 11 90.9 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 57 713 8.0 %

           Branch data     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                 :         44 : ftl_writer_init(struct spdk_ftl_dev *dev, struct ftl_writer *writer,
      13                 :            :                 uint64_t limit, enum ftl_band_type type)
      14                 :            : {
      15         [ -  + ]:         44 :         memset(writer, 0, sizeof(*writer));
      16   [ #  #  #  # ]:         44 :         writer->dev = dev;
      17   [ #  #  #  #  :         44 :         TAILQ_INIT(&writer->rq_queue);
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
      18   [ #  #  #  #  :         44 :         TAILQ_INIT(&writer->full_bands);
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
      19   [ #  #  #  # ]:         44 :         writer->limit = limit;
      20   [ #  #  #  # ]:         44 :         writer->halt = true;
      21   [ #  #  #  # ]:         44 :         writer->writer_type = type;
      22                 :         44 : }
      23                 :            : 
      24                 :            : static bool
      25                 :       3586 : can_write(struct ftl_writer *writer)
      26                 :            : {
      27   [ -  +  -  +  :       3586 :         if (spdk_unlikely(writer->halt)) {
             #  #  #  # ]
      28                 :          0 :                 return false;
      29                 :            :         }
      30                 :            : 
      31   [ #  #  #  #  :       3586 :         return writer->band->md->state == FTL_BAND_STATE_OPEN;
          #  #  #  #  #  
                #  #  # ]
      32                 :          0 : }
      33                 :            : 
      34                 :            : void
      35                 :          8 : ftl_writer_band_state_change(struct ftl_band *band)
      36                 :            : {
      37   [ #  #  #  #  :          8 :         struct ftl_writer *writer = band->owner.priv;
                   #  # ]
      38                 :            : 
      39   [ +  +  -  #  :          8 :         switch (band->md->state) {
          #  #  #  #  #  
                   #  # ]
      40                 :          4 :         case FTL_BAND_STATE_FULL:
      41   [ -  +  #  #  :          4 :                 assert(writer->band == band);
             #  #  #  # ]
      42   [ #  #  #  #  :          4 :                 TAILQ_INSERT_TAIL(&writer->full_bands, band, queue_entry);
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
      43   [ #  #  #  # ]:          4 :                 writer->band = NULL;
      44                 :          4 :                 break;
      45                 :            : 
      46                 :          4 :         case FTL_BAND_STATE_CLOSED:
      47   [ -  +  #  #  :          4 :                 assert(writer->num_bands > 0);
             #  #  #  # ]
      48         [ #  # ]:          4 :                 writer->num_bands--;
      49                 :          4 :                 ftl_band_clear_owner(band, ftl_writer_band_state_change, writer);
      50   [ #  #  #  #  :          4 :                 writer->last_seq_id = band->md->close_seq_id;
          #  #  #  #  #  
                #  #  # ]
      51                 :          4 :                 break;
      52                 :            : 
      53                 :          0 :         default:
      54                 :          0 :                 break;
      55                 :            :         }
      56                 :          8 : }
      57                 :            : 
      58                 :            : static void
      59                 :  122346838 : close_full_bands(struct ftl_writer *writer)
      60                 :            : {
      61                 :            :         struct ftl_band *band, *next;
      62                 :            : 
      63   [ +  +  #  #  :  122347024 :         TAILQ_FOREACH_SAFE(band, &writer->full_bands, queue_entry, next) {
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
      64   [ +  +  #  #  :        186 :                 if (band->queue_depth) {
                   #  # ]
      65                 :        182 :                         continue;
      66                 :            :                 }
      67                 :            : 
      68   [ -  +  #  #  :          4 :                 TAILQ_REMOVE(&writer->full_bands, band, queue_entry);
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
      69                 :          4 :                 ftl_band_close(band);
      70                 :          0 :         }
      71                 :  122346838 : }
      72                 :            : 
      73                 :            : static bool
      74                 :       1239 : is_active(struct ftl_writer *writer)
      75                 :            : {
      76   [ -  +  #  #  :       1239 :         if (writer->dev->limit < writer->limit) {
          #  #  #  #  #  
             #  #  #  #  
                      # ]
      77                 :          0 :                 return false;
      78                 :            :         }
      79                 :            : 
      80                 :       1239 :         return true;
      81                 :          0 : }
      82                 :            : 
      83                 :            : static struct ftl_band *
      84                 :       4843 : get_band(struct ftl_writer *writer)
      85                 :            : {
      86   [ +  +  #  #  :       4843 :         if (spdk_unlikely(!writer->band)) {
                   #  # ]
      87         [ -  + ]:       1239 :                 if (!is_active(writer)) {
      88                 :          0 :                         return NULL;
      89                 :            :                 }
      90                 :            : 
      91   [ -  +  #  #  :       1239 :                 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                 :          0 :                 }
     102                 :            : 
     103   [ +  +  #  #  :       1239 :                 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                 :       1233 :                         return NULL;
     108                 :            :                 }
     109                 :            : 
     110   [ #  #  #  #  :          6 :                 writer->band = ftl_band_get_next_free(writer->dev);
             #  #  #  # ]
     111   [ +  -  #  #  :          6 :                 if (writer->band) {
                   #  # ]
     112         [ #  # ]:          6 :                         writer->num_bands++;
     113   [ #  #  #  # ]:          6 :                         ftl_band_set_owner(writer->band,
     114                 :          0 :                                            ftl_writer_band_state_change, writer);
     115                 :            : 
     116   [ -  +  #  #  :          6 :                         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                 :          0 :                         }
     125                 :          0 :                 } else {
     126                 :          0 :                         return NULL;
     127                 :            :                 }
     128                 :          0 :         }
     129                 :            : 
     130   [ +  +  #  #  :       3610 :         if (spdk_likely(writer->band->md->state == FTL_BAND_STATE_OPEN)) {
          #  #  #  #  #  
             #  #  #  #  
                      # ]
     131   [ #  #  #  # ]:       3586 :                 return writer->band;
     132                 :            :         } else {
     133   [ +  +  #  #  :         24 :                 if (spdk_unlikely(writer->band->md->state == FTL_BAND_STATE_PREP)) {
          #  #  #  #  #  
             #  #  #  #  
                      # ]
     134   [ #  #  #  #  :          6 :                         ftl_band_open(writer->band, writer->writer_type);
             #  #  #  # ]
     135                 :          0 :                 }
     136                 :         24 :                 return NULL;
     137                 :            :         }
     138                 :          0 : }
     139                 :            : 
     140                 :            : void
     141                 :  122346838 : ftl_writer_run(struct ftl_writer *writer)
     142                 :            : {
     143                 :            :         struct ftl_band *band;
     144                 :            :         struct ftl_rq *rq;
     145                 :            : 
     146                 :  122346838 :         close_full_bands(writer);
     147                 :            : 
     148   [ +  +  #  #  :  122346838 :         if (!TAILQ_EMPTY(&writer->rq_queue)) {
             #  #  #  # ]
     149                 :       4843 :                 band = get_band(writer);
     150         [ +  + ]:       4843 :                 if (spdk_unlikely(!band)) {
     151                 :       1257 :                         return;
     152                 :            :                 }
     153                 :            : 
     154         [ -  + ]:       3586 :                 if (!can_write(writer)) {
     155                 :          0 :                         return;
     156                 :            :                 }
     157                 :            : 
     158                 :            :                 /* Finally we can write to band */
     159   [ #  #  #  #  :       3586 :                 rq = TAILQ_FIRST(&writer->rq_queue);
                   #  # ]
     160   [ +  +  #  #  :       3586 :                 TAILQ_REMOVE(&writer->rq_queue, rq, qentry);
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
     161   [ #  #  #  # ]:       3586 :                 ftl_band_rq_write(writer->band, rq);
     162                 :          0 :         }
     163                 :          0 : }
     164                 :            : 
     165                 :            : static void
     166                 :       1012 : ftl_writer_pad_band_cb(struct ftl_rq *rq)
     167                 :            : {
     168   [ -  +  #  #  :       1012 :         assert(1 == rq->iter.qd);
          #  #  #  #  #  
                      # ]
     169   [ #  #  #  #  :       1012 :         rq->iter.qd = 0;
                   #  # ]
     170                 :       1012 : }
     171                 :            : 
     172                 :            : static void
     173                 :       1012 : ftl_writer_pad_band(struct ftl_writer *writer)
     174                 :            : {
     175   [ #  #  #  # ]:       1012 :         struct spdk_ftl_dev *dev = writer->dev;
     176                 :            : 
     177   [ -  +  -  +  :       1012 :         assert(dev->conf.prep_upgrade_on_shutdown);
          #  #  #  #  #  
                #  #  # ]
     178   [ -  +  #  #  :       1012 :         assert(writer->band);
             #  #  #  # ]
     179   [ -  +  #  #  :       1012 :         assert(0 == writer->band->queue_depth);
          #  #  #  #  #  
                #  #  # ]
     180                 :            : 
     181                 :            :         /* First allocate the padding FTL request */
     182   [ +  +  #  #  :       1012 :         if (!writer->pad) {
                   #  # ]
     183   [ #  #  #  #  :          1 :                 writer->pad = ftl_rq_new(dev, dev->md_size);
             #  #  #  # ]
     184   [ -  +  #  #  :          1 :                 if (!writer->pad) {
                   #  # ]
     185   [ #  #  #  #  :          0 :                         FTL_ERRLOG(dev, "Cannot allocate FTL request to pad the band");
             #  #  #  # ]
     186                 :          0 :                         return;
     187                 :            :                 }
     188   [ #  #  #  #  :          1 :                 writer->pad->owner.cb = ftl_writer_pad_band_cb;
          #  #  #  #  #  
                      # ]
     189                 :          0 :         }
     190                 :            : 
     191   [ -  +  #  #  :       1012 :         if (writer->pad->iter.qd) {
          #  #  #  #  #  
                #  #  # ]
     192                 :            :                 /* The band is handling the pad request already */
     193                 :          0 :                 return;
     194                 :            :         }
     195                 :            : 
     196   [ +  -  #  #  :       1012 :         if (writer->band->md->state == FTL_BAND_STATE_OPEN) {
          #  #  #  #  #  
             #  #  #  #  
                      # ]
     197   [ #  #  #  #  :       1012 :                 ftl_band_rq_write(writer->band, writer->pad);
             #  #  #  # ]
     198   [ #  #  #  #  :       1012 :                 writer->pad->iter.qd++;
             #  #  #  # ]
     199                 :          0 :         }
     200                 :          0 : }
     201                 :            : 
     202                 :            : bool
     203                 :     112336 : ftl_writer_is_halted(struct ftl_writer *writer)
     204                 :            : {
     205   [ +  +  #  #  :     112336 :         if (spdk_unlikely(!TAILQ_EMPTY(&writer->full_bands))) {
             #  #  #  # ]
     206                 :        159 :                 return false;
     207                 :            :         }
     208                 :            : 
     209   [ +  +  #  #  :     112177 :         if (writer->band) {
                   #  # ]
     210   [ -  +  #  #  :     108232 :                 if (writer->band->md->state != FTL_BAND_STATE_OPEN) {
          #  #  #  #  #  
             #  #  #  #  
                      # ]
     211                 :          0 :                         return false;
     212                 :            :                 }
     213                 :            : 
     214   [ +  +  #  #  :     108232 :                 if (writer->band->queue_depth) {
          #  #  #  #  #  
                      # ]
     215                 :     107120 :                         return false;
     216                 :            :                 }
     217                 :          0 :         }
     218                 :            : 
     219   [ -  +  +  +  :       5057 :         if (writer->dev->conf.prep_upgrade_on_shutdown) {
          #  #  #  #  #  
             #  #  #  #  
                      # ]
     220   [ +  +  #  #  :       4574 :                 if (writer->band) {
                   #  # ]
     221                 :       1012 :                         ftl_writer_pad_band(writer);
     222   [ +  +  #  #  :       3562 :                 } else if (writer->num_bands) {
                   #  # ]
     223                 :       2550 :                         return false;
     224                 :            :                 } else {
     225                 :            :                         /* All bands closed, free padding request */
     226   [ #  #  #  # ]:       1012 :                         ftl_rq_del(writer->pad);
     227   [ #  #  #  # ]:       1012 :                         writer->pad = NULL;
     228                 :            :                 }
     229                 :          0 :         }
     230                 :            : 
     231   [ -  +  #  #  :       2507 :         return writer->halt;
                   #  # ]
     232                 :          0 : }
     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                 :          0 :         }
     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                 :          0 :         }
     248                 :            : 
     249                 :          0 :         return free_blocks;
     250                 :            : }

Generated by: LCOV version 1.15