lib/ftl: Check non evicted blocks during relocation

Since ftl write buffers are associated with IO channels
there can be situation that block that is being relocating
could be still in cache. Such scenario is very likely when
ftl is throttling user IO. l2p update should handle such
situation when data is coming from relocation.

Signed-off-by: Wojciech Malikowski <wojciech.malikowski@intel.com>
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/1439 (master)

(cherry picked from commit 40e5d4a0bc)
Change-Id: Id0bb53d8ce45213b05bafa9ebcb843ce8eadbc7a
Signed-off-by: Tomasz Zawadzki <tomasz.zawadzki@intel.com>
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/2119
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Reviewed-by: Wojciech Malikowski <wojciech.malikowski@intel.com>
Reviewed-by: Darek Stojaczyk <dariusz.stojaczyk@intel.com>
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
This commit is contained in:
Wojciech Malikowski 2020-03-24 12:07:38 -04:00 committed by Tomasz Zawadzki
parent d7b0ae8913
commit 58a35d24d5

View File

@ -1611,6 +1611,7 @@ ftl_update_l2p(struct spdk_ftl_dev *dev, const struct ftl_wbuf_entry *entry,
struct ftl_wbuf_entry *prev;
struct ftl_band *band;
int valid;
bool io_weak = entry->io_flags & FTL_IO_WEAK;
prev_addr = ftl_l2p_get(dev, entry->lba);
if (ftl_addr_invalid(prev_addr)) {
@ -1618,14 +1619,7 @@ ftl_update_l2p(struct spdk_ftl_dev *dev, const struct ftl_wbuf_entry *entry,
return;
}
/* If the L2P's physical address is different than what we expected we don't need to */
/* do anything (someone's already overwritten our data). */
if ((entry->io_flags & FTL_IO_WEAK) && !ftl_addr_cmp(prev_addr, entry->addr)) {
return;
}
if (ftl_addr_cached(prev_addr)) {
assert(!(entry->io_flags & FTL_IO_WEAK));
prev = ftl_get_entry_from_addr(dev, prev_addr);
pthread_spin_lock(&prev->lock);
@ -1634,12 +1628,33 @@ ftl_update_l2p(struct spdk_ftl_dev *dev, const struct ftl_wbuf_entry *entry,
prev_addr = ftl_l2p_get(dev, entry->lba);
/* If the entry is no longer in cache, another write has been */
/* scheduled in the meantime, so we have to invalidate its LBA */
/* scheduled in the meantime, so we can return to evicted path */
if (!ftl_addr_cached(prev_addr)) {
ftl_invalidate_addr(dev, prev_addr);
pthread_spin_unlock(&prev->lock);
goto evicted;
}
/* If previous entry is part of cache, remove and invalidate it */
/*
* Relocating block could still reside in cache due to fact that write
* buffers are independent for each IO channel and enough amount of data
* (write unit size) must be collected before it will be submitted to lower
* layer.
* When previous entry wasn't overwritten invalidate old address and entry.
* Otherwise skip relocating block.
*/
if (io_weak &&
/* Check if prev_addr was updated in meantime */
!(ftl_addr_cmp(prev_addr, ftl_get_addr_from_entry(prev)) &&
/* Check if relocating address it the same as in previous entry */
ftl_addr_cmp(prev->addr, entry->addr))) {
pthread_spin_unlock(&prev->lock);
return;
}
/*
* If previous entry is part of cache and was written into disk remove
* and invalidate it
*/
if (prev->valid) {
ftl_invalidate_addr(dev, prev->addr);
prev->valid = false;
@ -1650,6 +1665,15 @@ ftl_update_l2p(struct spdk_ftl_dev *dev, const struct ftl_wbuf_entry *entry,
return;
}
evicted:
/*
* If the L2P's physical address is different than what we expected we don't need to
* do anything (someone's already overwritten our data).
*/
if (io_weak && !ftl_addr_cmp(prev_addr, entry->addr)) {
return;
}
/* Lock the band containing previous physical address. This assures atomic changes to */
/* the L2P as wall as metadata. The valid bits in metadata are used to */
/* check weak writes validity. */
@ -1660,7 +1684,7 @@ ftl_update_l2p(struct spdk_ftl_dev *dev, const struct ftl_wbuf_entry *entry,
/* If the address has been invalidated already, we don't want to update */
/* the L2P for weak writes, as it means the write is no longer valid. */
if (!(entry->io_flags & FTL_IO_WEAK) || valid) {
if (!io_weak || valid) {
ftl_l2p_set(dev, entry->lba, addr);
}