rewrites discard support
Subsystems (3)
v2 cover rewrites discard support
From: Ming Lin <[email protected]>
This rewrites nvme_setup_discard() with blk_add_request_payload(). And moves it to common code so fabrics driver can also use it.
v2:
- add helper nvme_map_len()
- allocates only 16 bytes for discard payload
- moves command setup to common helper nvme_setup_cmd()
- returns BLK_MQ_RQ_QUEUE_BUSY when out of memory
Ming Lin (4):
nvme: add helper nvme_map_len()
block: add offset in blk_add_request_payload()
nvme: rewrite discard support
nvme: add helper nvme_setup_cmd()
block/blk-core.c | 5 ++- drivers/block/skd_main.c | 2 +- drivers/nvme/host/core.c | 105 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/nvme/host/nvme.h | 55 ++++--------------------- drivers/nvme/host/pci.c | 68 +++++++----------------------- drivers/scsi/sd.c | 2 +- include/linux/blkdev.h | 2 +- 7 files changed, 133 insertions(+), 106 deletions(-)
Signature · 1 line
1.9.1
PATCH v2 1/4 nvme: add helper nvme_map_len()
From: Ming Lin <[email protected]>
The helper returns the number of bytes that need to be mapped using PRPs/SGL entries.
--- drivers/nvme/host/nvme.h | 8 ++++++++ drivers/nvme/host/pci.c | 13 +++++-------- 2 files changed, 13 insertions(+), 8 deletions(-)
drivers/nvme/host/nvme.h +8 -0
@@ -181,6 +181,14 @@ static inline u64 nvme_block_nr(struct nvme_ns *ns, sector_t sector)return (sector >> (ns->lba_shift -9 )); } +static inline unsigned nvme_map_len (struct request *rq) +{ +if (rq->cmd_flags &REQ_DISCARD ) +return sizeof (struct nvme_dsm_range ); +else +return blk_rq_bytes (rq); +} +static inline void nvme_setup_flush (struct nvme_ns *ns,struct nvme_command *cmnd) {
drivers/nvme/host/pci.c +5 -8
@@ -348,16 +348,11 @@ static __le64 **iod_list(struct request *req)return (__le64 **)(iod->sg + req->nr_phys_segments); } -static int nvme_init_iod (struct request *rq,struct nvme_dev *dev) +static int nvme_init_iod (struct request *rq,unsigned size, +struct nvme_dev *dev) {struct nvme_iod *iod =blk_mq_rq_to_pdu (rq);int nseg = rq->nr_phys_segments; -unsigned size; - -if (rq->cmd_flags &REQ_DISCARD ) - size =sizeof (struct nvme_dsm_range ); -else - size =blk_rq_bytes (rq);if (nseg >NVME_INT_PAGES || size >NVME_INT_BYTES (dev)) { iod->sg =kmalloc (nvme_iod_alloc_size (dev, size, nseg),GFP_ATOMIC );
@@ -651,6 +646,7 @@ static int nvme_queue_rq(struct blk_mq_hw_ctx *hctx,struct nvme_dev *dev = nvmeq->dev;struct request *req = bd->rq;struct nvme_command cmnd; +unsigned map_len;int ret =BLK_MQ_RQ_QUEUE_OK ;/*
@@ -666,7 +662,8 @@ static int nvme_queue_rq(struct blk_mq_hw_ctx *hctx, } } - ret =nvme_init_iod (req, dev); + map_len =nvme_map_len (req); + ret =nvme_init_iod (req, map_len, dev);if (ret)return ret;
Signature · 1 line
1.9.1
Christoph Hellwig
maintainerPATCH v2 1/4 nvme: add helper nvme_map_len()
Looks fine,
PATCH v2 2/4 block: add offset in blk_add_request_payload()
In reply to Ming LinFrom: Ming Lin <[email protected]>
We could kmalloc() the payload, so need the offset in page.
--- block/blk-core.c | 5 +++-- drivers/block/skd_main.c | 2 +- drivers/scsi/sd.c | 2 +- include/linux/blkdev.h | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-)
block/blk-core.c +3 -2
@@ -1523,6 +1523,7 @@ EXPORT_SYMBOL(blk_put_request);* blk_add_request_payload - add a payload to a request * @rq: request to update * @page: page backing the payload +* @offset: offset in page * @len: length of the payload. * * This allows to later add a payload to an already submitted request by
@@ -1533,12 +1534,12 @@ EXPORT_SYMBOL(blk_put_request);* discard requests should ever use it. */ void blk_add_request_payload (struct request *rq,struct page *page, -unsigned int len) +int offset,unsigned int len) {struct bio *bio = rq->bio; bio->bi_io_vec->bv_page = page; - bio->bi_io_vec->bv_offset =0 ; + bio->bi_io_vec->bv_offset = offset; bio->bi_io_vec->bv_len = len; bio->bi_iter.bi_size = len;
drivers/block/skd_main.c +1 -1
@@ -562,7 +562,7 @@ skd_prep_discard_cdb(struct skd_scsi_request *scsi_req,put_unaligned_be32 (count, &buf[16 ]); req = skreq->req; -blk_add_request_payload (req, page, len); +blk_add_request_payload (req, page,0 , len); }static void skd_request_fn_not_online (struct request_queue *q);
drivers/scsi/sd.c +1 -1
@@ -779,7 +779,7 @@ static int sd_setup_discard_cmnd(struct scsi_cmnd *cmd)* discarded on disk. This allows us to report completion on the full * amount of blocks described by the request. */ -blk_add_request_payload (rq, page, len); +blk_add_request_payload (rq, page,0 , len); ret =scsi_init_io (cmd); rq->__data_len = nr_bytes;
include/linux/blkdev.h +1 -1
@@ -778,7 +778,7 @@ extern struct request *blk_make_request(struct request_queue *, struct bio *,extern void blk_rq_set_block_pc (struct request *);extern void blk_requeue_request (struct request_queue *,struct request *);extern void blk_add_request_payload (struct request *rq,struct page *page, -unsigned int len); +int offset,unsigned int len);extern int blk_lld_busy (struct request_queue *q); extern int blk_rq_prep_clone(struct request *rq, struct request *rq_src, struct bio_set *bs, gfp_t gfp_mask,
Signature · 1 line
1.9.1
Christoph Hellwig
maintainerPATCH v2 2/4 block: add offset in blk_add_request_payload()
Quoted 5 lines · Ming Lin
From: Ming Lin <ming.l at ssi.samsung.com>
We could
kmalloc()the payload, so need the offset in page.Signed-off-by Ming Lin <ming.l at ssi.samsung.com>
Looks fine,
PATCH v2 3/4 nvme: rewrite discard support
In reply to Ming LinFrom: Ming Lin <[email protected]>
This rewrites nvme_setup_discard() with blk_add_request_payload(). It allocates only the necessary amount(16 bytes) for the payload.
--- drivers/nvme/host/pci.c | 68 ++++++++++++++++++++++++++++--------------------- 1 file changed, 39 insertions(+), 29 deletions(-)
drivers/nvme/host/pci.c +39 -29
@@ -377,6 +377,9 @@ static void nvme_free_iod(struct nvme_dev *dev, struct request *req)__le64 **list =iod_list (req);dma_addr_t prp_dma = iod->first_dma; +if (req->cmd_flags &REQ_DISCARD ) +kfree (req->completion_data); +if (iod->npages ==0 )dma_pool_free (dev->prp_small_pool, list[0 ], prp_dma);for (i =0 ; i < iod->npages; i++) {
@@ -538,7 +541,7 @@ static bool nvme_setup_prps(struct nvme_dev *dev, struct request *req, }static int nvme_map_data (struct nvme_dev *dev,struct request *req, -struct nvme_command *cmnd) +unsigned size,struct nvme_command *cmnd) {struct nvme_iod *iod =blk_mq_rq_to_pdu (req);struct request_queue *q = req->q;
@@ -555,7 +558,7 @@ static int nvme_map_data(struct nvme_dev *dev, struct request *req,if (!dma_map_sg (dev->dev, iod->sg, iod->nents, dma_dir)) goto out; -if (!nvme_setup_prps (dev, req,blk_rq_bytes (req))) +if (!nvme_setup_prps (dev, req, size)) goto out_unmap; ret =BLK_MQ_RQ_QUEUE_ERROR ;
@@ -604,35 +607,41 @@ static void nvme_unmap_data(struct nvme_dev *dev, struct request *req)nvme_free_iod (dev, req); } -/* -* We reuse the small pool to allocate the 16-byte range here as it is not -* worth having a special pool for these or additional cases to handle freeing -* the iod. -*/ -static int nvme_setup_discard (struct nvme_queue *nvmeq,struct nvme_ns *ns, -struct request *req,struct nvme_command *cmnd) +static inline int nvme_setup_discard (struct nvme_ns *ns,struct request *req, +struct nvme_command *cmnd) { -struct nvme_iod *iod =blk_mq_rq_to_pdu (req);struct nvme_dsm_range *range; +struct page *page; +int offset; +unsigned int nr_bytes =blk_rq_bytes (req); - range =dma_pool_alloc (nvmeq->dev->prp_small_pool,GFP_ATOMIC , - &iod->first_dma); + range =kmalloc (sizeof (*range),GFP_ATOMIC );if (!range)return BLK_MQ_RQ_QUEUE_BUSY ; -iod_list (req)[0 ] = (__le64 *)range; - iod->npages =0 ; range->cattr =cpu_to_le32 (0 ); - range->nlb =cpu_to_le32 (blk_rq_bytes (req) >> ns->lba_shift); + range->nlb =cpu_to_le32 (nr_bytes >> ns->lba_shift); range->slba =cpu_to_le64 (nvme_block_nr (ns,blk_rq_pos (req)));memset (cmnd,0 ,sizeof (*cmnd)); cmnd->dsm.opcode = nvme_cmd_dsm; cmnd->dsm.nsid =cpu_to_le32 (ns->ns_id); - cmnd->dsm.prp1 =cpu_to_le64 (iod->first_dma); cmnd->dsm.nr =0 ; cmnd->dsm.attributes =cpu_to_le32 (NVME_DSMGMT_AD ); -return BLK_MQ_RQ_QUEUE_OK ; + + req->completion_data = range; + page =virt_to_page (range); + offset =offset_in_page (range); +blk_add_request_payload (req, page, offset,sizeof (*range)); + +/* +* we set __data_len back to the size of the area to be discarded +* on disk. This allows us to report completion on the full amount +* of blocks described by the request. +*/ + req->__data_len = nr_bytes; + +return 0 ; }/*
@@ -667,19 +676,20 @@ static int nvme_queue_rq(struct blk_mq_hw_ctx *hctx,if (ret)return ret; -if (req->cmd_flags &REQ_DISCARD ) { - ret =nvme_setup_discard (nvmeq, ns, req, &cmnd); - }else { -if (req->cmd_type ==REQ_TYPE_DRV_PRIV ) -memcpy (&cmnd, req->cmd,sizeof (cmnd)); -else if (req->cmd_flags &REQ_FLUSH ) -nvme_setup_flush (ns, &cmnd); -else -nvme_setup_rw (ns, req, &cmnd); +if (req->cmd_type ==REQ_TYPE_DRV_PRIV ) +memcpy (&cmnd, req->cmd,sizeof (cmnd)); +else if (req->cmd_flags &REQ_FLUSH ) +nvme_setup_flush (ns, &cmnd); +else if (req->cmd_flags &REQ_DISCARD ) + ret =nvme_setup_discard (ns, req, &cmnd); +else +nvme_setup_rw (ns, req, &cmnd); -if (req->nr_phys_segments) - ret =nvme_map_data (dev, req, &cmnd); - } +if (ret) + goto out; + +if (req->nr_phys_segments) + ret =nvme_map_data (dev, req, map_len, &cmnd);if (ret) goto out;
Signature · 1 line
1.9.1
Christoph Hellwig
maintainerPATCH v2 3/4 nvme: rewrite discard support
drivers/nvme/host/pci.c static void nvme_unmap_data(struct nvme_dev *dev, struct request *req) · line 620
Quoted 11 lines · Ming Lin
drivers/nvme/host/pci.c +6
-0+static inline int nvme_setup_discard (struct nvme_ns *ns,struct request *req, +struct nvme_command *cmnd) {struct nvme_dsm_range *range; +struct page *page; +int offset; +unsigned int nr_bytes =blk_rq_bytes (req); + range =kmalloc (sizeof (*range),GFP_ATOMIC );if (!range)return BLK_MQ_RQ_QUEUE_BUSY ;
I've been a bit worried about alignment vs dma transfers here, but it seems like we should be fine after all as NVMe doesn't limit our DMA payload alignment, and I couldn't see any platform limitations either.
Looks fine,
PATCH v2 4/4 nvme: add helper nvme_setup_cmd()
In reply to Ming LinFrom: Ming Lin <[email protected]>
This moves nvme_setup_{flush,discard,rw} calls into a common nvme_setup_cmd() helper. So we can eventually hide all the command setup in the core module and don't even need to update the fabrics drivers for any specific command type.
--- drivers/nvme/host/core.c | 105 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/nvme/host/nvme.h | 53 +----------------------- drivers/nvme/host/pci.c | 47 +-------------------- 3 files changed, 108 insertions(+), 97 deletions(-)
drivers/nvme/host/core.c +105 -0
@@ -127,6 +127,111 @@ struct request *nvme_alloc_request(struct request_queue *q,return req; } +static inline void nvme_setup_flush (struct nvme_ns *ns, +struct nvme_command *cmnd) +{ +memset (cmnd,0 ,sizeof (*cmnd)); + cmnd->common.opcode = nvme_cmd_flush; + cmnd->common.nsid =cpu_to_le32 (ns->ns_id); +} + +static inline int nvme_setup_discard (struct nvme_ns *ns,struct request *req, +struct nvme_command *cmnd) +{ +struct nvme_dsm_range *range; +struct page *page; +int offset; +unsigned int nr_bytes =blk_rq_bytes (req); + + range =kmalloc (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))); + +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.attributes =cpu_to_le32 (NVME_DSMGMT_AD ); + + req->completion_data = range; + page =virt_to_page (range); + offset =offset_in_page (range); +blk_add_request_payload (req, page, offset,sizeof (*range)); + +/* +* we set __data_len back to the size of the area to be discarded +* on disk. This allows us to report completion on the full amount +* of blocks described by the request. +*/ + req->__data_len = nr_bytes; + +return 0 ; +} + +static inline void nvme_setup_rw (struct nvme_ns *ns,struct request *req, +struct nvme_command *cmnd) +{ +u16 control =0 ; +u32 dsmgmt =0 ; + +if (req->cmd_flags &REQ_FUA ) + control |=NVME_RW_FUA ; +if (req->cmd_flags & (REQ_FAILFAST_DEV |REQ_RAHEAD )) + control |=NVME_RW_LR ; + +if (req->cmd_flags &REQ_RAHEAD ) + dsmgmt |=NVME_RW_DSM_FREQ_PREFETCH ; + +memset (cmnd,0 ,sizeof (*cmnd)); + cmnd->rw.opcode = (rq_data_dir (req) ? nvme_cmd_write : nvme_cmd_read); + cmnd->rw.command_id = req->tag; + cmnd->rw.nsid =cpu_to_le32 (ns->ns_id); + cmnd->rw.slba =cpu_to_le64 (nvme_block_nr (ns,blk_rq_pos (req))); + cmnd->rw.length =cpu_to_le16 ((blk_rq_bytes (req) >> ns->lba_shift) -1 ); + +if (ns->ms) { +switch (ns->pi_type) { +case NVME_NS_DPS_PI_TYPE3 : + control |=NVME_RW_PRINFO_PRCHK_GUARD ; +break ; +case NVME_NS_DPS_PI_TYPE1 : +case NVME_NS_DPS_PI_TYPE2 : + control |=NVME_RW_PRINFO_PRCHK_GUARD | +NVME_RW_PRINFO_PRCHK_REF ; + cmnd->rw.reftag =cpu_to_le32 ( +nvme_block_nr (ns,blk_rq_pos (req))); +break ; + } +if (!blk_integrity_rq (req)) + control |=NVME_RW_PRINFO_PRACT ; + } + + cmnd->rw.control =cpu_to_le16 (control); + cmnd->rw.dsmgmt =cpu_to_le32 (dsmgmt); +} + +int nvme_setup_cmd (struct nvme_ns *ns,struct request *req, +struct nvme_command *cmd) +{ +int ret =0 ; + +if (req->cmd_type ==REQ_TYPE_DRV_PRIV ) +memcpy (cmd, req->cmd,sizeof (*cmd)); +else if (req->cmd_flags &REQ_FLUSH ) +nvme_setup_flush (ns, cmd); +else if (req->cmd_flags &REQ_DISCARD ) + ret =nvme_setup_discard (ns, req, cmd); +else +nvme_setup_rw (ns, req, cmd); + +return ret; +} +EXPORT_SYMBOL_GPL (nvme_setup_cmd); +/* * Returns 0 on success. If the result is negative, it's a Linux error code; * if the result is positive, it's an NVM Express status code
drivers/nvme/host/nvme.h +2 -51
65 lines not on this page · raw message
drivers/nvme/host/pci.c +1 -46
59 lines not on this page · raw message
Signature · 1 line
1.9.1
Christoph Hellwig
maintainerPATCH v2 4/4 nvme: add helper nvme_setup_cmd()
Great! This is exactly how I wanted the interface to the I/O command set specific setup to look like.
v2 cover rewrites discard support
In reply to Ming LinQuoted 4 lines · Ming Lin
From: Ming Lin <ming.l at ssi.samsung.com>
This rewrites
nvme_setup_discard()withblk_add_request_payload(). And moves it to common code so fabrics driver can also use it.
Looks fine, for the series.
v2 cover rewrites discard support
In reply to Ming LinQuoted 17 lines · Ming Lin
From: Ming Lin <ming.l at ssi.samsung.com>
This rewrites
nvme_setup_discard()withblk_add_request_payload(). And moves it to common code so fabrics driver can also use it.v2:
- add helpernvme_map_len()
- allocates only 16 bytes for discard payload
- moves command setup to common helpernvme_setup_cmd()
- returnsBLK_MQ_RQ_QUEUE_BUSYwhen out of memoryMing Lin (4):
nvme: add helpernvme_map_len()
block: add offset inblk_add_request_payload()
nvme: rewrite discard support
nvme: add helpernvme_setup_cmd()
Quoted 8 lines
block/blk-core.c | 5 ++- drivers/block/skd_main.c | 2 +- drivers/nvme/host/core.c | 105 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/nvme/host/nvme.h | 55 ++++--------------------- drivers/nvme/host/pci.c | 68 +++++++----------------------- drivers/scsi/sd.c | 2 +- include/linux/blkdev.h | 2 +- 7 files changed, 133 insertions(+), 106 deletions(-)
Looks good to me, I'll queue it up for 4.7. Thanks.
Signature · 1 line
Jens Axboe