blob: 2eaaec8dbe843508422536483e18aa59a0cceb4f [file] [log] [blame] [raw]
Implement proc/diskstats as Linux 2.6+.
diff -ru --exclude-from freebsd-src-diff-exclude-names /usr/src/sys/compat/linprocfs/linprocfs.c freebsd-11.1/sys/compat/linprocfs/linprocfs.c
--- /usr/src/sys/compat/linprocfs/linprocfs.c 2017-07-21 07:42:01.000000000 +0800
+++ freebsd-11.1/sys/compat/linprocfs/linprocfs.c 2020-12-24 17:36:25.377847338 +0800
@@ -77,7 +84,7 @@
#include <sys/vmmeter.h>
#include <sys/vnode.h>
#include <sys/bus.h>
-
+#include <sys/devicestat.h>
#include <net/if.h>
#include <net/if_var.h>
#include <net/if_types.h>
@@ -94,6 +101,9 @@
#include <geom/geom.h>
#include <geom/geom_int.h>
+#ifdef LINPROCFS_HACK_GEOM_DISK_STAT
+#include <geom/geom_disk.h>
+#endif
#if defined(__i386__) || defined(__amd64__)
#include <machine/cputypes.h>
@@ -118,6 +128,7 @@
#define P2B(x) ((x) << PAGE_SHIFT) /* pages to bytes */
#define P2K(x) ((x) << (PAGE_SHIFT - 10)) /* pages to kbytes */
#define TV2J(x) ((x)->tv_sec * 100UL + (x)->tv_usec / 10000)
+#define BINTIME2MSEC(_bt) ((unsigned long int)((_bt)->sec + (((uint64_t)1000 * (uint32_t)((_bt)->frac >> 32)) >> 32)))
/**
* @brief Mapping of ki_stat in struct kinfo_proc to the linux state
@@ -394,6 +402,69 @@
return (0);
}
+/*
+ * Filler function for proc/diskstats
+ */
+static int
+linprocfs_dodiskstats(PFS_FILL_ARGS)
+{
+ struct g_class *cp;
+ struct g_geom *gp;
+ struct g_provider *pp;
+
+ g_topology_lock();
+ LIST_FOREACH(cp, &g_classes, class) {
+ if(strcmp(cp->name, "DISK") && strcmp(cp->name, "MD") && strcmp(cp->name, "ZFS::ZVOL")) {
+ continue;
+ }
+ LIST_FOREACH(gp, &cp->geom, geom) {
+ LIST_FOREACH(pp, &gp->provider, provider) {
+ int major, minor;
+ if (linux_driver_get_major_minor(
+ pp->name, &major, &minor) != 0) {
+ major = 0;
+ minor = 0;
+ }
+ const struct devstat *stat = pp->stat;
+#ifdef LINPROCFS_HACK_GEOM_DISK_STAT
+ if(!stat && strcmp(cp->name, "DISK") == 0 && pp->private) {
+ // XXX
+ struct g_disk_softc {
+ struct mtx done_mtx;
+ struct disk *dp;
+ } *sc = pp->private;
+ stat = sc->dp->d_devstat;
+ }
+#endif
+ if(stat) {
+ uint32_t block_size = stat->block_size;
+ if(!block_size) block_size = 512;
+ sbuf_printf(sb, "%4d %7d %s %lu %lu "
+ "%lu %lu %lu %lu %lu %lu "
+ "%u %lu %lu\n",
+ major, minor, pp->name,
+ (unsigned long int)stat->operations[DEVSTAT_READ],
+ 0UL,
+ (unsigned long int)(stat->bytes[DEVSTAT_READ] / block_size),
+ BINTIME2MSEC(stat->duration + DEVSTAT_READ),
+ (unsigned long int)stat->operations[DEVSTAT_WRITE],
+ 0UL,
+ (unsigned long int)(stat->bytes[DEVSTAT_WRITE] / block_size),
+ BINTIME2MSEC(stat->duration + DEVSTAT_WRITE),
+ stat->start_count - stat->end_count,
+ BINTIME2MSEC(&stat->busy_time),
+ BINTIME2MSEC(&stat->busy_time));
+ } else {
+ sbuf_printf(sb, "%4d %7d %s 0 0 0 0 0 0 0 0 0 0 0\n",
+ major, minor, pp->name);
+ }
+ }
+ }
+ }
+ g_topology_unlock();
+
+ return 0;
+}
/*
* Filler function for proc/stat
@@ -1497,6 +1578,8 @@
NULL, NULL, NULL, PFS_RD);
pfs_create_file(root, "devices", &linprocfs_dodevices,
NULL, NULL, NULL, PFS_RD);
+ pfs_create_file(root, "diskstats", &linprocfs_dodiskstats,
+ NULL, NULL, NULL, PFS_RD);
pfs_create_file(root, "filesystems", &linprocfs_dofilesystems,
NULL, NULL, NULL, PFS_RD);
pfs_create_file(root, "loadavg", &linprocfs_doloadavg,