1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Hypervisor filesystem for Linux on s390. z/VM implementation. |
4 | * |
5 | * Copyright IBM Corp. 2006 |
6 | * Author(s): Michael Holzheu <holzheu@de.ibm.com> |
7 | */ |
8 | |
9 | #include <linux/types.h> |
10 | #include <linux/errno.h> |
11 | #include <linux/string.h> |
12 | #include <linux/vmalloc.h> |
13 | #include <asm/extable.h> |
14 | #include <asm/diag.h> |
15 | #include <asm/ebcdic.h> |
16 | #include <asm/timex.h> |
17 | #include "hypfs_vm.h" |
18 | #include "hypfs.h" |
19 | |
20 | #define ATTRIBUTE(dir, name, member) \ |
21 | do { \ |
22 | void *rc; \ |
23 | rc = hypfs_create_u64(dir, name, member); \ |
24 | if (IS_ERR(rc)) \ |
25 | return PTR_ERR(rc); \ |
26 | } while (0) |
27 | |
28 | static int hypfs_vm_create_guest(struct dentry *systems_dir, |
29 | struct diag2fc_data *data) |
30 | { |
31 | char guest_name[DIAG2FC_NAME_LEN + 1] = {}; |
32 | struct dentry *guest_dir, *cpus_dir, *samples_dir, *mem_dir; |
33 | int dedicated_flag, capped_value; |
34 | |
35 | capped_value = (data->flags & 0x00000006) >> 1; |
36 | dedicated_flag = (data->flags & 0x00000008) >> 3; |
37 | |
38 | /* guest dir */ |
39 | memcpy(guest_name, data->guest_name, DIAG2FC_NAME_LEN); |
40 | EBCASC(guest_name, DIAG2FC_NAME_LEN); |
41 | strim(guest_name); |
42 | guest_dir = hypfs_mkdir(parent: systems_dir, name: guest_name); |
43 | if (IS_ERR(ptr: guest_dir)) |
44 | return PTR_ERR(ptr: guest_dir); |
45 | ATTRIBUTE(guest_dir, "onlinetime_us" , data->el_time); |
46 | |
47 | /* logical cpu information */ |
48 | cpus_dir = hypfs_mkdir(parent: guest_dir, name: "cpus" ); |
49 | if (IS_ERR(ptr: cpus_dir)) |
50 | return PTR_ERR(ptr: cpus_dir); |
51 | ATTRIBUTE(cpus_dir, "cputime_us" , data->used_cpu); |
52 | ATTRIBUTE(cpus_dir, "capped" , capped_value); |
53 | ATTRIBUTE(cpus_dir, "dedicated" , dedicated_flag); |
54 | ATTRIBUTE(cpus_dir, "count" , data->vcpus); |
55 | /* |
56 | * Note: The "weight_min" attribute got the wrong name. |
57 | * The value represents the number of non-stopped (operating) |
58 | * CPUS. |
59 | */ |
60 | ATTRIBUTE(cpus_dir, "weight_min" , data->ocpus); |
61 | ATTRIBUTE(cpus_dir, "weight_max" , data->cpu_max); |
62 | ATTRIBUTE(cpus_dir, "weight_cur" , data->cpu_shares); |
63 | |
64 | /* memory information */ |
65 | mem_dir = hypfs_mkdir(parent: guest_dir, name: "mem" ); |
66 | if (IS_ERR(ptr: mem_dir)) |
67 | return PTR_ERR(ptr: mem_dir); |
68 | ATTRIBUTE(mem_dir, "min_KiB" , data->mem_min_kb); |
69 | ATTRIBUTE(mem_dir, "max_KiB" , data->mem_max_kb); |
70 | ATTRIBUTE(mem_dir, "used_KiB" , data->mem_used_kb); |
71 | ATTRIBUTE(mem_dir, "share_KiB" , data->mem_share_kb); |
72 | |
73 | /* samples */ |
74 | samples_dir = hypfs_mkdir(parent: guest_dir, name: "samples" ); |
75 | if (IS_ERR(ptr: samples_dir)) |
76 | return PTR_ERR(ptr: samples_dir); |
77 | ATTRIBUTE(samples_dir, "cpu_using" , data->cpu_use_samp); |
78 | ATTRIBUTE(samples_dir, "cpu_delay" , data->cpu_delay_samp); |
79 | ATTRIBUTE(samples_dir, "mem_delay" , data->page_wait_samp); |
80 | ATTRIBUTE(samples_dir, "idle" , data->idle_samp); |
81 | ATTRIBUTE(samples_dir, "other" , data->other_samp); |
82 | ATTRIBUTE(samples_dir, "total" , data->total_samp); |
83 | return 0; |
84 | } |
85 | |
86 | int hypfs_vm_create_files(struct dentry *root) |
87 | { |
88 | struct dentry *dir, *file; |
89 | struct diag2fc_data *data; |
90 | unsigned int count = 0; |
91 | int rc, i; |
92 | |
93 | data = diag2fc_store(query: diag2fc_guest_query, count: &count, offset: 0); |
94 | if (IS_ERR(ptr: data)) |
95 | return PTR_ERR(ptr: data); |
96 | |
97 | /* Hypervisor Info */ |
98 | dir = hypfs_mkdir(parent: root, name: "hyp" ); |
99 | if (IS_ERR(ptr: dir)) { |
100 | rc = PTR_ERR(ptr: dir); |
101 | goto failed; |
102 | } |
103 | file = hypfs_create_str(dir, name: "type" , string: "z/VM Hypervisor" ); |
104 | if (IS_ERR(ptr: file)) { |
105 | rc = PTR_ERR(ptr: file); |
106 | goto failed; |
107 | } |
108 | |
109 | /* physical cpus */ |
110 | dir = hypfs_mkdir(parent: root, name: "cpus" ); |
111 | if (IS_ERR(ptr: dir)) { |
112 | rc = PTR_ERR(ptr: dir); |
113 | goto failed; |
114 | } |
115 | file = hypfs_create_u64(dir, name: "count" , value: data->lcpus); |
116 | if (IS_ERR(ptr: file)) { |
117 | rc = PTR_ERR(ptr: file); |
118 | goto failed; |
119 | } |
120 | |
121 | /* guests */ |
122 | dir = hypfs_mkdir(parent: root, name: "systems" ); |
123 | if (IS_ERR(ptr: dir)) { |
124 | rc = PTR_ERR(ptr: dir); |
125 | goto failed; |
126 | } |
127 | |
128 | for (i = 0; i < count; i++) { |
129 | rc = hypfs_vm_create_guest(systems_dir: dir, data: &data[i]); |
130 | if (rc) |
131 | goto failed; |
132 | } |
133 | diag2fc_free(data); |
134 | return 0; |
135 | |
136 | failed: |
137 | diag2fc_free(data); |
138 | return rc; |
139 | } |
140 | |