Skip to content

Commit 82316b5

Browse files
shroffniigaw
authored andcommitted
libnvme: add support for retrieving namespace gendisk I/O statistics
Gendisk I/O statistics provide useful insight into disk activity, including read/write/discard/flush operations, as well as information about in-flight I/Os and I/O timing. Parsing these statistics allows users to determine the number of I/Os processed, time spent servicing I/O, number of sectors accessed, and the count of in-flight requests. Add support for retrieving namespace gendisk I/O statistics. Also add support for computing deltas of these statistics between samples, such as I/O ticks, number of sectors, and number of serviced I/Os. These metrics can be used by tools such as nvme-top to display real-time disk activity. Signed-off-by: Nilay Shroff <nilay@linux.ibm.com> Link: https://patch.msgid.link/20260421145038.3458987-6-nilay@linux.ibm.com Signed-off-by: Daniel Wagner <wagi@kernel.org>
1 parent 8f91901 commit 82316b5

4 files changed

Lines changed: 251 additions & 0 deletions

File tree

libnvme/src/libnvme.ld

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,17 @@ LIBNVME_3 {
129129
libnvme_ns_get_serial;
130130
libnvme_ns_get_subsystem;
131131
libnvme_ns_get_uuid;
132+
libnvme_ns_reset_stat;
133+
libnvme_ns_update_stat;
134+
libnvme_ns_get_stat_interval;
135+
libnvme_ns_get_read_ios;
136+
libnvme_ns_get_write_ios;
137+
libnvme_ns_get_read_ticks;
138+
libnvme_ns_get_write_ticks;
139+
libnvme_ns_get_read_sectors;
140+
libnvme_ns_get_write_sectors;
141+
libnvme_ns_get_inflights;
142+
libnvme_ns_get_io_ticks;
132143
libnvme_ns_identify;
133144
libnvme_ns_read;
134145
libnvme_ns_verify;

libnvme/src/nvme/private.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,11 @@ struct libnvme_ns { // !generate-accessors
230230
struct libnvme_ns_head *head;
231231

232232
struct libnvme_global_ctx *ctx;
233+
234+
struct libnvme_stat stat[2]; /* gendisk I/O stat */
235+
unsigned int curr_idx; /* current index into the stat[] */
236+
bool diffstat; // !accessors:none
237+
233238
struct libnvme_transport_handle *hdl;
234239
__u32 nsid;
235240
char *name;

libnvme/src/nvme/tree.c

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -900,6 +900,21 @@ __public void libnvme_path_reset_stat(libnvme_path_t p)
900900
memset(stat, 0, 2 * sizeof(struct libnvme_stat));
901901
}
902902

903+
static libnvme_stat_t libnvme_ns_get_stat(libnvme_ns_t n, unsigned int idx)
904+
{
905+
if (idx > 1)
906+
return NULL;
907+
908+
return &n->stat[idx];
909+
}
910+
911+
__public void libnvme_ns_reset_stat(libnvme_ns_t n)
912+
{
913+
libnvme_stat_t stat = &n->stat[0];
914+
915+
memset(stat, 0, 2 * sizeof(struct libnvme_stat));
916+
}
917+
903918
static int libnvme_update_stat(const char *sysfs_stat_path, libnvme_stat_t stat)
904919
{
905920
int n;
@@ -974,6 +989,24 @@ __public int libnvme_path_update_stat(libnvme_path_t p, bool diffstat)
974989
return libnvme_update_stat(sysfs_stat_path, stat);
975990
}
976991

992+
__public int libnvme_ns_update_stat(libnvme_ns_t n, bool diffstat)
993+
{
994+
__cleanup_free char *sysfs_stat_path = NULL;
995+
libnvme_stat_t stat;
996+
997+
n->diffstat = diffstat;
998+
n->curr_idx ^= 1;
999+
stat = libnvme_ns_get_stat(n, n->curr_idx);
1000+
if (!stat)
1001+
return -EINVAL;
1002+
1003+
sysfs_stat_path = libnvme_get_ns_attr(n, "stat");
1004+
if (!sysfs_stat_path)
1005+
return -EINVAL;
1006+
1007+
return libnvme_update_stat(sysfs_stat_path, stat);
1008+
}
1009+
9771010
static int libnvme_stat_get_inflights(libnvme_stat_t stat)
9781011
{
9791012
return stat->inflights;
@@ -990,6 +1023,17 @@ __public unsigned int libnvme_path_get_inflights(libnvme_path_t p)
9901023
return libnvme_stat_get_inflights(curr);
9911024
}
9921025

1026+
__public unsigned int libnvme_ns_get_inflights(libnvme_ns_t n)
1027+
{
1028+
libnvme_stat_t curr;
1029+
1030+
curr = libnvme_ns_get_stat(n, n->curr_idx);
1031+
if (!curr)
1032+
return 0;
1033+
1034+
return libnvme_stat_get_inflights(curr);
1035+
}
1036+
9931037
static int libnvme_stat_get_io_ticks(libnvme_stat_t curr, libnvme_stat_t prev,
9941038
bool diffstat)
9951039
{
@@ -1017,6 +1061,19 @@ __public unsigned int libnvme_path_get_io_ticks(libnvme_path_t p)
10171061
return libnvme_stat_get_io_ticks(curr, prev, p->diffstat);
10181062
}
10191063

1064+
__public unsigned int libnvme_ns_get_io_ticks(libnvme_ns_t n)
1065+
{
1066+
libnvme_stat_t curr, prev;
1067+
1068+
curr = libnvme_ns_get_stat(n, n->curr_idx);
1069+
prev = libnvme_ns_get_stat(n, !n->curr_idx);
1070+
1071+
if (!curr || !prev)
1072+
return 0;
1073+
1074+
return libnvme_stat_get_io_ticks(curr, prev, n->diffstat);
1075+
}
1076+
10201077
static unsigned int libnvme_stat_get_ticks(libnvme_stat_t curr,
10211078
libnvme_stat_t prev, enum libnvme_stat_group grp, bool diffstat)
10221079
{
@@ -1055,6 +1112,30 @@ __public unsigned int libnvme_path_get_write_ticks(libnvme_path_t p)
10551112
return __libnvme_path_get_ticks(p, WRITE);
10561113
}
10571114

1115+
static unsigned int __libnvme_ns_get_ticks(libnvme_ns_t n,
1116+
enum libnvme_stat_group grp)
1117+
{
1118+
libnvme_stat_t curr, prev;
1119+
1120+
curr = libnvme_ns_get_stat(n, n->curr_idx);
1121+
prev = libnvme_ns_get_stat(n, !n->curr_idx);
1122+
1123+
if (!curr || !prev)
1124+
return 0;
1125+
1126+
return libnvme_stat_get_ticks(curr, prev, grp, n->diffstat);
1127+
}
1128+
1129+
__public unsigned int libnvme_ns_get_read_ticks(libnvme_ns_t n)
1130+
{
1131+
return __libnvme_ns_get_ticks(n, READ);
1132+
}
1133+
1134+
__public unsigned int libnvme_ns_get_write_ticks(libnvme_ns_t n)
1135+
{
1136+
return __libnvme_ns_get_ticks(n, WRITE);
1137+
}
1138+
10581139
static double libnvme_stat_get_interval(libnvme_stat_t curr,
10591140
libnvme_stat_t prev)
10601141
{
@@ -1079,6 +1160,19 @@ __public double libnvme_path_get_stat_interval(libnvme_path_t p)
10791160
return libnvme_stat_get_interval(curr, prev);
10801161
}
10811162

1163+
__public double libnvme_ns_get_stat_interval(libnvme_ns_t n)
1164+
{
1165+
libnvme_stat_t curr, prev;
1166+
1167+
curr = libnvme_ns_get_stat(n, n->curr_idx);
1168+
prev = libnvme_ns_get_stat(n, !n->curr_idx);
1169+
1170+
if (!curr || !prev)
1171+
return 0;
1172+
1173+
return libnvme_stat_get_interval(curr, prev);
1174+
}
1175+
10821176
static unsigned long libnvme_stat_get_ios(libnvme_stat_t curr,
10831177
libnvme_stat_t prev, enum libnvme_stat_group grp, bool diffstat)
10841178
{
@@ -1117,6 +1211,30 @@ __public unsigned long libnvme_path_get_write_ios(libnvme_path_t p)
11171211
return __libnvme_path_get_ios(p, WRITE);
11181212
}
11191213

1214+
static unsigned long __libnvme_ns_get_ios(libnvme_ns_t n,
1215+
enum libnvme_stat_group grp)
1216+
{
1217+
libnvme_stat_t curr, prev;
1218+
1219+
curr = libnvme_ns_get_stat(n, n->curr_idx);
1220+
prev = libnvme_ns_get_stat(n, !n->curr_idx);
1221+
1222+
if (!curr || !prev)
1223+
return 0;
1224+
1225+
return libnvme_stat_get_ios(curr, prev, grp, n->diffstat);
1226+
}
1227+
1228+
__public unsigned long libnvme_ns_get_read_ios(libnvme_ns_t n)
1229+
{
1230+
return __libnvme_ns_get_ios(n, READ);
1231+
}
1232+
1233+
__public unsigned long libnvme_ns_get_write_ios(libnvme_ns_t n)
1234+
{
1235+
return __libnvme_ns_get_ios(n, WRITE);
1236+
}
1237+
11201238
static unsigned long long libnvme_stat_get_sectors(libnvme_stat_t curr,
11211239
libnvme_stat_t prev, enum libnvme_stat_group grp, bool diffstat)
11221240
{
@@ -1155,6 +1273,30 @@ __public unsigned long long libnvme_path_get_write_sectors(libnvme_path_t p)
11551273
return __libnvme_path_get_sectors(p, WRITE);
11561274
}
11571275

1276+
static unsigned long long __libnvme_ns_get_sectors(libnvme_ns_t n,
1277+
enum libnvme_stat_group grp)
1278+
{
1279+
libnvme_stat_t curr, prev;
1280+
1281+
curr = libnvme_ns_get_stat(n, n->curr_idx);
1282+
prev = libnvme_ns_get_stat(n, !n->curr_idx);
1283+
1284+
if (!curr || !prev)
1285+
return 0;
1286+
1287+
return libnvme_stat_get_sectors(curr, prev, grp, n->diffstat);
1288+
}
1289+
1290+
__public unsigned long long libnvme_ns_get_read_sectors(libnvme_ns_t n)
1291+
{
1292+
return __libnvme_ns_get_sectors(n, READ);
1293+
}
1294+
1295+
__public unsigned long long libnvme_ns_get_write_sectors(libnvme_ns_t n)
1296+
{
1297+
return __libnvme_ns_get_sectors(n, WRITE);
1298+
}
1299+
11581300
void nvme_free_path(struct libnvme_path *p)
11591301
{
11601302
if (!p)

libnvme/src/nvme/tree.h

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -853,6 +853,99 @@ libnvme_subsystem_t libnvme_ctrl_get_subsystem(libnvme_ctrl_t c);
853853
*/
854854
const char *libnvme_ns_head_get_sysfs_dir(libnvme_ns_head_t head);
855855

856+
/**
857+
* libnvme_ns_update_stat() - update the nvme namespace stat
858+
* @n: &libnvme_ns_t object
859+
* @diffstat: If set to true then getters return the diff stat otherwise
860+
* return the current absolute stat
861+
*
862+
* Returns: 0 on success, -1 on error
863+
*/
864+
int libnvme_ns_update_stat(libnvme_ns_t n, bool diffstat);
865+
866+
/**
867+
* libnvme_ns_reset_stat() - Resets nvme namespace stat
868+
* @n: &libnvme_ns_t object
869+
*
870+
*/
871+
void libnvme_ns_reset_stat(libnvme_ns_t n);
872+
873+
/**
874+
* libnvme_ns_get_inflights() - Inflight IOs for nvme_ns_t object
875+
* @n: &libnvme_ns_t object
876+
*
877+
* Return: Inflight number of IOs
878+
*/
879+
unsigned int libnvme_ns_get_inflights(libnvme_ns_t n);
880+
881+
/**
882+
* libnvme_ns_get_io_ticks() - Get IO ticks
883+
* @n: &libnvme_ns_t object
884+
*
885+
* Return: Time consumed, in milliseconds, processing I/O requests between
886+
* two stat samples
887+
*/
888+
unsigned int libnvme_ns_get_io_ticks(libnvme_ns_t n);
889+
890+
/**
891+
* libnvme_ns_get_read_ticks() - Get read I/O ticks
892+
* @n: &libnvme_ns_t object
893+
*
894+
* Return: Time, in milliseconds, sepnt processing read I/O requests
895+
* between two stat samples
896+
*/
897+
unsigned int libnvme_ns_get_read_ticks(libnvme_ns_t n);
898+
899+
/**
900+
* libnvme_ns_get_write_ticks() - Get write I/O ticks
901+
* @n: &libnvme_ns_t object
902+
*
903+
* Return: Time, in milliseconds, sepnt processing write I/O requests
904+
* between two stat samples
905+
*/
906+
unsigned int libnvme_ns_get_write_ticks(libnvme_ns_t n);
907+
908+
/**
909+
* libnvme_ns_get_stat_interval() - Get interval between two stat samples
910+
* @n: &libnvme_ns_t object
911+
*
912+
* Return: Interval, in milliseconds, between collection of two consecutive
913+
* stat samples
914+
*/
915+
double libnvme_ns_get_stat_interval(libnvme_ns_t n);
916+
917+
/**
918+
* libnvme_ns_get_read_ios() - Get num of read I/Os
919+
* @n: &libnvme_ns_t object
920+
*
921+
* Return: Num of read IOs processed between two stat samples
922+
*/
923+
unsigned long libnvme_ns_get_read_ios(libnvme_ns_t n);
924+
925+
/**
926+
* libnvme_ns_get_write_ios() - Get num of write I/Os
927+
* @n: &libnvme_ns_t object
928+
*
929+
* Return: Num of write IOs processed between two consecutive stat samples
930+
*/
931+
unsigned long libnvme_ns_get_write_ios(libnvme_ns_t n);
932+
933+
/**
934+
* libnvme_ns_get_read_sectors() - Get num of read sectors
935+
* @n: &libnvme_ns_t object
936+
*
937+
* Return: Num of sectors read from the device between two stat samples
938+
*/
939+
unsigned long long libnvme_ns_get_read_sectors(libnvme_ns_t n);
940+
941+
/**
942+
* libnvme_ns_get_write_sectors() - Get num of write sectors
943+
* @n: &libnvme_ns_t object
944+
*
945+
* Return: Num of sectors written to the device between two stat samples
946+
*/
947+
unsigned long long libnvme_ns_get_write_sectors(libnvme_ns_t n);
948+
856949
/**
857950
* libnvme_ctrl_identify() - Issues an 'identify controller' command
858951
* @c: Controller instance

0 commit comments

Comments
 (0)