Commit 33cfdc2a authored by Max Gurtovoy's avatar Max Gurtovoy Committed by Christoph Hellwig

nvme: enforce extended LBA format for fabrics metadata

An extended LBA is a larger LBA that is created when metadata associated
with the LBA is transferred contiguously with the LBA data (AKA
interleaved). The metadata may be either transferred as part of the LBA
(creating an extended LBA) or it may be transferred as a separate
contiguous buffer of data. According to the NVMeoF spec, a fabrics ctrl
supports only an Extended LBA format. Fail revalidation in case we have a
spec violation. Also add a flag that will imply on capable transports and
controllers as part of a preparation for allowing end-to-end protection
information for fabric controllers.
Suggested-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarMax Gurtovoy <maxg@mellanox.com>
Signed-off-by: default avatarIsrael Rukshin <israelr@mellanox.com>
Reviewed-by: default avatarJames Smart <james.smart@broadcom.com>
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
parent 95093350
...@@ -1916,9 +1916,10 @@ static void nvme_update_disk_info(struct gendisk *disk, ...@@ -1916,9 +1916,10 @@ static void nvme_update_disk_info(struct gendisk *disk,
blk_mq_unfreeze_queue(disk->queue); blk_mq_unfreeze_queue(disk->queue);
} }
static void __nvme_revalidate_disk(struct gendisk *disk, struct nvme_id_ns *id) static int __nvme_revalidate_disk(struct gendisk *disk, struct nvme_id_ns *id)
{ {
struct nvme_ns *ns = disk->private_data; struct nvme_ns *ns = disk->private_data;
struct nvme_ctrl *ctrl = ns->ctrl;
u32 iob; u32 iob;
/* /*
...@@ -1929,9 +1930,9 @@ static void __nvme_revalidate_disk(struct gendisk *disk, struct nvme_id_ns *id) ...@@ -1929,9 +1930,9 @@ static void __nvme_revalidate_disk(struct gendisk *disk, struct nvme_id_ns *id)
if (ns->lba_shift == 0) if (ns->lba_shift == 0)
ns->lba_shift = 9; ns->lba_shift = 9;
if ((ns->ctrl->quirks & NVME_QUIRK_STRIPE_SIZE) && if ((ctrl->quirks & NVME_QUIRK_STRIPE_SIZE) &&
is_power_of_2(ns->ctrl->max_hw_sectors)) is_power_of_2(ctrl->max_hw_sectors))
iob = ns->ctrl->max_hw_sectors; iob = ctrl->max_hw_sectors;
else else
iob = nvme_lba_to_sect(ns, le16_to_cpu(id->noiob)); iob = nvme_lba_to_sect(ns, le16_to_cpu(id->noiob));
...@@ -1944,16 +1945,24 @@ static void __nvme_revalidate_disk(struct gendisk *disk, struct nvme_id_ns *id) ...@@ -1944,16 +1945,24 @@ static void __nvme_revalidate_disk(struct gendisk *disk, struct nvme_id_ns *id)
ns->pi_type = 0; ns->pi_type = 0;
if (ns->ms) { if (ns->ms) {
if (id->flbas & NVME_NS_FLBAS_META_EXT)
ns->features |= NVME_NS_EXT_LBAS;
/* /*
* For PCI, Extended logical block will be generated by the * For PCIe only the separate metadata pointer is supported,
* controller. Non-extended format can be generated by the * as the block layer supplies metadata in a separate bio_vec
* block layer. * chain. For Fabrics, only metadata as part of extended data
* LBA is supported on the wire per the Fabrics specification,
* but the HBA/HCA will do the remapping from the separate
* metadata buffers for us.
*/ */
if (ns->ctrl->ops->flags & NVME_F_METADATA_SUPPORTED) { if (id->flbas & NVME_NS_FLBAS_META_EXT) {
if (!(ns->features & NVME_NS_EXT_LBAS)) ns->features |= NVME_NS_EXT_LBAS;
if ((ctrl->ops->flags & NVME_F_FABRICS) &&
(ctrl->ops->flags & NVME_F_METADATA_SUPPORTED) &&
ctrl->max_integrity_segments)
ns->features |= NVME_NS_METADATA_SUPPORTED;
} else {
if (WARN_ON_ONCE(ctrl->ops->flags & NVME_F_FABRICS))
return -EINVAL;
if (ctrl->ops->flags & NVME_F_METADATA_SUPPORTED)
ns->features |= NVME_NS_METADATA_SUPPORTED; ns->features |= NVME_NS_METADATA_SUPPORTED;
} }
} }
...@@ -1968,6 +1977,7 @@ static void __nvme_revalidate_disk(struct gendisk *disk, struct nvme_id_ns *id) ...@@ -1968,6 +1977,7 @@ static void __nvme_revalidate_disk(struct gendisk *disk, struct nvme_id_ns *id)
revalidate_disk(ns->head->disk); revalidate_disk(ns->head->disk);
} }
#endif #endif
return 0;
} }
static int nvme_revalidate_disk(struct gendisk *disk) static int nvme_revalidate_disk(struct gendisk *disk)
...@@ -2003,7 +2013,7 @@ static int nvme_revalidate_disk(struct gendisk *disk) ...@@ -2003,7 +2013,7 @@ static int nvme_revalidate_disk(struct gendisk *disk)
goto free_id; goto free_id;
} }
__nvme_revalidate_disk(disk, id); ret = __nvme_revalidate_disk(disk, id);
free_id: free_id:
kfree(id); kfree(id);
out: out:
...@@ -3657,7 +3667,8 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid) ...@@ -3657,7 +3667,8 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid)
memcpy(disk->disk_name, disk_name, DISK_NAME_LEN); memcpy(disk->disk_name, disk_name, DISK_NAME_LEN);
ns->disk = disk; ns->disk = disk;
__nvme_revalidate_disk(disk, id); if (__nvme_revalidate_disk(disk, id))
goto out_free_disk;
if ((ctrl->quirks & NVME_QUIRK_LIGHTNVM) && id->vs[0] == 0x1) { if ((ctrl->quirks & NVME_QUIRK_LIGHTNVM) && id->vs[0] == 0x1) {
ret = nvme_nvm_register(ns, disk_name, node); ret = nvme_nvm_register(ns, disk_name, node);
...@@ -3684,6 +3695,8 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid) ...@@ -3684,6 +3695,8 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid)
/* prevent double queue cleanup */ /* prevent double queue cleanup */
ns->disk->queue = NULL; ns->disk->queue = NULL;
put_disk(ns->disk); put_disk(ns->disk);
out_free_disk:
del_gendisk(ns->disk);
out_unlink_ns: out_unlink_ns:
mutex_lock(&ctrl->subsys->lock); mutex_lock(&ctrl->subsys->lock);
list_del_rcu(&ns->siblings); list_del_rcu(&ns->siblings);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment