@@ -1856,7 +1856,7 @@ static void nvme_update_disk_info(struct gendisk *disk,
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;
@@ -1884,11 +1884,21 @@ static void __nvme_revalidate_disk(struct gendisk *disk, struct nvme_id_ns *id)
ns->features |= NVME_NS_EXT_LBAS;
/*
+ * For Fabrics, only metadata as part of extended data LBA is
+ * supported. Fail in case of a spec violation.
+ */
+ if (ns->ctrl->ops->flags & NVME_F_FABRICS) {
+ if (WARN_ON_ONCE(!(ns->features & NVME_NS_EXT_LBAS)))
+ return -EINVAL;
+ }
+
+ /*
* For PCI, Extended logical block will be generated by the
* controller.
*/
if (ns->ctrl->ops->flags & NVME_F_METADATA_SUPPORTED) {
- if (!(ns->features & NVME_NS_EXT_LBAS))
+ if (ns->ctrl->ops->flags & NVME_F_FABRICS ||
+ !(ns->features & NVME_NS_EXT_LBAS))
ns->features |= NVME_NS_MD_HOST_SUPPORTED;
}
}
@@ -1903,6 +1913,7 @@ static void __nvme_revalidate_disk(struct gendisk *disk, struct nvme_id_ns *id)
revalidate_disk(ns->head->disk);
}
#endif
+ return 0;
}
static int nvme_revalidate_disk(struct gendisk *disk)
@@ -1927,7 +1938,10 @@ static int nvme_revalidate_disk(struct gendisk *disk)
goto free_id;
}
- __nvme_revalidate_disk(disk, id);
+ ret = __nvme_revalidate_disk(disk, id);
+ if (ret)
+ goto free_id;
+
ret = nvme_report_ns_ids(ctrl, ns->head->ns_id, id, &ids);
if (ret)
goto free_id;
@@ -3614,7 +3628,8 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid)
memcpy(disk->disk_name, disk_name, DISK_NAME_LEN);
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) {
ret = nvme_nvm_register(ns, disk_name, node);
@@ -3639,6 +3654,8 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid)
return;
out_put_disk:
put_disk(ns->disk);
+ out_free_disk:
+ del_gendisk(ns->disk);
out_unlink_ns:
mutex_lock(&ctrl->subsys->lock);
list_del_rcu(&ns->siblings);