Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2018 Intel Corporation.
3 : : * All rights reserved.
4 : : */
5 : :
6 : : #include "spdk/likely.h"
7 : : #include "spdk/stdinc.h"
8 : : #include "spdk/nvme.h"
9 : : #include "spdk/thread.h"
10 : : #include "spdk/bdev_module.h"
11 : : #include "spdk/string.h"
12 : : #include "spdk/ftl.h"
13 : : #include "spdk/crc32.h"
14 : :
15 : : #include "ftl_core.h"
16 : : #include "ftl_band.h"
17 : : #include "ftl_io.h"
18 : : #include "ftl_debug.h"
19 : : #include "ftl_internal.h"
20 : : #include "mngt/ftl_mngt.h"
21 : :
22 : :
23 : : size_t
24 : 4268 : spdk_ftl_io_size(void)
25 : : {
26 : 4268 : return sizeof(struct ftl_io);
27 : : }
28 : :
29 : : static void
30 : 1956783 : ftl_io_cmpl_cb(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
31 : : {
32 : 1956783 : struct ftl_io *io = cb_arg;
33 : 1956783 : struct spdk_ftl_dev *dev = io->dev;
34 : :
35 : 1956783 : ftl_stats_bdev_io_completed(dev, FTL_STATS_TYPE_USER, bdev_io);
36 : :
37 [ - + ]: 1956783 : if (spdk_unlikely(!success)) {
38 : 0 : io->status = -EIO;
39 : : }
40 : :
41 : 1956783 : ftl_trace_completion(dev, io, FTL_TRACE_COMPLETION_DISK);
42 : :
43 : 1956783 : ftl_io_dec_req(io);
44 [ + - ]: 1956783 : if (ftl_io_done(io)) {
45 : 1956783 : ftl_io_complete(io);
46 : : }
47 : :
48 : 1956783 : spdk_bdev_free_io(bdev_io);
49 : 1956783 : }
50 : :
51 : : static void
52 : 7 : ftl_band_erase(struct ftl_band *band)
53 : : {
54 [ + - - + ]: 7 : assert(band->md->state == FTL_BAND_STATE_CLOSED ||
55 : : band->md->state == FTL_BAND_STATE_FREE);
56 : :
57 : 7 : ftl_band_set_state(band, FTL_BAND_STATE_PREP);
58 : 7 : }
59 : :
60 : : static size_t
61 : 21073470 : ftl_get_limit(const struct spdk_ftl_dev *dev, int type)
62 : : {
63 [ - + ]: 21073470 : assert(type < SPDK_FTL_LIMIT_MAX);
64 : 21073470 : return dev->conf.limits[type];
65 : : }
66 : :
67 : : static bool
68 : 103750 : ftl_shutdown_complete(struct spdk_ftl_dev *dev)
69 : : {
70 : : uint64_t i;
71 : :
72 [ - + ]: 103750 : if (dev->num_inflight) {
73 : 0 : return false;
74 : : }
75 : :
76 [ + + ]: 103750 : if (!ftl_nv_cache_is_halted(&dev->nv_cache)) {
77 : 4357 : ftl_nv_cache_halt(&dev->nv_cache);
78 : 4357 : return false;
79 : : }
80 : :
81 [ + + ]: 99393 : if (!ftl_writer_is_halted(&dev->writer_user)) {
82 : 97886 : ftl_writer_halt(&dev->writer_user);
83 : 97886 : return false;
84 : : }
85 : :
86 [ + + ]: 1507 : if (!ftl_reloc_is_halted(dev->reloc)) {
87 : 417 : ftl_reloc_halt(dev->reloc);
88 : 417 : return false;
89 : : }
90 : :
91 [ + + ]: 1090 : if (!ftl_writer_is_halted(&dev->writer_gc)) {
92 : 27 : ftl_writer_halt(&dev->writer_gc);
93 : 27 : return false;
94 : : }
95 : :
96 [ - + ]: 1063 : if (!ftl_nv_cache_chunks_busy(&dev->nv_cache)) {
97 : 0 : return false;
98 : : }
99 : :
100 [ + + ]: 7957 : for (i = 0; i < ftl_get_num_bands(dev); ++i) {
101 [ + + ]: 7903 : if (dev->bands[i].queue_depth ||
102 [ + + ]: 7090 : dev->bands[i].md->state == FTL_BAND_STATE_CLOSING) {
103 : 1009 : return false;
104 : : }
105 : : }
106 : :
107 [ + + ]: 54 : if (!ftl_l2p_is_halted(dev)) {
108 : 27 : ftl_l2p_halt(dev);
109 : 27 : return false;
110 : : }
111 : :
112 : 27 : return true;
113 : : }
114 : :
115 : : void
116 : 2562 : ftl_apply_limits(struct spdk_ftl_dev *dev)
117 : : {
118 : : size_t limit;
119 : 2562 : struct ftl_stats *stats = &dev->stats;
120 : : int i;
121 : :
122 : : /* Clear existing limit */
123 : 2562 : dev->limit = SPDK_FTL_LIMIT_MAX;
124 : :
125 [ + + ]: 12432 : for (i = SPDK_FTL_LIMIT_CRIT; i < SPDK_FTL_LIMIT_MAX; ++i) {
126 : 10005 : limit = ftl_get_limit(dev, i);
127 : :
128 [ + + ]: 10005 : if (dev->num_free <= limit) {
129 : 135 : stats->limits[i]++;
130 : 135 : dev->limit = i;
131 : 135 : break;
132 : : }
133 : : }
134 : :
135 : 2562 : ftl_trace_limits(dev, dev->limit, dev->num_free);
136 : 2562 : }
137 : :
138 : : void
139 : 1369149 : ftl_invalidate_addr(struct spdk_ftl_dev *dev, ftl_addr addr)
140 : : {
141 : : struct ftl_band *band;
142 : : struct ftl_p2l_map *p2l_map;
143 : :
144 [ + + ]: 1369149 : if (ftl_addr_in_nvc(dev, addr)) {
145 : 1369137 : ftl_bitmap_clear(dev->valid_map, addr);
146 : 1369137 : return;
147 : : }
148 : :
149 : 12 : band = ftl_band_from_addr(dev, addr);
150 : 12 : p2l_map = &band->p2l_map;
151 : :
152 : : /* The bit might be already cleared if two writes are scheduled to the */
153 : : /* same LBA at the same time */
154 [ + - ]: 12 : if (ftl_bitmap_get(dev->valid_map, addr)) {
155 [ - + ]: 12 : assert(p2l_map->num_valid > 0);
156 : 12 : ftl_bitmap_clear(dev->valid_map, addr);
157 : 12 : p2l_map->num_valid--;
158 : : }
159 : :
160 : : /* Invalidate open/full band p2l_map entry to keep p2l and l2p
161 : : * consistency when band is going to close state */
162 [ + - - + ]: 12 : if (FTL_BAND_STATE_OPEN == band->md->state || FTL_BAND_STATE_FULL == band->md->state) {
163 : 0 : p2l_map->band_map[ftl_band_block_offset_from_addr(band, addr)].lba = FTL_LBA_INVALID;
164 : 0 : p2l_map->band_map[ftl_band_block_offset_from_addr(band, addr)].seq_id = 0;
165 : : }
166 : : }
167 : :
168 : : static int
169 : 1959001 : ftl_read_canceled(int rc)
170 : : {
171 : 1959001 : return rc == -EFAULT;
172 : : }
173 : :
174 : : static int
175 : 1959001 : ftl_get_next_read_addr(struct ftl_io *io, ftl_addr *addr)
176 : : {
177 : 1959001 : struct spdk_ftl_dev *dev = io->dev;
178 : : ftl_addr next_addr;
179 : : size_t i;
180 : 1959001 : bool addr_cached = false;
181 : :
182 : 1959001 : *addr = ftl_l2p_get(dev, ftl_io_current_lba(io));
183 : 1959001 : io->map[io->pos] = *addr;
184 : :
185 : : /* If the address is invalid, skip it */
186 [ + + ]: 1959001 : if (*addr == FTL_ADDR_INVALID) {
187 : 2218 : return -EFAULT;
188 : : }
189 : :
190 : 1956783 : addr_cached = ftl_addr_in_nvc(dev, *addr);
191 : :
192 [ + + ]: 3033801 : for (i = 1; i < ftl_io_iovec_len_left(io); ++i) {
193 : 1077018 : next_addr = ftl_l2p_get(dev, ftl_io_get_lba(io, io->pos + i));
194 : :
195 [ - + ]: 1077018 : if (next_addr == FTL_ADDR_INVALID) {
196 : 0 : break;
197 : : }
198 : :
199 : : /* It's not enough to check for contiguity, if user data is on the last block
200 : : * of base device and first nvc, then they're 'contiguous', but can't be handled
201 : : * with one read request.
202 : : */
203 [ - + ]: 1077018 : if (addr_cached != ftl_addr_in_nvc(dev, next_addr)) {
204 : 0 : break;
205 : : }
206 : :
207 [ - + ]: 1077018 : if (*addr + i != next_addr) {
208 : 0 : break;
209 : : }
210 : :
211 : 1077018 : io->map[io->pos + i] = next_addr;
212 : : }
213 : :
214 : 1956783 : return i;
215 : : }
216 : :
217 : : static void ftl_submit_read(struct ftl_io *io);
218 : :
219 : : static void
220 : 0 : _ftl_submit_read(void *_io)
221 : : {
222 : 0 : struct ftl_io *io = _io;
223 : :
224 : 0 : ftl_submit_read(io);
225 : 0 : }
226 : :
227 : : static void
228 : 1958882 : ftl_submit_read(struct ftl_io *io)
229 : : {
230 : 1958882 : struct spdk_ftl_dev *dev = io->dev;
231 : 1958882 : ftl_addr addr;
232 : 1958882 : int rc = 0, num_blocks;
233 : :
234 [ + + ]: 3917883 : while (io->pos < io->num_blocks) {
235 : 1959001 : num_blocks = ftl_get_next_read_addr(io, &addr);
236 : 1959001 : rc = num_blocks;
237 : :
238 : : /* User LBA doesn't hold valid data (trimmed or never written to), fill with 0 and skip this block */
239 [ + + ]: 1959001 : if (ftl_read_canceled(rc)) {
240 [ - + ]: 2218 : memset(ftl_io_iovec_addr(io), 0, FTL_BLOCK_SIZE);
241 : 2218 : ftl_io_advance(io, 1);
242 : 2218 : continue;
243 : : }
244 : :
245 [ - + ]: 1956783 : assert(num_blocks > 0);
246 : :
247 : 1956783 : ftl_trace_submission(dev, io, addr, num_blocks);
248 : :
249 [ + + ]: 1956783 : if (ftl_addr_in_nvc(dev, addr)) {
250 : 1670571 : rc = ftl_nv_cache_read(io, addr, num_blocks, ftl_io_cmpl_cb, io);
251 : : } else {
252 : 286212 : rc = spdk_bdev_read_blocks(dev->base_bdev_desc, dev->base_ioch,
253 : : ftl_io_iovec_addr(io),
254 : : addr, num_blocks, ftl_io_cmpl_cb, io);
255 : : }
256 : :
257 [ - + ]: 1956783 : if (spdk_unlikely(rc)) {
258 [ # # ]: 0 : if (rc == -ENOMEM) {
259 : : struct spdk_bdev *bdev;
260 : : struct spdk_io_channel *ch;
261 : :
262 [ # # ]: 0 : if (ftl_addr_in_nvc(dev, addr)) {
263 : 0 : bdev = spdk_bdev_desc_get_bdev(dev->nv_cache.bdev_desc);
264 : 0 : ch = dev->nv_cache.cache_ioch;
265 : : } else {
266 : 0 : bdev = spdk_bdev_desc_get_bdev(dev->base_bdev_desc);
267 : 0 : ch = dev->base_ioch;
268 : : }
269 : 0 : io->bdev_io_wait.bdev = bdev;
270 : 0 : io->bdev_io_wait.cb_fn = _ftl_submit_read;
271 : 0 : io->bdev_io_wait.cb_arg = io;
272 : 0 : spdk_bdev_queue_io_wait(bdev, ch, &io->bdev_io_wait);
273 : 0 : return;
274 : : } else {
275 : 0 : ftl_abort();
276 : : }
277 : : }
278 : :
279 : 1956783 : ftl_io_inc_req(io);
280 : 1956783 : ftl_io_advance(io, num_blocks);
281 : : }
282 : :
283 : : /* If we didn't have to read anything from the device, */
284 : : /* complete the request right away */
285 [ + + ]: 1958882 : if (ftl_io_done(io)) {
286 : 2099 : ftl_io_complete(io);
287 : : }
288 : : }
289 : :
290 : : bool
291 : 21063465 : ftl_needs_reloc(struct spdk_ftl_dev *dev)
292 : : {
293 : 21063465 : size_t limit = ftl_get_limit(dev, SPDK_FTL_LIMIT_START);
294 : :
295 [ - + ]: 21063465 : if (dev->num_free <= limit) {
296 : 0 : return true;
297 : : }
298 : :
299 : 21063465 : return false;
300 : : }
301 : :
302 : : void
303 : 30 : spdk_ftl_dev_get_attrs(const struct spdk_ftl_dev *dev, struct spdk_ftl_attrs *attrs,
304 : : size_t attrs_size)
305 : : {
306 : 30 : attrs->num_blocks = dev->num_lbas;
307 : 30 : attrs->block_size = FTL_BLOCK_SIZE;
308 : 30 : attrs->optimum_io_size = dev->xfer_size;
309 : : /* NOTE: check any new fields in attrs against attrs_size */
310 : 30 : }
311 : :
312 : : static void
313 : 1958882 : ftl_io_pin_cb(struct spdk_ftl_dev *dev, int status, struct ftl_l2p_pin_ctx *pin_ctx)
314 : : {
315 : 1958882 : struct ftl_io *io = pin_ctx->cb_ctx;
316 : :
317 [ - + ]: 1958882 : if (spdk_unlikely(status != 0)) {
318 : : /* Retry on the internal L2P fault */
319 : 0 : io->status = -EAGAIN;
320 : 0 : ftl_io_complete(io);
321 : 0 : return;
322 : : }
323 : :
324 : 1958882 : io->flags |= FTL_IO_PINNED;
325 : 1958882 : ftl_submit_read(io);
326 : : }
327 : :
328 : : static void
329 : 1958882 : ftl_io_pin(struct ftl_io *io)
330 : : {
331 [ - + ]: 1958882 : if (spdk_unlikely(io->flags & FTL_IO_PINNED)) {
332 : : /*
333 : : * The IO is in a retry path and it had been pinned already.
334 : : * Continue with further processing.
335 : : */
336 : 0 : ftl_l2p_pin_skip(io->dev, ftl_io_pin_cb, io, &io->l2p_pin_ctx);
337 : : } else {
338 : : /* First time when pinning the IO */
339 : 1958882 : ftl_l2p_pin(io->dev, io->lba, io->num_blocks,
340 : : ftl_io_pin_cb, io, &io->l2p_pin_ctx);
341 : : }
342 : 1958882 : }
343 : :
344 : : static void
345 : 3607805 : start_io(struct ftl_io *io)
346 : : {
347 : 3607805 : struct ftl_io_channel *ioch = ftl_io_channel_get_ctx(io->ioch);
348 : 3607805 : struct spdk_ftl_dev *dev = io->dev;
349 : :
350 : 3607805 : io->map = ftl_mempool_get(ioch->map_pool);
351 [ - + ]: 3607805 : if (spdk_unlikely(!io->map)) {
352 : 0 : io->status = -ENOMEM;
353 : 0 : ftl_io_complete(io);
354 : 0 : return;
355 : : }
356 : :
357 [ + + + - ]: 3607805 : switch (io->type) {
358 : 1958880 : case FTL_IO_READ:
359 : 1958880 : TAILQ_INSERT_TAIL(&dev->rd_sq, io, queue_entry);
360 : 1958880 : break;
361 : 1648921 : case FTL_IO_WRITE:
362 : 1648921 : TAILQ_INSERT_TAIL(&dev->wr_sq, io, queue_entry);
363 : 1648921 : break;
364 : 4 : case FTL_IO_TRIM:
365 : 4 : TAILQ_INSERT_TAIL(&dev->trim_sq, io, queue_entry);
366 : 4 : break;
367 : 0 : default:
368 : 0 : io->status = -EOPNOTSUPP;
369 : 0 : ftl_io_complete(io);
370 : : }
371 : : }
372 : :
373 : : static int
374 : 3607805 : queue_io(struct spdk_ftl_dev *dev, struct ftl_io *io)
375 : : {
376 : : size_t result;
377 : 3607805 : struct ftl_io_channel *ioch = ftl_io_channel_get_ctx(io->ioch);
378 : :
379 : 3607805 : result = spdk_ring_enqueue(ioch->sq, (void **)&io, 1, NULL);
380 [ - + ]: 3607805 : if (spdk_unlikely(0 == result)) {
381 : 0 : return -EAGAIN;
382 : : }
383 : :
384 : 3607805 : return 0;
385 : : }
386 : :
387 : : int
388 : 1648921 : spdk_ftl_writev(struct spdk_ftl_dev *dev, struct ftl_io *io, struct spdk_io_channel *ch,
389 : : uint64_t lba, uint64_t lba_cnt, struct iovec *iov, size_t iov_cnt, spdk_ftl_fn cb_fn,
390 : : void *cb_arg)
391 : : {
392 : : int rc;
393 : :
394 [ - + ]: 1648921 : if (iov_cnt == 0) {
395 : 0 : return -EINVAL;
396 : : }
397 : :
398 [ - + ]: 1648921 : if (lba_cnt == 0) {
399 : 0 : return -EINVAL;
400 : : }
401 : :
402 [ - + ]: 1648921 : if (lba_cnt != ftl_iovec_num_blocks(iov, iov_cnt)) {
403 [ # # ]: 0 : FTL_ERRLOG(dev, "Invalid IO vector to handle, device %s, LBA %"PRIu64"\n",
404 : : dev->conf.name, lba);
405 : 0 : return -EINVAL;
406 : : }
407 : :
408 [ - + - + ]: 1648921 : if (!dev->initialized) {
409 : 0 : return -EBUSY;
410 : : }
411 : :
412 : 1648921 : rc = ftl_io_init(ch, io, lba, lba_cnt, iov, iov_cnt, cb_fn, cb_arg, FTL_IO_WRITE);
413 [ - + ]: 1648921 : if (rc) {
414 : 0 : return rc;
415 : : }
416 : :
417 : 1648921 : return queue_io(dev, io);
418 : : }
419 : :
420 : : int
421 : 1958880 : spdk_ftl_readv(struct spdk_ftl_dev *dev, struct ftl_io *io, struct spdk_io_channel *ch,
422 : : uint64_t lba, uint64_t lba_cnt, struct iovec *iov, size_t iov_cnt, spdk_ftl_fn cb_fn, void *cb_arg)
423 : : {
424 : : int rc;
425 : :
426 [ - + ]: 1958880 : if (iov_cnt == 0) {
427 : 0 : return -EINVAL;
428 : : }
429 : :
430 [ - + ]: 1958880 : if (lba_cnt == 0) {
431 : 0 : return -EINVAL;
432 : : }
433 : :
434 [ - + ]: 1958880 : if (lba_cnt != ftl_iovec_num_blocks(iov, iov_cnt)) {
435 [ # # ]: 0 : FTL_ERRLOG(dev, "Invalid IO vector to handle, device %s, LBA %"PRIu64"\n",
436 : : dev->conf.name, lba);
437 : 0 : return -EINVAL;
438 : : }
439 : :
440 [ - + - + ]: 1958880 : if (!dev->initialized) {
441 : 0 : return -EBUSY;
442 : : }
443 : :
444 : 1958880 : rc = ftl_io_init(ch, io, lba, lba_cnt, iov, iov_cnt, cb_fn, cb_arg, FTL_IO_READ);
445 [ - + ]: 1958880 : if (rc) {
446 : 0 : return rc;
447 : : }
448 : :
449 : 1958880 : return queue_io(dev, io);
450 : : }
451 : :
452 : : int
453 : 4 : ftl_trim(struct spdk_ftl_dev *dev, struct ftl_io *io, struct spdk_io_channel *ch,
454 : : uint64_t lba, uint64_t lba_cnt, spdk_ftl_fn cb_fn, void *cb_arg)
455 : : {
456 : : int rc;
457 : :
458 : 4 : rc = ftl_io_init(ch, io, lba, lba_cnt, NULL, 0, cb_fn, cb_arg, FTL_IO_TRIM);
459 [ - + ]: 4 : if (rc) {
460 : 0 : return rc;
461 : : }
462 : :
463 : 4 : return queue_io(dev, io);
464 : : }
465 : :
466 : : int
467 : 8 : spdk_ftl_unmap(struct spdk_ftl_dev *dev, struct ftl_io *io, struct spdk_io_channel *ch,
468 : : uint64_t lba, uint64_t lba_cnt, spdk_ftl_fn cb_fn, void *cb_arg)
469 : : {
470 : : int rc;
471 : 8 : uint64_t alignment = dev->layout.l2p.lbas_in_page;
472 : :
473 [ - + ]: 8 : if (lba_cnt == 0) {
474 : 0 : return -EINVAL;
475 : : }
476 : :
477 [ - + ]: 8 : if (lba + lba_cnt < lba_cnt) {
478 : 0 : return -EINVAL;
479 : : }
480 : :
481 [ - + ]: 8 : if (lba + lba_cnt > dev->num_lbas) {
482 : 0 : return -EINVAL;
483 : : }
484 : :
485 [ - + - + ]: 8 : if (!dev->initialized) {
486 : 0 : return -EBUSY;
487 : : }
488 : :
489 [ - + + - : 8 : if (lba % alignment || lba_cnt % alignment) {
- + - + ]
490 [ # # ]: 0 : if (!io) {
491 : : /* This is management/RPC path, its parameters must be aligned to 1MiB. */
492 : 0 : return -EINVAL;
493 : : }
494 : :
495 : : /* Otherwise unaligned IO requests are NOPs */
496 : 0 : rc = ftl_io_init(ch, io, lba, lba_cnt, NULL, 0, cb_fn, cb_arg, FTL_IO_TRIM);
497 [ # # ]: 0 : if (rc) {
498 : 0 : return rc;
499 : : }
500 : :
501 : 0 : io->status = 0;
502 : 0 : ftl_io_complete(io);
503 : 0 : return 0;
504 : : }
505 : :
506 [ + + ]: 8 : if (io) {
507 : 4 : rc = ftl_trim(dev, io, ch, lba, lba_cnt, cb_fn, cb_arg);
508 : : } else {
509 : 4 : rc = ftl_mngt_trim(dev, lba, lba_cnt, cb_fn, cb_arg);
510 : : }
511 : :
512 : 8 : return rc;
513 : : }
514 : :
515 : : #define FTL_IO_QUEUE_BATCH 16
516 : : int
517 : 57024890 : ftl_io_channel_poll(void *arg)
518 : : {
519 : 57024890 : struct ftl_io_channel *ch = arg;
520 : 57024890 : void *ios[FTL_IO_QUEUE_BATCH];
521 : : uint64_t i, count;
522 : :
523 : 57024890 : count = spdk_ring_dequeue(ch->cq, ios, FTL_IO_QUEUE_BATCH);
524 [ + + ]: 57024890 : if (count == 0) {
525 : 54243747 : return SPDK_POLLER_IDLE;
526 : : }
527 : :
528 [ + + ]: 6388948 : for (i = 0; i < count; i++) {
529 : 3607805 : struct ftl_io *io = ios[i];
530 : 3607805 : io->user_fn(io->cb_ctx, io->status);
531 : : }
532 : :
533 : 2781143 : return SPDK_POLLER_BUSY;
534 : : }
535 : :
536 : : static void
537 : 24602950 : ftl_process_io_channel(struct spdk_ftl_dev *dev, struct ftl_io_channel *ioch)
538 : : {
539 : 24602950 : void *ios[FTL_IO_QUEUE_BATCH];
540 : : size_t count, i;
541 : :
542 : 24602950 : count = spdk_ring_dequeue(ioch->sq, ios, FTL_IO_QUEUE_BATCH);
543 [ + + ]: 24602950 : if (count == 0) {
544 : 22024844 : return;
545 : : }
546 : :
547 [ + + ]: 6185911 : for (i = 0; i < count; i++) {
548 : 3607805 : struct ftl_io *io = ios[i];
549 : 3607805 : start_io(io);
550 : : }
551 : : }
552 : :
553 : : static void
554 : 4 : ftl_trim_log_clear(struct spdk_ftl_dev *dev)
555 : : {
556 : 4 : struct ftl_trim_log *log = ftl_md_get_buffer(dev->layout.md[FTL_LAYOUT_REGION_TYPE_TRIM_LOG]);
557 : :
558 [ - + ]: 4 : memset(&log->hdr, 0, sizeof(log->hdr));
559 : 4 : }
560 : :
561 : : static void
562 : 4 : ftl_trim_finish(struct ftl_io *io, int status)
563 : : {
564 : 4 : io->dev->trim_qd--;
565 : :
566 [ - + ]: 4 : if (spdk_unlikely(status)) {
567 : : #ifdef SPDK_FTL_RETRY_ON_ERROR
568 : : ftl_io_clear(io);
569 : : TAILQ_INSERT_HEAD(&io->dev->trim_sq, io, queue_entry);
570 : : return;
571 : : #else
572 : 0 : io->status = status;
573 : : #endif
574 : : }
575 : :
576 : 4 : ftl_io_complete(io);
577 : 4 : }
578 : :
579 : : static void
580 : 4 : ftl_trim_log_close_cb(int status, void *cb_arg)
581 : : {
582 : 4 : struct ftl_io *io = cb_arg;
583 : :
584 : 4 : ftl_trim_finish(io, status);
585 : 4 : }
586 : :
587 : : static void
588 : 8 : ftl_trim_log_persist(struct ftl_io *io, ftl_md_io_entry_cb cb)
589 : : {
590 : 8 : struct spdk_ftl_dev *dev = io->dev;
591 : 8 : struct ftl_md *trim_log = dev->layout.md[FTL_LAYOUT_REGION_TYPE_TRIM_LOG];
592 : :
593 : 8 : ftl_md_persist_entries(trim_log, 0, 1, ftl_md_get_buffer(trim_log), NULL,
594 : : cb, io, &dev->trim_md_io_entry_ctx);
595 : 8 : }
596 : :
597 : : static void
598 : 4 : ftl_trim_md_cb(int status, void *cb_arg)
599 : : {
600 : 4 : struct ftl_io *io = cb_arg;
601 : 4 : struct spdk_ftl_dev *dev = io->dev;
602 : :
603 [ - + ]: 4 : if (status) {
604 : 0 : io->status = status;
605 : : }
606 : 4 : ftl_trim_log_clear(dev);
607 : 4 : ftl_trim_log_persist(io, ftl_trim_log_close_cb);
608 : 4 : }
609 : :
610 : : static void
611 : 4 : ftl_trim_log_open_cb(int status, void *cb_arg)
612 : : {
613 : 4 : struct ftl_io *io = cb_arg;
614 : 4 : struct spdk_ftl_dev *dev = io->dev;
615 : 4 : struct ftl_md *trim_md = dev->layout.md[FTL_LAYOUT_REGION_TYPE_TRIM_MD];
616 : : uint64_t first, entires;
617 : 4 : const uint64_t entires_in_block = FTL_BLOCK_SIZE / sizeof(uint64_t);
618 : : char *buffer;
619 : :
620 [ - + ]: 4 : if (status) {
621 : 0 : ftl_trim_finish(io, status);
622 : 0 : return;
623 : : }
624 : :
625 : : /* Map trim space into L2P pages */
626 [ - + ]: 4 : first = io->lba / dev->layout.l2p.lbas_in_page;
627 [ - + ]: 4 : entires = io->num_blocks / dev->layout.l2p.lbas_in_page;
628 : : /* Map pages into trim metadata location */
629 [ - + ]: 4 : first = first / entires_in_block;
630 : 4 : entires = spdk_divide_round_up(entires, entires_in_block);
631 : :
632 : : /* Get trim metadata buffer */
633 : 4 : buffer = (char *)ftl_md_get_buffer(trim_md) + (FTL_BLOCK_SIZE * first);
634 : :
635 : : /* Persist the trim metadata snippet which corresponds to the trim IO */
636 : 4 : ftl_md_persist_entries(trim_md, first, entires, buffer, NULL,
637 : : ftl_trim_md_cb, io, &dev->trim_md_io_entry_ctx);
638 : : }
639 : :
640 : : void
641 : 4 : ftl_set_trim_map(struct spdk_ftl_dev *dev, uint64_t lba, uint64_t num_blocks, uint64_t seq_id)
642 : : {
643 : : uint64_t first_page, num_pages;
644 : 4 : uint64_t lbas_in_page = dev->layout.l2p.lbas_in_page;
645 : 4 : struct ftl_md *md = dev->layout.md[FTL_LAYOUT_REGION_TYPE_TRIM_MD];
646 : 4 : uint64_t *page = ftl_md_get_buffer(md);
647 : : struct ftl_trim_log *log;
648 : : size_t i;
649 : :
650 [ - + ]: 4 : first_page = lba / lbas_in_page;
651 [ - + ]: 4 : num_pages = num_blocks / lbas_in_page;
652 : :
653 : : /* Fill trim metadata */
654 [ + + ]: 8 : for (i = first_page; i < first_page + num_pages; ++i) {
655 : 4 : ftl_bitmap_set(dev->trim_map, i);
656 : 4 : page[i] = seq_id;
657 : : }
658 : :
659 : : /* Fill trim log */
660 : 4 : log = ftl_md_get_buffer(dev->layout.md[FTL_LAYOUT_REGION_TYPE_TRIM_LOG]);
661 : 4 : log->hdr.trim.seq_id = seq_id;
662 : 4 : log->hdr.trim.num_blocks = num_blocks;
663 : 4 : log->hdr.trim.start_lba = lba;
664 : 4 : }
665 : :
666 : : static bool
667 : 4 : ftl_process_trim(struct ftl_io *io)
668 : : {
669 : 4 : struct spdk_ftl_dev *dev = io->dev;
670 : : uint64_t seq_id;
671 : :
672 : 4 : seq_id = ftl_nv_cache_acquire_trim_seq_id(&dev->nv_cache);
673 [ - + ]: 4 : if (seq_id == 0) {
674 : 0 : return false;
675 : : }
676 : :
677 : 4 : dev->trim_in_progress = true;
678 : 4 : dev->trim_qd++;
679 : :
680 : 4 : dev->sb_shm->trim.start_lba = io->lba;
681 : 4 : dev->sb_shm->trim.num_blocks = io->num_blocks;
682 : 4 : dev->sb_shm->trim.seq_id = seq_id;
683 : 4 : dev->sb_shm->trim.in_progress = true;
684 : 4 : ftl_set_trim_map(dev, io->lba, io->num_blocks, seq_id);
685 : 4 : ftl_debug_inject_trim_error();
686 : 4 : dev->sb_shm->trim.in_progress = false;
687 : :
688 : 4 : ftl_trim_log_persist(io, ftl_trim_log_open_cb);
689 : 4 : return true;
690 : : }
691 : :
692 : : static void
693 : 21163854 : ftl_process_io_queue(struct spdk_ftl_dev *dev)
694 : : {
695 : : struct ftl_io_channel *ioch;
696 : : struct ftl_io *io;
697 : :
698 : : /* TODO: Try to figure out a mechanism to batch more requests at the same time,
699 : : * with keeping enough resources (pinned pages), between reads, writes and gc/compaction
700 : : */
701 [ + + ]: 21163854 : if (!TAILQ_EMPTY(&dev->rd_sq)) {
702 : 1958882 : io = TAILQ_FIRST(&dev->rd_sq);
703 [ + + ]: 1958882 : TAILQ_REMOVE(&dev->rd_sq, io, queue_entry);
704 [ - + ]: 1958882 : assert(io->type == FTL_IO_READ);
705 : 1958882 : ftl_io_pin(io);
706 : 1958882 : ftl_add_io_activity(dev);
707 : : }
708 : :
709 [ + + + + ]: 22812775 : while (!TAILQ_EMPTY(&dev->wr_sq) && !ftl_nv_cache_throttle(dev)) {
710 : 1648921 : io = TAILQ_FIRST(&dev->wr_sq);
711 [ + + ]: 1648921 : TAILQ_REMOVE(&dev->wr_sq, io, queue_entry);
712 [ - + ]: 1648921 : assert(io->type == FTL_IO_WRITE);
713 [ - + ]: 1648921 : if (!ftl_nv_cache_write(io)) {
714 [ # # ]: 0 : TAILQ_INSERT_HEAD(&dev->wr_sq, io, queue_entry);
715 : 0 : break;
716 : : }
717 : 1648921 : ftl_add_io_activity(dev);
718 : : }
719 : :
720 [ + + + - ]: 21163854 : if (!TAILQ_EMPTY(&dev->trim_sq) && dev->trim_qd == 0) {
721 : 4 : io = TAILQ_FIRST(&dev->trim_sq);
722 [ - + ]: 4 : TAILQ_REMOVE(&dev->trim_sq, io, queue_entry);
723 [ - + ]: 4 : assert(io->type == FTL_IO_TRIM);
724 : :
725 : : /*
726 : : * Trim operation requires generating a sequence id for itself, which it gets based on the open chunk
727 : : * in nv cache. If there are no open chunks (because we're in the middle of state transition or compaction
728 : : * lagged behind), then we need to wait for the nv cache to resolve the situation - it's fine to just put the
729 : : * trim and try again later.
730 : : */
731 [ - + ]: 4 : if (!ftl_process_trim(io)) {
732 [ # # ]: 0 : TAILQ_INSERT_HEAD(&dev->trim_sq, io, queue_entry);
733 : : } else {
734 : 4 : ftl_add_io_activity(dev);
735 : : }
736 : : }
737 : :
738 [ + + ]: 45766804 : TAILQ_FOREACH(ioch, &dev->ioch_queue, entry) {
739 : 24602950 : ftl_process_io_channel(dev, ioch);
740 : : }
741 : 21163854 : }
742 : :
743 : : int
744 : 21163881 : ftl_core_poller(void *ctx)
745 : : {
746 : 21163881 : struct spdk_ftl_dev *dev = ctx;
747 : 21163881 : uint64_t io_activity_total_old = dev->stats.io_activity_total;
748 : :
749 [ - + + + : 21163881 : if (dev->halt && ftl_shutdown_complete(dev)) {
+ + ]
750 : 27 : spdk_poller_unregister(&dev->core_poller);
751 : 27 : return SPDK_POLLER_IDLE;
752 : : }
753 : :
754 : 21163854 : ftl_process_io_queue(dev);
755 : 21163854 : ftl_writer_run(&dev->writer_user);
756 : 21163854 : ftl_writer_run(&dev->writer_gc);
757 : 21163854 : ftl_reloc(dev->reloc);
758 : 21163854 : ftl_nv_cache_process(dev);
759 : 21163854 : ftl_l2p_process(dev);
760 : :
761 [ + + ]: 21163854 : if (io_activity_total_old != dev->stats.io_activity_total) {
762 : 2805969 : return SPDK_POLLER_BUSY;
763 : : }
764 : :
765 : 18357885 : return SPDK_POLLER_IDLE;
766 : : }
767 : :
768 : : struct ftl_band *
769 : 7 : ftl_band_get_next_free(struct spdk_ftl_dev *dev)
770 : : {
771 : 7 : struct ftl_band *band = NULL;
772 : :
773 [ + - ]: 7 : if (!TAILQ_EMPTY(&dev->free_bands)) {
774 : 7 : band = TAILQ_FIRST(&dev->free_bands);
775 [ + - ]: 7 : TAILQ_REMOVE(&dev->free_bands, band, queue_entry);
776 : 7 : ftl_band_erase(band);
777 : : }
778 : :
779 : 7 : return band;
780 : : }
781 : :
782 : : void *g_ftl_write_buf;
783 : : void *g_ftl_read_buf;
784 : :
785 : : int
786 : 2134 : spdk_ftl_init(void)
787 : : {
788 : 2134 : g_ftl_write_buf = spdk_zmalloc(FTL_ZERO_BUFFER_SIZE, FTL_ZERO_BUFFER_SIZE, NULL,
789 : : SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
790 [ - + ]: 2134 : if (!g_ftl_write_buf) {
791 : 0 : return -ENOMEM;
792 : : }
793 : :
794 : 2134 : g_ftl_read_buf = spdk_zmalloc(FTL_ZERO_BUFFER_SIZE, FTL_ZERO_BUFFER_SIZE, NULL,
795 : : SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
796 [ - + ]: 2134 : if (!g_ftl_read_buf) {
797 : 0 : spdk_free(g_ftl_write_buf);
798 : 0 : g_ftl_write_buf = NULL;
799 : 0 : return -ENOMEM;
800 : : }
801 : 2134 : return 0;
802 : : }
803 : :
804 : : void
805 : 2134 : spdk_ftl_fini(void)
806 : : {
807 : 2134 : spdk_free(g_ftl_write_buf);
808 : 2134 : spdk_free(g_ftl_read_buf);
809 : 2134 : }
810 : :
811 : : void
812 : 5 : spdk_ftl_dev_set_fast_shutdown(struct spdk_ftl_dev *dev, bool fast_shutdown)
813 : : {
814 [ - + ]: 5 : assert(dev);
815 : 5 : dev->conf.fast_shutdown = fast_shutdown;
816 : 5 : }
817 : :
818 : : void
819 : 3845744 : ftl_stats_bdev_io_completed(struct spdk_ftl_dev *dev, enum ftl_stats_type type,
820 : : struct spdk_bdev_io *bdev_io)
821 : : {
822 : 3845744 : struct ftl_stats_entry *stats_entry = &dev->stats.entries[type];
823 : : struct ftl_stats_group *stats_group;
824 : 3845744 : uint32_t cdw0;
825 : 3845744 : int sct;
826 : 3845744 : int sc;
827 : :
828 [ + + - ]: 3845744 : switch (bdev_io->type) {
829 : 2078279 : case SPDK_BDEV_IO_TYPE_READ:
830 : 2078279 : stats_group = &stats_entry->read;
831 : 2078279 : break;
832 : 1767465 : case SPDK_BDEV_IO_TYPE_WRITE:
833 : : case SPDK_BDEV_IO_TYPE_WRITE_ZEROES:
834 : 1767465 : stats_group = &stats_entry->write;
835 : 1767465 : break;
836 : 0 : default:
837 : 0 : return;
838 : : }
839 : :
840 : 3845744 : spdk_bdev_io_get_nvme_status(bdev_io, &cdw0, &sct, &sc);
841 : :
842 [ + - + - ]: 3845744 : if (sct == SPDK_NVME_SCT_GENERIC && sc == SPDK_NVME_SC_SUCCESS) {
843 : 3845744 : stats_group->ios++;
844 : 3845744 : stats_group->blocks += bdev_io->u.bdev.num_blocks;
845 [ # # ]: 0 : } else if (sct == SPDK_NVME_SCT_MEDIA_ERROR) {
846 : 0 : stats_group->errors.media++;
847 : : } else {
848 : 0 : stats_group->errors.other++;
849 : : }
850 : : }
851 : :
852 : : struct spdk_io_channel *
853 : 51 : spdk_ftl_get_io_channel(struct spdk_ftl_dev *dev)
854 : : {
855 : 51 : return spdk_get_io_channel(dev);
856 : : }
857 : :
858 : : void
859 : 0 : ftl_stats_crc_error(struct spdk_ftl_dev *dev, enum ftl_stats_type type)
860 : : {
861 : :
862 : 0 : struct ftl_stats_entry *stats_entry = &dev->stats.entries[type];
863 : 0 : struct ftl_stats_group *stats_group = &stats_entry->read;
864 : :
865 : 0 : stats_group->errors.crc++;
866 : 0 : }
867 : :
868 : : struct ftl_get_stats_ctx {
869 : : struct spdk_ftl_dev *dev;
870 : : struct ftl_stats *stats;
871 : : struct spdk_thread *thread;
872 : : spdk_ftl_stats_fn cb_fn;
873 : : void *cb_arg;
874 : : };
875 : :
876 : : static void
877 : 1 : _ftl_get_stats_cb(void *_ctx)
878 : : {
879 : 1 : struct ftl_get_stats_ctx *stats_ctx = _ctx;
880 : :
881 : 1 : stats_ctx->cb_fn(stats_ctx->stats, stats_ctx->cb_arg);
882 : 1 : free(stats_ctx);
883 : 1 : }
884 : :
885 : : static void
886 : 1 : _ftl_get_stats(void *_ctx)
887 : : {
888 : 1 : struct ftl_get_stats_ctx *stats_ctx = _ctx;
889 : :
890 : 1 : *stats_ctx->stats = stats_ctx->dev->stats;
891 : :
892 [ - + ]: 1 : if (spdk_thread_send_msg(stats_ctx->thread, _ftl_get_stats_cb, stats_ctx)) {
893 : 0 : ftl_abort();
894 : : }
895 : 1 : }
896 : :
897 : : int
898 : 1 : spdk_ftl_get_stats(struct spdk_ftl_dev *dev, struct ftl_stats *stats, spdk_ftl_stats_fn cb_fn,
899 : : void *cb_arg)
900 : : {
901 : : struct ftl_get_stats_ctx *stats_ctx;
902 : : int rc;
903 : :
904 : 1 : stats_ctx = calloc(1, sizeof(struct ftl_get_stats_ctx));
905 [ - + ]: 1 : if (!stats_ctx) {
906 : 0 : return -ENOMEM;
907 : : }
908 : :
909 : 1 : stats_ctx->dev = dev;
910 : 1 : stats_ctx->stats = stats;
911 : 1 : stats_ctx->cb_fn = cb_fn;
912 : 1 : stats_ctx->cb_arg = cb_arg;
913 : 1 : stats_ctx->thread = spdk_get_thread();
914 : :
915 : 1 : rc = spdk_thread_send_msg(dev->core_thread, _ftl_get_stats, stats_ctx);
916 [ - + ]: 1 : if (rc) {
917 : 0 : goto stats_allocated;
918 : : }
919 : :
920 : 1 : return 0;
921 : :
922 : 0 : stats_allocated:
923 : 0 : free(stats_ctx);
924 : 0 : return rc;
925 : : }
926 : :
927 : 2332 : SPDK_LOG_REGISTER_COMPONENT(ftl_core)
|