Commit d6234332 authored by Wojciech Malikowski's avatar Wojciech Malikowski Committed by Tomasz Zawadzki
Browse files

lib/ftl: Represent ftl_addr just with the offset value



This patch removes parallel unit and zone id fields
from ftl_addr struct.

Change-Id: Ica42208eafdbbecab60430708197f5f3ba6167d6
Signed-off-by: default avatarWojciech Malikowski <wojciech.malikowski@intel.com>
Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/468701


Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
Reviewed-by: default avatarShuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Reviewed-by: default avatarKonrad Sztyber <konrad.sztyber@intel.com>
Community-CI: SPDK CI Jenkins <sys_sgci@intel.com>
parent 59acbc91
Loading
Loading
Loading
Loading
+4 −11
Original line number Diff line number Diff line
@@ -45,20 +45,13 @@

/* This structure represents on-disk address. It can have one of the following */
/* formats: */
/*        - addr describing the raw address */
/*        - offset inside the disk */
/*        - cache_offset inside the cache (indicated by the cached flag) */
/*        - packed version of the two formats above (can be only used when the */
/*          raw address can be represented in less than 32 bits) */
/*          offset can be represented in less than 32 bits) */
/* Packed format is used, when possible, to avoid wasting RAM on the L2P table. */
struct ftl_addr {
	union {
		struct {
			uint64_t offset	 : 32;
			uint64_t zone_id : 16;
			uint64_t pu	 : 15;
			uint64_t rsvd	 : 1;
		};

		struct {
			uint64_t cache_offset : 63;
			uint64_t cached	      : 1;
@@ -71,12 +64,12 @@ struct ftl_addr {
					uint32_t cached	      : 1;
				};

				uint32_t addr;
				uint32_t offset;
			};
			uint32_t rsvd;
		} pack;

		uint64_t addr;
		uint64_t offset;
	};
};

+35 −41
Original line number Diff line number Diff line
@@ -405,8 +405,7 @@ ftl_band_tail_md_addr(struct ftl_band *band)
	}

	addr.offset = (num_req / band->num_zones) * xfer_size;
	addr.zone_id = band->id;
	addr.pu = zone->start_addr.pu;
	addr.offset += zone->start_addr.offset;

	return addr;
}
@@ -414,16 +413,11 @@ ftl_band_tail_md_addr(struct ftl_band *band)
struct ftl_addr
ftl_band_head_md_addr(struct ftl_band *band)
{
	struct ftl_addr addr = {};

	if (spdk_unlikely(!band->num_zones)) {
		return ftl_to_addr(FTL_ADDR_INVALID);
	}

	addr.pu = CIRCLEQ_FIRST(&band->zones)->start_addr.pu;
	addr.zone_id = band->id;

	return addr;
	return CIRCLEQ_FIRST(&band->zones)->start_addr;
}

void
@@ -511,23 +505,27 @@ ftl_band_user_lbks(const struct ftl_band *band)
struct ftl_band *
ftl_band_from_addr(struct spdk_ftl_dev *dev, struct ftl_addr addr)
{
	assert(addr.zone_id < ftl_get_num_bands(dev));
	return &dev->bands[addr.zone_id];
	size_t band_id = ftl_addr_get_band(dev, addr);

	assert(band_id < ftl_get_num_bands(dev));
	return &dev->bands[band_id];
}

struct ftl_zone *
ftl_band_zone_from_addr(struct ftl_band *band, struct ftl_addr addr)
{
	assert(addr.pu < ftl_get_num_punits(band->dev));
	return &band->zone_buf[addr.pu];
	size_t pu_id = ftl_addr_get_punit(band->dev, addr);

	assert(pu_id < ftl_get_num_punits(band->dev));
	return &band->zone_buf[pu_id];
}

