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