Commit d565f549 authored by Daniel Verkamp's avatar Daniel Verkamp
Browse files

bdev/nvme: support large (> 2TB) unmap requests



spdk_bdev_unmap_blocks() accepts a 64-bit number of blocks, which can
exceed the NVMe Dataset Management range's 32-bit number of blocks,
which can represent up to 2 TB with 512-byte blocks.

We can support up to 0.5 PB unmap requests by using the maximum number
of descriptors in a single Dataset Management command, which should be
sufficient for now.

Change-Id: I0a4ee77a9be148355991e1a081007ffa020a3ee5
Signed-off-by: default avatarDaniel Verkamp <daniel.verkamp@intel.com>
Reviewed-on: https://review.gerrithub.io/379202


Tested-by: default avatarSPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
Reviewed-by: default avatarChangpeng Liu <changpeng.liu@intel.com>
parent b0c91df8
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -67,6 +67,11 @@ extern "C" {
 */
#define SPDK_NVME_DATASET_MANAGEMENT_MAX_RANGES	256

/**
 * Maximum number of blocks that may be specified in a single dataset management range.
 */
#define SPDK_NVME_DATASET_MANAGEMENT_RANGE_MAX_BLOCKS	0xFFFFFFFFu

union spdk_nvme_cap_register {
	uint64_t	raw;
	struct {
+35 −5
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@
#include "spdk/io_channel.h"
#include "spdk/string.h"
#include "spdk/likely.h"
#include "spdk/util.h"

#include "spdk_internal/bdev.h"
#include "spdk_internal/log.h"
@@ -1267,15 +1268,44 @@ bdev_nvme_unmap(struct nvme_bdev *nbdev, struct spdk_io_channel *ch,
		uint64_t num_blocks)
{
	struct nvme_io_channel *nvme_ch = spdk_io_channel_get_ctx(ch);
	int rc = 0;
	struct spdk_nvme_dsm_range dsm_range = {};
	struct spdk_nvme_dsm_range dsm_ranges[SPDK_NVME_DATASET_MANAGEMENT_MAX_RANGES];
	struct spdk_nvme_dsm_range *range;
	uint64_t offset, remaining;
	uint64_t num_ranges_u64;
	uint16_t num_ranges;
	int rc;

	num_ranges_u64 = (num_blocks + SPDK_NVME_DATASET_MANAGEMENT_RANGE_MAX_BLOCKS - 1) /
			 SPDK_NVME_DATASET_MANAGEMENT_RANGE_MAX_BLOCKS;
	if (num_ranges_u64 > SPDK_COUNTOF(dsm_ranges)) {
		SPDK_ERRLOG("Unmap request for %" PRIu64 " blocks is too large\n", num_blocks);
		return -EINVAL;
	}
	num_ranges = (uint16_t)num_ranges_u64;

	offset = offset_blocks;
	remaining = num_blocks;
	range = &dsm_ranges[0];

	/* Fill max-size ranges until the remaining blocks fit into one range */
	while (remaining > SPDK_NVME_DATASET_MANAGEMENT_RANGE_MAX_BLOCKS) {
		range->attributes.raw = 0;
		range->length = SPDK_NVME_DATASET_MANAGEMENT_RANGE_MAX_BLOCKS;
		range->starting_lba = offset;

		offset += SPDK_NVME_DATASET_MANAGEMENT_RANGE_MAX_BLOCKS;
		remaining -= SPDK_NVME_DATASET_MANAGEMENT_RANGE_MAX_BLOCKS;
		range++;
	}

	dsm_range.starting_lba = offset_blocks;
	dsm_range.length = num_blocks;
	/* Final range describes the remaining blocks */
	range->attributes.raw = 0;
	range->length = remaining;
	range->starting_lba = offset;

	rc = spdk_nvme_ns_cmd_dataset_management(nbdev->ns, nvme_ch->qpair,
			SPDK_NVME_DSM_ATTR_DEALLOCATE,
			&dsm_range, 1,
			dsm_ranges, num_ranges,
			bdev_nvme_queued_done, bio);

	return rc;