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 : 89092218 : close_full_bands(struct ftl_writer *writer)
60 : : {
61 : : struct ftl_band *band, *next;
62 : :
63 [ + + # # : 89092535 : TAILQ_FOREACH_SAFE(band, &writer->full_bands, queue_entry, next) {
# # # # #
# # # # #
# # ]
64 [ + + # # : 317 : if (band->queue_depth) {
# # ]
65 : 313 : continue;
66 : : }
67 : :
68 [ - + # # : 4 : TAILQ_REMOVE(&writer->full_bands, band, queue_entry);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
69 : 4 : ftl_band_close(band);
70 : 0 : }
71 : 89092218 : }
72 : :
73 : : static bool
74 : 1392 : is_active(struct ftl_writer *writer)
75 : : {
76 [ - + # # : 1392 : if (writer->dev->limit < writer->limit) {
# # # # #
# # # #
# ]
77 : 0 : return false;
78 : : }
79 : :
80 : 1392 : return true;
81 : 0 : }
82 : :
83 : : static struct ftl_band *
84 : 4989 : get_band(struct ftl_writer *writer)
85 : : {
86 [ + + # # : 4989 : if (spdk_unlikely(!writer->band)) {
# # ]
87 [ - + ]: 1392 : if (!is_active(writer)) {
88 : 0 : return NULL;
89 : : }
90 : :
91 [ - + # # : 1392 : 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 [ + + # # : 1392 : 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 : 1386 : 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 [ + + # # : 3603 : if (spdk_likely(writer->band->md->state == FTL_BAND_STATE_OPEN)) {
# # # # #
# # # #
# ]
131 [ # # # # ]: 3586 : return writer->band;
132 : : } else {
133 [ + + # # : 17 : if (spdk_unlikely(writer->band->md->state == FTL_BAND_STATE_PREP)) {
# # # # #
# # # #
# ]
134 [ # # # # : 6 : ftl_band_open(writer->band, writer->writer_type);
# # # # ]
135 : 0 : }
136 : 17 : return NULL;
137 : : }
138 : 0 : }
139 : :
140 : : void
141 : 89092218 : ftl_writer_run(struct ftl_writer *writer)
142 : : {
143 : : struct ftl_band *band;
144 : : struct ftl_rq *rq;
145 : :
146 : 89092218 : close_full_bands(writer);
147 : :
148 [ + + # # : 89092218 : if (!TAILQ_EMPTY(&writer->rq_queue)) {
# # # # ]
149 : 4989 : band = get_band(writer);
150 [ + + ]: 4989 : if (spdk_unlikely(!band)) {
151 : 1403 : 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 : 256034 : ftl_writer_is_halted(struct ftl_writer *writer)
204 : : {
205 [ + + # # : 256034 : if (spdk_unlikely(!TAILQ_EMPTY(&writer->full_bands))) {
# # # # ]
206 : 289 : return false;
207 : : }
208 : :
209 [ + + # # : 255745 : if (writer->band) {
# # ]
210 [ - + # # : 251294 : if (writer->band->md->state != FTL_BAND_STATE_OPEN) {
# # # # #
# # # #
# ]
211 : 0 : return false;
212 : : }
213 : :
214 [ + + # # : 251294 : if (writer->band->queue_depth) {
# # # # #
# ]
215 : 250182 : return false;
216 : : }
217 : 0 : }
218 : :
219 [ - + + + : 5563 : if (writer->dev->conf.prep_upgrade_on_shutdown) {
# # # # #
# # # #
# ]
220 [ + + # # : 5080 : if (writer->band) {
# # ]
221 : 1012 : ftl_writer_pad_band(writer);
222 [ + + # # : 4068 : } else if (writer->num_bands) {
# # ]
223 : 3054 : return false;
224 : : } else {
225 : : /* All bands closed, free padding request */
226 [ # # # # ]: 1014 : ftl_rq_del(writer->pad);
227 [ # # # # ]: 1014 : writer->pad = NULL;
228 : : }
229 : 0 : }
230 : :
231 [ - + # # : 2509 : 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 : : }
|