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: Daniel Verkamp <daniel.verkamp@intel.com>
Reviewed-on: https://review.gerrithub.io/379202
Tested-by: SPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Changpeng Liu <changpeng.liu@intel.com>
This commit is contained in:
Daniel Verkamp 2017-09-19 10:59:58 -07:00
parent b0c91df8e7
commit d565f549b9
2 changed files with 40 additions and 5 deletions

View File

@ -67,6 +67,11 @@ extern "C" {
*/ */
#define SPDK_NVME_DATASET_MANAGEMENT_MAX_RANGES 256 #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 { union spdk_nvme_cap_register {
uint64_t raw; uint64_t raw;
struct { struct {

View File

@ -44,6 +44,7 @@
#include "spdk/io_channel.h" #include "spdk/io_channel.h"
#include "spdk/string.h" #include "spdk/string.h"
#include "spdk/likely.h" #include "spdk/likely.h"
#include "spdk/util.h"
#include "spdk_internal/bdev.h" #include "spdk_internal/bdev.h"
#include "spdk_internal/log.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) uint64_t num_blocks)
{ {
struct nvme_io_channel *nvme_ch = spdk_io_channel_get_ctx(ch); struct nvme_io_channel *nvme_ch = spdk_io_channel_get_ctx(ch);
int rc = 0; struct spdk_nvme_dsm_range dsm_ranges[SPDK_NVME_DATASET_MANAGEMENT_MAX_RANGES];
struct spdk_nvme_dsm_range dsm_range = {}; struct spdk_nvme_dsm_range *range;
uint64_t offset, remaining;
uint64_t num_ranges_u64;
uint16_t num_ranges;
int rc;
dsm_range.starting_lba = offset_blocks; num_ranges_u64 = (num_blocks + SPDK_NVME_DATASET_MANAGEMENT_RANGE_MAX_BLOCKS - 1) /
dsm_range.length = num_blocks; 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++;
}
/* 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, rc = spdk_nvme_ns_cmd_dataset_management(nbdev->ns, nvme_ch->qpair,
SPDK_NVME_DSM_ATTR_DEALLOCATE, SPDK_NVME_DSM_ATTR_DEALLOCATE,
&dsm_range, 1, dsm_ranges, num_ranges,
bdev_nvme_queued_done, bio); bdev_nvme_queued_done, bio);
return rc; return rc;