131cf6336SKozlowski Mateusz /* SPDX-License-Identifier: BSD-3-Clause
2a6dbe372Spaul luse * Copyright (C) 2022 Intel Corporation.
331cf6336SKozlowski Mateusz * All rights reserved.
431cf6336SKozlowski Mateusz */
531cf6336SKozlowski Mateusz
631cf6336SKozlowski Mateusz #include "spdk/likely.h"
731cf6336SKozlowski Mateusz
831cf6336SKozlowski Mateusz #include "ftl_writer.h"
931cf6336SKozlowski Mateusz #include "ftl_band.h"
1031cf6336SKozlowski Mateusz
1131cf6336SKozlowski Mateusz void
ftl_writer_init(struct spdk_ftl_dev * dev,struct ftl_writer * writer,uint64_t limit,enum ftl_band_type type)1231cf6336SKozlowski Mateusz ftl_writer_init(struct spdk_ftl_dev *dev, struct ftl_writer *writer,
1331cf6336SKozlowski Mateusz uint64_t limit, enum ftl_band_type type)
1431cf6336SKozlowski Mateusz {
1531cf6336SKozlowski Mateusz memset(writer, 0, sizeof(*writer));
1631cf6336SKozlowski Mateusz writer->dev = dev;
1731cf6336SKozlowski Mateusz TAILQ_INIT(&writer->rq_queue);
1831cf6336SKozlowski Mateusz TAILQ_INIT(&writer->full_bands);
1931cf6336SKozlowski Mateusz writer->limit = limit;
2031cf6336SKozlowski Mateusz writer->halt = true;
2131cf6336SKozlowski Mateusz writer->writer_type = type;
2231cf6336SKozlowski Mateusz }
2331cf6336SKozlowski Mateusz
2431cf6336SKozlowski Mateusz static bool
can_write(struct ftl_writer * writer)2531cf6336SKozlowski Mateusz can_write(struct ftl_writer *writer)
2631cf6336SKozlowski Mateusz {
2731cf6336SKozlowski Mateusz if (spdk_unlikely(writer->halt)) {
2831cf6336SKozlowski Mateusz return false;
2931cf6336SKozlowski Mateusz }
3031cf6336SKozlowski Mateusz
3131cf6336SKozlowski Mateusz return writer->band->md->state == FTL_BAND_STATE_OPEN;
3231cf6336SKozlowski Mateusz }
3331cf6336SKozlowski Mateusz
3431cf6336SKozlowski Mateusz void
ftl_writer_band_state_change(struct ftl_band * band)3531cf6336SKozlowski Mateusz ftl_writer_band_state_change(struct ftl_band *band)
3631cf6336SKozlowski Mateusz {
3731cf6336SKozlowski Mateusz struct ftl_writer *writer = band->owner.priv;
3831cf6336SKozlowski Mateusz
3931cf6336SKozlowski Mateusz switch (band->md->state) {
4031cf6336SKozlowski Mateusz case FTL_BAND_STATE_FULL:
4131cf6336SKozlowski Mateusz assert(writer->band == band);
4231cf6336SKozlowski Mateusz TAILQ_INSERT_TAIL(&writer->full_bands, band, queue_entry);
4331cf6336SKozlowski Mateusz writer->band = NULL;
4431cf6336SKozlowski Mateusz break;
4531cf6336SKozlowski Mateusz
4631cf6336SKozlowski Mateusz case FTL_BAND_STATE_CLOSED:
4731cf6336SKozlowski Mateusz assert(writer->num_bands > 0);
4831cf6336SKozlowski Mateusz writer->num_bands--;
4931cf6336SKozlowski Mateusz ftl_band_clear_owner(band, ftl_writer_band_state_change, writer);
5036049672SArtur Paszkiewicz writer->last_seq_id = band->md->close_seq_id;
5131cf6336SKozlowski Mateusz break;
5231cf6336SKozlowski Mateusz
5331cf6336SKozlowski Mateusz default:
5431cf6336SKozlowski Mateusz break;
5531cf6336SKozlowski Mateusz }
5631cf6336SKozlowski Mateusz }
5731cf6336SKozlowski Mateusz
5831cf6336SKozlowski Mateusz static void
close_full_bands(struct ftl_writer * writer)5931cf6336SKozlowski Mateusz close_full_bands(struct ftl_writer *writer)
6031cf6336SKozlowski Mateusz {
6131cf6336SKozlowski Mateusz struct ftl_band *band, *next;
6231cf6336SKozlowski Mateusz
6331cf6336SKozlowski Mateusz TAILQ_FOREACH_SAFE(band, &writer->full_bands, queue_entry, next) {
6431cf6336SKozlowski Mateusz if (band->queue_depth) {
6531cf6336SKozlowski Mateusz continue;
6631cf6336SKozlowski Mateusz }
6731cf6336SKozlowski Mateusz
6831cf6336SKozlowski Mateusz TAILQ_REMOVE(&writer->full_bands, band, queue_entry);
6931cf6336SKozlowski Mateusz ftl_band_close(band);
7031cf6336SKozlowski Mateusz }
7131cf6336SKozlowski Mateusz }
7231cf6336SKozlowski Mateusz
7331cf6336SKozlowski Mateusz static bool
is_active(struct ftl_writer * writer)7431cf6336SKozlowski Mateusz is_active(struct ftl_writer *writer)
7531cf6336SKozlowski Mateusz {
7631cf6336SKozlowski Mateusz if (writer->dev->limit < writer->limit) {
7731cf6336SKozlowski Mateusz return false;
7831cf6336SKozlowski Mateusz }
7931cf6336SKozlowski Mateusz
8031cf6336SKozlowski Mateusz return true;
8131cf6336SKozlowski Mateusz }
8231cf6336SKozlowski Mateusz
8331cf6336SKozlowski Mateusz static struct ftl_band *
get_band(struct ftl_writer * writer)8431cf6336SKozlowski Mateusz get_band(struct ftl_writer *writer)
8531cf6336SKozlowski Mateusz {
8631cf6336SKozlowski Mateusz if (spdk_unlikely(!writer->band)) {
8731cf6336SKozlowski Mateusz if (!is_active(writer)) {
8831cf6336SKozlowski Mateusz return NULL;
8931cf6336SKozlowski Mateusz }
9031cf6336SKozlowski Mateusz
9131cf6336SKozlowski Mateusz if (spdk_unlikely(NULL != writer->next_band)) {
9231cf6336SKozlowski Mateusz if (FTL_BAND_STATE_OPEN == writer->next_band->md->state) {
9331cf6336SKozlowski Mateusz writer->band = writer->next_band;
9431cf6336SKozlowski Mateusz writer->next_band = NULL;
9531cf6336SKozlowski Mateusz
9631cf6336SKozlowski Mateusz return writer->band;
9731cf6336SKozlowski Mateusz } else {
9831cf6336SKozlowski Mateusz assert(FTL_BAND_STATE_OPEN == writer->next_band->md->state);
9931cf6336SKozlowski Mateusz ftl_abort();
10031cf6336SKozlowski Mateusz }
10131cf6336SKozlowski Mateusz }
10231cf6336SKozlowski Mateusz
1031738488eSArtur Paszkiewicz if (writer->num_bands >= FTL_LAYOUT_REGION_TYPE_P2L_COUNT / 2) {
1041738488eSArtur Paszkiewicz /* Maximum number of opened band exceed (we split this
1051738488eSArtur Paszkiewicz * value between and compaction and GC writer
1061738488eSArtur Paszkiewicz */
1071738488eSArtur Paszkiewicz return NULL;
1081738488eSArtur Paszkiewicz }
1091738488eSArtur Paszkiewicz
11031cf6336SKozlowski Mateusz writer->band = ftl_band_get_next_free(writer->dev);
11131cf6336SKozlowski Mateusz if (writer->band) {
11231cf6336SKozlowski Mateusz writer->num_bands++;
11331cf6336SKozlowski Mateusz ftl_band_set_owner(writer->band,
11431cf6336SKozlowski Mateusz ftl_writer_band_state_change, writer);
11531cf6336SKozlowski Mateusz
11631cf6336SKozlowski Mateusz if (ftl_band_write_prep(writer->band)) {
11731cf6336SKozlowski Mateusz /*
11831cf6336SKozlowski Mateusz * This error might happen due to allocation failure. However number
11931cf6336SKozlowski Mateusz * of open bands is controlled and it should have enough resources
12031cf6336SKozlowski Mateusz * to do it. So here is better to perform a crash and recover from
12131cf6336SKozlowski Mateusz * shared memory to bring back stable state.
12231cf6336SKozlowski Mateusz * */
12331cf6336SKozlowski Mateusz ftl_abort();
12431cf6336SKozlowski Mateusz }
12531cf6336SKozlowski Mateusz } else {
12631cf6336SKozlowski Mateusz return NULL;
12731cf6336SKozlowski Mateusz }
12831cf6336SKozlowski Mateusz }
12931cf6336SKozlowski Mateusz
13031cf6336SKozlowski Mateusz if (spdk_likely(writer->band->md->state == FTL_BAND_STATE_OPEN)) {
13131cf6336SKozlowski Mateusz return writer->band;
13231cf6336SKozlowski Mateusz } else {
13331cf6336SKozlowski Mateusz if (spdk_unlikely(writer->band->md->state == FTL_BAND_STATE_PREP)) {
13431cf6336SKozlowski Mateusz ftl_band_open(writer->band, writer->writer_type);
13531cf6336SKozlowski Mateusz }
13631cf6336SKozlowski Mateusz return NULL;
13731cf6336SKozlowski Mateusz }
13831cf6336SKozlowski Mateusz }
13931cf6336SKozlowski Mateusz
14031cf6336SKozlowski Mateusz void
ftl_writer_run(struct ftl_writer * writer)14131cf6336SKozlowski Mateusz ftl_writer_run(struct ftl_writer *writer)
14231cf6336SKozlowski Mateusz {
14331cf6336SKozlowski Mateusz struct ftl_band *band;
14431cf6336SKozlowski Mateusz struct ftl_rq *rq;
14531cf6336SKozlowski Mateusz
14631cf6336SKozlowski Mateusz close_full_bands(writer);
14731cf6336SKozlowski Mateusz
14831cf6336SKozlowski Mateusz if (!TAILQ_EMPTY(&writer->rq_queue)) {
14931cf6336SKozlowski Mateusz band = get_band(writer);
15031cf6336SKozlowski Mateusz if (spdk_unlikely(!band)) {
15131cf6336SKozlowski Mateusz return;
15231cf6336SKozlowski Mateusz }
15331cf6336SKozlowski Mateusz
15431cf6336SKozlowski Mateusz if (!can_write(writer)) {
15531cf6336SKozlowski Mateusz return;
15631cf6336SKozlowski Mateusz }
15731cf6336SKozlowski Mateusz
15831cf6336SKozlowski Mateusz /* Finally we can write to band */
15931cf6336SKozlowski Mateusz rq = TAILQ_FIRST(&writer->rq_queue);
16031cf6336SKozlowski Mateusz TAILQ_REMOVE(&writer->rq_queue, rq, qentry);
16131cf6336SKozlowski Mateusz ftl_band_rq_write(writer->band, rq);
16231cf6336SKozlowski Mateusz }
16331cf6336SKozlowski Mateusz }
16431cf6336SKozlowski Mateusz
165*d4a2d28dSMateusz Kozlowski static void
ftl_writer_pad_band_cb(struct ftl_rq * rq)166*d4a2d28dSMateusz Kozlowski ftl_writer_pad_band_cb(struct ftl_rq *rq)
167*d4a2d28dSMateusz Kozlowski {
168*d4a2d28dSMateusz Kozlowski assert(1 == rq->iter.qd);
169*d4a2d28dSMateusz Kozlowski rq->iter.qd = 0;
170*d4a2d28dSMateusz Kozlowski }
171*d4a2d28dSMateusz Kozlowski
172*d4a2d28dSMateusz Kozlowski static void
ftl_writer_pad_band(struct ftl_writer * writer)173*d4a2d28dSMateusz Kozlowski ftl_writer_pad_band(struct ftl_writer *writer)
174*d4a2d28dSMateusz Kozlowski {
175*d4a2d28dSMateusz Kozlowski struct spdk_ftl_dev *dev = writer->dev;
176*d4a2d28dSMateusz Kozlowski
177*d4a2d28dSMateusz Kozlowski assert(dev->conf.prep_upgrade_on_shutdown);
178*d4a2d28dSMateusz Kozlowski assert(writer->band);
179*d4a2d28dSMateusz Kozlowski assert(0 == writer->band->queue_depth);
180*d4a2d28dSMateusz Kozlowski
181*d4a2d28dSMateusz Kozlowski /* First allocate the padding FTL request */
182*d4a2d28dSMateusz Kozlowski if (!writer->pad) {
183*d4a2d28dSMateusz Kozlowski writer->pad = ftl_rq_new(dev, dev->md_size);
184*d4a2d28dSMateusz Kozlowski if (!writer->pad) {
185*d4a2d28dSMateusz Kozlowski FTL_ERRLOG(dev, "Cannot allocate FTL request to pad the band");
186*d4a2d28dSMateusz Kozlowski return;
187*d4a2d28dSMateusz Kozlowski }
188*d4a2d28dSMateusz Kozlowski writer->pad->owner.cb = ftl_writer_pad_band_cb;
189*d4a2d28dSMateusz Kozlowski }
190*d4a2d28dSMateusz Kozlowski
191*d4a2d28dSMateusz Kozlowski if (writer->pad->iter.qd) {
192*d4a2d28dSMateusz Kozlowski /* The band is handling the pad request already */
193*d4a2d28dSMateusz Kozlowski return;
194*d4a2d28dSMateusz Kozlowski }
195*d4a2d28dSMateusz Kozlowski
196*d4a2d28dSMateusz Kozlowski if (writer->band->md->state == FTL_BAND_STATE_OPEN) {
197*d4a2d28dSMateusz Kozlowski ftl_band_rq_write(writer->band, writer->pad);
198*d4a2d28dSMateusz Kozlowski writer->pad->iter.qd++;
199*d4a2d28dSMateusz Kozlowski }
200*d4a2d28dSMateusz Kozlowski }
201*d4a2d28dSMateusz Kozlowski
20231cf6336SKozlowski Mateusz bool
ftl_writer_is_halted(struct ftl_writer * writer)20331cf6336SKozlowski Mateusz ftl_writer_is_halted(struct ftl_writer *writer)
20431cf6336SKozlowski Mateusz {
20531cf6336SKozlowski Mateusz if (spdk_unlikely(!TAILQ_EMPTY(&writer->full_bands))) {
20631cf6336SKozlowski Mateusz return false;
20731cf6336SKozlowski Mateusz }
20831cf6336SKozlowski Mateusz
20931cf6336SKozlowski Mateusz if (writer->band) {
21031cf6336SKozlowski Mateusz if (writer->band->md->state != FTL_BAND_STATE_OPEN) {
21131cf6336SKozlowski Mateusz return false;
21231cf6336SKozlowski Mateusz }
21331cf6336SKozlowski Mateusz
21431cf6336SKozlowski Mateusz if (writer->band->queue_depth) {
21531cf6336SKozlowski Mateusz return false;
21631cf6336SKozlowski Mateusz }
21731cf6336SKozlowski Mateusz }
21831cf6336SKozlowski Mateusz
219*d4a2d28dSMateusz Kozlowski if (writer->dev->conf.prep_upgrade_on_shutdown) {
220*d4a2d28dSMateusz Kozlowski if (writer->band) {
221*d4a2d28dSMateusz Kozlowski ftl_writer_pad_band(writer);
222*d4a2d28dSMateusz Kozlowski } else if (writer->num_bands) {
223*d4a2d28dSMateusz Kozlowski return false;
224*d4a2d28dSMateusz Kozlowski } else {
225*d4a2d28dSMateusz Kozlowski /* All bands closed, free padding request */
226*d4a2d28dSMateusz Kozlowski ftl_rq_del(writer->pad);
227*d4a2d28dSMateusz Kozlowski writer->pad = NULL;
228*d4a2d28dSMateusz Kozlowski }
229*d4a2d28dSMateusz Kozlowski }
230*d4a2d28dSMateusz Kozlowski
23131cf6336SKozlowski Mateusz return writer->halt;
23231cf6336SKozlowski Mateusz }
23331cf6336SKozlowski Mateusz
23431cf6336SKozlowski Mateusz uint64_t
ftl_writer_get_free_blocks(struct ftl_writer * writer)23531cf6336SKozlowski Mateusz ftl_writer_get_free_blocks(struct ftl_writer *writer)
23631cf6336SKozlowski Mateusz {
23731cf6336SKozlowski Mateusz uint64_t free_blocks = 0;
23831cf6336SKozlowski Mateusz
23931cf6336SKozlowski Mateusz if (writer->band) {
24031cf6336SKozlowski Mateusz free_blocks += ftl_band_user_blocks_left(writer->band,
24131cf6336SKozlowski Mateusz writer->band->md->iter.offset);
24231cf6336SKozlowski Mateusz }
24331cf6336SKozlowski Mateusz
24431cf6336SKozlowski Mateusz if (writer->next_band) {
24531cf6336SKozlowski Mateusz free_blocks += ftl_band_user_blocks_left(writer->next_band,
24631cf6336SKozlowski Mateusz writer->next_band->md->iter.offset);
24731cf6336SKozlowski Mateusz }
24831cf6336SKozlowski Mateusz
24931cf6336SKozlowski Mateusz return free_blocks;
25031cf6336SKozlowski Mateusz }
251