bdev/ocssd: update write pointers

Update write pointers during successful write / reset completion.  This
is needed in order to support the append operation.

This patch also introduces the zone busy flag, which makes sure only one
write (or reset) operation can be active at a time.  If a request is
directed to a zone that is already processing another operation, it will
be completed with a failed status.

Change-Id: I085438431577e4f0cd2d5d9eff7a220090f21176
Signed-off-by: Konrad Sztyber <konrad.sztyber@intel.com>
Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/469119
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Mateusz Kozlowski <mateusz.kozlowski@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Community-CI: Broadcom SPDK FC-NVMe CI <spdk-ci.pdl@broadcom.com>
Community-CI: SPDK CI Jenkins <sys_sgci@intel.com>
This commit is contained in:
Konrad Sztyber 2019-09-23 10:40:44 +02:00 committed by Tomasz Zawadzki
parent b63be39461
commit ffd53b6bad

View File

@ -62,9 +62,10 @@ struct bdev_ocssd_zone {
struct bdev_ocssd_io {
union {
struct {
size_t iov_pos;
size_t iov_off;
uint64_t lba[SPDK_NVME_OCSSD_MAX_LBAL_ENTRIES];
struct bdev_ocssd_zone *zone;
size_t iov_pos;
size_t iov_off;
uint64_t lba[SPDK_NVME_OCSSD_MAX_LBAL_ENTRIES];
} io;
struct {
size_t chunk_offset;
@ -151,20 +152,28 @@ static struct spdk_bdev_module ocssd_if = {
SPDK_BDEV_MODULE_REGISTER(ocssd, &ocssd_if);
static struct bdev_ocssd_zone *
bdev_ocssd_get_zone_by_slba(struct ocssd_bdev *ocssd_bdev, uint64_t slba)
bdev_ocssd_get_zone_by_lba(struct ocssd_bdev *ocssd_bdev, uint64_t lba)
{
struct nvme_bdev *nvme_bdev = &ocssd_bdev->nvme_bdev;
size_t zone_size = nvme_bdev->disk.zone_size;
if (slba % zone_size != 0) {
if (lba >= nvme_bdev->disk.blockcnt) {
return NULL;
}
if (slba >= nvme_bdev->disk.blockcnt) {
return &ocssd_bdev->zones[lba / zone_size];
}
static struct bdev_ocssd_zone *
bdev_ocssd_get_zone_by_slba(struct ocssd_bdev *ocssd_bdev, uint64_t slba)
{
struct nvme_bdev *nvme_bdev = &ocssd_bdev->nvme_bdev;
if (slba % nvme_bdev->disk.zone_size != 0) {
return NULL;
}
return &ocssd_bdev->zones[slba / zone_size];
return bdev_ocssd_get_zone_by_lba(ocssd_bdev, slba);
}
static void
@ -338,7 +347,14 @@ static void
bdev_ocssd_write_cb(void *ctx, const struct spdk_nvme_cpl *cpl)
{
struct spdk_bdev_io *bdev_io = ctx;
struct bdev_ocssd_io *ocdev_io = (struct bdev_ocssd_io *)bdev_io->driver_ctx;
ocdev_io->io.zone->write_pointer = bdev_io->u.bdev.offset_blocks +
bdev_io->u.bdev.num_blocks;
assert(ocdev_io->io.zone->write_pointer <= ocdev_io->io.zone->slba +
ocdev_io->io.zone->capacity);
__atomic_store_n(&ocdev_io->io.zone->busy, false, __ATOMIC_SEQ_CST);
spdk_bdev_io_complete_nvme_status(bdev_io, 0, cpl->status.sct, cpl->status.sc);
}
@ -351,21 +367,31 @@ bdev_ocssd_write(struct spdk_io_channel *ioch, struct spdk_bdev_io *bdev_io)
struct bdev_ocssd_io *ocdev_io = (struct bdev_ocssd_io *)bdev_io->driver_ctx;
const size_t zone_size = nvme_bdev->disk.zone_size;
uint64_t lba;
int rc;
if ((bdev_io->u.bdev.offset_blocks % zone_size) + bdev_io->u.bdev.num_blocks > zone_size) {
SPDK_ERRLOG("Tried to cross zone boundary during write command\n");
return -EINVAL;
}
ocdev_io->io.zone = bdev_ocssd_get_zone_by_lba(ocssd_bdev, bdev_io->u.bdev.offset_blocks);
if (__atomic_exchange_n(&ocdev_io->io.zone->busy, true, __ATOMIC_SEQ_CST)) {
return -EINVAL;
}
ocdev_io->io.iov_pos = 0;
ocdev_io->io.iov_off = 0;
lba = bdev_ocssd_to_disk_lba(ocssd_bdev, bdev_io->u.bdev.offset_blocks);
rc = spdk_nvme_ns_cmd_writev_with_md(nvme_bdev->nvme_ns->ns, nvme_ioch->qpair, lba,
bdev_io->u.bdev.num_blocks, bdev_ocssd_write_cb,
bdev_io, 0, bdev_ocssd_reset_sgl,
bdev_ocssd_next_sge, bdev_io->u.bdev.md_buf, 0, 0);
if (spdk_unlikely(rc != 0)) {
__atomic_store_n(&ocdev_io->io.zone->busy, false, __ATOMIC_SEQ_CST);
}
return spdk_nvme_ns_cmd_writev_with_md(nvme_bdev->nvme_ns->ns, nvme_ioch->qpair, lba,
bdev_io->u.bdev.num_blocks, bdev_ocssd_write_cb,
bdev_io, 0, bdev_ocssd_reset_sgl,
bdev_ocssd_next_sge, bdev_io->u.bdev.md_buf, 0, 0);
return rc;
}
static void
@ -392,7 +418,10 @@ static void
bdev_ocssd_reset_zone_cb(void *ctx, const struct spdk_nvme_cpl *cpl)
{
struct spdk_bdev_io *bdev_io = ctx;
struct bdev_ocssd_io *ocdev_io = (struct bdev_ocssd_io *)bdev_io->driver_ctx;
ocdev_io->io.zone->write_pointer = ocdev_io->io.zone->slba;
__atomic_store_n(&ocdev_io->io.zone->busy, false, __ATOMIC_SEQ_CST);
spdk_bdev_io_complete_nvme_status(bdev_io, 0, cpl->status.sct, cpl->status.sc);
}
@ -405,19 +434,31 @@ bdev_ocssd_reset_zone(struct spdk_io_channel *ioch, struct spdk_bdev_io *bdev_io
struct nvme_io_channel *nvme_ioch = spdk_io_channel_get_ctx(ioch);
struct bdev_ocssd_io *ocdev_io = (struct bdev_ocssd_io *)bdev_io->driver_ctx;
uint64_t offset, zone_size = nvme_bdev->disk.zone_size;
int rc;
if (num_zones > 1) {
SPDK_ERRLOG("Exceeded maximum number of zones per single reset: 1\n");
return -EINVAL;
}
ocdev_io->io.zone = bdev_ocssd_get_zone_by_slba(ocssd_bdev, slba);
if (__atomic_exchange_n(&ocdev_io->io.zone->busy, true, __ATOMIC_SEQ_CST)) {
return -EINVAL;
}
for (offset = 0; offset < num_zones; ++offset) {
ocdev_io->io.lba[offset] = bdev_ocssd_to_disk_lba(ocssd_bdev,
slba + offset * zone_size);
}
return spdk_nvme_ocssd_ns_cmd_vector_reset(nvme_bdev->nvme_ns->ns, nvme_ioch->qpair,
ocdev_io->io.lba, num_zones, NULL, bdev_ocssd_reset_zone_cb, bdev_io);
rc = spdk_nvme_ocssd_ns_cmd_vector_reset(nvme_bdev->nvme_ns->ns, nvme_ioch->qpair,
ocdev_io->io.lba, num_zones, NULL,
bdev_ocssd_reset_zone_cb, bdev_io);
if (spdk_unlikely(rc != 0)) {
__atomic_store_n(&ocdev_io->io.zone->busy, false, __ATOMIC_SEQ_CST);
}
return rc;
}
static int _bdev_ocssd_get_zone_info(struct spdk_bdev_io *bdev_io);