diff options
author | Heiko Carstens <heiko.carstens@de.ibm.com> | 2012-09-03 03:38:30 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2012-09-26 09:45:07 -0400 |
commit | 0facaa170a6a0255092d3b32325a15672465ac4c (patch) | |
tree | 4f5220dc76f33fbb315751ab7f4d84dccea2ea40 /arch/s390/kernel/sysinfo.c | |
parent | 78609132795b4e3d6d51c6b67d461bf1626afb2f (diff) |
s390/sysinfo: convert /proc/sysinfo to seqfile
The current proc implementation of the /proc/sysinfo file writes all
informations contained in all system information blocks to a single
page.
This is done by calling sprintf all the time in the expectation that
everything will fit into a single page. This however is not necessarily
true if the configuration of a machine is very large.
So convert /proc/sysinfo to avoid writing into random memory regions.
For readability reasons a couple of lines are longer than 80 characters.
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390/kernel/sysinfo.c')
-rw-r--r-- | arch/s390/kernel/sysinfo.c | 282 |
1 files changed, 115 insertions, 167 deletions
diff --git a/arch/s390/kernel/sysinfo.c b/arch/s390/kernel/sysinfo.c index fa0eb238dac7..d3b543c3617a 100644 --- a/arch/s390/kernel/sysinfo.c +++ b/arch/s390/kernel/sysinfo.c | |||
@@ -25,14 +25,14 @@ | |||
25 | static inline int stsi_0(void) | 25 | static inline int stsi_0(void) |
26 | { | 26 | { |
27 | int rc = stsi(NULL, 0, 0, 0); | 27 | int rc = stsi(NULL, 0, 0, 0); |
28 | |||
28 | return rc == -ENOSYS ? rc : (((unsigned int) rc) >> 28); | 29 | return rc == -ENOSYS ? rc : (((unsigned int) rc) >> 28); |
29 | } | 30 | } |
30 | 31 | ||
31 | static int stsi_1_1_1(struct sysinfo_1_1_1 *info, char *page, int len) | 32 | static void stsi_1_1_1(struct seq_file *m, struct sysinfo_1_1_1 *info) |
32 | { | 33 | { |
33 | if (stsi(info, 1, 1, 1) == -ENOSYS) | 34 | if (stsi(info, 1, 1, 1) == -ENOSYS) |
34 | return len; | 35 | return; |
35 | |||
36 | EBCASC(info->manufacturer, sizeof(info->manufacturer)); | 36 | EBCASC(info->manufacturer, sizeof(info->manufacturer)); |
37 | EBCASC(info->type, sizeof(info->type)); | 37 | EBCASC(info->type, sizeof(info->type)); |
38 | EBCASC(info->model, sizeof(info->model)); | 38 | EBCASC(info->model, sizeof(info->model)); |
@@ -41,58 +41,45 @@ static int stsi_1_1_1(struct sysinfo_1_1_1 *info, char *page, int len) | |||
41 | EBCASC(info->model_capacity, sizeof(info->model_capacity)); | 41 | EBCASC(info->model_capacity, sizeof(info->model_capacity)); |
42 | EBCASC(info->model_perm_cap, sizeof(info->model_perm_cap)); | 42 | EBCASC(info->model_perm_cap, sizeof(info->model_perm_cap)); |
43 | EBCASC(info->model_temp_cap, sizeof(info->model_temp_cap)); | 43 | EBCASC(info->model_temp_cap, sizeof(info->model_temp_cap)); |
44 | len += sprintf(page + len, "Manufacturer: %-16.16s\n", | 44 | seq_printf(m, "Manufacturer: %-16.16s\n", info->manufacturer); |
45 | info->manufacturer); | 45 | seq_printf(m, "Type: %-4.4s\n", info->type); |
46 | len += sprintf(page + len, "Type: %-4.4s\n", | 46 | /* |
47 | info->type); | 47 | * Sigh: the model field has been renamed with System z9 |
48 | * to model_capacity and a new model field has been added | ||
49 | * after the plant field. To avoid confusing older programs | ||
50 | * the "Model:" prints "model_capacity model" or just | ||
51 | * "model_capacity" if the model string is empty . | ||
52 | */ | ||
53 | seq_printf(m, "Model: %-16.16s", info->model_capacity); | ||
48 | if (info->model[0] != '\0') | 54 | if (info->model[0] != '\0') |
49 | /* | 55 | seq_printf(m, " %-16.16s", info->model); |
50 | * Sigh: the model field has been renamed with System z9 | 56 | seq_putc(m, '\n'); |
51 | * to model_capacity and a new model field has been added | 57 | seq_printf(m, "Sequence Code: %-16.16s\n", info->sequence); |
52 | * after the plant field. To avoid confusing older programs | 58 | seq_printf(m, "Plant: %-4.4s\n", info->plant); |
53 | * the "Model:" prints "model_capacity model" or just | 59 | seq_printf(m, "Model Capacity: %-16.16s %08u\n", |
54 | * "model_capacity" if the model string is empty . | 60 | info->model_capacity, *(u32 *) info->model_cap_rating); |
55 | */ | ||
56 | len += sprintf(page + len, | ||
57 | "Model: %-16.16s %-16.16s\n", | ||
58 | info->model_capacity, info->model); | ||
59 | else | ||
60 | len += sprintf(page + len, "Model: %-16.16s\n", | ||
61 | info->model_capacity); | ||
62 | len += sprintf(page + len, "Sequence Code: %-16.16s\n", | ||
63 | info->sequence); | ||
64 | len += sprintf(page + len, "Plant: %-4.4s\n", | ||
65 | info->plant); | ||
66 | len += sprintf(page + len, "Model Capacity: %-16.16s %08u\n", | ||
67 | info->model_capacity, *(u32 *) info->model_cap_rating); | ||
68 | if (info->model_perm_cap[0] != '\0') | 61 | if (info->model_perm_cap[0] != '\0') |
69 | len += sprintf(page + len, | 62 | seq_printf(m, "Model Perm. Capacity: %-16.16s %08u\n", |
70 | "Model Perm. Capacity: %-16.16s %08u\n", | 63 | info->model_perm_cap, |
71 | info->model_perm_cap, | 64 | *(u32 *) info->model_perm_cap_rating); |
72 | *(u32 *) info->model_perm_cap_rating); | ||
73 | if (info->model_temp_cap[0] != '\0') | 65 | if (info->model_temp_cap[0] != '\0') |
74 | len += sprintf(page + len, | 66 | seq_printf(m, "Model Temp. Capacity: %-16.16s %08u\n", |
75 | "Model Temp. Capacity: %-16.16s %08u\n", | 67 | info->model_temp_cap, |
76 | info->model_temp_cap, | 68 | *(u32 *) info->model_temp_cap_rating); |
77 | *(u32 *) info->model_temp_cap_rating); | ||
78 | if (info->cai) { | 69 | if (info->cai) { |
79 | len += sprintf(page + len, | 70 | seq_printf(m, "Capacity Adj. Ind.: %d\n", info->cai); |
80 | "Capacity Adj. Ind.: %d\n", | 71 | seq_printf(m, "Capacity Ch. Reason: %d\n", info->ccr); |
81 | info->cai); | ||
82 | len += sprintf(page + len, "Capacity Ch. Reason: %d\n", | ||
83 | info->ccr); | ||
84 | } | 72 | } |
85 | return len; | ||
86 | } | 73 | } |
87 | 74 | ||
88 | static int stsi_15_1_x(struct sysinfo_15_1_x *info, char *page, int len) | 75 | static void stsi_15_1_x(struct seq_file *m, struct sysinfo_15_1_x *info) |
89 | { | 76 | { |
90 | static int max_mnest; | 77 | static int max_mnest; |
91 | int i, rc; | 78 | int i, rc; |
92 | 79 | ||
93 | len += sprintf(page + len, "\n"); | 80 | seq_putc(m, '\n'); |
94 | if (!MACHINE_HAS_TOPOLOGY) | 81 | if (!MACHINE_HAS_TOPOLOGY) |
95 | return len; | 82 | return; |
96 | if (max_mnest) { | 83 | if (max_mnest) { |
97 | stsi(info, 15, 1, max_mnest); | 84 | stsi(info, 15, 1, max_mnest); |
98 | } else { | 85 | } else { |
@@ -102,181 +89,142 @@ static int stsi_15_1_x(struct sysinfo_15_1_x *info, char *page, int len) | |||
102 | break; | 89 | break; |
103 | } | 90 | } |
104 | } | 91 | } |
105 | len += sprintf(page + len, "CPU Topology HW: "); | 92 | seq_printf(m, "CPU Topology HW: "); |
106 | for (i = 0; i < TOPOLOGY_NR_MAG; i++) | 93 | for (i = 0; i < TOPOLOGY_NR_MAG; i++) |
107 | len += sprintf(page + len, " %d", info->mag[i]); | 94 | seq_printf(m, " %d", info->mag[i]); |
108 | len += sprintf(page + len, "\n"); | 95 | seq_putc(m, '\n'); |
109 | #ifdef CONFIG_SCHED_MC | 96 | #ifdef CONFIG_SCHED_MC |
110 | store_topology(info); | 97 | store_topology(info); |
111 | len += sprintf(page + len, "CPU Topology SW: "); | 98 | seq_printf(m, "CPU Topology SW: "); |
112 | for (i = 0; i < TOPOLOGY_NR_MAG; i++) | 99 | for (i = 0; i < TOPOLOGY_NR_MAG; i++) |
113 | len += sprintf(page + len, " %d", info->mag[i]); | 100 | seq_printf(m, " %d", info->mag[i]); |
114 | len += sprintf(page + len, "\n"); | 101 | seq_putc(m, '\n'); |
115 | #endif | 102 | #endif |
116 | return len; | ||
117 | } | 103 | } |
118 | 104 | ||
119 | static int stsi_1_2_2(struct sysinfo_1_2_2 *info, char *page, int len) | 105 | static void stsi_1_2_2(struct seq_file *m, struct sysinfo_1_2_2 *info) |
120 | { | 106 | { |
121 | struct sysinfo_1_2_2_extension *ext; | 107 | struct sysinfo_1_2_2_extension *ext; |
122 | int i; | 108 | int i; |
123 | 109 | ||
124 | if (stsi(info, 1, 2, 2) == -ENOSYS) | 110 | if (stsi(info, 1, 2, 2) == -ENOSYS) |
125 | return len; | 111 | return; |
126 | ext = (struct sysinfo_1_2_2_extension *) | 112 | ext = (struct sysinfo_1_2_2_extension *) |
127 | ((unsigned long) info + info->acc_offset); | 113 | ((unsigned long) info + info->acc_offset); |
128 | 114 | seq_printf(m, "CPUs Total: %d\n", info->cpus_total); | |
129 | len += sprintf(page + len, "CPUs Total: %d\n", | 115 | seq_printf(m, "CPUs Configured: %d\n", info->cpus_configured); |
130 | info->cpus_total); | 116 | seq_printf(m, "CPUs Standby: %d\n", info->cpus_standby); |
131 | len += sprintf(page + len, "CPUs Configured: %d\n", | 117 | seq_printf(m, "CPUs Reserved: %d\n", info->cpus_reserved); |
132 | info->cpus_configured); | 118 | /* |
133 | len += sprintf(page + len, "CPUs Standby: %d\n", | 119 | * Sigh 2. According to the specification the alternate |
134 | info->cpus_standby); | 120 | * capability field is a 32 bit floating point number |
135 | len += sprintf(page + len, "CPUs Reserved: %d\n", | 121 | * if the higher order 8 bits are not zero. Printing |
136 | info->cpus_reserved); | 122 | * a floating point number in the kernel is a no-no, |
137 | 123 | * always print the number as 32 bit unsigned integer. | |
138 | if (info->format == 1) { | 124 | * The user-space needs to know about the strange |
139 | /* | 125 | * encoding of the alternate cpu capability. |
140 | * Sigh 2. According to the specification the alternate | 126 | */ |
141 | * capability field is a 32 bit floating point number | 127 | seq_printf(m, "Capability: %u", info->capability); |
142 | * if the higher order 8 bits are not zero. Printing | 128 | if (info->format == 1) |
143 | * a floating point number in the kernel is a no-no, | 129 | seq_printf(m, " %u", ext->alt_capability); |
144 | * always print the number as 32 bit unsigned integer. | 130 | seq_putc(m, '\n'); |
145 | * The user-space needs to know about the strange | 131 | for (i = 2; i <= info->cpus_total; i++) { |
146 | * encoding of the alternate cpu capability. | 132 | seq_printf(m, "Adjustment %02d-way: %u", |
147 | */ | 133 | i, info->adjustment[i-2]); |
148 | len += sprintf(page + len, "Capability: %u %u\n", | 134 | if (info->format == 1) |
149 | info->capability, ext->alt_capability); | 135 | seq_printf(m, " %u", ext->alt_adjustment[i-2]); |
150 | for (i = 2; i <= info->cpus_total; i++) | 136 | seq_putc(m, '\n'); |
151 | len += sprintf(page + len, | ||
152 | "Adjustment %02d-way: %u %u\n", | ||
153 | i, info->adjustment[i-2], | ||
154 | ext->alt_adjustment[i-2]); | ||
155 | |||
156 | } else { | ||
157 | len += sprintf(page + len, "Capability: %u\n", | ||
158 | info->capability); | ||
159 | for (i = 2; i <= info->cpus_total; i++) | ||
160 | len += sprintf(page + len, | ||
161 | "Adjustment %02d-way: %u\n", | ||
162 | i, info->adjustment[i-2]); | ||
163 | } | 137 | } |
164 | 138 | if (info->secondary_capability) | |
165 | if (info->secondary_capability != 0) | 139 | seq_printf(m, "Secondary Capability: %d\n", |
166 | len += sprintf(page + len, "Secondary Capability: %d\n", | 140 | info->secondary_capability); |
167 | info->secondary_capability); | ||
168 | return len; | ||
169 | } | 141 | } |
170 | 142 | ||
171 | static int stsi_2_2_2(struct sysinfo_2_2_2 *info, char *page, int len) | 143 | static void stsi_2_2_2(struct seq_file *m, struct sysinfo_2_2_2 *info) |
172 | { | 144 | { |
173 | if (stsi(info, 2, 2, 2) == -ENOSYS) | 145 | if (stsi(info, 2, 2, 2) == -ENOSYS) |
174 | return len; | 146 | return; |
175 | |||
176 | EBCASC(info->name, sizeof(info->name)); | 147 | EBCASC(info->name, sizeof(info->name)); |
177 | 148 | seq_putc(m, '\n'); | |
178 | len += sprintf(page + len, "\n"); | 149 | seq_printf(m, "LPAR Number: %d\n", info->lpar_number); |
179 | len += sprintf(page + len, "LPAR Number: %d\n", | 150 | seq_printf(m, "LPAR Characteristics: "); |
180 | info->lpar_number); | ||
181 | |||
182 | len += sprintf(page + len, "LPAR Characteristics: "); | ||
183 | if (info->characteristics & LPAR_CHAR_DEDICATED) | 151 | if (info->characteristics & LPAR_CHAR_DEDICATED) |
184 | len += sprintf(page + len, "Dedicated "); | 152 | seq_printf(m, "Dedicated "); |
185 | if (info->characteristics & LPAR_CHAR_SHARED) | 153 | if (info->characteristics & LPAR_CHAR_SHARED) |
186 | len += sprintf(page + len, "Shared "); | 154 | seq_printf(m, "Shared "); |
187 | if (info->characteristics & LPAR_CHAR_LIMITED) | 155 | if (info->characteristics & LPAR_CHAR_LIMITED) |
188 | len += sprintf(page + len, "Limited "); | 156 | seq_printf(m, "Limited "); |
189 | len += sprintf(page + len, "\n"); | 157 | seq_putc(m, '\n'); |
190 | 158 | seq_printf(m, "LPAR Name: %-8.8s\n", info->name); | |
191 | len += sprintf(page + len, "LPAR Name: %-8.8s\n", | 159 | seq_printf(m, "LPAR Adjustment: %d\n", info->caf); |
192 | info->name); | 160 | seq_printf(m, "LPAR CPUs Total: %d\n", info->cpus_total); |
193 | 161 | seq_printf(m, "LPAR CPUs Configured: %d\n", info->cpus_configured); | |
194 | len += sprintf(page + len, "LPAR Adjustment: %d\n", | 162 | seq_printf(m, "LPAR CPUs Standby: %d\n", info->cpus_standby); |
195 | info->caf); | 163 | seq_printf(m, "LPAR CPUs Reserved: %d\n", info->cpus_reserved); |
196 | 164 | seq_printf(m, "LPAR CPUs Dedicated: %d\n", info->cpus_dedicated); | |
197 | len += sprintf(page + len, "LPAR CPUs Total: %d\n", | 165 | seq_printf(m, "LPAR CPUs Shared: %d\n", info->cpus_shared); |
198 | info->cpus_total); | ||
199 | len += sprintf(page + len, "LPAR CPUs Configured: %d\n", | ||
200 | info->cpus_configured); | ||
201 | len += sprintf(page + len, "LPAR CPUs Standby: %d\n", | ||
202 | info->cpus_standby); | ||
203 | len += sprintf(page + len, "LPAR CPUs Reserved: %d\n", | ||
204 | info->cpus_reserved); | ||
205 | len += sprintf(page + len, "LPAR CPUs Dedicated: %d\n", | ||
206 | info->cpus_dedicated); | ||
207 | len += sprintf(page + len, "LPAR CPUs Shared: %d\n", | ||
208 | info->cpus_shared); | ||
209 | return len; | ||
210 | } | 166 | } |
211 | 167 | ||
212 | static int stsi_3_2_2(struct sysinfo_3_2_2 *info, char *page, int len) | 168 | static void stsi_3_2_2(struct seq_file *m, struct sysinfo_3_2_2 *info) |
213 | { | 169 | { |
214 | int i; | 170 | int i; |
215 | 171 | ||
216 | if (stsi(info, 3, 2, 2) == -ENOSYS) | 172 | if (stsi(info, 3, 2, 2) == -ENOSYS) |
217 | return len; | 173 | return; |
218 | for (i = 0; i < info->count; i++) { | 174 | for (i = 0; i < info->count; i++) { |
219 | EBCASC(info->vm[i].name, sizeof(info->vm[i].name)); | 175 | EBCASC(info->vm[i].name, sizeof(info->vm[i].name)); |
220 | EBCASC(info->vm[i].cpi, sizeof(info->vm[i].cpi)); | 176 | EBCASC(info->vm[i].cpi, sizeof(info->vm[i].cpi)); |
221 | len += sprintf(page + len, "\n"); | 177 | seq_putc(m, '\n'); |
222 | len += sprintf(page + len, "VM%02d Name: %-8.8s\n", | 178 | seq_printf(m, "VM%02d Name: %-8.8s\n", i, info->vm[i].name); |
223 | i, info->vm[i].name); | 179 | seq_printf(m, "VM%02d Control Program: %-16.16s\n", i, info->vm[i].cpi); |
224 | len += sprintf(page + len, "VM%02d Control Program: %-16.16s\n", | 180 | seq_printf(m, "VM%02d Adjustment: %d\n", i, info->vm[i].caf); |
225 | i, info->vm[i].cpi); | 181 | seq_printf(m, "VM%02d CPUs Total: %d\n", i, info->vm[i].cpus_total); |
226 | 182 | seq_printf(m, "VM%02d CPUs Configured: %d\n", i, info->vm[i].cpus_configured); | |
227 | len += sprintf(page + len, "VM%02d Adjustment: %d\n", | 183 | seq_printf(m, "VM%02d CPUs Standby: %d\n", i, info->vm[i].cpus_standby); |
228 | i, info->vm[i].caf); | 184 | seq_printf(m, "VM%02d CPUs Reserved: %d\n", i, info->vm[i].cpus_reserved); |
229 | |||
230 | len += sprintf(page + len, "VM%02d CPUs Total: %d\n", | ||
231 | i, info->vm[i].cpus_total); | ||
232 | len += sprintf(page + len, "VM%02d CPUs Configured: %d\n", | ||
233 | i, info->vm[i].cpus_configured); | ||
234 | len += sprintf(page + len, "VM%02d CPUs Standby: %d\n", | ||
235 | i, info->vm[i].cpus_standby); | ||
236 | len += sprintf(page + len, "VM%02d CPUs Reserved: %d\n", | ||
237 | i, info->vm[i].cpus_reserved); | ||
238 | } | 185 | } |
239 | return len; | ||
240 | } | 186 | } |
241 | 187 | ||
242 | static int proc_read_sysinfo(char *page, char **start, | 188 | static int sysinfo_show(struct seq_file *m, void *v) |
243 | off_t off, int count, | ||
244 | int *eof, void *data) | ||
245 | { | 189 | { |
246 | unsigned long info = get_zeroed_page(GFP_KERNEL); | 190 | void *info = (void *)get_zeroed_page(GFP_KERNEL); |
247 | int level, len; | 191 | int level; |
248 | 192 | ||
249 | if (!info) | 193 | if (!info) |
250 | return 0; | 194 | return 0; |
251 | |||
252 | len = 0; | ||
253 | level = stsi_0(); | 195 | level = stsi_0(); |
254 | if (level >= 1) | 196 | if (level >= 1) |
255 | len = stsi_1_1_1((struct sysinfo_1_1_1 *) info, page, len); | 197 | stsi_1_1_1(m, info); |
256 | |||
257 | if (level >= 1) | 198 | if (level >= 1) |
258 | len = stsi_15_1_x((struct sysinfo_15_1_x *) info, page, len); | 199 | stsi_15_1_x(m, info); |
259 | |||
260 | if (level >= 1) | 200 | if (level >= 1) |
261 | len = stsi_1_2_2((struct sysinfo_1_2_2 *) info, page, len); | 201 | stsi_1_2_2(m, info); |
262 | |||
263 | if (level >= 2) | 202 | if (level >= 2) |
264 | len = stsi_2_2_2((struct sysinfo_2_2_2 *) info, page, len); | 203 | stsi_2_2_2(m, info); |
265 | |||
266 | if (level >= 3) | 204 | if (level >= 3) |
267 | len = stsi_3_2_2((struct sysinfo_3_2_2 *) info, page, len); | 205 | stsi_3_2_2(m, info); |
206 | free_page((unsigned long)info); | ||
207 | return 0; | ||
208 | } | ||
268 | 209 | ||
269 | free_page(info); | 210 | static int sysinfo_open(struct inode *inode, struct file *file) |
270 | return len; | 211 | { |
212 | return single_open(file, sysinfo_show, NULL); | ||
271 | } | 213 | } |
272 | 214 | ||
273 | static __init int create_proc_sysinfo(void) | 215 | static const struct file_operations sysinfo_fops = { |
216 | .open = sysinfo_open, | ||
217 | .read = seq_read, | ||
218 | .llseek = seq_lseek, | ||
219 | .release = single_release, | ||
220 | }; | ||
221 | |||
222 | static int __init sysinfo_create_proc(void) | ||
274 | { | 223 | { |
275 | create_proc_read_entry("sysinfo", 0444, NULL, | 224 | proc_create("sysinfo", 0444, NULL, &sysinfo_fops); |
276 | proc_read_sysinfo, NULL); | ||
277 | return 0; | 225 | return 0; |
278 | } | 226 | } |
279 | device_initcall(create_proc_sysinfo); | 227 | device_initcall(sysinfo_create_proc); |
280 | 228 | ||
281 | /* | 229 | /* |
282 | * Service levels interface. | 230 | * Service levels interface. |