Loading include/uapi/linux/sysstats.h 0 → 100644 +92 −0 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ /* * Copyright (c) 2019, The Linux Foundation. All rights reserved. */ #ifndef _LINUX_SYSSTATS_H #define _LINUX_SYSSTATS_H #include <linux/types.h> #include <linux/taskstats.h> #include <linux/cgroupstats.h> #define SYSSTATS_VERSION 1 /* * Data shared between user space and kernel space * Each member is aligned to a 8 byte boundary. * All values in KB. */ struct sys_memstats { __u64 version; __u64 memtotal; __u64 vmalloc_total; __u64 reclaimable; __u64 zram_compressed; __u64 swap_used; __u64 swap_total; __u64 unreclaimable; __u64 buffer; __u64 slab_reclaimable; __u64 slab_unreclaimable; __u64 free_cma; __u64 file_mapped; __u64 swapcache; __u64 pagetable; __u64 kernelstack; __u64 shmem; __u64 dma_nr_free_pages; __u64 dma_nr_active_anon; __u64 dma_nr_inactive_anon; __u64 dma_nr_active_file; __u64 dma_nr_inactive_file; __u64 normal_nr_free_pages; __u64 normal_nr_active_anon; __u64 normal_nr_inactive_anon; __u64 normal_nr_active_file; __u64 normal_nr_inactive_file; __u64 movable_nr_free_pages; __u64 movable_nr_active_anon; __u64 movable_nr_inactive_anon; __u64 movable_nr_active_file; __u64 movable_nr_inactive_file; __u64 highmem_nr_free_pages; __u64 highmem_nr_active_anon; __u64 highmem_nr_inactive_anon; __u64 highmem_nr_active_file; __u64 highmem_nr_inactive_file; /* version 1 ends here */ }; /* * Commands sent from userspace * Not versioned. New commands should only be inserted at the enum's end. */ enum { SYSSTATS_CMD_UNSPEC = __CGROUPSTATS_CMD_MAX, /* Reserved */ SYSSTATS_CMD_GET, /* user->kernel request/get-response */ SYSSTATS_CMD_NEW, /* kernel->user event */ }; #define SYSSTATS_CMD_UNSPEC SYSSTATS_CMD_UNSPEC #define SYSSTATS_CMD_GET SYSSTATS_CMD_GET #define SYSSTATS_CMD_NEW SYSSTATS_CMD_NEW enum { SYSSTATS_TYPE_UNSPEC = 0, /* Reserved */ SYSSTATS_TYPE_SYSMEM_STATS, /* contains name + memory stats */ }; #define SYSSTATS_TYPE_UNSPEC SYSSTATS_TYPE_UNSPEC #define SYSSTATS_TYPE_SYSMEM_STATS SYSSTATS_TYPE_SYSMEM_STATS enum { SYSSTATS_CMD_ATTR_UNSPEC = 0, SYSSTATS_CMD_ATTR_SYSMEM_STATS, }; #define SYSSTATS_CMD_ATTR_UNSPEC SYSSTATS_CMD_ATTR_UNSPEC #define SYSSTATS_CMD_ATTR_SYSMEM_STATS SYSSTATS_CMD_ATTR_SYSMEM_STATS #endif /* _LINUX_SYSSTATS_H */ kernel/taskstats.c +149 −0 Original line number Diff line number Diff line Loading @@ -23,7 +23,10 @@ #include <linux/cpumask.h> #include <linux/percpu.h> #include <linux/slab.h> #include <linux/swap.h> #include <linux/vmalloc.h> #include <linux/cgroupstats.h> #include <linux/sysstats.h> #include <linux/cgroup.h> #include <linux/fs.h> #include <linux/file.h> Loading Loading @@ -58,6 +61,11 @@ static const struct nla_policy cgroupstats_cmd_get_policy[TASKSTATS_CMD_ATTR_MAX [CGROUPSTATS_CMD_ATTR_FD] = { .type = NLA_U32 }, }; static const struct nla_policy sysstats_cmd_get_policy[TASKSTATS_CMD_ATTR_MAX+1] = { [SYSSTATS_CMD_ATTR_SYSMEM_STATS] = { .type = NLA_U32 }, }; struct listener { struct list_head list; pid_t pid; Loading Loading @@ -400,6 +408,142 @@ static struct taskstats *mk_reply(struct sk_buff *skb, int type, u32 pid) return NULL; } #define K(x) ((x) << (PAGE_SHIFT - 10)) #ifndef CONFIG_NUMA static void sysstats_fill_zoneinfo(struct sys_memstats *stats) { pg_data_t *pgdat; struct zone *zone; struct zone *node_zones; unsigned long zspages = 0; pgdat = NODE_DATA(0); node_zones = pgdat->node_zones; for (zone = node_zones; zone - node_zones < MAX_NR_ZONES; ++zone) { if (!populated_zone(zone)) continue; zspages += zone_page_state(zone, NR_ZSPAGES); if (!strcmp(zone->name, "DMA")) { stats->dma_nr_free_pages = K(zone_page_state(zone, NR_FREE_PAGES)); stats->dma_nr_active_anon = K(zone_page_state(zone, NR_ZONE_ACTIVE_ANON)); stats->dma_nr_inactive_anon = K(zone_page_state(zone, NR_ZONE_INACTIVE_ANON)); stats->dma_nr_active_file = K(zone_page_state(zone, NR_ZONE_ACTIVE_FILE)); stats->dma_nr_inactive_file = K(zone_page_state(zone, NR_ZONE_INACTIVE_FILE)); } else if (!strcmp(zone->name, "Normal")) { stats->normal_nr_free_pages = K(zone_page_state(zone, NR_FREE_PAGES)); stats->normal_nr_active_anon = K(zone_page_state(zone, NR_ZONE_ACTIVE_ANON)); stats->normal_nr_inactive_anon = K(zone_page_state(zone, NR_ZONE_INACTIVE_ANON)); stats->normal_nr_active_file = K(zone_page_state(zone, NR_ZONE_ACTIVE_FILE)); stats->normal_nr_inactive_file = K(zone_page_state(zone, NR_ZONE_INACTIVE_FILE)); } else if (!strcmp(zone->name, "HighMem")) { stats->highmem_nr_free_pages = K(zone_page_state(zone, NR_FREE_PAGES)); stats->highmem_nr_active_anon = K(zone_page_state(zone, NR_ZONE_ACTIVE_ANON)); stats->highmem_nr_inactive_anon = K(zone_page_state(zone, NR_ZONE_INACTIVE_ANON)); stats->highmem_nr_active_file = K(zone_page_state(zone, NR_ZONE_ACTIVE_FILE)); stats->highmem_nr_inactive_file = K(zone_page_state(zone, NR_ZONE_INACTIVE_FILE)); } else if (!strcmp(zone->name, "Movable")) { stats->movable_nr_free_pages = K(zone_page_state(zone, NR_FREE_PAGES)); stats->movable_nr_active_anon = K(zone_page_state(zone, NR_ZONE_ACTIVE_ANON)); stats->movable_nr_inactive_anon = K(zone_page_state(zone, NR_ZONE_INACTIVE_ANON)); stats->movable_nr_active_file = K(zone_page_state(zone, NR_ZONE_ACTIVE_FILE)); stats->movable_nr_inactive_file = K(zone_page_state(zone, NR_ZONE_INACTIVE_FILE)); } } stats->zram_compressed = K(zspages); } #elif static void sysstats_fill_zoneinfo(struct sys_memstats *stats) { } #endif static void sysstats_build(struct sys_memstats *stats) { struct sysinfo i; si_meminfo(&i); si_swapinfo(&i); stats->version = SYSSTATS_VERSION; stats->memtotal = K(i.totalram); stats->reclaimable = global_node_page_state(NR_INDIRECTLY_RECLAIMABLE_BYTES) >> 10; stats->swap_used = K(i.totalswap - i.freeswap); stats->swap_total = K(i.totalswap); stats->vmalloc_total = K(vmalloc_nr_pages()); stats->unreclaimable = K(global_node_page_state(NR_UNRECLAIMABLE_PAGES)); stats->buffer = K(i.bufferram); stats->swapcache = K(total_swapcache_pages()); stats->slab_reclaimable = K(global_node_page_state(NR_SLAB_RECLAIMABLE)); stats->slab_unreclaimable = K(global_node_page_state(NR_SLAB_UNRECLAIMABLE)); stats->free_cma = K(global_zone_page_state(NR_FREE_CMA_PAGES)); stats->file_mapped = K(global_node_page_state(NR_FILE_MAPPED)); stats->kernelstack = global_zone_page_state(NR_KERNEL_STACK_KB); stats->pagetable = K(global_zone_page_state(NR_PAGETABLE)); stats->shmem = K(i.sharedram); sysstats_fill_zoneinfo(stats); } #undef K static int sysstats_user_cmd(struct sk_buff *skb, struct genl_info *info) { int rc = 0; struct sk_buff *rep_skb; struct sys_memstats *stats; struct nlattr *na; size_t size; size = nla_total_size(sizeof(struct sys_memstats)); rc = prepare_reply(info, SYSSTATS_CMD_NEW, &rep_skb, size); if (rc < 0) goto err; na = nla_reserve(rep_skb, SYSSTATS_TYPE_SYSMEM_STATS, sizeof(struct sys_memstats)); if (na == NULL) { nlmsg_free(rep_skb); rc = -EMSGSIZE; goto err; } stats = nla_data(na); memset(stats, 0, sizeof(*stats)); sysstats_build(stats); rc = send_reply(rep_skb, info); err: return rc; } static int cgroupstats_user_cmd(struct sk_buff *skb, struct genl_info *info) { int rc = 0; Loading Loading @@ -662,6 +806,11 @@ static const struct genl_ops taskstats_ops[] = { .doit = cgroupstats_user_cmd, .policy = cgroupstats_cmd_get_policy, }, { .cmd = SYSSTATS_CMD_GET, .doit = sysstats_user_cmd, .policy = sysstats_cmd_get_policy, }, }; static struct genl_family family __ro_after_init = { Loading Loading
include/uapi/linux/sysstats.h 0 → 100644 +92 −0 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ /* * Copyright (c) 2019, The Linux Foundation. All rights reserved. */ #ifndef _LINUX_SYSSTATS_H #define _LINUX_SYSSTATS_H #include <linux/types.h> #include <linux/taskstats.h> #include <linux/cgroupstats.h> #define SYSSTATS_VERSION 1 /* * Data shared between user space and kernel space * Each member is aligned to a 8 byte boundary. * All values in KB. */ struct sys_memstats { __u64 version; __u64 memtotal; __u64 vmalloc_total; __u64 reclaimable; __u64 zram_compressed; __u64 swap_used; __u64 swap_total; __u64 unreclaimable; __u64 buffer; __u64 slab_reclaimable; __u64 slab_unreclaimable; __u64 free_cma; __u64 file_mapped; __u64 swapcache; __u64 pagetable; __u64 kernelstack; __u64 shmem; __u64 dma_nr_free_pages; __u64 dma_nr_active_anon; __u64 dma_nr_inactive_anon; __u64 dma_nr_active_file; __u64 dma_nr_inactive_file; __u64 normal_nr_free_pages; __u64 normal_nr_active_anon; __u64 normal_nr_inactive_anon; __u64 normal_nr_active_file; __u64 normal_nr_inactive_file; __u64 movable_nr_free_pages; __u64 movable_nr_active_anon; __u64 movable_nr_inactive_anon; __u64 movable_nr_active_file; __u64 movable_nr_inactive_file; __u64 highmem_nr_free_pages; __u64 highmem_nr_active_anon; __u64 highmem_nr_inactive_anon; __u64 highmem_nr_active_file; __u64 highmem_nr_inactive_file; /* version 1 ends here */ }; /* * Commands sent from userspace * Not versioned. New commands should only be inserted at the enum's end. */ enum { SYSSTATS_CMD_UNSPEC = __CGROUPSTATS_CMD_MAX, /* Reserved */ SYSSTATS_CMD_GET, /* user->kernel request/get-response */ SYSSTATS_CMD_NEW, /* kernel->user event */ }; #define SYSSTATS_CMD_UNSPEC SYSSTATS_CMD_UNSPEC #define SYSSTATS_CMD_GET SYSSTATS_CMD_GET #define SYSSTATS_CMD_NEW SYSSTATS_CMD_NEW enum { SYSSTATS_TYPE_UNSPEC = 0, /* Reserved */ SYSSTATS_TYPE_SYSMEM_STATS, /* contains name + memory stats */ }; #define SYSSTATS_TYPE_UNSPEC SYSSTATS_TYPE_UNSPEC #define SYSSTATS_TYPE_SYSMEM_STATS SYSSTATS_TYPE_SYSMEM_STATS enum { SYSSTATS_CMD_ATTR_UNSPEC = 0, SYSSTATS_CMD_ATTR_SYSMEM_STATS, }; #define SYSSTATS_CMD_ATTR_UNSPEC SYSSTATS_CMD_ATTR_UNSPEC #define SYSSTATS_CMD_ATTR_SYSMEM_STATS SYSSTATS_CMD_ATTR_SYSMEM_STATS #endif /* _LINUX_SYSSTATS_H */
kernel/taskstats.c +149 −0 Original line number Diff line number Diff line Loading @@ -23,7 +23,10 @@ #include <linux/cpumask.h> #include <linux/percpu.h> #include <linux/slab.h> #include <linux/swap.h> #include <linux/vmalloc.h> #include <linux/cgroupstats.h> #include <linux/sysstats.h> #include <linux/cgroup.h> #include <linux/fs.h> #include <linux/file.h> Loading Loading @@ -58,6 +61,11 @@ static const struct nla_policy cgroupstats_cmd_get_policy[TASKSTATS_CMD_ATTR_MAX [CGROUPSTATS_CMD_ATTR_FD] = { .type = NLA_U32 }, }; static const struct nla_policy sysstats_cmd_get_policy[TASKSTATS_CMD_ATTR_MAX+1] = { [SYSSTATS_CMD_ATTR_SYSMEM_STATS] = { .type = NLA_U32 }, }; struct listener { struct list_head list; pid_t pid; Loading Loading @@ -400,6 +408,142 @@ static struct taskstats *mk_reply(struct sk_buff *skb, int type, u32 pid) return NULL; } #define K(x) ((x) << (PAGE_SHIFT - 10)) #ifndef CONFIG_NUMA static void sysstats_fill_zoneinfo(struct sys_memstats *stats) { pg_data_t *pgdat; struct zone *zone; struct zone *node_zones; unsigned long zspages = 0; pgdat = NODE_DATA(0); node_zones = pgdat->node_zones; for (zone = node_zones; zone - node_zones < MAX_NR_ZONES; ++zone) { if (!populated_zone(zone)) continue; zspages += zone_page_state(zone, NR_ZSPAGES); if (!strcmp(zone->name, "DMA")) { stats->dma_nr_free_pages = K(zone_page_state(zone, NR_FREE_PAGES)); stats->dma_nr_active_anon = K(zone_page_state(zone, NR_ZONE_ACTIVE_ANON)); stats->dma_nr_inactive_anon = K(zone_page_state(zone, NR_ZONE_INACTIVE_ANON)); stats->dma_nr_active_file = K(zone_page_state(zone, NR_ZONE_ACTIVE_FILE)); stats->dma_nr_inactive_file = K(zone_page_state(zone, NR_ZONE_INACTIVE_FILE)); } else if (!strcmp(zone->name, "Normal")) { stats->normal_nr_free_pages = K(zone_page_state(zone, NR_FREE_PAGES)); stats->normal_nr_active_anon = K(zone_page_state(zone, NR_ZONE_ACTIVE_ANON)); stats->normal_nr_inactive_anon = K(zone_page_state(zone, NR_ZONE_INACTIVE_ANON)); stats->normal_nr_active_file = K(zone_page_state(zone, NR_ZONE_ACTIVE_FILE)); stats->normal_nr_inactive_file = K(zone_page_state(zone, NR_ZONE_INACTIVE_FILE)); } else if (!strcmp(zone->name, "HighMem")) { stats->highmem_nr_free_pages = K(zone_page_state(zone, NR_FREE_PAGES)); stats->highmem_nr_active_anon = K(zone_page_state(zone, NR_ZONE_ACTIVE_ANON)); stats->highmem_nr_inactive_anon = K(zone_page_state(zone, NR_ZONE_INACTIVE_ANON)); stats->highmem_nr_active_file = K(zone_page_state(zone, NR_ZONE_ACTIVE_FILE)); stats->highmem_nr_inactive_file = K(zone_page_state(zone, NR_ZONE_INACTIVE_FILE)); } else if (!strcmp(zone->name, "Movable")) { stats->movable_nr_free_pages = K(zone_page_state(zone, NR_FREE_PAGES)); stats->movable_nr_active_anon = K(zone_page_state(zone, NR_ZONE_ACTIVE_ANON)); stats->movable_nr_inactive_anon = K(zone_page_state(zone, NR_ZONE_INACTIVE_ANON)); stats->movable_nr_active_file = K(zone_page_state(zone, NR_ZONE_ACTIVE_FILE)); stats->movable_nr_inactive_file = K(zone_page_state(zone, NR_ZONE_INACTIVE_FILE)); } } stats->zram_compressed = K(zspages); } #elif static void sysstats_fill_zoneinfo(struct sys_memstats *stats) { } #endif static void sysstats_build(struct sys_memstats *stats) { struct sysinfo i; si_meminfo(&i); si_swapinfo(&i); stats->version = SYSSTATS_VERSION; stats->memtotal = K(i.totalram); stats->reclaimable = global_node_page_state(NR_INDIRECTLY_RECLAIMABLE_BYTES) >> 10; stats->swap_used = K(i.totalswap - i.freeswap); stats->swap_total = K(i.totalswap); stats->vmalloc_total = K(vmalloc_nr_pages()); stats->unreclaimable = K(global_node_page_state(NR_UNRECLAIMABLE_PAGES)); stats->buffer = K(i.bufferram); stats->swapcache = K(total_swapcache_pages()); stats->slab_reclaimable = K(global_node_page_state(NR_SLAB_RECLAIMABLE)); stats->slab_unreclaimable = K(global_node_page_state(NR_SLAB_UNRECLAIMABLE)); stats->free_cma = K(global_zone_page_state(NR_FREE_CMA_PAGES)); stats->file_mapped = K(global_node_page_state(NR_FILE_MAPPED)); stats->kernelstack = global_zone_page_state(NR_KERNEL_STACK_KB); stats->pagetable = K(global_zone_page_state(NR_PAGETABLE)); stats->shmem = K(i.sharedram); sysstats_fill_zoneinfo(stats); } #undef K static int sysstats_user_cmd(struct sk_buff *skb, struct genl_info *info) { int rc = 0; struct sk_buff *rep_skb; struct sys_memstats *stats; struct nlattr *na; size_t size; size = nla_total_size(sizeof(struct sys_memstats)); rc = prepare_reply(info, SYSSTATS_CMD_NEW, &rep_skb, size); if (rc < 0) goto err; na = nla_reserve(rep_skb, SYSSTATS_TYPE_SYSMEM_STATS, sizeof(struct sys_memstats)); if (na == NULL) { nlmsg_free(rep_skb); rc = -EMSGSIZE; goto err; } stats = nla_data(na); memset(stats, 0, sizeof(*stats)); sysstats_build(stats); rc = send_reply(rep_skb, info); err: return rc; } static int cgroupstats_user_cmd(struct sk_buff *skb, struct genl_info *info) { int rc = 0; Loading Loading @@ -662,6 +806,11 @@ static const struct genl_ops taskstats_ops[] = { .doit = cgroupstats_user_cmd, .policy = cgroupstats_cmd_get_policy, }, { .cmd = SYSSTATS_CMD_GET, .doit = sysstats_user_cmd, .policy = sysstats_cmd_get_policy, }, }; static struct genl_family family __ro_after_init = { Loading