nvme: fix and clarify the check for missing metadata
authorChristoph Hellwig <hch@lst.de>
Tue, 7 Nov 2017 16:27:34 +0000 (17:27 +0100)
committerJens Axboe <axboe@kernel.dk>
Sat, 11 Nov 2017 02:53:25 +0000 (19:53 -0700)
Update the check in nvme_setup_rw for missing metadata so that it is
together with the other metadata handling, does not contain impossible
to reach conditions and warns if we get an impossible requests for
a (non-PI) metadata-enabled namespace when CONFIG_BLK_DEV_INTEGRITY
is not set.

Also add a little helper that checks if a given metadata configuration
contains protection information

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reported-by: Javier González <jg@lightnvm.io>
Reviewed-by: Keith Busch <keith.busch@intel.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
drivers/nvme/host/core.c

index 28d58d353a420a71c8dc73924e1ef67a0c9a2b61..3aabaa103e106e8999ebf70f3996710f9ee64fb0 100644 (file)
@@ -137,6 +137,11 @@ int nvme_delete_ctrl_sync(struct nvme_ctrl *ctrl)
 }
 EXPORT_SYMBOL_GPL(nvme_delete_ctrl_sync);
 
+static inline bool nvme_ns_has_pi(struct nvme_ns *ns)
+{
+       return ns->pi_type && ns->ms == sizeof(struct t10_pi_tuple);
+}
+
 static blk_status_t nvme_error_status(struct request *req)
 {
        switch (nvme_req(req)->status & 0x7ff) {
@@ -472,16 +477,6 @@ static inline blk_status_t nvme_setup_rw(struct nvme_ns *ns,
        u16 control = 0;
        u32 dsmgmt = 0;
 
-       /*
-        * If formated with metadata, require the block layer provide a buffer
-        * unless this namespace is formated such that the metadata can be
-        * stripped/generated by the controller with PRACT=1.
-        */
-       if (ns && ns->ms &&
-           (!ns->pi_type || ns->ms != sizeof(struct t10_pi_tuple)) &&
-           !blk_integrity_rq(req) && !blk_rq_is_passthrough(req))
-               return BLK_STS_NOTSUPP;
-
        if (req->cmd_flags & REQ_FUA)
                control |= NVME_RW_FUA;
        if (req->cmd_flags & (REQ_FAILFAST_DEV | REQ_RAHEAD))
@@ -500,6 +495,18 @@ static inline blk_status_t nvme_setup_rw(struct nvme_ns *ns,
                nvme_assign_write_stream(ctrl, req, &control, &dsmgmt);
 
        if (ns->ms) {
+               /*
+                * If formated with metadata, the block layer always provides a
+                * metadata buffer if CONFIG_BLK_DEV_INTEGRITY is enabled.  Else
+                * we enable the PRACT bit for protection information or set the
+                * namespace capacity to zero to prevent any I/O.
+                */
+               if (!blk_integrity_rq(req)) {
+                       if (WARN_ON_ONCE(!nvme_ns_has_pi(ns)))
+                               return BLK_STS_NOTSUPP;
+                       control |= NVME_RW_PRINFO_PRACT;
+               }
+
                switch (ns->pi_type) {
                case NVME_NS_DPS_PI_TYPE3:
                        control |= NVME_RW_PRINFO_PRCHK_GUARD;
@@ -512,8 +519,6 @@ static inline blk_status_t nvme_setup_rw(struct nvme_ns *ns,
                                        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);
@@ -1173,7 +1178,7 @@ static void nvme_update_disk_info(struct gendisk *disk,
        if (ns->ms && !ns->ext &&
            (ns->ctrl->ops->flags & NVME_F_METADATA_SUPPORTED))
                nvme_init_integrity(disk, ns->ms, ns->pi_type);
-       if (ns->ms && !(ns->ms == 8 && ns->pi_type) && !blk_get_integrity(disk))
+       if (ns->ms && !nvme_ns_has_pi(ns) && !blk_get_integrity(disk))
                capacity = 0;
        set_capacity(disk, capacity);