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 : }