Skip to content

Commit

Permalink
ioctl: Add support for 64-bit ioctls latency logging
Browse files Browse the repository at this point in the history
Note: The latency logging enabled for other nvme ioctl requests also.

Signed-off-by: Tokunori Ikegami <[email protected]>
  • Loading branch information
ikegami-t committed Jan 17, 2024
1 parent 1a08c34 commit 80cac76
Show file tree
Hide file tree
Showing 4 changed files with 157 additions and 42 deletions.
1 change: 1 addition & 0 deletions src/libnvme.map
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ LIBNVME_1_7 {
nvme_get_latency;
nvme_admin_to_string;
nvme_nvm_to_string;
nvme_ioctl_to_string;
};

LIBNVME_1_6 {
Expand Down
149 changes: 109 additions & 40 deletions src/nvme/ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <string.h>
#include <unistd.h>
#include <inttypes.h>
#include <stdarg.h>

#include <sys/ioctl.h>
#include <sys/stat.h>
Expand Down Expand Up @@ -43,14 +44,116 @@ static int nvme_verify_chr(int fd)
return 0;
}

static bool nvme_ioctl_cmd_admin(unsigned long req)
{
if (req == NVME_IOCTL_ADMIN_CMD || req == NVME_IOCTL_ADMIN64_CMD)
return true;

return false;
}

static bool nvme_ioctl_cmd_64(unsigned long req)
{
if (req == NVME_IOCTL_ADMIN64_CMD || req == NVME_IOCTL_IO64_CMD)
return true;

return false;
}

static const char *nvme_cmd_to_string(unsigned long req, __u8 opcode)
{
const char *cmd_name;

if (nvme_ioctl_cmd_admin(req))
cmd_name = nvme_admin_to_string(opcode);
else
cmd_name = nvme_nvm_to_string(opcode);

if (!cmd_name)
return "Unknown";

return cmd_name;
}

static void nvme_show_latency(unsigned long req, __u8 *opcode, struct timeval *start,
struct timeval *end)
{
struct timeval latency;

timersub(end, start, &latency);

if (opcode)
printf("%s%s Command opcode: %02x (%s) ",
nvme_ioctl_cmd_admin(req) ? "Admin" : "IO",
nvme_ioctl_cmd_64(req) ? "64" : "", *opcode,
nvme_cmd_to_string(req, *opcode));
else
printf("ioctl: %lx (%s) ", req, nvme_ioctl_to_string(req));

printf("latency: %lu us\n", latency.tv_sec * 1000000 + latency.tv_usec);
}

static bool nvme_ioctl_cmd(unsigned long req)
{
bool ioctl_cmd = false;

switch (req) {
case NVME_IOCTL_ADMIN_CMD:
fallthrough;
case NVME_IOCTL_IO_CMD:
fallthrough;
case NVME_IOCTL_ADMIN64_CMD:
fallthrough;
case NVME_IOCTL_IO64_CMD:
ioctl_cmd = true;
break;
default:
break;
}

return ioctl_cmd;
}

static int nvme_ioctl(int fd, unsigned long req, ...)
{
struct timeval start;
struct timeval end;
int err;
va_list ap;
__u8 *opcode = NULL;
void *ioctl_cmd = NULL;

if (nvme_ioctl_cmd(req)) {
va_start(ap, req);
ioctl_cmd = va_arg(ap, void *);
va_end(ap);
if (nvme_ioctl_cmd_64(req))
opcode = &((struct nvme_passthru_cmd64 *)ioctl_cmd)->opcode;
else
opcode = &((struct nvme_passthru_cmd *)ioctl_cmd)->opcode;
}

if (nvme_get_latency())
gettimeofday(&start, NULL);

err = ioctl_cmd ? ioctl(fd, req, ioctl_cmd) : ioctl(fd, req);

if (nvme_get_latency()) {
gettimeofday(&end, NULL);
nvme_show_latency(req, opcode, &start, &end);
}

return err;
}

int nvme_subsystem_reset(int fd)
{
int ret;

ret = nvme_verify_chr(fd);
if (ret)
return ret;
return ioctl(fd, NVME_IOCTL_SUBSYS_RESET);
return nvme_ioctl(fd, NVME_IOCTL_SUBSYS_RESET);
}

int nvme_ctrl_reset(int fd)
Expand All @@ -60,7 +163,7 @@ int nvme_ctrl_reset(int fd)
ret = nvme_verify_chr(fd);
if (ret)
return ret;
return ioctl(fd, NVME_IOCTL_RESET);
return nvme_ioctl(fd, NVME_IOCTL_RESET);
}

int nvme_ns_rescan(int fd)
Expand All @@ -70,21 +173,21 @@ int nvme_ns_rescan(int fd)
ret = nvme_verify_chr(fd);
if (ret)
return ret;
return ioctl(fd, NVME_IOCTL_RESCAN);
return nvme_ioctl(fd, NVME_IOCTL_RESCAN);
}

