ia64/linux-2.6.18-xen.hg

view drivers/xen/core/xen_sysfs.c @ 685:b54652ee29ef

xen: fix kdump kernel crash on Xen3.2

The kernel is supposed to create some "Crash note" resources (children
of the "Hypervisor code and data" resource in /proc/iomem). However,
when running on Xen 3.2, xen_machine_kexec_setup_resources()
encounters an error and returns prior to doing this.

The error occurs when it calls the "kexec_get_range" hypercall to
determine the location of the "vmcoreinfo". This was only implemented
in Xen 3.3.

This patch makes the kernel handle this error gracefully by simply not
creating the sysfs file "hypervisor/vmcoreinfo" if the hypervisor is
unable to provide the info - rather than bailing out of
xen_machine_kexec_setup_resources() early.

Signed-off-by: Alex Zeffertt <alex.zeffertt@eu.citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Oct 02 11:29:02 2008 +0100 (2008-10-02)
parents a5bb490065f6
children f40f4f86d5a2
line source
1 /*
2 * copyright (c) 2006 IBM Corporation
3 * Authored by: Mike D. Day <ncmike@us.ibm.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 */
10 #include <linux/err.h>
11 #include <linux/kernel.h>
12 #include <linux/module.h>
13 #include <linux/init.h>
14 #include <asm/hypervisor.h>
15 #include <xen/features.h>
16 #include <xen/hypervisor_sysfs.h>
17 #include <xen/xenbus.h>
18 #include <xen/interface/kexec.h>
20 MODULE_LICENSE("GPL");
21 MODULE_AUTHOR("Mike D. Day <ncmike@us.ibm.com>");
23 static ssize_t type_show(struct hyp_sysfs_attr *attr, char *buffer)
24 {
25 return sprintf(buffer, "xen\n");
26 }
28 HYPERVISOR_ATTR_RO(type);
30 static int __init xen_sysfs_type_init(void)
31 {
32 return sysfs_create_file(&hypervisor_subsys.kset.kobj, &type_attr.attr);
33 }
35 static void xen_sysfs_type_destroy(void)
36 {
37 sysfs_remove_file(&hypervisor_subsys.kset.kobj, &type_attr.attr);
38 }
40 /* xen version attributes */
41 static ssize_t major_show(struct hyp_sysfs_attr *attr, char *buffer)
42 {
43 int version = HYPERVISOR_xen_version(XENVER_version, NULL);
44 if (version)
45 return sprintf(buffer, "%d\n", version >> 16);
46 return -ENODEV;
47 }
49 HYPERVISOR_ATTR_RO(major);
51 static ssize_t minor_show(struct hyp_sysfs_attr *attr, char *buffer)
52 {
53 int version = HYPERVISOR_xen_version(XENVER_version, NULL);
54 if (version)
55 return sprintf(buffer, "%d\n", version & 0xff);
56 return -ENODEV;
57 }
59 HYPERVISOR_ATTR_RO(minor);
61 static ssize_t extra_show(struct hyp_sysfs_attr *attr, char *buffer)
62 {
63 int ret = -ENOMEM;
64 char *extra;
66 extra = kmalloc(XEN_EXTRAVERSION_LEN, GFP_KERNEL);
67 if (extra) {
68 ret = HYPERVISOR_xen_version(XENVER_extraversion, extra);
69 if (!ret)
70 ret = sprintf(buffer, "%s\n", extra);
71 kfree(extra);
72 }
74 return ret;
75 }
77 HYPERVISOR_ATTR_RO(extra);
79 static struct attribute *version_attrs[] = {
80 &major_attr.attr,
81 &minor_attr.attr,
82 &extra_attr.attr,
83 NULL
84 };
86 static struct attribute_group version_group = {
87 .name = "version",
88 .attrs = version_attrs,
89 };
91 static int __init xen_sysfs_version_init(void)
92 {
93 return sysfs_create_group(&hypervisor_subsys.kset.kobj,
94 &version_group);
95 }
97 static void xen_sysfs_version_destroy(void)
98 {
99 sysfs_remove_group(&hypervisor_subsys.kset.kobj, &version_group);
100 }
102 /* UUID */
104 static ssize_t uuid_show(struct hyp_sysfs_attr *attr, char *buffer)
105 {
106 char *vm, *val;
107 int ret;
108 extern int xenstored_ready;
110 if (!xenstored_ready)
111 return -EBUSY;
113 vm = xenbus_read(XBT_NIL, "vm", "", NULL);
114 if (IS_ERR(vm))
115 return PTR_ERR(vm);
116 val = xenbus_read(XBT_NIL, vm, "uuid", NULL);
117 kfree(vm);
118 if (IS_ERR(val))
119 return PTR_ERR(val);
120 ret = sprintf(buffer, "%s\n", val);
121 kfree(val);
122 return ret;
123 }
125 HYPERVISOR_ATTR_RO(uuid);
127 static int __init xen_sysfs_uuid_init(void)
128 {
129 return sysfs_create_file(&hypervisor_subsys.kset.kobj, &uuid_attr.attr);
130 }
132 static void xen_sysfs_uuid_destroy(void)
133 {
134 sysfs_remove_file(&hypervisor_subsys.kset.kobj, &uuid_attr.attr);
135 }
137 /* xen compilation attributes */
139 static ssize_t compiler_show(struct hyp_sysfs_attr *attr, char *buffer)
140 {
141 int ret = -ENOMEM;
142 struct xen_compile_info *info;
144 info = kmalloc(sizeof(struct xen_compile_info), GFP_KERNEL);
145 if (info) {
146 ret = HYPERVISOR_xen_version(XENVER_compile_info, info);
147 if (!ret)
148 ret = sprintf(buffer, "%s\n", info->compiler);
149 kfree(info);
150 }
152 return ret;
153 }
155 HYPERVISOR_ATTR_RO(compiler);
157 static ssize_t compiled_by_show(struct hyp_sysfs_attr *attr, char *buffer)
158 {
159 int ret = -ENOMEM;
160 struct xen_compile_info *info;
162 info = kmalloc(sizeof(struct xen_compile_info), GFP_KERNEL);
163 if (info) {
164 ret = HYPERVISOR_xen_version(XENVER_compile_info, info);
165 if (!ret)
166 ret = sprintf(buffer, "%s\n", info->compile_by);
167 kfree(info);
168 }
170 return ret;
171 }
173 HYPERVISOR_ATTR_RO(compiled_by);
175 static ssize_t compile_date_show(struct hyp_sysfs_attr *attr, char *buffer)
176 {
177 int ret = -ENOMEM;
178 struct xen_compile_info *info;
180 info = kmalloc(sizeof(struct xen_compile_info), GFP_KERNEL);
181 if (info) {
182 ret = HYPERVISOR_xen_version(XENVER_compile_info, info);
183 if (!ret)
184 ret = sprintf(buffer, "%s\n", info->compile_date);
185 kfree(info);
186 }
188 return ret;
189 }
191 HYPERVISOR_ATTR_RO(compile_date);
193 static struct attribute *xen_compile_attrs[] = {
194 &compiler_attr.attr,
195 &compiled_by_attr.attr,
196 &compile_date_attr.attr,
197 NULL
198 };
200 static struct attribute_group xen_compilation_group = {
201 .name = "compilation",
202 .attrs = xen_compile_attrs,
203 };
205 int __init static xen_compilation_init(void)
206 {
207 return sysfs_create_group(&hypervisor_subsys.kset.kobj,
208 &xen_compilation_group);
209 }
211 static void xen_compilation_destroy(void)
212 {
213 sysfs_remove_group(&hypervisor_subsys.kset.kobj,
214 &xen_compilation_group);
215 }
217 /* xen properties info */
219 static ssize_t capabilities_show(struct hyp_sysfs_attr *attr, char *buffer)
220 {
221 int ret = -ENOMEM;
222 char *caps;
224 caps = kmalloc(XEN_CAPABILITIES_INFO_LEN, GFP_KERNEL);
225 if (caps) {
226 ret = HYPERVISOR_xen_version(XENVER_capabilities, caps);
227 if (!ret)
228 ret = sprintf(buffer, "%s\n", caps);
229 kfree(caps);
230 }
232 return ret;
233 }
235 HYPERVISOR_ATTR_RO(capabilities);
237 static ssize_t changeset_show(struct hyp_sysfs_attr *attr, char *buffer)
238 {
239 int ret = -ENOMEM;
240 char *cset;
242 cset = kmalloc(XEN_CHANGESET_INFO_LEN, GFP_KERNEL);
243 if (cset) {
244 ret = HYPERVISOR_xen_version(XENVER_changeset, cset);
245 if (!ret)
246 ret = sprintf(buffer, "%s\n", cset);
247 kfree(cset);
248 }
250 return ret;
251 }
253 HYPERVISOR_ATTR_RO(changeset);
255 static ssize_t virtual_start_show(struct hyp_sysfs_attr *attr, char *buffer)
256 {
257 int ret = -ENOMEM;
258 struct xen_platform_parameters *parms;
260 parms = kmalloc(sizeof(struct xen_platform_parameters), GFP_KERNEL);
261 if (parms) {
262 ret = HYPERVISOR_xen_version(XENVER_platform_parameters,
263 parms);
264 if (!ret)
265 ret = sprintf(buffer, "%lx\n", parms->virt_start);
266 kfree(parms);
267 }
269 return ret;
270 }
272 HYPERVISOR_ATTR_RO(virtual_start);
274 static ssize_t pagesize_show(struct hyp_sysfs_attr *attr, char *buffer)
275 {
276 int ret;
278 ret = HYPERVISOR_xen_version(XENVER_pagesize, NULL);
279 if (ret > 0)
280 ret = sprintf(buffer, "%x\n", ret);
282 return ret;
283 }
285 HYPERVISOR_ATTR_RO(pagesize);
287 /* eventually there will be several more features to export */
288 static ssize_t xen_feature_show(int index, char *buffer)
289 {
290 int ret = -ENOMEM;
291 struct xen_feature_info *info;
293 info = kmalloc(sizeof(struct xen_feature_info), GFP_KERNEL);
294 if (info) {
295 info->submap_idx = index;
296 ret = HYPERVISOR_xen_version(XENVER_get_features, info);
297 if (!ret)
298 ret = sprintf(buffer, "%d\n", info->submap);
299 kfree(info);
300 }
302 return ret;
303 }
305 static ssize_t writable_pt_show(struct hyp_sysfs_attr *attr, char *buffer)
306 {
307 return xen_feature_show(XENFEAT_writable_page_tables, buffer);
308 }
310 HYPERVISOR_ATTR_RO(writable_pt);
312 static struct attribute *xen_properties_attrs[] = {
313 &capabilities_attr.attr,
314 &changeset_attr.attr,
315 &virtual_start_attr.attr,
316 &pagesize_attr.attr,
317 &writable_pt_attr.attr,
318 NULL
319 };
321 static struct attribute_group xen_properties_group = {
322 .name = "properties",
323 .attrs = xen_properties_attrs,
324 };
326 static int __init xen_properties_init(void)
327 {
328 return sysfs_create_group(&hypervisor_subsys.kset.kobj,
329 &xen_properties_group);
330 }
332 static void xen_properties_destroy(void)
333 {
334 sysfs_remove_group(&hypervisor_subsys.kset.kobj,
335 &xen_properties_group);
336 }
338 #ifdef CONFIG_KEXEC
340 static ssize_t vmcoreinfo_show(struct hyp_sysfs_attr *attr, char *page)
341 {
342 return sprintf(page, "%lx %zx\n",
343 paddr_vmcoreinfo_xen, vmcoreinfo_size_xen);
344 }
346 HYPERVISOR_ATTR_RO(vmcoreinfo);
348 static int __init xen_sysfs_vmcoreinfo_init(void)
349 {
350 return sysfs_create_file(&hypervisor_subsys.kset.kobj,
351 &vmcoreinfo_attr.attr);
352 }
354 static void xen_sysfs_vmcoreinfo_destroy(void)
355 {
356 sysfs_remove_file(&hypervisor_subsys.kset.kobj, &vmcoreinfo_attr.attr);
357 }
359 #endif
361 static int __init hyper_sysfs_init(void)
362 {
363 int ret;
365 if (!is_running_on_xen())
366 return -ENODEV;
368 ret = xen_sysfs_type_init();
369 if (ret)
370 goto out;
371 ret = xen_sysfs_version_init();
372 if (ret)
373 goto version_out;
374 ret = xen_compilation_init();
375 if (ret)
376 goto comp_out;
377 ret = xen_sysfs_uuid_init();
378 if (ret)
379 goto uuid_out;
380 ret = xen_properties_init();
381 if (ret)
382 goto prop_out;
383 #ifdef CONFIG_KEXEC
384 if (vmcoreinfo_size_xen != 0) {
385 ret = xen_sysfs_vmcoreinfo_init();
386 if (ret)
387 goto vmcoreinfo_out;
388 }
389 #endif
391 goto out;
393 #ifdef CONFIG_KEXEC
394 vmcoreinfo_out:
395 #endif
396 xen_properties_destroy();
397 prop_out:
398 xen_sysfs_uuid_destroy();
399 uuid_out:
400 xen_compilation_destroy();
401 comp_out:
402 xen_sysfs_version_destroy();
403 version_out:
404 xen_sysfs_type_destroy();
405 out:
406 return ret;
407 }
409 static void __exit hyper_sysfs_exit(void)
410 {
411 #ifdef CONFIG_KEXEC
412 if (vmcoreinfo_size_xen != 0)
413 xen_sysfs_vmcoreinfo_destroy();
414 #endif
415 xen_properties_destroy();
416 xen_compilation_destroy();
417 xen_sysfs_uuid_destroy();
418 xen_sysfs_version_destroy();
419 xen_sysfs_type_destroy();
421 }
423 module_init(hyper_sysfs_init);
424 module_exit(hyper_sysfs_exit);