xref: /spdk/lib/ftl/ftl_writer.c (revision d4a2d28da1c6bc02a50c28428defdc7a2a99058d)
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