int nvme_get_nsid(int fd, __u32 *nsid)
{
errno = 0;
*nsid = ioctl(fd, NVME_IOCTL_ID);
*nsid = nvme_ioctl(fd, NVME_IOCTL_ID);
return -1 * (errno != 0);
}

static int nvme_submit_passthru64(int fd, unsigned long ioctl_cmd,
struct nvme_passthru_cmd64 *cmd,
__u64 *result)
{
int err = ioctl(fd, ioctl_cmd, cmd);
int err = nvme_ioctl(fd, ioctl_cmd, cmd);

if (err >= 0 && result)
*result = cmd->result;
Expand Down Expand Up @@ -114,30 +217,6 @@ static void nvme_show_command(struct nvme_passthru_cmd *cmd, int err)
printf("err : %d\n", err);
}

static const char *nvme_cmd_to_string(bool admin, __u8 opcode)
{
const char *cmd_name;

if (admin)
cmd_name = nvme_admin_to_string(opcode);
else
cmd_name = nvme_nvm_to_string(opcode);

if (!cmd_name)
return "Unknown";

return cmd_name;
}

static void nvme_show_latency(bool admin, __u8 opcode, struct timeval *start, struct timeval *end)
{
struct timeval latency;

timersub(end, start, &latency);
printf("%s Command opcode: %02x (%s) latency: %lu us\n", admin ? "Admin" : "IO", opcode,
nvme_cmd_to_string(admin, opcode), latency.tv_sec * 1000000 + latency.tv_usec);
}

void nvme_set_debug(bool debug)
{
nvme_debug = debug;
Expand All @@ -161,19 +240,9 @@ bool nvme_get_latency(void)
static int nvme_submit_passthru(int fd, unsigned long ioctl_cmd,
struct nvme_passthru_cmd *cmd, __u32 *result)
{
struct timeval start;
struct timeval end;
int err;

if (nvme_get_latency())
gettimeofday(&start, NULL);

err = ioctl(fd, ioctl_cmd, cmd);

if (nvme_get_latency()) {
gettimeofday(&end, NULL);
nvme_show_latency(ioctl_cmd == NVME_IOCTL_ADMIN_CMD, cmd->opcode, &start, &end);
}
err = nvme_ioctl(fd, ioctl_cmd, cmd);

if (nvme_get_debug())
nvme_show_command(cmd, err);
Expand Down
36 changes: 36 additions & 0 deletions src/nvme/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -1181,3 +1181,39 @@ const char *nvme_nvm_to_string(__u8 opcode)

return NULL;
}

const char *nvme_ioctl_to_string(unsigned long req)
{
char *ret = NULL;

switch (req) {
case NVME_IOCTL_ID:
ret = "ID";
break;
case NVME_IOCTL_RESET:
ret = "Reset";
break;
case NVME_IOCTL_SUBSYS_RESET:
ret = "Subsystem reset";
break;
case NVME_IOCTL_RESCAN:
ret = "Rescan";
break;
case NVME_IOCTL_ADMIN_CMD:
ret = "Admin command";
break;
case NVME_IOCTL_IO_CMD:
ret = "IO command";
break;
case NVME_IOCTL_ADMIN64_CMD:
ret = "Admin64 command";
break;
case NVME_IOCTL_IO64_CMD:
ret = "IO64 command";
break;
default:
break;
}

return ret;
}
13 changes: 11 additions & 2 deletions src/nvme/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -704,7 +704,7 @@ bool nvme_iface_primary_addr_matches(const struct ifaddrs *iface_list, const cha

/**
* nvme_admin_to_string - Returns string describing nvme admin opcode
* @opcode: Admin opcode for an nvme command
* @opcode: Admin opcode for an nvme command
*
* Return: representation of the admin opcode if it is an admin opcode field,
* or NULL if opcode is unknown.
Expand All @@ -713,10 +713,19 @@ const char *nvme_admin_to_string(__u8 opcode);

/**
* nvme_nvm_to_string - Returns string describing nvme nvm opcode
* @opcode: NVM opcode for an nvme command
* @opcode: NVM opcode for an nvme command
*
* Return: representation of the nvm opcode if it is an nvm opcode field,
* or NULL if opcode is unknown.
*/
const char *nvme_nvm_to_string(__u8 opcode);

/**
* nvme_ioctl_to_string - Returns string describing nvme ioctl request
* @req: ioctl request for an nvme command
*
* Return: representation of the ioctl request if it is an ioctl request,
* or NULL if request is unknown.
*/
const char *nvme_ioctl_to_string(unsigned long req);
#endif /* _LIBNVME_UTIL_H */

0 comments on commit 80cac76

Please sign in to comment.