@@ -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