0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/types.h>
0010 #include <linux/errno.h>
0011 #include <linux/string.h>
0012 #include <linux/vmalloc.h>
0013 #include <asm/extable.h>
0014 #include <asm/diag.h>
0015 #include <asm/ebcdic.h>
0016 #include <asm/timex.h>
0017 #include "hypfs.h"
0018
0019 #define NAME_LEN 8
0020 #define DBFS_D2FC_HDR_VERSION 0
0021
0022 static char local_guest[] = " ";
0023 static char all_guests[] = "* ";
0024 static char *all_groups = all_guests;
0025 static char *guest_query;
0026
0027 struct diag2fc_data {
0028 __u32 version;
0029 __u32 flags;
0030 __u64 used_cpu;
0031 __u64 el_time;
0032 __u64 mem_min_kb;
0033 __u64 mem_max_kb;
0034 __u64 mem_share_kb;
0035 __u64 mem_used_kb;
0036 __u32 pcpus;
0037 __u32 lcpus;
0038 __u32 vcpus;
0039 __u32 ocpus;
0040 __u32 cpu_max;
0041 __u32 cpu_shares;
0042 __u32 cpu_use_samp;
0043 __u32 cpu_delay_samp;
0044 __u32 page_wait_samp;
0045 __u32 idle_samp;
0046 __u32 other_samp;
0047 __u32 total_samp;
0048 char guest_name[NAME_LEN];
0049 };
0050
0051 struct diag2fc_parm_list {
0052 char userid[NAME_LEN];
0053 char aci_grp[NAME_LEN];
0054 __u64 addr;
0055 __u32 size;
0056 __u32 fmt;
0057 };
0058
0059 static int diag2fc(int size, char* query, void *addr)
0060 {
0061 unsigned long residual_cnt;
0062 unsigned long rc;
0063 struct diag2fc_parm_list parm_list;
0064
0065 memcpy(parm_list.userid, query, NAME_LEN);
0066 ASCEBC(parm_list.userid, NAME_LEN);
0067 memcpy(parm_list.aci_grp, all_groups, NAME_LEN);
0068 ASCEBC(parm_list.aci_grp, NAME_LEN);
0069 parm_list.addr = (unsigned long)addr;
0070 parm_list.size = size;
0071 parm_list.fmt = 0x02;
0072 rc = -1;
0073
0074 diag_stat_inc(DIAG_STAT_X2FC);
0075 asm volatile(
0076 " diag %0,%1,0x2fc\n"
0077 "0: nopr %%r7\n"
0078 EX_TABLE(0b,0b)
0079 : "=d" (residual_cnt), "+d" (rc) : "0" (&parm_list) : "memory");
0080
0081 if ((rc != 0 ) && (rc != -2))
0082 return rc;
0083 else
0084 return -residual_cnt;
0085 }
0086
0087
0088
0089
0090 static void *diag2fc_store(char *query, unsigned int *count, int offset)
0091 {
0092 void *data;
0093 int size;
0094
0095 do {
0096 size = diag2fc(0, query, NULL);
0097 if (size < 0)
0098 return ERR_PTR(-EACCES);
0099 data = vmalloc(size + offset);
0100 if (!data)
0101 return ERR_PTR(-ENOMEM);
0102 if (diag2fc(size, query, data + offset) == 0)
0103 break;
0104 vfree(data);
0105 } while (1);
0106 *count = (size / sizeof(struct diag2fc_data));
0107
0108 return data;
0109 }
0110
0111 static void diag2fc_free(const void *data)
0112 {
0113 vfree(data);
0114 }
0115
0116 #define ATTRIBUTE(dir, name, member) \
0117 do { \
0118 void *rc; \
0119 rc = hypfs_create_u64(dir, name, member); \
0120 if (IS_ERR(rc)) \
0121 return PTR_ERR(rc); \
0122 } while(0)
0123
0124 static int hypfs_vm_create_guest(struct dentry *systems_dir,
0125 struct diag2fc_data *data)
0126 {
0127 char guest_name[NAME_LEN + 1] = {};
0128 struct dentry *guest_dir, *cpus_dir, *samples_dir, *mem_dir;
0129 int dedicated_flag, capped_value;
0130
0131 capped_value = (data->flags & 0x00000006) >> 1;
0132 dedicated_flag = (data->flags & 0x00000008) >> 3;
0133
0134
0135 memcpy(guest_name, data->guest_name, NAME_LEN);
0136 EBCASC(guest_name, NAME_LEN);
0137 strim(guest_name);
0138 guest_dir = hypfs_mkdir(systems_dir, guest_name);
0139 if (IS_ERR(guest_dir))
0140 return PTR_ERR(guest_dir);
0141 ATTRIBUTE(guest_dir, "onlinetime_us", data->el_time);
0142
0143
0144 cpus_dir = hypfs_mkdir(guest_dir, "cpus");
0145 if (IS_ERR(cpus_dir))
0146 return PTR_ERR(cpus_dir);
0147 ATTRIBUTE(cpus_dir, "cputime_us", data->used_cpu);
0148 ATTRIBUTE(cpus_dir, "capped", capped_value);
0149 ATTRIBUTE(cpus_dir, "dedicated", dedicated_flag);
0150 ATTRIBUTE(cpus_dir, "count", data->vcpus);
0151
0152
0153
0154
0155
0156 ATTRIBUTE(cpus_dir, "weight_min", data->ocpus);
0157 ATTRIBUTE(cpus_dir, "weight_max", data->cpu_max);
0158 ATTRIBUTE(cpus_dir, "weight_cur", data->cpu_shares);
0159
0160
0161 mem_dir = hypfs_mkdir(guest_dir, "mem");
0162 if (IS_ERR(mem_dir))
0163 return PTR_ERR(mem_dir);
0164 ATTRIBUTE(mem_dir, "min_KiB", data->mem_min_kb);
0165 ATTRIBUTE(mem_dir, "max_KiB", data->mem_max_kb);
0166 ATTRIBUTE(mem_dir, "used_KiB", data->mem_used_kb);
0167 ATTRIBUTE(mem_dir, "share_KiB", data->mem_share_kb);
0168
0169
0170 samples_dir = hypfs_mkdir(guest_dir, "samples");
0171 if (IS_ERR(samples_dir))
0172 return PTR_ERR(samples_dir);
0173 ATTRIBUTE(samples_dir, "cpu_using", data->cpu_use_samp);
0174 ATTRIBUTE(samples_dir, "cpu_delay", data->cpu_delay_samp);
0175 ATTRIBUTE(samples_dir, "mem_delay", data->page_wait_samp);
0176 ATTRIBUTE(samples_dir, "idle", data->idle_samp);
0177 ATTRIBUTE(samples_dir, "other", data->other_samp);
0178 ATTRIBUTE(samples_dir, "total", data->total_samp);
0179 return 0;
0180 }
0181
0182 int hypfs_vm_create_files(struct dentry *root)
0183 {
0184 struct dentry *dir, *file;
0185 struct diag2fc_data *data;
0186 unsigned int count = 0;
0187 int rc, i;
0188
0189 data = diag2fc_store(guest_query, &count, 0);
0190 if (IS_ERR(data))
0191 return PTR_ERR(data);
0192
0193
0194 dir = hypfs_mkdir(root, "hyp");
0195 if (IS_ERR(dir)) {
0196 rc = PTR_ERR(dir);
0197 goto failed;
0198 }
0199 file = hypfs_create_str(dir, "type", "z/VM Hypervisor");
0200 if (IS_ERR(file)) {
0201 rc = PTR_ERR(file);
0202 goto failed;
0203 }
0204
0205
0206 dir = hypfs_mkdir(root, "cpus");
0207 if (IS_ERR(dir)) {
0208 rc = PTR_ERR(dir);
0209 goto failed;
0210 }
0211 file = hypfs_create_u64(dir, "count", data->lcpus);
0212 if (IS_ERR(file)) {
0213 rc = PTR_ERR(file);
0214 goto failed;
0215 }
0216
0217
0218 dir = hypfs_mkdir(root, "systems");
0219 if (IS_ERR(dir)) {
0220 rc = PTR_ERR(dir);
0221 goto failed;
0222 }
0223
0224 for (i = 0; i < count; i++) {
0225 rc = hypfs_vm_create_guest(dir, &(data[i]));
0226 if (rc)
0227 goto failed;
0228 }
0229 diag2fc_free(data);
0230 return 0;
0231
0232 failed:
0233 diag2fc_free(data);
0234 return rc;
0235 }
0236
0237 struct dbfs_d2fc_hdr {
0238 u64 len;
0239 u16 version;
0240 union tod_clock tod_ext;
0241 u64 count;
0242 char reserved[30];
0243 } __attribute__ ((packed));
0244
0245 struct dbfs_d2fc {
0246 struct dbfs_d2fc_hdr hdr;
0247 char buf[];
0248 } __attribute__ ((packed));
0249
0250 static int dbfs_diag2fc_create(void **data, void **data_free_ptr, size_t *size)
0251 {
0252 struct dbfs_d2fc *d2fc;
0253 unsigned int count;
0254
0255 d2fc = diag2fc_store(guest_query, &count, sizeof(d2fc->hdr));
0256 if (IS_ERR(d2fc))
0257 return PTR_ERR(d2fc);
0258 store_tod_clock_ext(&d2fc->hdr.tod_ext);
0259 d2fc->hdr.len = count * sizeof(struct diag2fc_data);
0260 d2fc->hdr.version = DBFS_D2FC_HDR_VERSION;
0261 d2fc->hdr.count = count;
0262 memset(&d2fc->hdr.reserved, 0, sizeof(d2fc->hdr.reserved));
0263 *data = d2fc;
0264 *data_free_ptr = d2fc;
0265 *size = d2fc->hdr.len + sizeof(struct dbfs_d2fc_hdr);
0266 return 0;
0267 }
0268
0269 static struct hypfs_dbfs_file dbfs_file_2fc = {
0270 .name = "diag_2fc",
0271 .data_create = dbfs_diag2fc_create,
0272 .data_free = diag2fc_free,
0273 };
0274
0275 int hypfs_vm_init(void)
0276 {
0277 if (!MACHINE_IS_VM)
0278 return 0;
0279 if (diag2fc(0, all_guests, NULL) > 0)
0280 guest_query = all_guests;
0281 else if (diag2fc(0, local_guest, NULL) > 0)
0282 guest_query = local_guest;
0283 else
0284 return -EACCES;
0285 hypfs_dbfs_create_file(&dbfs_file_2fc);
0286 return 0;
0287 }
0288
0289 void hypfs_vm_exit(void)
0290 {
0291 if (!MACHINE_IS_VM)
0292 return;
0293 hypfs_dbfs_remove_file(&dbfs_file_2fc);
0294 }