Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

nvme: refactor namespace probing

Change nvme_ns_scan to gather all information needed for generic
namespace setup into a nvme_ns_info structure. This structure is filled
from the Command Set Idependent Identify Namespace data structure if
it is available or else the legacy Identify namespace structure.

With that everything related to the NVM command set (and the ZNS command
set derived from it) can be encapsulated in the nvme_update_ns_info_block
function while keeping the rest of the namespace probing generic.

The downside is that we now always issue two Identify Namespace calls for
each probed namespace instead of usually just a single one previously.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Javier González <javier.gonz@samsung.com>
Reviewed-by: Joel Granados <j.granados@samsung.com>
Reviewed-by: Sagi Grimberg <sagi@grimberg.me>
Signed-off-by: Jens Axboe <axboe@kernel.dk>

authored by

Christoph Hellwig and committed by
Jens Axboe
1a893c2b 71882e7d

+132 -112
+132 -112
drivers/nvme/host/core.c
··· 31 31 32 32 #define NVME_MINORS (1U << MINORBITS) 33 33 34 + struct nvme_ns_info { 35 + struct nvme_ns_ids ids; 36 + u32 nsid; 37 + __le32 anagrpid; 38 + bool is_shared; 39 + bool is_ready; 40 + }; 41 + 34 42 unsigned int admin_timeout = 60; 35 43 module_param(admin_timeout, uint, 0644); 36 44 MODULE_PARM_DESC(admin_timeout, "timeout in seconds for admin commands"); ··· 1350 1342 } 1351 1343 } 1352 1344 1353 - static int nvme_identify_ns_descs(struct nvme_ctrl *ctrl, unsigned nsid, 1354 - struct nvme_ns_ids *ids) 1345 + static int nvme_identify_ns_descs(struct nvme_ctrl *ctrl, 1346 + struct nvme_ns_info *info) 1355 1347 { 1356 1348 struct nvme_command c = { }; 1357 1349 bool csi_seen = false; ··· 1364 1356 return 0; 1365 1357 1366 1358 c.identify.opcode = nvme_admin_identify; 1367 - c.identify.nsid = cpu_to_le32(nsid); 1359 + c.identify.nsid = cpu_to_le32(info->nsid); 1368 1360 c.identify.cns = NVME_ID_CNS_NS_DESC_LIST; 1369 1361 1370 1362 data = kzalloc(NVME_IDENTIFY_DATA_SIZE, GFP_KERNEL); ··· 1376 1368 if (status) { 1377 1369 dev_warn(ctrl->device, 1378 1370 "Identify Descriptors failed (nsid=%u, status=0x%x)\n", 1379 - nsid, status); 1371 + info->nsid, status); 1380 1372 goto free_data; 1381 1373 } 1382 1374 ··· 1386 1378 if (cur->nidl == 0) 1387 1379 break; 1388 1380 1389 - len = nvme_process_ns_desc(ctrl, ids, cur, &csi_seen); 1381 + len = nvme_process_ns_desc(ctrl, &info->ids, cur, &csi_seen); 1390 1382 if (len < 0) 1391 1383 break; 1392 1384 ··· 1395 1387 1396 1388 if (nvme_multi_css(ctrl) && !csi_seen) { 1397 1389 dev_warn(ctrl->device, "Command set not reported for nsid:%d\n", 1398 - nsid); 1390 + info->nsid); 1399 1391 status = -EINVAL; 1400 1392 } 1401 1393 ··· 1405 1397 } 1406 1398 1407 1399 static int nvme_identify_ns(struct nvme_ctrl *ctrl, unsigned nsid, 1408 - struct nvme_ns_ids *ids, struct nvme_id_ns **id) 1400 + struct nvme_id_ns **id) 1409 1401 { 1410 1402 struct nvme_command c = { }; 1411 1403 int error; ··· 1428 1420 error = NVME_SC_INVALID_NS | NVME_SC_DNR; 1429 1421 if ((*id)->ncap == 0) /* namespace not allocated or attached */ 1430 1422 goto out_free_id; 1431 - 1432 - 1433 - if (ctrl->quirks & NVME_QUIRK_BOGUS_NID) { 1434 - dev_info(ctrl->device, 1435 - "Ignoring bogus Namespace Identifiers\n"); 1436 - } else { 1437 - if (ctrl->vs >= NVME_VS(1, 1, 0) && 1438 - !memchr_inv(ids->eui64, 0, sizeof(ids->eui64))) 1439 - memcpy(ids->eui64, (*id)->eui64, sizeof(ids->eui64)); 1440 - if (ctrl->vs >= NVME_VS(1, 2, 0) && 1441 - !memchr_inv(ids->nguid, 0, sizeof(ids->nguid))) 1442 - memcpy(ids->nguid, (*id)->nguid, sizeof(ids->nguid)); 1443 - } 1444 - 1445 1423 return 0; 1446 1424 1447 1425 out_free_id: ··· 1435 1441 return error; 1436 1442 } 1437 1443 1438 - static int nvme_identify_ns_cs_indep(struct nvme_ctrl *ctrl, unsigned nsid, 1439 - struct nvme_id_ns_cs_indep **id) 1444 + static int nvme_ns_info_from_identify(struct nvme_ctrl *ctrl, 1445 + struct nvme_ns_info *info) 1440 1446 { 1447 + struct nvme_ns_ids *ids = &info->ids; 1448 + struct nvme_id_ns *id; 1449 + int ret; 1450 + 1451 + ret = nvme_identify_ns(ctrl, info->nsid, &id); 1452 + if (ret) 1453 + return ret; 1454 + info->anagrpid = id->anagrpid; 1455 + info->is_shared = id->nmic & NVME_NS_NMIC_SHARED; 1456 + info->is_ready = true; 1457 + if (ctrl->quirks & NVME_QUIRK_BOGUS_NID) { 1458 + dev_info(ctrl->device, 1459 + "Ignoring bogus Namespace Identifiers\n"); 1460 + } else { 1461 + if (ctrl->vs >= NVME_VS(1, 1, 0) && 1462 + !memchr_inv(ids->eui64, 0, sizeof(ids->eui64))) 1463 + memcpy(ids->eui64, id->eui64, sizeof(ids->eui64)); 1464 + if (ctrl->vs >= NVME_VS(1, 2, 0) && 1465 + !memchr_inv(ids->nguid, 0, sizeof(ids->nguid))) 1466 + memcpy(ids->nguid, id->nguid, sizeof(ids->nguid)); 1467 + } 1468 + kfree(id); 1469 + return 0; 1470 + } 1471 + 1472 + static int nvme_ns_info_from_id_cs_indep(struct nvme_ctrl *ctrl, 1473 + struct nvme_ns_info *info) 1474 + { 1475 + struct nvme_id_ns_cs_indep *id; 1441 1476 struct nvme_command c = { 1442 1477 .identify.opcode = nvme_admin_identify, 1443 - .identify.nsid = cpu_to_le32(nsid), 1478 + .identify.nsid = cpu_to_le32(info->nsid), 1444 1479 .identify.cns = NVME_ID_CNS_NS_CS_INDEP, 1445 1480 }; 1446 1481 int ret; 1447 1482 1448 - *id = kmalloc(sizeof(**id), GFP_KERNEL); 1449 - if (!*id) 1483 + id = kmalloc(sizeof(*id), GFP_KERNEL); 1484 + if (!id) 1450 1485 return -ENOMEM; 1451 1486 1452 - ret = nvme_submit_sync_cmd(ctrl->admin_q, &c, *id, sizeof(**id)); 1453 - if (ret) { 1454 - dev_warn(ctrl->device, 1455 - "Identify namespace (CS independent) failed (%d)\n", 1456 - ret); 1457 - kfree(*id); 1458 - return ret; 1487 + ret = nvme_submit_sync_cmd(ctrl->admin_q, &c, id, sizeof(*id)); 1488 + if (!ret) { 1489 + info->anagrpid = id->anagrpid; 1490 + info->is_shared = id->nmic & NVME_NS_NMIC_SHARED; 1491 + info->is_ready = id->nstat & NVME_NSTAT_NRDY; 1459 1492 } 1460 - 1461 - return 0; 1493 + kfree(id); 1494 + return ret; 1462 1495 } 1463 1496 1464 1497 static int nvme_features(struct nvme_ctrl *dev, u8 op, unsigned int fid, ··· 1946 1925 blk_queue_chunk_sectors(ns->queue, iob); 1947 1926 } 1948 1927 1949 - static int nvme_update_ns_info(struct nvme_ns *ns, struct nvme_id_ns *id) 1928 + static int nvme_update_ns_info_block(struct nvme_ns *ns, 1929 + struct nvme_ns_info *info) 1950 1930 { 1951 - unsigned lbaf = nvme_lbaf_index(id->flbas); 1931 + struct nvme_id_ns *id; 1932 + unsigned lbaf; 1952 1933 int ret; 1953 1934 1935 + ret = nvme_identify_ns(ns->ctrl, info->nsid, &id); 1936 + if (ret) 1937 + return ret; 1938 + 1954 1939 blk_mq_freeze_queue(ns->disk->queue); 1940 + lbaf = nvme_lbaf_index(id->flbas); 1955 1941 ns->lba_shift = id->lbaf[lbaf].ds; 1956 1942 nvme_set_queue_limits(ns->ctrl, ns->queue); 1957 1943 ··· 2009 1981 set_bit(NVME_NS_READY, &ns->flags); 2010 1982 ret = 0; 2011 1983 } 1984 + kfree(id); 2012 1985 return ret; 1986 + } 1987 + 1988 + static int nvme_update_ns_info(struct nvme_ns *ns, struct nvme_ns_info *info) 1989 + { 1990 + switch (info->ids.csi) { 1991 + case NVME_CSI_ZNS: 1992 + if (!IS_ENABLED(CONFIG_BLK_DEV_ZONED)) { 1993 + dev_warn(ns->ctrl->device, 1994 + "nsid %u not supported without CONFIG_BLK_DEV_ZONED\n", 1995 + info->nsid); 1996 + return -ENODEV; 1997 + } 1998 + return nvme_update_ns_info_block(ns, info); 1999 + case NVME_CSI_NVM: 2000 + return nvme_update_ns_info_block(ns, info); 2001 + default: 2002 + dev_warn(ns->ctrl->device, "unknown csi %u for nsid %u\n", 2003 + info->ids.csi, info->nsid); 2004 + return -ENODEV; 2005 + } 2013 2006 } 2014 2007 2015 2008 static char nvme_pr_type(enum pr_type type) ··· 3962 3913 } 3963 3914 3964 3915 static struct nvme_ns_head *nvme_alloc_ns_head(struct nvme_ctrl *ctrl, 3965 - unsigned nsid, struct nvme_ns_ids *ids, bool is_shared) 3916 + struct nvme_ns_info *info) 3966 3917 { 3967 3918 struct nvme_ns_head *head; 3968 3919 size_t size = sizeof(*head); ··· 3984 3935 if (ret) 3985 3936 goto out_ida_remove; 3986 3937 head->subsys = ctrl->subsys; 3987 - head->ns_id = nsid; 3988 - head->ids = *ids; 3989 - head->shared = is_shared; 3938 + head->ns_id = info->nsid; 3939 + head->ids = info->ids; 3940 + head->shared = info->is_shared; 3990 3941 kref_init(&head->ref); 3991 3942 3992 3943 if (head->ids.csi) { ··· 4043 3994 return ret; 4044 3995 } 4045 3996 4046 - static int nvme_init_ns_head(struct nvme_ns *ns, unsigned nsid, 4047 - struct nvme_ns_ids *ids, bool is_shared) 3997 + static int nvme_init_ns_head(struct nvme_ns *ns, struct nvme_ns_info *info) 4048 3998 { 4049 3999 struct nvme_ctrl *ctrl = ns->ctrl; 4050 4000 struct nvme_ns_head *head = NULL; 4051 4001 int ret; 4052 4002 4053 - ret = nvme_global_check_duplicate_ids(ctrl->subsys, ids); 4003 + ret = nvme_global_check_duplicate_ids(ctrl->subsys, &info->ids); 4054 4004 if (ret) { 4055 4005 dev_err(ctrl->device, 4056 - "globally duplicate IDs for nsid %d\n", nsid); 4006 + "globally duplicate IDs for nsid %d\n", info->nsid); 4057 4007 nvme_print_device_info(ctrl); 4058 4008 return ret; 4059 4009 } 4060 4010 4061 4011 mutex_lock(&ctrl->subsys->lock); 4062 - head = nvme_find_ns_head(ctrl, nsid); 4012 + head = nvme_find_ns_head(ctrl, info->nsid); 4063 4013 if (!head) { 4064 - ret = nvme_subsys_check_duplicate_ids(ctrl->subsys, ids); 4014 + ret = nvme_subsys_check_duplicate_ids(ctrl->subsys, &info->ids); 4065 4015 if (ret) { 4066 4016 dev_err(ctrl->device, 4067 4017 "duplicate IDs in subsystem for nsid %d\n", 4068 - nsid); 4018 + info->nsid); 4069 4019 goto out_unlock; 4070 4020 } 4071 - head = nvme_alloc_ns_head(ctrl, nsid, ids, is_shared); 4021 + head = nvme_alloc_ns_head(ctrl, info); 4072 4022 if (IS_ERR(head)) { 4073 4023 ret = PTR_ERR(head); 4074 4024 goto out_unlock; 4075 4025 } 4076 4026 } else { 4077 4027 ret = -EINVAL; 4078 - if (!is_shared || !head->shared) { 4028 + if (!info->is_shared || !head->shared) { 4079 4029 dev_err(ctrl->device, 4080 - "Duplicate unshared namespace %d\n", nsid); 4030 + "Duplicate unshared namespace %d\n", 4031 + info->nsid); 4081 4032 goto out_put_ns_head; 4082 4033 } 4083 - if (!nvme_ns_ids_equal(&head->ids, ids)) { 4034 + if (!nvme_ns_ids_equal(&head->ids, &info->ids)) { 4084 4035 dev_err(ctrl->device, 4085 4036 "IDs don't match for shared namespace %d\n", 4086 - nsid); 4037 + info->nsid); 4087 4038 goto out_put_ns_head; 4088 4039 } 4089 4040 4090 4041 if (!multipath && !list_empty(&head->list)) { 4091 4042 dev_warn(ctrl->device, 4092 4043 "Found shared namespace %d, but multipathing not supported.\n", 4093 - nsid); 4044 + info->nsid); 4094 4045 dev_warn_once(ctrl->device, 4095 4046 "Support for shared namespaces without CONFIG_NVME_MULTIPATH is deprecated and will be removed in Linux 6.0\n."); 4096 4047 } ··· 4144 4095 list_add(&ns->list, &ns->ctrl->namespaces); 4145 4096 } 4146 4097 4147 - static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid, 4148 - struct nvme_ns_ids *ids) 4098 + static void nvme_alloc_ns(struct nvme_ctrl *ctrl, struct nvme_ns_info *info) 4149 4099 { 4150 4100 struct nvme_ns *ns; 4151 4101 struct gendisk *disk; 4152 - struct nvme_id_ns *id; 4153 4102 int node = ctrl->numa_node; 4154 - 4155 - if (nvme_identify_ns(ctrl, nsid, ids, &id)) 4156 - return; 4157 4103 4158 4104 ns = kzalloc_node(sizeof(*ns), GFP_KERNEL, node); 4159 4105 if (!ns) 4160 - goto out_free_id; 4106 + return; 4161 4107 4162 4108 disk = blk_mq_alloc_disk(ctrl->tagset, ns); 4163 4109 if (IS_ERR(disk)) ··· 4173 4129 ns->ctrl = ctrl; 4174 4130 kref_init(&ns->kref); 4175 4131 4176 - if (nvme_init_ns_head(ns, nsid, ids, id->nmic & NVME_NS_NMIC_SHARED)) 4132 + if (nvme_init_ns_head(ns, info)) 4177 4133 goto out_cleanup_disk; 4178 4134 4179 4135 /* ··· 4199 4155 ns->head->instance); 4200 4156 } 4201 4157 4202 - if (nvme_update_ns_info(ns, id)) 4158 + if (nvme_update_ns_info(ns, info)) 4203 4159 goto out_unlink_ns; 4204 4160 4205 4161 down_write(&ctrl->namespaces_rwsem); ··· 4213 4169 if (!nvme_ns_head_multipath(ns->head)) 4214 4170 nvme_add_ns_cdev(ns); 4215 4171 4216 - nvme_mpath_add_disk(ns, id->anagrpid); 4172 + nvme_mpath_add_disk(ns, info->anagrpid); 4217 4173 nvme_fault_inject_init(&ns->fault_inject, ns->disk->disk_name); 4218 - kfree(id); 4219 4174 4220 4175 return; 4221 4176 ··· 4234 4191 put_disk(disk); 4235 4192 out_free_ns: 4236 4193 kfree(ns); 4237 - out_free_id: 4238 - kfree(id); 4239 4194 } 4240 4195 4241 4196 static void nvme_ns_remove(struct nvme_ns *ns) ··· 4291 4250 } 4292 4251 } 4293 4252 4294 - static void nvme_validate_ns(struct nvme_ns *ns, struct nvme_ns_ids *ids) 4253 + static void nvme_validate_ns(struct nvme_ns *ns, struct nvme_ns_info *info) 4295 4254 { 4296 - struct nvme_id_ns *id; 4297 4255 int ret = NVME_SC_INVALID_NS | NVME_SC_DNR; 4298 4256 4299 4257 if (test_bit(NVME_NS_DEAD, &ns->flags)) 4300 4258 goto out; 4301 4259 4302 - ret = nvme_identify_ns(ns->ctrl, ns->head->ns_id, ids, &id); 4303 - if (ret) 4304 - goto out; 4305 - 4306 4260 ret = NVME_SC_INVALID_NS | NVME_SC_DNR; 4307 - if (!nvme_ns_ids_equal(&ns->head->ids, ids)) { 4261 + if (!nvme_ns_ids_equal(&ns->head->ids, &info->ids)) { 4308 4262 dev_err(ns->ctrl->device, 4309 4263 "identifiers changed for nsid %d\n", ns->head->ns_id); 4310 - goto out_free_id; 4264 + goto out; 4311 4265 } 4312 4266 4313 - ret = nvme_update_ns_info(ns, id); 4314 - 4315 - out_free_id: 4316 - kfree(id); 4267 + ret = nvme_update_ns_info(ns, info); 4317 4268 out: 4318 4269 /* 4319 4270 * Only remove the namespace if we got a fatal error back from the ··· 4319 4286 4320 4287 static void nvme_scan_ns(struct nvme_ctrl *ctrl, unsigned nsid) 4321 4288 { 4322 - struct nvme_ns_ids ids = { }; 4323 - struct nvme_id_ns_cs_indep *id; 4289 + struct nvme_ns_info info = { .nsid = nsid }; 4324 4290 struct nvme_ns *ns; 4325 - bool ready = true; 4326 4291 4327 - if (nvme_identify_ns_descs(ctrl, nsid, &ids)) 4292 + if (nvme_identify_ns_descs(ctrl, &info)) 4328 4293 return; 4329 4294 4330 - if (ids.csi != NVME_CSI_NVM && !nvme_multi_css(ctrl)) { 4295 + if (info.ids.csi != NVME_CSI_NVM && !nvme_multi_css(ctrl)) { 4331 4296 dev_warn(ctrl->device, 4332 4297 "command set not reported for nsid: %d\n", nsid); 4333 4298 return; 4334 4299 } 4335 4300 4336 4301 /* 4337 - * Check if the namespace is ready. If not ignore it, we will get an 4338 - * AEN once it becomes ready and restart the scan. 4302 + * If available try to use the Command Set Idependent Identify Namespace 4303 + * data structure to find all the generic information that is needed to 4304 + * set up a namespace. If not fall back to the legacy version. 4339 4305 */ 4340 - if ((ctrl->cap & NVME_CAP_CRMS_CRIMS) && 4341 - !nvme_identify_ns_cs_indep(ctrl, nsid, &id)) { 4342 - ready = id->nstat & NVME_NSTAT_NRDY; 4343 - kfree(id); 4306 + if (ctrl->cap & NVME_CAP_CRMS_CRIMS) { 4307 + if (nvme_ns_info_from_id_cs_indep(ctrl, &info)) 4308 + return; 4309 + } else { 4310 + if (nvme_ns_info_from_identify(ctrl, &info)) 4311 + return; 4344 4312 } 4345 4313 4346 - if (!ready) 4314 + /* 4315 + * Ignore the namespace if it is not ready. We will get an AEN once it 4316 + * becomes ready and restart the scan. 4317 + */ 4318 + if (!info.is_ready) 4347 4319 return; 4348 4320 4349 4321 ns = nvme_find_get_ns(ctrl, nsid); 4350 4322 if (ns) { 4351 - nvme_validate_ns(ns, &ids); 4323 + nvme_validate_ns(ns, &info); 4352 4324 nvme_put_ns(ns); 4353 - return; 4354 - } 4355 - 4356 - switch (ids.csi) { 4357 - case NVME_CSI_NVM: 4358 - nvme_alloc_ns(ctrl, nsid, &ids); 4359 - break; 4360 - case NVME_CSI_ZNS: 4361 - if (!IS_ENABLED(CONFIG_BLK_DEV_ZONED)) { 4362 - dev_warn(ctrl->device, 4363 - "nsid %u not supported without CONFIG_BLK_DEV_ZONED\n", 4364 - nsid); 4365 - break; 4366 - } 4367 - nvme_alloc_ns(ctrl, nsid, &ids); 4368 - break; 4369 - default: 4370 - dev_warn(ctrl->device, "unknown csi %u for nsid %u\n", 4371 - ids.csi, nsid); 4372 - break; 4325 + } else { 4326 + nvme_alloc_ns(ctrl, &info); 4373 4327 } 4374 4328 } 4375 4329