summaryrefslogtreecommitdiffstats
path: root/src/spdk/lib/ftl/ftl_band.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/spdk/lib/ftl/ftl_band.h')
-rw-r--r--src/spdk/lib/ftl/ftl_band.h287
1 files changed, 287 insertions, 0 deletions
diff --git a/src/spdk/lib/ftl/ftl_band.h b/src/spdk/lib/ftl/ftl_band.h
new file mode 100644
index 000000000..109b369a5
--- /dev/null
+++ b/src/spdk/lib/ftl/ftl_band.h
@@ -0,0 +1,287 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FTL_BAND_H
+#define FTL_BAND_H
+
+#include "spdk/stdinc.h"
+#include "spdk/bit_array.h"
+#include "spdk/queue.h"
+#include "spdk/bdev_zone.h"
+
+#include "ftl_io.h"
+#include "ftl_addr.h"
+#include "ftl_core.h"
+
+/* Number of LBAs that could be stored in a single block */
+#define FTL_NUM_LBA_IN_BLOCK (FTL_BLOCK_SIZE / sizeof(uint64_t))
+
+struct spdk_ftl_dev;
+struct ftl_lba_map_request;
+
+struct ftl_zone {
+ struct spdk_bdev_zone_info info;
+
+ /* Indicates that there is inflight write */
+ bool busy;
+
+ CIRCLEQ_ENTRY(ftl_zone) circleq;
+};
+
+enum ftl_md_status {
+ FTL_MD_SUCCESS,
+ /* Metadata read failure */
+ FTL_MD_IO_FAILURE,
+ /* Invalid version */
+ FTL_MD_INVALID_VER,
+ /* UUID doesn't match */
+ FTL_MD_NO_MD,
+ /* UUID and version matches but CRC doesn't */
+ FTL_MD_INVALID_CRC,
+ /* Vld or lba map size doesn't match */
+ FTL_MD_INVALID_SIZE
+};
+
+enum ftl_lba_map_seg_state {
+ FTL_LBA_MAP_SEG_CLEAR,
+ FTL_LBA_MAP_SEG_PENDING,
+ FTL_LBA_MAP_SEG_CACHED
+};
+
+struct ftl_lba_map {
+ /* LBA/vld map lock */
+ pthread_spinlock_t lock;
+
+ /* Number of valid LBAs */
+ size_t num_vld;
+
+ /* LBA map's reference count */
+ size_t ref_cnt;
+
+ /* Bitmap of valid LBAs */
+ struct spdk_bit_array *vld;
+
+ /* LBA map (only valid for open/relocating bands) */
+ uint64_t *map;
+
+ /* LBA map segment state map (clear, pending, cached) */
+ uint8_t *segments;
+
+ LIST_HEAD(, ftl_lba_map_request) request_list;
+
+ /* Metadata DMA buffer (only valid for open/relocating bands) */
+ void *dma_buf;
+};
+
+enum ftl_band_state {
+ FTL_BAND_STATE_FREE,
+ FTL_BAND_STATE_PREP,
+ FTL_BAND_STATE_OPENING,
+ FTL_BAND_STATE_OPEN,
+ FTL_BAND_STATE_FULL,
+ FTL_BAND_STATE_CLOSING,
+ FTL_BAND_STATE_CLOSED,
+ FTL_BAND_STATE_MAX
+};
+
+struct ftl_lba_map_request {
+ /* Completion callback */
+ ftl_io_fn cb;
+
+ /* Completion callback context */
+ void *cb_ctx;
+
+ /* Bit array of requested segments */
+ struct spdk_bit_array *segments;
+
+ /* Number of pending segments to read */
+ size_t num_pending;
+
+ LIST_ENTRY(ftl_lba_map_request) list_entry;
+};
+
+struct ftl_band {
+ /* Device this band belongs to */
+ struct spdk_ftl_dev *dev;
+
+ /* Number of operational zones */
+ size_t num_zones;
+
+ /* Array of zones */
+ struct ftl_zone *zone_buf;
+
+ /* List of operational zones */
+ CIRCLEQ_HEAD(, ftl_zone) zones;
+
+ /* LBA map */
+ struct ftl_lba_map lba_map;
+
+ /* Band's state */
+ enum ftl_band_state state;
+
+ /* Band's index */
+ unsigned int id;
+
+ /* Latest merit calculation */
+ double merit;
+
+ /* High defrag priority - means that the metadata should be copied and */
+ /* the band should be defragged immediately */
+ int high_prio;
+
+ /* Sequence number */
+ uint64_t seq;
+
+ /* Number of defrag cycles */
+ uint64_t wr_cnt;
+
+ /* End metadata start addr */
+ struct ftl_addr tail_md_addr;
+
+ /* Bitmap of all bands that have its data moved onto this band */
+ struct spdk_bit_array *reloc_bitmap;
+ /* Number of open bands containing data moved from this band */
+ size_t num_reloc_bands;
+ /* Number of blocks currently being moved from this band */
+ size_t num_reloc_blocks;
+
+ /* Free/shut bands' lists */
+ LIST_ENTRY(ftl_band) list_entry;
+
+ /* High priority queue link */
+ STAILQ_ENTRY(ftl_band) prio_stailq;
+};
+
+uint64_t ftl_band_block_offset_from_addr(struct ftl_band *band, struct ftl_addr addr);
+struct ftl_addr ftl_band_addr_from_block_offset(struct ftl_band *band, uint64_t block_off);
+void ftl_band_set_state(struct ftl_band *band, enum ftl_band_state state);
+size_t ftl_band_age(const struct ftl_band *band);
+void ftl_band_acquire_lba_map(struct ftl_band *band);
+int ftl_band_alloc_lba_map(struct ftl_band *band);
+void ftl_band_clear_lba_map(struct ftl_band *band);
+void ftl_band_release_lba_map(struct ftl_band *band);
+int ftl_band_read_lba_map(struct ftl_band *band,
+ size_t offset, size_t lba_cnt,
+ ftl_io_fn cb_fn, void *cb_ctx);
+struct ftl_addr ftl_band_next_xfer_addr(struct ftl_band *band, struct ftl_addr addr,
+ size_t num_blocks);
+struct ftl_addr ftl_band_next_addr(struct ftl_band *band, struct ftl_addr addr,
+ size_t offset);
+size_t ftl_band_num_usable_blocks(const struct ftl_band *band);
+size_t ftl_band_user_blocks_left(const struct ftl_band *band, size_t offset);
+size_t ftl_band_user_blocks(const struct ftl_band *band);
+void ftl_band_set_addr(struct ftl_band *band, uint64_t lba,
+ struct ftl_addr addr);
+struct ftl_band *ftl_band_from_addr(struct spdk_ftl_dev *dev, struct ftl_addr addr);
+struct ftl_zone *ftl_band_zone_from_addr(struct ftl_band *band, struct ftl_addr);
+void ftl_band_md_clear(struct ftl_band *band);
+int ftl_band_read_tail_md(struct ftl_band *band, struct ftl_addr,
+ ftl_io_fn cb_fn, void *cb_ctx);
+int ftl_band_read_head_md(struct ftl_band *band, ftl_io_fn cb_fn, void *cb_ctx);
+int ftl_band_write_tail_md(struct ftl_band *band, ftl_io_fn cb);
+int ftl_band_write_head_md(struct ftl_band *band, ftl_io_fn cb);
+struct ftl_addr ftl_band_tail_md_addr(struct ftl_band *band);
+struct ftl_addr ftl_band_head_md_addr(struct ftl_band *band);
+void ftl_band_write_failed(struct ftl_band *band);
+int ftl_band_full(struct ftl_band *band, size_t offset);
+int ftl_band_write_prep(struct ftl_band *band);
+struct ftl_zone *ftl_band_next_operational_zone(struct ftl_band *band,
+ struct ftl_zone *zone);
+size_t ftl_lba_map_pool_elem_size(struct spdk_ftl_dev *dev);
+void ftl_band_remove_zone(struct ftl_band *band, struct ftl_zone *zone);
+
+
+static inline int
+ftl_band_empty(const struct ftl_band *band)
+{
+ return band->lba_map.num_vld == 0;
+}
+
+static inline struct ftl_zone *
+ftl_band_next_zone(struct ftl_band *band, struct ftl_zone *zone)
+{
+ assert(zone->info.state != SPDK_BDEV_ZONE_STATE_OFFLINE);
+ return CIRCLEQ_LOOP_NEXT(&band->zones, zone, circleq);
+}
+
+static inline void
+ftl_band_set_next_state(struct ftl_band *band)
+{
+ ftl_band_set_state(band, (band->state + 1) % FTL_BAND_STATE_MAX);
+}
+
+static inline int
+ftl_band_state_changing(struct ftl_band *band)
+{
+ return band->state == FTL_BAND_STATE_OPENING ||
+ band->state == FTL_BAND_STATE_CLOSING;
+}
+
+static inline int
+ftl_band_block_offset_valid(struct ftl_band *band, size_t block_off)
+{
+ struct ftl_lba_map *lba_map = &band->lba_map;
+
+ pthread_spin_lock(&lba_map->lock);
+ if (spdk_bit_array_get(lba_map->vld, block_off)) {
+ pthread_spin_unlock(&lba_map->lock);
+ return 1;
+ }
+
+ pthread_spin_unlock(&lba_map->lock);
+ return 0;
+}
+
+static inline int
+ftl_band_zone_is_last(struct ftl_band *band, struct ftl_zone *zone)
+{
+ return zone == CIRCLEQ_LAST(&band->zones);
+}
+
+static inline int
+ftl_band_zone_is_first(struct ftl_band *band, struct ftl_zone *zone)
+{
+ return zone == CIRCLEQ_FIRST(&band->zones);
+}
+
+static inline int
+ftl_zone_is_writable(const struct spdk_ftl_dev *dev, const struct ftl_zone *zone)
+{
+ bool busy = ftl_is_append_supported(dev) ? false : zone->busy;
+
+ return (zone->info.state == SPDK_BDEV_ZONE_STATE_OPEN ||
+ zone->info.state == SPDK_BDEV_ZONE_STATE_EMPTY) &&
+ !busy;
+}
+
+#endif /* FTL_BAND_H */