1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Data gathering module for Linux-VM Monitor Stream, Stage 1. |
4 | * Collects data related to memory management. |
5 | * |
6 | * Copyright IBM Corp. 2003, 2006 |
7 | * |
8 | * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com> |
9 | */ |
10 | |
11 | #include <linux/module.h> |
12 | #include <linux/init.h> |
13 | #include <linux/errno.h> |
14 | #include <linux/kernel_stat.h> |
15 | #include <linux/pagemap.h> |
16 | #include <linux/swap.h> |
17 | #include <linux/slab.h> |
18 | #include <linux/io.h> |
19 | |
20 | #include "appldata.h" |
21 | |
22 | |
23 | #define P2K(x) ((x) << (PAGE_SHIFT - 10)) /* Converts #Pages to KB */ |
24 | |
25 | /* |
26 | * Memory data |
27 | * |
28 | * This is accessed as binary data by z/VM. If changes to it can't be avoided, |
29 | * the structure version (product ID, see appldata_base.c) needs to be changed |
30 | * as well and all documentation and z/VM applications using it must be |
31 | * updated. |
32 | */ |
33 | struct appldata_mem_data { |
34 | u64 timestamp; |
35 | u32 sync_count_1; /* after VM collected the record data, */ |
36 | u32 sync_count_2; /* sync_count_1 and sync_count_2 should be the |
37 | same. If not, the record has been updated on |
38 | the Linux side while VM was collecting the |
39 | (possibly corrupt) data */ |
40 | |
41 | u64 pgpgin; /* data read from disk */ |
42 | u64 pgpgout; /* data written to disk */ |
43 | u64 pswpin; /* pages swapped in */ |
44 | u64 pswpout; /* pages swapped out */ |
45 | |
46 | u64 sharedram; /* sharedram is currently set to 0 */ |
47 | |
48 | u64 totalram; /* total main memory size */ |
49 | u64 freeram; /* free main memory size */ |
50 | u64 totalhigh; /* total high memory size */ |
51 | u64 freehigh; /* free high memory size */ |
52 | |
53 | u64 bufferram; /* memory reserved for buffers, free cache */ |
54 | u64 cached; /* size of (used) cache, w/o buffers */ |
55 | u64 totalswap; /* total swap space size */ |
56 | u64 freeswap; /* free swap space */ |
57 | |
58 | // New in 2.6 --> |
59 | u64 pgalloc; /* page allocations */ |
60 | u64 pgfault; /* page faults (major+minor) */ |
61 | u64 pgmajfault; /* page faults (major only) */ |
62 | // <-- New in 2.6 |
63 | |
64 | } __packed; |
65 | |
66 | |
67 | /* |
68 | * appldata_get_mem_data() |
69 | * |
70 | * gather memory data |
71 | */ |
72 | static void appldata_get_mem_data(void *data) |
73 | { |
74 | /* |
75 | * don't put large structures on the stack, we are |
76 | * serialized through the appldata_ops_mutex and can use static |
77 | */ |
78 | static struct sysinfo val; |
79 | unsigned long ev[NR_VM_EVENT_ITEMS]; |
80 | struct appldata_mem_data *mem_data; |
81 | |
82 | mem_data = data; |
83 | mem_data->sync_count_1++; |
84 | |
85 | all_vm_events(ev); |
86 | mem_data->pgpgin = ev[PGPGIN] >> 1; |
87 | mem_data->pgpgout = ev[PGPGOUT] >> 1; |
88 | mem_data->pswpin = ev[PSWPIN]; |
89 | mem_data->pswpout = ev[PSWPOUT]; |
90 | mem_data->pgalloc = ev[PGALLOC_NORMAL]; |
91 | mem_data->pgalloc += ev[PGALLOC_DMA]; |
92 | mem_data->pgfault = ev[PGFAULT]; |
93 | mem_data->pgmajfault = ev[PGMAJFAULT]; |
94 | |
95 | si_meminfo(val: &val); |
96 | mem_data->sharedram = val.sharedram; |
97 | mem_data->totalram = P2K(val.totalram); |
98 | mem_data->freeram = P2K(val.freeram); |
99 | mem_data->totalhigh = P2K(val.totalhigh); |
100 | mem_data->freehigh = P2K(val.freehigh); |
101 | mem_data->bufferram = P2K(val.bufferram); |
102 | mem_data->cached = P2K(global_node_page_state(NR_FILE_PAGES) |
103 | - val.bufferram); |
104 | |
105 | si_swapinfo(&val); |
106 | mem_data->totalswap = P2K(val.totalswap); |
107 | mem_data->freeswap = P2K(val.freeswap); |
108 | |
109 | mem_data->timestamp = get_tod_clock(); |
110 | mem_data->sync_count_2++; |
111 | } |
112 | |
113 | |
114 | static struct appldata_ops ops = { |
115 | .name = "mem" , |
116 | .record_nr = APPLDATA_RECORD_MEM_ID, |
117 | .size = sizeof(struct appldata_mem_data), |
118 | .callback = &appldata_get_mem_data, |
119 | .owner = THIS_MODULE, |
120 | .mod_lvl = {0xF0, 0xF0}, /* EBCDIC "00" */ |
121 | }; |
122 | |
123 | |
124 | /* |
125 | * appldata_mem_init() |
126 | * |
127 | * init_data, register ops |
128 | */ |
129 | static int __init appldata_mem_init(void) |
130 | { |
131 | int ret; |
132 | |
133 | ops.data = kzalloc(size: sizeof(struct appldata_mem_data), GFP_KERNEL); |
134 | if (!ops.data) |
135 | return -ENOMEM; |
136 | |
137 | ret = appldata_register_ops(ops: &ops); |
138 | if (ret) |
139 | kfree(objp: ops.data); |
140 | |
141 | return ret; |
142 | } |
143 | |
144 | /* |
145 | * appldata_mem_exit() |
146 | * |
147 | * unregister ops |
148 | */ |
149 | static void __exit appldata_mem_exit(void) |
150 | { |
151 | appldata_unregister_ops(ops: &ops); |
152 | kfree(objp: ops.data); |
153 | } |
154 | |
155 | |
156 | module_init(appldata_mem_init); |
157 | module_exit(appldata_mem_exit); |
158 | |
159 | MODULE_LICENSE("GPL" ); |
160 | MODULE_AUTHOR("Gerald Schaefer" ); |
161 | MODULE_DESCRIPTION("Linux-VM Monitor Stream, MEMORY statistics" ); |
162 | |