Skip to content

Commit 7959f52

Browse files
dwsuseigaw
authored andcommitted
tree: read all attributes from sysfs when available
The kernel already exposes parts or all attributes we are looking up with the ns id command. By reading these from the sysfs we can remove the last command we are issuing during the topology scan. Signed-off-by: Daniel Wagner <[email protected]>
1 parent ab4d0ae commit 7959f52

1 file changed

Lines changed: 146 additions & 45 deletions

File tree

src/nvme/tree.c

Lines changed: 146 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -2322,60 +2322,164 @@ int nvme_ns_flush(nvme_ns_t n)
23222322
return nvme_flush(nvme_ns_get_fd(n), nvme_ns_get_nsid(n));
23232323
}
23242324

2325-
static void nvme_ns_parse_descriptors(struct nvme_ns *n,
2326-
struct nvme_ns_id_desc *descs)
2325+
static int nvme_strtou64(const char *str, void *res)
23272326
{
2328-
void *d = descs;
2329-
int i, len;
2327+
char *endptr;
2328+
__u64 v;
23302329

2331-
for (i = 0; i < NVME_IDENTIFY_DATA_SIZE; i += len) {
2332-
struct nvme_ns_id_desc *desc = d + i;
2330+
errno = 0;
2331+
v = strtoull(str, &endptr, 0);
23332332

2334-
if (!desc->nidl)
2335-
break;
2336-
len = desc->nidl + sizeof(*desc);
2333+
if (errno != 0)
2334+
return -errno;
23372335

2338-
switch (desc->nidt) {
2339-
case NVME_NIDT_EUI64:
2340-
memcpy(n->eui64, desc->nid, sizeof(n->eui64));
2341-
break;
2342-
case NVME_NIDT_NGUID:
2343-
memcpy(n->nguid, desc->nid, sizeof(n->nguid));
2344-
break;
2345-
case NVME_NIDT_UUID:
2346-
memcpy(n->uuid, desc->nid, sizeof(n->uuid));
2347-
break;
2348-
case NVME_NIDT_CSI:
2349-
memcpy(&n->csi, desc->nid, sizeof(n->csi));
2350-
break;
2336+
if (endptr == str) {
2337+
/* no digits found */
2338+
return -EINVAL;
2339+
}
2340+
2341+
*(__u64 *)res = v;
2342+
return 0;
2343+
}
2344+
2345+
static int nvme_strtou32(const char *str, void *res)
2346+
{
2347+
char *endptr;
2348+
__u32 v;
2349+
2350+
errno = 0;
2351+
v = strtol(str, &endptr, 0);
2352+
2353+
if (errno != 0)
2354+
return -errno;
2355+
2356+
if (endptr == str) {
2357+
/* no digits found */
2358+
return -EINVAL;
2359+
}
2360+
2361+
*(__u32 *)res = v;
2362+
return 0;
2363+
}
2364+
2365+
static int nvme_strtoi(const char *str, void *res)
2366+
{
2367+
char *endptr;
2368+
int v;
2369+
2370+
errno = 0;
2371+
v = strtol(str, &endptr, 0);
2372+
2373+
if (errno != 0)
2374+
return -errno;
2375+
2376+
if (endptr == str) {
2377+
/* no digits found */
2378+
return -EINVAL;
2379+
}
2380+
2381+
*(int *)res = v;
2382+
return 0;
2383+
}
2384+
2385+
static int nvme_strtoeuid(const char *str, void *res)
2386+
{
2387+
memcpy(res, str, 8);
2388+
return 0;
2389+
}
2390+
2391+
static int nvme_strtouuid(const char *str, void *res)
2392+
{
2393+
memcpy(res, str, NVME_UUID_LEN);
2394+
return 0;
2395+
}
2396+
2397+
struct sysfs_attr_table {
2398+
void *var;
2399+
int (*parse)(const char *str, void *res);
2400+
bool mandatory;
2401+
const char *name;
2402+
};
2403+
2404+
#define GETSHIFT(x) (__builtin_ffsll(x) - 1)
2405+
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
2406+
2407+
static int parse_attrs(const char *path, struct sysfs_attr_table *tbl, int size)
2408+
{
2409+
char *str;
2410+
int ret, i;
2411+
2412+
for (i = 0; i < size; i++) {
2413+
struct sysfs_attr_table *e = &tbl[i];
2414+
2415+
str = nvme_get_attr(path, e->name);
2416+
if (!str) {
2417+
if (!e->mandatory)
2418+
continue;
2419+
return -ENOENT;
23512420
}
2421+
ret = e->parse(str, e->var);
2422+
free(str);
2423+
if (ret)
2424+
return ret;
23522425
}
2426+
2427+
return 0;
23532428
}
23542429

2355-
static int nvme_ns_init(struct nvme_ns *n)
2430+
static int nvme_ns_init(const char *path, struct nvme_ns *ns)
23562431
{
2357-
_cleanup_free_ struct nvme_id_ns *ns;
2358-
_cleanup_free_ struct nvme_ns_id_desc *descs = NULL;
2359-
uint8_t flbas;
2432+
_cleanup_free_ char *attr = NULL;
2433+
struct stat sb;
23602434
int ret;
23612435

2362-
ns = __nvme_alloc(sizeof(*ns));
2363-
if (!ns)
2364-
return 0;
2365-
ret = nvme_ns_identify(n, ns);
2436+
struct sysfs_attr_table base[] = {
2437+
{ &ns->nsid, nvme_strtou32, true, "nsid" },
2438+
{ &ns->lba_count, nvme_strtou64, true, "size" },
2439+
{ &ns->lba_size, nvme_strtou64, true, "queue/physical_block_size" },
2440+
{ ns->eui64, nvme_strtoeuid, false, "eui" },
2441+
{ ns->nguid, nvme_strtouuid, false, "nguid" },
2442+
{ ns->uuid, nvme_strtouuid, false, "uuid" }
2443+
};
2444+
2445+
ret = parse_attrs(path, base, ARRAY_SIZE(base));
23662446
if (ret)
23672447
return ret;
23682448

2369-
nvme_id_ns_flbas_to_lbaf_inuse(ns->flbas, &flbas);
2370-
n->lba_shift = ns->lbaf[flbas].ds;
2371-
n->lba_size = 1 << n->lba_shift;
2372-
n->lba_count = le64_to_cpu(ns->nsze);
2373-
n->lba_util = le64_to_cpu(ns->nuse);
2374-
n->meta_size = le16_to_cpu(ns->lbaf[flbas].ms);
2449+
ns->lba_shift = GETSHIFT(ns->lba_size);
2450+
2451+
if (asprintf(&attr, "%s/csi", path) < 0)
2452+
return -errno;
2453+
ret = stat(attr, &sb);
2454+
if (ret == 0) {
2455+
/* only available on kernels >= 6.8 */
2456+
struct sysfs_attr_table ext[] = {
2457+
{ &ns->csi, nvme_strtoi, true, "csi" },
2458+
{ &ns->lba_util, nvme_strtou64, true, "nuse" },
2459+
{ &ns->meta_size, nvme_strtoi, true, "metadata_bytes"},
2460+
2461+
};
23752462

2376-
descs = __nvme_alloc(NVME_IDENTIFY_DATA_SIZE);
2377-
if (descs && !nvme_ns_identify_descs(n, descs))
2378-
nvme_ns_parse_descriptors(n, descs);
2463+
ret = parse_attrs(path, ext, ARRAY_SIZE(ext));
2464+
if (ret)
2465+
return ret;
2466+
} else {
2467+
struct nvme_id_ns *id;
2468+
uint8_t flbas;
2469+
2470+
id = __nvme_alloc(sizeof(*ns));
2471+
if (!id)
2472+
return -ENOMEM;
2473+
2474+
ret = nvme_ns_identify(ns, id);
2475+
if (ret)
2476+
free(ns);
2477+
2478+
nvme_id_ns_flbas_to_lbaf_inuse(id->flbas, &flbas);
2479+
ns->lba_count = le64_to_cpu(id->nsze);
2480+
ns->lba_util = le64_to_cpu(id->nuse);
2481+
ns->meta_size = le16_to_cpu(id->lbaf[flbas].ms);
2482+
}
23792483

23802484
return 0;
23812485
}
@@ -2394,7 +2498,7 @@ static void nvme_ns_set_generic_name(struct nvme_ns *n, const char *name)
23942498
n->generic_name = strdup(generic_name);
23952499
}
23962500

2397-
static nvme_ns_t nvme_ns_open(const char *name)
2501+
static nvme_ns_t nvme_ns_open(const char *sys_path, const char *name)
23982502
{
23992503
struct nvme_ns *n;
24002504
int fd;
@@ -2414,10 +2518,7 @@ static nvme_ns_t nvme_ns_open(const char *name)
24142518

24152519
nvme_ns_set_generic_name(n, name);
24162520

2417-
if (nvme_get_nsid(fd, &n->nsid) < 0)
2418-
goto free_ns;
2419-
2420-
if (nvme_ns_init(n) != 0)
2521+
if (nvme_ns_init(sys_path, n) != 0)
24212522
goto free_ns;
24222523

24232524
list_head_init(&n->paths);
@@ -2477,7 +2578,7 @@ static struct nvme_ns *__nvme_scan_namespace(const char *sysfs_dir, const char *
24772578
return NULL;
24782579
}
24792580

2480-
n = nvme_ns_open(blkdev);
2581+
n = nvme_ns_open(path, blkdev);
24812582
if (!n)
24822583
return NULL;
24832584

0 commit comments

Comments
 (0)