root/arch/s390/hypfs/hypfs_vm.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. diag2fc
  2. diag2fc_store
  3. diag2fc_free
  4. hypfs_vm_create_guest
  5. hypfs_vm_create_files
  6. dbfs_diag2fc_create
  7. hypfs_vm_init
  8. hypfs_vm_exit

   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/diag.h>
  14 #include <asm/ebcdic.h>
  15 #include <asm/timex.h>
  16 #include "hypfs.h"
  17 
  18 #define NAME_LEN 8
  19 #define DBFS_D2FC_HDR_VERSION 0
  20 
  21 static char local_guest[] = "        ";
  22 static char all_guests[] = "*       ";
  23 static char *guest_query;
  24 
  25 struct diag2fc_data {
  26         __u32 version;
  27         __u32 flags;
  28         __u64 used_cpu;
  29         __u64 el_time;
  30         __u64 mem_min_kb;
  31         __u64 mem_max_kb;
  32         __u64 mem_share_kb;
  33         __u64 mem_used_kb;
  34         __u32 pcpus;
  35         __u32 lcpus;
  36         __u32 vcpus;
  37         __u32 ocpus;
  38         __u32 cpu_max;
  39         __u32 cpu_shares;
  40         __u32 cpu_use_samp;
  41         __u32 cpu_delay_samp;
  42         __u32 page_wait_samp;
  43         __u32 idle_samp;
  44         __u32 other_samp;
  45         __u32 total_samp;
  46         char  guest_name[NAME_LEN];
  47 };
  48 
  49 struct diag2fc_parm_list {
  50         char userid[NAME_LEN];
  51         char aci_grp[NAME_LEN];
  52         __u64 addr;
  53         __u32 size;
  54         __u32 fmt;
  55 };
  56 
  57 static int diag2fc(int size, char* query, void *addr)
  58 {
  59         unsigned long residual_cnt;
  60         unsigned long rc;
  61         struct diag2fc_parm_list parm_list;
  62 
  63         memcpy(parm_list.userid, query, NAME_LEN);
  64         ASCEBC(parm_list.userid, NAME_LEN);
  65         parm_list.addr = (unsigned long) addr ;
  66         parm_list.size = size;
  67         parm_list.fmt = 0x02;
  68         memset(parm_list.aci_grp, 0x40, NAME_LEN);
  69         rc = -1;
  70 
  71         diag_stat_inc(DIAG_STAT_X2FC);
  72         asm volatile(
  73                 "       diag    %0,%1,0x2fc\n"
  74                 "0:     nopr    %%r7\n"
  75                 EX_TABLE(0b,0b)
  76                 : "=d" (residual_cnt), "+d" (rc) : "0" (&parm_list) : "memory");
  77 
  78         if ((rc != 0 ) && (rc != -2))
  79                 return rc;
  80         else
  81                 return -residual_cnt;
  82 }
  83 
  84 /*
  85  * Allocate buffer for "query" and store diag 2fc at "offset"
  86  */
  87 static void *diag2fc_store(char *query, unsigned int *count, int offset)
  88 {
  89         void *data;
  90         int size;
  91 
  92         do {
  93                 size = diag2fc(0, query, NULL);
  94                 if (size < 0)
  95                         return ERR_PTR(-EACCES);
  96                 data = vmalloc(size + offset);
  97                 if (!data)
  98                         return ERR_PTR(-ENOMEM);
  99                 if (diag2fc(size, query, data + offset) == 0)
 100                         break;
 101                 vfree(data);
 102         } while (1);
 103         *count = (size / sizeof(struct diag2fc_data));
 104 
 105         return data;
 106 }
 107 
 108 static void diag2fc_free(const void *data)
 109 {
 110         vfree(data);
 111 }
 112 
 113 #define ATTRIBUTE(dir, name, member) \
 114 do { \
 115         void *rc; \
 116         rc = hypfs_create_u64(dir, name, member); \
 117         if (IS_ERR(rc)) \
 118                 return PTR_ERR(rc); \
 119 } while(0)
 120 
 121 static int hypfs_vm_create_guest(struct dentry *systems_dir,
 122                                  struct diag2fc_data *data)
 123 {
 124         char guest_name[NAME_LEN + 1] = {};
 125         struct dentry *guest_dir, *cpus_dir, *samples_dir, *mem_dir;
 126         int dedicated_flag, capped_value;
 127 
 128         capped_value = (data->flags & 0x00000006) >> 1;
 129         dedicated_flag = (data->flags & 0x00000008) >> 3;
 130 
 131         /* guest dir */
 132         memcpy(guest_name, data->guest_name, NAME_LEN);
 133         EBCASC(guest_name, NAME_LEN);
 134         strim(guest_name);
 135         guest_dir = hypfs_mkdir(systems_dir, guest_name);
 136         if (IS_ERR(guest_dir))
 137                 return PTR_ERR(guest_dir);
 138         ATTRIBUTE(guest_dir, "onlinetime_us", data->el_time);
 139 
 140         /* logical cpu information */
 141         cpus_dir = hypfs_mkdir(guest_dir, "cpus");
 142         if (IS_ERR(cpus_dir))
 143                 return PTR_ERR(cpus_dir);
 144         ATTRIBUTE(cpus_dir, "cputime_us", data->used_cpu);
 145         ATTRIBUTE(cpus_dir, "capped", capped_value);
 146         ATTRIBUTE(cpus_dir, "dedicated", dedicated_flag);
 147         ATTRIBUTE(cpus_dir, "count", data->vcpus);
 148         /*
 149          * Note: The "weight_min" attribute got the wrong name.
 150          * The value represents the number of non-stopped (operating)
 151          * CPUS.
 152          */
 153         ATTRIBUTE(cpus_dir, "weight_min", data->ocpus);
 154         ATTRIBUTE(cpus_dir, "weight_max", data->cpu_max);
 155         ATTRIBUTE(cpus_dir, "weight_cur", data->cpu_shares);
 156 
 157         /* memory information */
 158         mem_dir = hypfs_mkdir(guest_dir, "mem");
 159         if (IS_ERR(mem_dir))
 160                 return PTR_ERR(mem_dir);
 161         ATTRIBUTE(mem_dir, "min_KiB", data->mem_min_kb);
 162         ATTRIBUTE(mem_dir, "max_KiB", data->mem_max_kb);
 163         ATTRIBUTE(mem_dir, "used_KiB", data->mem_used_kb);
 164         ATTRIBUTE(mem_dir, "share_KiB", data->mem_share_kb);
 165 
 166         /* samples */
 167         samples_dir = hypfs_mkdir(guest_dir, "samples");
 168         if (IS_ERR(samples_dir))
 169                 return PTR_ERR(samples_dir);
 170         ATTRIBUTE(samples_dir, "cpu_using", data->cpu_use_samp);
 171         ATTRIBUTE(samples_dir, "cpu_delay", data->cpu_delay_samp);
 172         ATTRIBUTE(samples_dir, "mem_delay", data->page_wait_samp);
 173         ATTRIBUTE(samples_dir, "idle", data->idle_samp);
 174         ATTRIBUTE(samples_dir, "other", data->other_samp);
 175         ATTRIBUTE(samples_dir, "total", data->total_samp);
 176         return 0;
 177 }
 178 
 179 int hypfs_vm_create_files(struct dentry *root)
 180 {
 181         struct dentry *dir, *file;
 182         struct diag2fc_data *data;
 183         unsigned int count = 0;
 184         int rc, i;
 185 
 186         data = diag2fc_store(guest_query, &count, 0);
 187         if (IS_ERR(data))
 188                 return PTR_ERR(data);
 189 
 190         /* Hpervisor Info */
 191         dir = hypfs_mkdir(root, "hyp");
 192         if (IS_ERR(dir)) {
 193                 rc = PTR_ERR(dir);
 194                 goto failed;
 195         }
 196         file = hypfs_create_str(dir, "type", "z/VM Hypervisor");
 197         if (IS_ERR(file)) {
 198                 rc = PTR_ERR(file);
 199                 goto failed;
 200         }
 201 
 202         /* physical cpus */
 203         dir = hypfs_mkdir(root, "cpus");
 204         if (IS_ERR(dir)) {
 205                 rc = PTR_ERR(dir);
 206                 goto failed;
 207         }
 208         file = hypfs_create_u64(dir, "count", data->lcpus);
 209         if (IS_ERR(file)) {
 210                 rc = PTR_ERR(file);
 211                 goto failed;
 212         }
 213 
 214         /* guests */
 215         dir = hypfs_mkdir(root, "systems");
 216         if (IS_ERR(dir)) {
 217                 rc = PTR_ERR(dir);
 218                 goto failed;
 219         }
 220 
 221         for (i = 0; i < count; i++) {
 222                 rc = hypfs_vm_create_guest(dir, &(data[i]));
 223                 if (rc)
 224                         goto failed;
 225         }
 226         diag2fc_free(data);
 227         return 0;
 228 
 229 failed:
 230         diag2fc_free(data);
 231         return rc;
 232 }
 233 
 234 struct dbfs_d2fc_hdr {
 235         u64     len;            /* Length of d2fc buffer without header */
 236         u16     version;        /* Version of header */
 237         char    tod_ext[STORE_CLOCK_EXT_SIZE]; /* TOD clock for d2fc */
 238         u64     count;          /* Number of VM guests in d2fc buffer */
 239         char    reserved[30];
 240 } __attribute__ ((packed));
 241 
 242 struct dbfs_d2fc {
 243         struct dbfs_d2fc_hdr    hdr;    /* 64 byte header */
 244         char                    buf[];  /* d2fc buffer */
 245 } __attribute__ ((packed));
 246 
 247 static int dbfs_diag2fc_create(void **data, void **data_free_ptr, size_t *size)
 248 {
 249         struct dbfs_d2fc *d2fc;
 250         unsigned int count;
 251 
 252         d2fc = diag2fc_store(guest_query, &count, sizeof(d2fc->hdr));
 253         if (IS_ERR(d2fc))
 254                 return PTR_ERR(d2fc);
 255         get_tod_clock_ext(d2fc->hdr.tod_ext);
 256         d2fc->hdr.len = count * sizeof(struct diag2fc_data);
 257         d2fc->hdr.version = DBFS_D2FC_HDR_VERSION;
 258         d2fc->hdr.count = count;
 259         memset(&d2fc->hdr.reserved, 0, sizeof(d2fc->hdr.reserved));
 260         *data = d2fc;
 261         *data_free_ptr = d2fc;
 262         *size = d2fc->hdr.len + sizeof(struct dbfs_d2fc_hdr);
 263         return 0;
 264 }
 265 
 266 static struct hypfs_dbfs_file dbfs_file_2fc = {
 267         .name           = "diag_2fc",
 268         .data_create    = dbfs_diag2fc_create,
 269         .data_free      = diag2fc_free,
 270 };
 271 
 272 int hypfs_vm_init(void)
 273 {
 274         if (!MACHINE_IS_VM)
 275                 return 0;
 276         if (diag2fc(0, all_guests, NULL) > 0)
 277                 guest_query = all_guests;
 278         else if (diag2fc(0, local_guest, NULL) > 0)
 279                 guest_query = local_guest;
 280         else
 281                 return -EACCES;
 282         hypfs_dbfs_create_file(&dbfs_file_2fc);
 283         return 0;
 284 }
 285 
 286 void hypfs_vm_exit(void)
 287 {
 288         if (!MACHINE_IS_VM)
 289                 return;
 290         hypfs_dbfs_remove_file(&dbfs_file_2fc);
 291 }

/* [<][>][^][v][top][bottom][index][help] */