Skip to content

Commit

Permalink
nvme: support ranged discard requests
Browse files Browse the repository at this point in the history
NVMe supports up to 256 ranges per DSM command, so wire up support
for ranged discards up to that limit.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Jens Axboe <axboe@fb.com>
  • Loading branch information
Christoph Hellwig authored and axboe committed Feb 8, 2017
1 parent 1e73973 commit b35ba01
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 7 deletions.
30 changes: 23 additions & 7 deletions drivers/nvme/host/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -238,26 +238,38 @@ static inline void nvme_setup_flush(struct nvme_ns *ns,
static inline int nvme_setup_discard(struct nvme_ns *ns, struct request *req,
struct nvme_command *cmnd)
{
unsigned short segments = blk_rq_nr_discard_segments(req), n = 0;
struct nvme_dsm_range *range;
unsigned int nr_bytes = blk_rq_bytes(req);
struct bio *bio;

range = kmalloc(sizeof(*range), GFP_ATOMIC);
range = kmalloc_array(segments, sizeof(*range), GFP_ATOMIC);
if (!range)
return BLK_MQ_RQ_QUEUE_BUSY;

range->cattr = cpu_to_le32(0);
range->nlb = cpu_to_le32(nr_bytes >> ns->lba_shift);
range->slba = cpu_to_le64(nvme_block_nr(ns, blk_rq_pos(req)));
__rq_for_each_bio(bio, req) {
u64 slba = nvme_block_nr(ns, bio->bi_iter.bi_sector);
u32 nlb = bio->bi_iter.bi_size >> ns->lba_shift;

range[n].cattr = cpu_to_le32(0);
range[n].nlb = cpu_to_le32(nlb);
range[n].slba = cpu_to_le64(slba);
n++;
}

if (WARN_ON_ONCE(n != segments)) {
kfree(range);
return BLK_MQ_RQ_QUEUE_ERROR;
}

memset(cmnd, 0, sizeof(*cmnd));
cmnd->dsm.opcode = nvme_cmd_dsm;
cmnd->dsm.nsid = cpu_to_le32(ns->ns_id);
cmnd->dsm.nr = 0;
cmnd->dsm.nr = segments - 1;
cmnd->dsm.attributes = cpu_to_le32(NVME_DSMGMT_AD);

req->special_vec.bv_page = virt_to_page(range);
req->special_vec.bv_offset = offset_in_page(range);
req->special_vec.bv_len = sizeof(*range);
req->special_vec.bv_len = sizeof(*range) * segments;
req->rq_flags |= RQF_SPECIAL_PAYLOAD;

return BLK_MQ_RQ_QUEUE_OK;
Expand Down Expand Up @@ -871,6 +883,9 @@ static void nvme_config_discard(struct nvme_ns *ns)
struct nvme_ctrl *ctrl = ns->ctrl;
u32 logical_block_size = queue_logical_block_size(ns->queue);

BUILD_BUG_ON(PAGE_SIZE / sizeof(struct nvme_dsm_range) <
NVME_DSM_MAX_RANGES);

if (ctrl->quirks & NVME_QUIRK_DISCARD_ZEROES)
ns->queue->limits.discard_zeroes_data = 1;
else
Expand All @@ -879,6 +894,7 @@ static void nvme_config_discard(struct nvme_ns *ns)
ns->queue->limits.discard_alignment = logical_block_size;
ns->queue->limits.discard_granularity = logical_block_size;
blk_queue_max_discard_sectors(ns->queue, UINT_MAX);
blk_queue_max_discard_segments(ns->queue, NVME_DSM_MAX_RANGES);
queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, ns->queue);
}

Expand Down
2 changes: 2 additions & 0 deletions include/linux/nvme.h
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,8 @@ enum {
NVME_DSMGMT_AD = 1 << 2,
};

#define NVME_DSM_MAX_RANGES 256

struct nvme_dsm_range {
__le32 cattr;
__le32 nlb;
Expand Down

0 comments on commit b35ba01

Please sign in to comment.