From: Alan Adamson <alan.adamson@xxxxxxxxxx> There is no dedicated NVMe atomic write command (which may error for a command which exceeds the controller atomic write limits). As an insurance policy against the block layer sending requests which cannot be executed atomically, add a check in the queue path. Signed-off-by: Alan Adamson <alan.adamson@xxxxxxxxxx> Signed-off-by: John Garry <john.g.garry@xxxxxxxxxx> --- drivers/nvme/host/core.c | 23 +++++++++++++++++++++++ drivers/nvme/host/nvme.h | 2 ++ 2 files changed, 25 insertions(+) diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index fd4f09f9dbe8..6b89ee7e9921 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -905,6 +905,26 @@ static inline blk_status_t nvme_setup_rw(struct nvme_ns *ns, if (req->cmd_flags & REQ_RAHEAD) dsmgmt |= NVME_RW_DSM_FREQ_PREFETCH; + /* + * Ensure that nothing has been sent which cannot be executed + * atomically. + */ + if (req->cmd_flags & REQ_ATOMIC) { + if (blk_rq_bytes(req) > ns->atomic_max) + return BLK_STS_IOERR; + + if (ns->atomic_boundary) { + u32 boundary = ns->atomic_boundary >> ns->lba_shift; + u32 imask = ~(boundary - 1); + u32 lba = nvme_sect_to_lba(ns, blk_rq_pos(req)); + u32 end = lba + (blk_rq_bytes(req) >> ns->lba_shift) + - 1; + + if ((lba & imask) != (end & imask)) + return BLK_STS_IOERR; + } + } + cmnd->rw.opcode = op; cmnd->rw.flags = 0; cmnd->rw.nsid = cpu_to_le32(ns->head->ns_id); @@ -1937,6 +1957,9 @@ static void nvme_update_atomic_write_disk_info(struct gendisk *disk, id->nabo); } + ns->atomic_max = atomic_bs; + ns->atomic_boundary = boundary; + blk_queue_atomic_write_max_bytes(disk->queue, atomic_bs); blk_queue_atomic_write_unit_min_sectors(disk->queue, bs >> SECTOR_SHIFT); blk_queue_atomic_write_unit_max_sectors(disk->queue, diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h index e7411dac00f7..5a3d76bc816f 100644 --- a/drivers/nvme/host/nvme.h +++ b/drivers/nvme/host/nvme.h @@ -520,6 +520,8 @@ struct nvme_ns { struct nvme_fault_inject fault_inject; + u32 atomic_max; + u32 atomic_boundary; }; /* NVMe ns supports metadata actions by the controller (generate/strip) */ -- 2.35.3