xref: /spdk/lib/ftl/ftl_writer.c (revision 31cf633679934e2472a3db80fbeef4e206e3b7c9)
1*31cf6336SKozlowski Mateusz /*   SPDX-License-Identifier: BSD-3-Clause
2*31cf6336SKozlowski Mateusz  *   Copyright (c) Intel Corporation.
3*31cf6336SKozlowski Mateusz  *   All rights reserved.
4*31cf6336SKozlowski Mateusz  */
5*31cf6336SKozlowski Mateusz 
6*31cf6336SKozlowski Mateusz #include "spdk/likely.h"
7*31cf6336SKozlowski Mateusz 
8*31cf6336SKozlowski Mateusz #include "ftl_writer.h"
9*31cf6336SKozlowski Mateusz #include "ftl_band.h"
10*31cf6336SKozlowski Mateusz 
11*31cf6336SKozlowski Mateusz void
12*31cf6336SKozlowski Mateusz ftl_writer_init(struct spdk_ftl_dev *dev, struct ftl_writer *writer,
13*31cf6336SKozlowski Mateusz 		uint64_t limit, enum ftl_band_type type)
14*31cf6336SKozlowski Mateusz {
15*31cf6336SKozlowski Mateusz 	memset(writer, 0, sizeof(*writer));
16*31cf6336SKozlowski Mateusz 	writer->dev = dev;
17*31cf6336SKozlowski Mateusz 	TAILQ_INIT(&writer->rq_queue);
18*31cf6336SKozlowski Mateusz 	TAILQ_INIT(&writer->full_bands);
19*31cf6336SKozlowski Mateusz 	writer->limit = limit;
20*31cf6336SKozlowski Mateusz 	writer->halt = true;
21*31cf6336SKozlowski Mateusz 	writer->writer_type = type;
22*31cf6336SKozlowski Mateusz }
23*31cf6336SKozlowski Mateusz 
24*31cf6336SKozlowski Mateusz static bool
25*31cf6336SKozlowski Mateusz can_write(struct ftl_writer *writer)
26*31cf6336SKozlowski Mateusz {
27*31cf6336SKozlowski Mateusz 	if (spdk_unlikely(writer->halt)) {
28*31cf6336SKozlowski Mateusz 		return false;
29*31cf6336SKozlowski Mateusz 	}
30*31cf6336SKozlowski Mateusz 
31*31cf6336SKozlowski Mateusz 	return writer->band->md->state == FTL_BAND_STATE_OPEN;
32*31cf6336SKozlowski Mateusz }
33*31cf6336SKozlowski Mateusz 
34*31cf6336SKozlowski Mateusz void
35*31cf6336SKozlowski Mateusz ftl_writer_band_state_change(struct ftl_band *band)
36*31cf6336SKozlowski Mateusz {
37*31cf6336SKozlowski Mateusz 	struct ftl_writer *writer = band->owner.priv;
38*31cf6336SKozlowski Mateusz 
39*31cf6336SKozlowski Mateusz 	switch (band->md->state) {
40*31cf6336SKozlowski Mateusz 	case FTL_BAND_STATE_FULL:
41*31cf6336SKozlowski Mateusz 		assert(writer->band == band);
42*31cf6336SKozlowski Mateusz 		TAILQ_INSERT_TAIL(&writer->full_bands, band, queue_entry);
43*31cf6336SKozlowski Mateusz 		writer->band = NULL;
44*31cf6336SKozlowski Mateusz 		break;
45*31cf6336SKozlowski Mateusz 
46*31cf6336SKozlowski Mateusz 	case FTL_BAND_STATE_CLOSED:
47*31cf6336SKozlowski Mateusz 		assert(writer->num_bands > 0);
48*31cf6336SKozlowski Mateusz 		writer->num_bands--;
49*31cf6336SKozlowski Mateusz 		ftl_band_clear_owner(band, ftl_writer_band_state_change, writer);
50*31cf6336SKozlowski Mateusz 		break;
51*31cf6336SKozlowski Mateusz 
52*31cf6336SKozlowski Mateusz 	default:
53*31cf6336SKozlowski Mateusz 		break;
54*31cf6336SKozlowski Mateusz 	}
55*31cf6336SKozlowski Mateusz }
56*31cf6336SKozlowski Mateusz 
57*31cf6336SKozlowski Mateusz static void
58*31cf6336SKozlowski Mateusz close_full_bands(struct ftl_writer *writer)
59*31cf6336SKozlowski Mateusz {
60*31cf6336SKozlowski Mateusz 	struct ftl_band *band, *next;
61*31cf6336SKozlowski Mateusz 
62*31cf6336SKozlowski Mateusz 	TAILQ_FOREACH_SAFE(band, &writer->full_bands, queue_entry, next) {
63*31cf6336SKozlowski Mateusz 		if (band->queue_depth) {
64*31cf6336SKozlowski Mateusz 			continue;
65*31cf6336SKozlowski Mateusz 		}
66*31cf6336SKozlowski Mateusz 
67*31cf6336SKozlowski Mateusz 		TAILQ_REMOVE(&writer->full_bands, band, queue_entry);
68*31cf6336SKozlowski Mateusz 		ftl_band_close(band);
69*31cf6336SKozlowski Mateusz 	}
70*31cf6336SKozlowski Mateusz }
71*31cf6336SKozlowski Mateusz 
72*31cf6336SKozlowski Mateusz static bool
73*31cf6336SKozlowski Mateusz is_active(struct ftl_writer *writer)
74*31cf6336SKozlowski Mateusz {
75*31cf6336SKozlowski Mateusz 	if (writer->dev->limit < writer->limit) {
76*31cf6336SKozlowski Mateusz 		return false;
77*31cf6336SKozlowski Mateusz 	}
78*31cf6336SKozlowski Mateusz 
79*31cf6336SKozlowski Mateusz 	return true;
80*31cf6336SKozlowski Mateusz }
81*31cf6336SKozlowski Mateusz 
82*31cf6336SKozlowski Mateusz static struct ftl_band *
83*31cf6336SKozlowski Mateusz get_band(struct ftl_writer *writer)
84*31cf6336SKozlowski Mateusz {
85*31cf6336SKozlowski Mateusz 	if (spdk_unlikely(!writer->band)) {
86*31cf6336SKozlowski Mateusz 		if (!is_active(writer)) {
87*31cf6336SKozlowski Mateusz 			return NULL;
88*31cf6336SKozlowski Mateusz 		}
89*31cf6336SKozlowski Mateusz 
90*31cf6336SKozlowski Mateusz 		if (spdk_unlikely(NULL != writer->next_band)) {
91*31cf6336SKozlowski Mateusz 			if (FTL_BAND_STATE_OPEN == writer->next_band->md->state) {
92*31cf6336SKozlowski Mateusz 				writer->band = writer->next_band;
93*31cf6336SKozlowski Mateusz 				writer->next_band = NULL;
94*31cf6336SKozlowski Mateusz 
95*31cf6336SKozlowski Mateusz 				return writer->band;
96*31cf6336SKozlowski Mateusz 			} else {
97*31cf6336SKozlowski Mateusz 				assert(FTL_BAND_STATE_OPEN == writer->next_band->md->state);
98*31cf6336SKozlowski Mateusz 				ftl_abort();
99*31cf6336SKozlowski Mateusz 			}
100*31cf6336SKozlowski Mateusz 		}
101*31cf6336SKozlowski Mateusz 
102*31cf6336SKozlowski Mateusz 		writer->band = ftl_band_get_next_free(writer->dev);
103*31cf6336SKozlowski Mateusz 		if (writer->band) {
104*31cf6336SKozlowski Mateusz 			writer->num_bands++;
105*31cf6336SKozlowski Mateusz 			ftl_band_set_owner(writer->band,
106*31cf6336SKozlowski Mateusz 					   ftl_writer_band_state_change, writer);
107*31cf6336SKozlowski Mateusz 
108*31cf6336SKozlowski Mateusz 			if (ftl_band_write_prep(writer->band)) {
109*31cf6336SKozlowski Mateusz 				/*
110*31cf6336SKozlowski Mateusz 				 * This error might happen due to allocation failure. However number
111*31cf6336SKozlowski Mateusz 				 * of open bands is controlled and it should have enough resources
112*31cf6336SKozlowski Mateusz 				 * to do it. So here is better to perform a crash and recover from
113*31cf6336SKozlowski Mateusz 				 * shared memory to bring back stable state.
114*31cf6336SKozlowski Mateusz 				 *  */
115*31cf6336SKozlowski Mateusz 				ftl_abort();
116*31cf6336SKozlowski Mateusz 			}
117*31cf6336SKozlowski Mateusz 		} else {
118*31cf6336SKozlowski Mateusz 			return NULL;
119*31cf6336SKozlowski Mateusz 		}
120*31cf6336SKozlowski Mateusz 	}
121*31cf6336SKozlowski Mateusz 
122*31cf6336SKozlowski Mateusz 	if (spdk_likely(writer->band->md->state == FTL_BAND_STATE_OPEN)) {
123*31cf6336SKozlowski Mateusz 		return writer->band;
124*31cf6336SKozlowski Mateusz 	} else {
125*31cf6336SKozlowski Mateusz 		if (spdk_unlikely(writer->band->md->state == FTL_BAND_STATE_PREP)) {
126*31cf6336SKozlowski Mateusz 			ftl_band_open(writer->band, writer->writer_type);
127*31cf6336SKozlowski Mateusz 		}
128*31cf6336SKozlowski Mateusz 		return NULL;
129*31cf6336SKozlowski Mateusz 	}
130*31cf6336SKozlowski Mateusz }
131*31cf6336SKozlowski Mateusz 
132*31cf6336SKozlowski Mateusz void
133*31cf6336SKozlowski Mateusz ftl_writer_run(struct ftl_writer *writer)
134*31cf6336SKozlowski Mateusz {
135*31cf6336SKozlowski Mateusz 	struct ftl_band *band;
136*31cf6336SKozlowski Mateusz 	struct ftl_rq *rq;
137*31cf6336SKozlowski Mateusz 
138*31cf6336SKozlowski Mateusz 	close_full_bands(writer);
139*31cf6336SKozlowski Mateusz 
140*31cf6336SKozlowski Mateusz 	if (!TAILQ_EMPTY(&writer->rq_queue)) {
141*31cf6336SKozlowski Mateusz 		band = get_band(writer);
142*31cf6336SKozlowski Mateusz 		if (spdk_unlikely(!band)) {
143*31cf6336SKozlowski Mateusz 			return;
144*31cf6336SKozlowski Mateusz 		}
145*31cf6336SKozlowski Mateusz 
146*31cf6336SKozlowski Mateusz 		if (!can_write(writer)) {
147*31cf6336SKozlowski Mateusz 			return;
148*31cf6336SKozlowski Mateusz 		}
149*31cf6336SKozlowski Mateusz 
150*31cf6336SKozlowski Mateusz 		/* Finally we can write to band */
151*31cf6336SKozlowski Mateusz 		rq = TAILQ_FIRST(&writer->rq_queue);
152*31cf6336SKozlowski Mateusz 		TAILQ_REMOVE(&writer->rq_queue, rq, qentry);
153*31cf6336SKozlowski Mateusz 		ftl_band_rq_write(writer->band, rq);
154*31cf6336SKozlowski Mateusz 	}
155*31cf6336SKozlowski Mateusz }
156*31cf6336SKozlowski Mateusz 
157*31cf6336SKozlowski Mateusz bool
158*31cf6336SKozlowski Mateusz ftl_writer_is_halted(struct ftl_writer *writer)
159*31cf6336SKozlowski Mateusz {
160*31cf6336SKozlowski Mateusz 	if (spdk_unlikely(!TAILQ_EMPTY(&writer->full_bands))) {
161*31cf6336SKozlowski Mateusz 		return false;
162*31cf6336SKozlowski Mateusz 	}
163*31cf6336SKozlowski Mateusz 
164*31cf6336SKozlowski Mateusz 	if (writer->band) {
165*31cf6336SKozlowski Mateusz 		if (writer->band->md->state != FTL_BAND_STATE_OPEN) {
166*31cf6336SKozlowski Mateusz 			return false;
167*31cf6336SKozlowski Mateusz 		}
168*31cf6336SKozlowski Mateusz 
169*31cf6336SKozlowski Mateusz 		if (writer->band->queue_depth) {
170*31cf6336SKozlowski Mateusz 			return false;
171*31cf6336SKozlowski Mateusz 		}
172*31cf6336SKozlowski Mateusz 	}
173*31cf6336SKozlowski Mateusz 
174*31cf6336SKozlowski Mateusz 	return writer->halt;
175*31cf6336SKozlowski Mateusz }
176*31cf6336SKozlowski Mateusz 
177*31cf6336SKozlowski Mateusz uint64_t
178*31cf6336SKozlowski Mateusz ftl_writer_get_free_blocks(struct ftl_writer *writer)
179*31cf6336SKozlowski Mateusz {
180*31cf6336SKozlowski Mateusz 	uint64_t free_blocks = 0;
181*31cf6336SKozlowski Mateusz 
182*31cf6336SKozlowski Mateusz 	if (writer->band) {
183*31cf6336SKozlowski Mateusz 		free_blocks += ftl_band_user_blocks_left(writer->band,
184*31cf6336SKozlowski Mateusz 				writer->band->md->iter.offset);
185*31cf6336SKozlowski Mateusz 	}
186*31cf6336SKozlowski Mateusz 
187*31cf6336SKozlowski Mateusz 	if (writer->next_band) {
188*31cf6336SKozlowski Mateusz 		free_blocks += ftl_band_user_blocks_left(writer->next_band,
189*31cf6336SKozlowski Mateusz 				writer->next_band->md->iter.offset);
190*31cf6336SKozlowski Mateusz 	}
191*31cf6336SKozlowski Mateusz 
192*31cf6336SKozlowski Mateusz 	return free_blocks;
193*31cf6336SKozlowski Mateusz }
194