uint64_t
ftl_band_lbkoff_from_addr(struct ftl_band *band, struct ftl_addr addr)
{
	assert(addr.zone_id == band->id);
	assert(addr.pu < ftl_get_num_punits(band->dev));
	return addr.pu * ftl_get_num_blocks_in_zone(band->dev) + addr.offset;
	assert(ftl_addr_get_band(band->dev, addr) == band->id);
	assert(ftl_addr_get_punit(band->dev, addr) < ftl_get_num_punits(band->dev));
	return addr.offset % ftl_get_num_blocks_in_band(band->dev);
}

struct ftl_addr
@@ -536,13 +534,15 @@ ftl_band_next_xfer_addr(struct ftl_band *band, struct ftl_addr addr, size_t num_
	struct spdk_ftl_dev *dev = band->dev;
	struct ftl_zone *zone;
	size_t num_xfers, num_stripes;
	uint64_t offset;

	assert(addr.zone_id == band->id);
	assert(ftl_addr_get_band(dev, addr) == band->id);

	offset = ftl_addr_get_zone_offset(dev, addr);
	zone = ftl_band_zone_from_addr(band, addr);

	num_lbks += (addr.offset % dev->xfer_size);
	addr.offset  -= (addr.offset % dev->xfer_size);
	num_lbks += (offset % dev->xfer_size);
	offset -= (offset % dev->xfer_size);

#if defined(DEBUG)
	/* Check that the number of zones has not been changed */
@@ -557,10 +557,10 @@ ftl_band_next_xfer_addr(struct ftl_band *band, struct ftl_addr addr, size_t num_
#endif
	assert(band->num_zones != 0);
	num_stripes = (num_lbks / dev->xfer_size) / band->num_zones;
	addr.offset  += num_stripes * dev->xfer_size;
	offset += num_stripes * dev->xfer_size;
	num_lbks -= num_stripes * dev->xfer_size * band->num_zones;

	if (addr.offset > ftl_get_num_blocks_in_zone(dev)) {
	if (offset > ftl_get_num_blocks_in_zone(dev)) {
		return ftl_to_addr(FTL_ADDR_INVALID);
	}

@@ -569,26 +569,26 @@ ftl_band_next_xfer_addr(struct ftl_band *band, struct ftl_addr addr, size_t num_
		/* When the last zone is reached the lbk part of the address */
		/* needs to be increased by xfer_size */
		if (ftl_band_zone_is_last(band, zone)) {
			addr.offset += dev->xfer_size;
			if (addr.offset > ftl_get_num_blocks_in_zone(dev)) {
			offset += dev->xfer_size;
			if (offset > ftl_get_num_blocks_in_zone(dev)) {
				return ftl_to_addr(FTL_ADDR_INVALID);
			}
		}

		zone = ftl_band_next_operational_zone(band, zone);
		assert(zone);
		addr.pu = zone->start_addr.pu;

		num_lbks -= dev->xfer_size;
	}

	if (num_lbks) {
		addr.offset += num_lbks;
		if (addr.offset > ftl_get_num_blocks_in_zone(dev)) {
		offset += num_lbks;
		if (offset > ftl_get_num_blocks_in_zone(dev)) {
			return ftl_to_addr(FTL_ADDR_INVALID);
		}
	}

	addr.offset = zone->start_addr.offset + offset;
	return addr;
}

@@ -597,12 +597,13 @@ ftl_xfer_offset_from_addr(struct ftl_band *band, struct ftl_addr addr)
{
	struct ftl_zone *zone, *current_zone;
	unsigned int punit_offset = 0;
	size_t off, num_stripes, xfer_size = band->dev->xfer_size;
	size_t num_stripes, xfer_size = band->dev->xfer_size;
	uint64_t offset;

	assert(addr.zone_id == band->id);
	assert(ftl_addr_get_band(band->dev, addr) == band->id);

	num_stripes = (addr.offset / xfer_size) * band->num_zones;
	off = addr.offset % xfer_size;
	offset = ftl_addr_get_zone_offset(band->dev, addr);
	num_stripes = (offset / xfer_size) * band->num_zones;

	current_zone = ftl_band_zone_from_addr(band, addr);
	CIRCLEQ_FOREACH(zone, &band->zones, circleq) {
@@ -612,22 +613,15 @@ ftl_xfer_offset_from_addr(struct ftl_band *band, struct ftl_addr addr)
		punit_offset++;
	}

	return xfer_size * (num_stripes + punit_offset) + off;
	return xfer_size * (num_stripes + punit_offset) + offset % xfer_size;
}

struct ftl_addr
ftl_band_addr_from_lbkoff(struct ftl_band *band, uint64_t lbkoff)
{
	struct ftl_addr addr = { .addr = 0 };
	struct spdk_ftl_dev *dev = band->dev;
	uint64_t punit;

	punit = lbkoff / ftl_get_num_blocks_in_zone(dev);

	addr.offset = lbkoff % ftl_get_num_blocks_in_zone(dev);
	addr.zone_id = band->id;
	addr.pu = punit;
	struct ftl_addr addr = { .offset = 0 };

	addr.offset = lbkoff + band->id * ftl_get_num_blocks_in_band(band->dev);
	return addr;
}

@@ -1055,7 +1049,7 @@ ftl_band_erase_cb(struct ftl_io *io, void *ctx, int status)
	}
	zone = ftl_band_zone_from_addr(io->band, io->addr);
	zone->state = SPDK_BDEV_ZONE_STATE_EMPTY;
	zone->write_offset = 0;
	zone->write_offset = zone->start_addr.offset;
}

int
@@ -1122,7 +1116,7 @@ ftl_band_next_operational_zone(struct ftl_band *band, struct ftl_zone *zone)
		result = ftl_band_next_zone(band, zone);
	} else {
		CIRCLEQ_FOREACH_REVERSE(entry, &band->zones, circleq) {
			if (entry->start_addr.pu > zone->start_addr.pu) {
			if (entry->start_addr.offset > zone->start_addr.offset) {
				result = entry;
			} else {
				if (!result) {
+20 −21
Original line number Diff line number Diff line
@@ -356,11 +356,10 @@ ftl_submit_erase(struct ftl_io *io)
			addr = zone->start_addr;
		}

		assert(addr.offset == 0);
		assert(ftl_addr_get_zone_offset(dev, addr) == 0);

		ftl_trace_submission(dev, io, addr, 1);
		rc = spdk_bdev_zone_management(dev->base_bdev_desc, ioch->base_ioch,
					       ftl_block_offset_from_addr(dev, addr),
		rc = spdk_bdev_zone_management(dev->base_bdev_desc, ioch->base_ioch, addr.offset,
					       SPDK_BDEV_ZONE_RESET, ftl_io_cmpl_cb, io);
		if (spdk_unlikely(rc)) {
			ftl_io_fail(io, rc);
@@ -590,8 +589,10 @@ ftl_wptr_advance(struct ftl_wptr *wptr, size_t xfer_size)

	assert(!ftl_addr_invalid(wptr->addr));

	SPDK_DEBUGLOG(SPDK_LOG_FTL_CORE, "wptr: pu:%d zone:%d, lbk:%u\n",
		      wptr->addr.pu, wptr->addr.zone_id, wptr->addr.offset);
	SPDK_DEBUGLOG(SPDK_LOG_FTL_CORE, "wptr: pu:%lu band:%lu, offset:%lu\n",
		      ftl_addr_get_punit(dev, wptr->addr),
		      ftl_addr_get_band(dev, wptr->addr),
		      wptr->addr.offset);

	if (wptr->offset >= next_thld && !dev->next_band) {
		dev->next_band = ftl_next_write_band(dev);
@@ -917,7 +918,7 @@ ftl_cache_read(struct ftl_io *io, uint64_t lba,
	pthread_spin_lock(&entry->lock);

	naddr = ftl_l2p_get(io->dev, lba);
	if (addr.addr != naddr.addr) {
	if (addr.offset != naddr.offset) {
		rc = -1;
		goto out;
	}
@@ -938,7 +939,7 @@ ftl_read_next_logical_addr(struct ftl_io *io, struct ftl_addr *addr)
	*addr = ftl_l2p_get(dev, ftl_io_current_lba(io));

	SPDK_DEBUGLOG(SPDK_LOG_FTL_CORE, "Read addr:%lx, lba:%lu\n",
		      addr->addr, ftl_io_current_lba(io));
		      addr->offset, ftl_io_current_lba(io));

	/* If the address is invalid, skip it (the buffer should already be zero'ed) */
	if (ftl_addr_invalid(*addr)) {
@@ -961,8 +962,7 @@ ftl_read_next_logical_addr(struct ftl_io *io, struct ftl_addr *addr)
			break;
		}

		if (ftl_block_offset_from_addr(dev, *addr) + i !=
		    ftl_block_offset_from_addr(dev, next_addr)) {
		if (addr->offset + i != next_addr.offset) {
			break;
		}
	}
@@ -1010,7 +1010,7 @@ ftl_submit_read(struct ftl_io *io)
		ftl_trace_submission(dev, io, addr, lbk_cnt);
		rc = spdk_bdev_read_blocks(dev->base_bdev_desc, ioch->base_ioch,
					   ftl_io_iovec_addr(io),
					   ftl_block_offset_from_addr(dev, addr),
					   addr.offset,
					   lbk_cnt, ftl_io_cmpl_cb, io);
		if (spdk_unlikely(rc)) {
			if (rc == -ENOMEM) {
@@ -1157,7 +1157,7 @@ ftl_nv_cache_submit_cb(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
	struct ftl_nv_cache *nv_cache = &io->dev->nv_cache;

	if (spdk_unlikely(!success)) {
		SPDK_ERRLOG("Non-volatile cache write failed at %"PRIx64"\n", io->addr.addr);
		SPDK_ERRLOG("Non-volatile cache write failed at %"PRIx64"\n", io->addr.offset);
		io->status = -EIO;
	}

@@ -1184,14 +1184,14 @@ ftl_submit_nv_cache(void *ctx)
	thread = spdk_io_channel_get_thread(io->ioch);

	rc = spdk_bdev_write_blocks_with_md(nv_cache->bdev_desc, ioch->cache_ioch,
					    ftl_io_iovec_addr(io), io->md, io->addr.addr,
					    ftl_io_iovec_addr(io), io->md, io->addr.offset,
					    io->lbk_cnt, ftl_nv_cache_submit_cb, io);
	if (rc == -ENOMEM) {
		spdk_thread_send_msg(thread, ftl_submit_nv_cache, io);
		return;
	} else if (rc) {
		SPDK_ERRLOG("Write to persistent cache failed: %s (%"PRIu64", %"PRIu64")\n",
			    spdk_strerror(-rc), io->addr.addr, io->lbk_cnt);
			    spdk_strerror(-rc), io->addr.offset, io->lbk_cnt);
		spdk_mempool_put(nv_cache->md_pool, io->md);
		io->status = -EIO;
		ftl_io_complete(io);
@@ -1247,8 +1247,8 @@ _ftl_write_nv_cache(void *ctx)
		}

		/* Reserve area on the write buffer cache */
		child->addr.addr = ftl_reserve_nv_cache(&dev->nv_cache, &num_lbks, &phase);
		if (child->addr.addr == FTL_LBA_INVALID) {
		child->addr.offset = ftl_reserve_nv_cache(&dev->nv_cache, &num_lbks, &phase);
		if (child->addr.offset == FTL_LBA_INVALID) {
			spdk_mempool_put(dev->nv_cache.md_pool, child->md);
			ftl_io_free(child);
			spdk_thread_send_msg(thread, _ftl_write_nv_cache, io);
@@ -1371,7 +1371,7 @@ ftl_write_cb(struct ftl_io *io, void *arg, int status)
		}

		SPDK_DEBUGLOG(SPDK_LOG_FTL_CORE, "Write addr:%lu, lba:%lu\n",
			      entry->addr.addr, entry->lba);
			      entry->addr.offset, entry->lba);
	}

	ftl_process_flush(dev, batch);
@@ -1515,7 +1515,7 @@ ftl_submit_child_write(struct ftl_wptr *wptr, struct ftl_io *io, int lbk_cnt)
		addr = wptr->addr;
	} else {
		assert(io->flags & FTL_IO_DIRECT_ACCESS);
		assert(io->addr.zone_id == wptr->band->id);
		assert(ftl_addr_get_band(dev, io->addr) == wptr->band->id);
		addr = io->addr;
	}

@@ -1530,14 +1530,14 @@ ftl_submit_child_write(struct ftl_wptr *wptr, struct ftl_io *io, int lbk_cnt)

	rc = spdk_bdev_write_blocks(dev->base_bdev_desc, ioch->base_ioch,
				    ftl_io_iovec_addr(child),
				    ftl_block_offset_from_addr(dev, addr),
				    addr.offset,
				    lbk_cnt, ftl_io_cmpl_cb, child);
	if (rc) {
		wptr->num_outstanding--;
		ftl_io_fail(child, rc);
		ftl_io_complete(child);
		SPDK_ERRLOG("spdk_bdev_write_blocks_with_md failed with status:%d, addr:%lu\n",
			    rc, addr.addr);
			    rc, addr.offset);
		return -EIO;
	}

@@ -1687,8 +1687,7 @@ ftl_wptr_process_writes(struct ftl_wptr *wptr)
		addr = ftl_band_next_addr(wptr->band, addr, 1);
	}

	SPDK_DEBUGLOG(SPDK_LOG_FTL_CORE, "Write addr:%lx, %lx\n", wptr->addr.addr,
		      ftl_block_offset_from_addr(dev, wptr->addr));
	SPDK_DEBUGLOG(SPDK_LOG_FTL_CORE, "Write addr:%lx\n", wptr->addr.offset);

	if (ftl_submit_write(wptr, io)) {
		/* TODO: we need some recovery here */
+28 −30
Original line number Diff line number Diff line
@@ -279,10 +279,10 @@ struct spdk_io_channel *
ftl_get_io_channel(const struct spdk_ftl_dev *dev);

#define ftl_to_addr(address) \
	(struct ftl_addr) { .addr = (uint64_t)(address) }
	(struct ftl_addr) { .offset = (uint64_t)(address) }

#define ftl_to_addr_packed(address) \
	(struct ftl_addr) { .pack.addr = (uint32_t)(address) }
	(struct ftl_addr) { .pack.offset = (uint32_t)(address) }

static inline struct spdk_thread *
ftl_get_core_thread(const struct spdk_ftl_dev *dev)
@@ -326,6 +326,24 @@ ftl_get_num_blocks_in_band(const struct spdk_ftl_dev *dev)
	return ftl_get_num_punits(dev) * ftl_get_num_blocks_in_zone(dev);
}

static inline uint64_t
ftl_addr_get_band(const struct spdk_ftl_dev *dev, struct ftl_addr addr)
{
	return addr.offset / ftl_get_num_blocks_in_band(dev);
}

static inline uint64_t
ftl_addr_get_punit(const struct spdk_ftl_dev *dev, struct ftl_addr addr)
{
	return (addr.offset / ftl_get_num_blocks_in_zone(dev)) % ftl_get_num_punits(dev);
}

static inline uint64_t
ftl_addr_get_zone_offset(const struct spdk_ftl_dev *dev, struct ftl_addr addr)
{
	return addr.offset % ftl_get_num_blocks_in_zone(dev);
}

static inline size_t
ftl_vld_map_size(const struct spdk_ftl_dev *dev)
{
@@ -341,7 +359,7 @@ ftl_addr_packed(const struct spdk_ftl_dev *dev)
static inline int
ftl_addr_invalid(struct ftl_addr addr)
{
	return addr.addr == ftl_to_addr(FTL_ADDR_INVALID).addr;
	return addr.offset == ftl_to_addr(FTL_ADDR_INVALID).offset;
}

static inline int
@@ -350,27 +368,6 @@ ftl_addr_cached(struct ftl_addr addr)
	return !ftl_addr_invalid(addr) && addr.cached;
}

static inline struct ftl_addr
ftl_addr_from_block_offset(const struct spdk_ftl_dev *dev, uint64_t offset)
{
	struct ftl_addr addr = {};
	uint64_t zone_num;

	addr.offset = offset % ftl_get_num_blocks_in_zone(dev);
	zone_num = offset / ftl_get_num_blocks_in_zone(dev);
	addr.pu = zone_num % ftl_get_num_punits(dev);
	addr.zone_id = zone_num / ftl_get_num_punits(dev);

	return addr;
}

static inline uint64_t
ftl_block_offset_from_addr(const struct spdk_ftl_dev *dev, struct ftl_addr addr)
{
	return (addr.zone_id * ftl_get_num_punits(dev) + addr.pu) *
	       ftl_get_num_blocks_in_zone(dev) + addr.offset;
}

static inline struct ftl_addr
ftl_addr_to_packed(const struct spdk_ftl_dev *dev, struct ftl_addr addr)
{
@@ -382,7 +379,7 @@ ftl_addr_to_packed(const struct spdk_ftl_dev *dev, struct ftl_addr addr)
		p.pack.cached = 1;
		p.pack.cache_offset = (uint32_t) addr.cache_offset;
	} else {
		p.pack.addr = (uint32_t) ftl_block_offset_from_addr(dev, addr);
		p.pack.offset = (uint32_t) addr.offset;
	}

	return p;
@@ -393,13 +390,13 @@ ftl_addr_from_packed(const struct spdk_ftl_dev *dev, struct ftl_addr p)
{
	struct ftl_addr addr = {};

	if (p.pack.addr == (uint32_t)FTL_ADDR_INVALID) {
	if (p.pack.offset == (uint32_t)FTL_ADDR_INVALID) {
		addr = ftl_to_addr(FTL_ADDR_INVALID);
	} else if (p.pack.cached) {
		addr.cached = 1;
		addr.cache_offset = p.pack.cache_offset;
	} else {
		addr = ftl_addr_from_block_offset(dev, p.pack.addr);
		addr = p;
	}

	return addr;
@@ -424,7 +421,7 @@ ftl_addr_from_packed(const struct spdk_ftl_dev *dev, struct ftl_addr p)
	_ftl_l2p_get(l2p, off, 64)

#define ftl_addr_cmp(p1, p2) \
	((p1).addr == (p2).addr)
	((p1).offset == (p2).offset)

static inline void
ftl_l2p_set(struct spdk_ftl_dev *dev, uint64_t lba, struct ftl_addr addr)
@@ -432,9 +429,9 @@ ftl_l2p_set(struct spdk_ftl_dev *dev, uint64_t lba, struct ftl_addr addr)
	assert(dev->num_lbas > lba);

	if (ftl_addr_packed(dev)) {
		_ftl_l2p_set32(dev->l2p, lba, ftl_addr_to_packed(dev, addr).addr);
		_ftl_l2p_set32(dev->l2p, lba, ftl_addr_to_packed(dev, addr).offset);
	} else {
		_ftl_l2p_set64(dev->l2p, lba, addr.addr);
		_ftl_l2p_set64(dev->l2p, lba, addr.offset);
	}
}

@@ -450,6 +447,7 @@ ftl_l2p_get(struct spdk_ftl_dev *dev, uint64_t lba)
		return ftl_to_addr(_ftl_l2p_get64(dev->l2p, lba));
	}
}

static inline bool
ftl_dev_has_nv_cache(const struct spdk_ftl_dev *dev)
{
+1 −1
Original line number Diff line number Diff line
@@ -79,7 +79,7 @@ ftl_band_validate_md(struct ftl_band *band)
			continue;
		}

		if (addr_l2p.addr != addr_md.addr) {
		if (addr_l2p.offset != addr_md.offset) {
			valid = false;
			break;
		}
Loading