Adding upstream version 1.0.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
809e3412a9
commit
336fe81026
743 changed files with 51081 additions and 0 deletions
167
examples/telemetry-listen.c
Normal file
167
examples/telemetry-listen.c
Normal file
|
@ -0,0 +1,167 @@
|
|||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
/**
|
||||
* This file is part of libnvme.
|
||||
* Copyright (c) 2020 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors: Keith Busch <keith.busch@wdc.com>
|
||||
*/
|
||||
|
||||
/**
|
||||
* Open all nvme controller's uevent and listen for changes. If NVME_AEN event
|
||||
* is observed with controller telemetry data, read the log and save it to a
|
||||
* file in /var/log/ with the device's unique name and epoch timestamp.
|
||||
*/
|
||||
#include <fcntl.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <libnvme.h>
|
||||
|
||||
#include <ccan/endian/endian.h>
|
||||
|
||||
struct events {
|
||||
nvme_ctrl_t c;
|
||||
int uevent_fd;
|
||||
};
|
||||
|
||||
static int open_uevent(nvme_ctrl_t c)
|
||||
{
|
||||
char buf[0x1000];
|
||||
if (snprintf(buf, sizeof(buf), "%s/uevent", nvme_ctrl_get_sysfs_dir(c)) < 0)
|
||||
return -1;
|
||||
return open(buf, O_RDONLY);
|
||||
}
|
||||
|
||||
static void save_telemetry(nvme_ctrl_t c)
|
||||
{
|
||||
char buf[0x1000];
|
||||
size_t log_size;
|
||||
int ret, fd;
|
||||
struct nvme_telemetry_log *log;
|
||||
time_t s;
|
||||
|
||||
/* Clear the log (rae == false) at the end to see new telemetry events later */
|
||||
ret = nvme_get_ctrl_telemetry(nvme_ctrl_get_fd(c), false, &log, NVME_TELEMETRY_DA_3, &log_size);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
s = time(NULL);
|
||||
ret = snprintf(buf, sizeof(buf), "/var/log/%s-telemetry-%ld",
|
||||
nvme_ctrl_get_subsysnqn(c), s);
|
||||
if (ret < 0) {
|
||||
free(log);
|
||||
return;
|
||||
}
|
||||
log_size = (le16_to_cpu(log->dalb3) + 1) * NVME_LOG_TELEM_BLOCK_SIZE;
|
||||
|
||||
fd = open(buf, O_CREAT|O_WRONLY, S_IRUSR|S_IRGRP);
|
||||
if (fd < 0) {
|
||||
free(log);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = write(fd, log, log_size);
|
||||
if (ret < 0)
|
||||
printf("failed to write telemetry log\n");
|
||||
else
|
||||
printf("telemetry log save as %s, wrote:%d size:%ld\n", buf,
|
||||
ret, log_size);
|
||||
close(fd);
|
||||
free(log);
|
||||
}
|
||||
|
||||
static void check_telemetry(nvme_ctrl_t c, int ufd)
|
||||
{
|
||||
char buf[0x1000] = { 0 };
|
||||
char *p, *ptr;
|
||||
|
||||
if (read(ufd, buf, sizeof(buf)) < 0)
|
||||
return;
|
||||
|
||||
ptr = buf;
|
||||
while ((p = strsep(&ptr, "\n")) != NULL) {
|
||||
__u32 aen, type, info, lid;
|
||||
|
||||
if (sscanf(p, "NVME_AEN=0x%08x", &aen) != 1)
|
||||
continue;
|
||||
|
||||
type = aen & 0x07;
|
||||
info = (aen >> 8) & 0xff;
|
||||
lid = (aen >> 16) & 0xff;
|
||||
|
||||
printf("%s: aen type:%x info:%x lid:%d\n",
|
||||
nvme_ctrl_get_name(c), type, info, lid);
|
||||
if (type == NVME_AER_NOTICE &&
|
||||
info == NVME_AER_NOTICE_TELEMETRY)
|
||||
save_telemetry(c);
|
||||
}
|
||||
}
|
||||
|
||||
static void wait_events(fd_set *fds, struct events *e, int nr)
|
||||
{
|
||||
int ret, i;
|
||||
|
||||
for (i = 0; i < nr; i++)
|
||||
check_telemetry(e[i].c, e[i].uevent_fd);
|
||||
|
||||
while (1) {
|
||||
ret = select(nr, fds, NULL, NULL, NULL);
|
||||
if (ret < 0)
|
||||
return;
|
||||
|
||||
for (i = 0; i < nr; i++) {
|
||||
if (!FD_ISSET(e[i].uevent_fd, fds))
|
||||
continue;
|
||||
check_telemetry(e[i].c, e[i].uevent_fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
struct events *e;
|
||||
fd_set fds;
|
||||
int i = 0;
|
||||
|
||||
nvme_subsystem_t s;
|
||||
nvme_ctrl_t c;
|
||||
nvme_host_t h;
|
||||
nvme_root_t r;
|
||||
|
||||
r = nvme_scan(NULL);
|
||||
if (!r)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
nvme_for_each_host(r, h)
|
||||
nvme_for_each_subsystem(h, s)
|
||||
nvme_subsystem_for_each_ctrl(s, c)
|
||||
i++;
|
||||
|
||||
e = calloc(i, sizeof(e));
|
||||
FD_ZERO(&fds);
|
||||
i = 0;
|
||||
|
||||
nvme_for_each_host(r, h) {
|
||||
nvme_for_each_subsystem(h, s) {
|
||||
nvme_subsystem_for_each_ctrl(s, c) {
|
||||
int fd = open_uevent(c);
|
||||
|
||||
if (fd < 0)
|
||||
continue;
|
||||
FD_SET(fd, &fds);
|
||||
e[i].uevent_fd = fd;
|
||||
e[i].c = c;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wait_events(&fds, e, i);
|
||||
nvme_free_tree(r);
|
||||
free(e);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue