Commit ffd53b6b authored by Konrad Sztyber's avatar Konrad Sztyber Committed by Tomasz Zawadzki
Browse files

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: default avatarKonrad Sztyber <konrad.sztyber@intel.com>
Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/469119


Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
Reviewed-by: default avatarMateusz Kozlowski <mateusz.kozlowski@intel.com>
Reviewed-by: default avatarBen Walker <benjamin.walker@intel.com>
Tested-by: default avatarSPDK 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>
parent b63be394
Loading
Loading
Loading
Loading
+54 −13
Original line number Diff line number Diff line
@@ -62,6 +62,7 @@ struct bdev_ocssd_zone {
struct bdev_ocssd_io {
	union {
		struct {
			struct bdev_ocssd_zone	*zone;
			size_t			iov_pos;
			size_t			iov_off;
			uint64_t		lba[SPDK_NVME_OCSSD_MAX_LBAL_ENTRIES];
@@ -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);

	return spdk_nvme_ns_cmd_writev_with_md(nvme_bdev->nvme_ns->ns, nvme_ioch->qpair, lba,
	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 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);