diff options
| -rw-r--r-- | arch/s390/hypfs/Makefile | 2 | ||||
| -rw-r--r-- | arch/s390/hypfs/hypfs.h | 9 | ||||
| -rw-r--r-- | arch/s390/hypfs/hypfs_diag.h | 16 | ||||
| -rw-r--r-- | arch/s390/hypfs/hypfs_vm.c | 231 | ||||
| -rw-r--r-- | arch/s390/hypfs/inode.c | 31 |
5 files changed, 262 insertions, 27 deletions
diff --git a/arch/s390/hypfs/Makefile b/arch/s390/hypfs/Makefile index f4b00cd81f7c..b08d2abf6178 100644 --- a/arch/s390/hypfs/Makefile +++ b/arch/s390/hypfs/Makefile | |||
| @@ -4,4 +4,4 @@ | |||
| 4 | 4 | ||
| 5 | obj-$(CONFIG_S390_HYPFS_FS) += s390_hypfs.o | 5 | obj-$(CONFIG_S390_HYPFS_FS) += s390_hypfs.o |
| 6 | 6 | ||
| 7 | s390_hypfs-objs := inode.o hypfs_diag.o | 7 | s390_hypfs-objs := inode.o hypfs_diag.o hypfs_vm.o |
diff --git a/arch/s390/hypfs/hypfs.h b/arch/s390/hypfs/hypfs.h index f3dbd91965c6..aea572009d60 100644 --- a/arch/s390/hypfs/hypfs.h +++ b/arch/s390/hypfs/hypfs.h | |||
| @@ -27,4 +27,13 @@ extern struct dentry *hypfs_create_str(struct super_block *sb, | |||
| 27 | struct dentry *dir, const char *name, | 27 | struct dentry *dir, const char *name, |
| 28 | char *string); | 28 | char *string); |
| 29 | 29 | ||
| 30 | /* LPAR Hypervisor */ | ||
| 31 | extern int hypfs_diag_init(void); | ||
| 32 | extern void hypfs_diag_exit(void); | ||
| 33 | extern int hypfs_diag_create_files(struct super_block *sb, struct dentry *root); | ||
| 34 | |||
| 35 | /* VM Hypervisor */ | ||
| 36 | extern int hypfs_vm_init(void); | ||
| 37 | extern int hypfs_vm_create_files(struct super_block *sb, struct dentry *root); | ||
| 38 | |||
| 30 | #endif /* _HYPFS_H_ */ | 39 | #endif /* _HYPFS_H_ */ |
diff --git a/arch/s390/hypfs/hypfs_diag.h b/arch/s390/hypfs/hypfs_diag.h deleted file mode 100644 index 256b384aebe1..000000000000 --- a/arch/s390/hypfs/hypfs_diag.h +++ /dev/null | |||
| @@ -1,16 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * arch/s390/hypfs_diag.h | ||
| 3 | * Hypervisor filesystem for Linux on s390. | ||
| 4 | * | ||
| 5 | * Copyright (C) IBM Corp. 2006 | ||
| 6 | * Author(s): Michael Holzheu <holzheu@de.ibm.com> | ||
| 7 | */ | ||
| 8 | |||
| 9 | #ifndef _HYPFS_DIAG_H_ | ||
| 10 | #define _HYPFS_DIAG_H_ | ||
| 11 | |||
| 12 | extern int hypfs_diag_init(void); | ||
| 13 | extern void hypfs_diag_exit(void); | ||
| 14 | extern int hypfs_diag_create_files(struct super_block *sb, struct dentry *root); | ||
| 15 | |||
| 16 | #endif /* _HYPFS_DIAG_H_ */ | ||
diff --git a/arch/s390/hypfs/hypfs_vm.c b/arch/s390/hypfs/hypfs_vm.c new file mode 100644 index 000000000000..d01fc8f799f0 --- /dev/null +++ b/arch/s390/hypfs/hypfs_vm.c | |||
| @@ -0,0 +1,231 @@ | |||
| 1 | /* | ||
| 2 | * Hypervisor filesystem for Linux on s390. z/VM implementation. | ||
| 3 | * | ||
| 4 | * Copyright (C) IBM Corp. 2006 | ||
| 5 | * Author(s): Michael Holzheu <holzheu@de.ibm.com> | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <linux/types.h> | ||
| 9 | #include <linux/errno.h> | ||
| 10 | #include <linux/string.h> | ||
| 11 | #include <linux/vmalloc.h> | ||
| 12 | #include <asm/ebcdic.h> | ||
| 13 | #include "hypfs.h" | ||
| 14 | |||
| 15 | #define NAME_LEN 8 | ||
| 16 | |||
| 17 | static char local_guest[] = " "; | ||
| 18 | static char all_guests[] = "* "; | ||
| 19 | static char *guest_query; | ||
| 20 | |||
| 21 | struct diag2fc_data { | ||
| 22 | __u32 version; | ||
| 23 | __u32 flags; | ||
| 24 | __u64 used_cpu; | ||
| 25 | __u64 el_time; | ||
| 26 | __u64 mem_min_kb; | ||
| 27 | __u64 mem_max_kb; | ||
| 28 | __u64 mem_share_kb; | ||
| 29 | __u64 mem_used_kb; | ||
| 30 | __u32 pcpus; | ||
| 31 | __u32 lcpus; | ||
| 32 | __u32 vcpus; | ||
| 33 | __u32 cpu_min; | ||
| 34 | __u32 cpu_max; | ||
| 35 | __u32 cpu_shares; | ||
| 36 | __u32 cpu_use_samp; | ||
| 37 | __u32 cpu_delay_samp; | ||
| 38 | __u32 page_wait_samp; | ||
| 39 | __u32 idle_samp; | ||
| 40 | __u32 other_samp; | ||
| 41 | __u32 total_samp; | ||
| 42 | char guest_name[NAME_LEN]; | ||
| 43 | }; | ||
| 44 | |||
| 45 | struct diag2fc_parm_list { | ||
| 46 | char userid[NAME_LEN]; | ||
| 47 | char aci_grp[NAME_LEN]; | ||
| 48 | __u64 addr; | ||
| 49 | __u32 size; | ||
| 50 | __u32 fmt; | ||
| 51 | }; | ||
| 52 | |||
| 53 | static int diag2fc(int size, char* query, void *addr) | ||
| 54 | { | ||
| 55 | unsigned long residual_cnt; | ||
| 56 | unsigned long rc; | ||
| 57 | struct diag2fc_parm_list parm_list; | ||
| 58 | |||
| 59 | memcpy(parm_list.userid, query, NAME_LEN); | ||
| 60 | ASCEBC(parm_list.userid, NAME_LEN); | ||
| 61 | parm_list.addr = (unsigned long) addr ; | ||
| 62 | parm_list.size = size; | ||
| 63 | parm_list.fmt = 0x02; | ||
| 64 | memset(parm_list.aci_grp, 0x40, NAME_LEN); | ||
| 65 | rc = -1; | ||
| 66 | |||
| 67 | asm volatile( | ||
| 68 | " diag %0,%1,0x2fc\n" | ||
| 69 | "0:\n" | ||
| 70 | EX_TABLE(0b,0b) | ||
| 71 | : "=d" (residual_cnt), "+d" (rc) : "0" (&parm_list) : "memory"); | ||
| 72 | |||
| 73 | if ((rc != 0 ) && (rc != -2)) | ||
| 74 | return rc; | ||
| 75 | else | ||
| 76 | return -residual_cnt; | ||
| 77 | } | ||
| 78 | |||
| 79 | static struct diag2fc_data *diag2fc_store(char *query, int *count) | ||
| 80 | { | ||
| 81 | int size; | ||
| 82 | struct diag2fc_data *data; | ||
| 83 | |||
| 84 | do { | ||
| 85 | size = diag2fc(0, query, NULL); | ||
| 86 | if (size < 0) | ||
| 87 | return ERR_PTR(-EACCES); | ||
| 88 | data = vmalloc(size); | ||
| 89 | if (!data) | ||
| 90 | return ERR_PTR(-ENOMEM); | ||
| 91 | if (diag2fc(size, query, data) == 0) | ||
| 92 | break; | ||
| 93 | vfree(data); | ||
| 94 | } while (1); | ||
| 95 | *count = (size / sizeof(*data)); | ||
| 96 | |||
| 97 | return data; | ||
| 98 | } | ||
| 99 | |||
| 100 | static void diag2fc_free(void *data) | ||
| 101 | { | ||
| 102 | vfree(data); | ||
| 103 | } | ||
| 104 | |||
| 105 | #define ATTRIBUTE(sb, dir, name, member) \ | ||
| 106 | do { \ | ||
| 107 | void *rc; \ | ||
| 108 | rc = hypfs_create_u64(sb, dir, name, member); \ | ||
| 109 | if (IS_ERR(rc)) \ | ||
| 110 | return PTR_ERR(rc); \ | ||
| 111 | } while(0) | ||
| 112 | |||
| 113 | static int hpyfs_vm_create_guest(struct super_block *sb, | ||
| 114 | struct dentry *systems_dir, | ||
| 115 | struct diag2fc_data *data) | ||
| 116 | { | ||
| 117 | char guest_name[NAME_LEN + 1] = {}; | ||
| 118 | struct dentry *guest_dir, *cpus_dir, *samples_dir, *mem_dir; | ||
| 119 | int dedicated_flag, capped_value; | ||
| 120 | |||
| 121 | capped_value = (data->flags & 0x00000006) >> 1; | ||
| 122 | dedicated_flag = (data->flags & 0x00000008) >> 3; | ||
| 123 | |||
| 124 | /* guest dir */ | ||
| 125 | memcpy(guest_name, data->guest_name, NAME_LEN); | ||
| 126 | EBCASC(guest_name, NAME_LEN); | ||
| 127 | strstrip(guest_name); | ||
| 128 | guest_dir = hypfs_mkdir(sb, systems_dir, guest_name); | ||
| 129 | if (IS_ERR(guest_dir)) | ||
| 130 | return PTR_ERR(guest_dir); | ||
| 131 | ATTRIBUTE(sb, guest_dir, "onlinetime_us", data->el_time); | ||
| 132 | |||
| 133 | /* logical cpu information */ | ||
| 134 | cpus_dir = hypfs_mkdir(sb, guest_dir, "cpus"); | ||
| 135 | if (IS_ERR(cpus_dir)) | ||
| 136 | return PTR_ERR(cpus_dir); | ||
| 137 | ATTRIBUTE(sb, cpus_dir, "cputime_us", data->used_cpu); | ||
| 138 | ATTRIBUTE(sb, cpus_dir, "capped", capped_value); | ||
| 139 | ATTRIBUTE(sb, cpus_dir, "dedicated", dedicated_flag); | ||
| 140 | ATTRIBUTE(sb, cpus_dir, "count", data->vcpus); | ||
| 141 | ATTRIBUTE(sb, cpus_dir, "weight_min", data->cpu_min); | ||
| 142 | ATTRIBUTE(sb, cpus_dir, "weight_max", data->cpu_max); | ||
| 143 | ATTRIBUTE(sb, cpus_dir, "weight_cur", data->cpu_shares); | ||
| 144 | |||
| 145 | /* memory information */ | ||
| 146 | mem_dir = hypfs_mkdir(sb, guest_dir, "mem"); | ||
| 147 | if (IS_ERR(mem_dir)) | ||
| 148 | return PTR_ERR(mem_dir); | ||
| 149 | ATTRIBUTE(sb, mem_dir, "min_KiB", data->mem_min_kb); | ||
| 150 | ATTRIBUTE(sb, mem_dir, "max_KiB", data->mem_max_kb); | ||
| 151 | ATTRIBUTE(sb, mem_dir, "used_KiB", data->mem_used_kb); | ||
| 152 | ATTRIBUTE(sb, mem_dir, "share_KiB", data->mem_share_kb); | ||
| 153 | |||
| 154 | /* samples */ | ||
| 155 | samples_dir = hypfs_mkdir(sb, guest_dir, "samples"); | ||
| 156 | if (IS_ERR(samples_dir)) | ||
| 157 | return PTR_ERR(samples_dir); | ||
| 158 | ATTRIBUTE(sb, samples_dir, "cpu_using", data->cpu_use_samp); | ||
| 159 | ATTRIBUTE(sb, samples_dir, "cpu_delay", data->cpu_delay_samp); | ||
| 160 | ATTRIBUTE(sb, samples_dir, "mem_delay", data->page_wait_samp); | ||
| 161 | ATTRIBUTE(sb, samples_dir, "idle", data->idle_samp); | ||
| 162 | ATTRIBUTE(sb, samples_dir, "other", data->other_samp); | ||
| 163 | ATTRIBUTE(sb, samples_dir, "total", data->total_samp); | ||
| 164 | return 0; | ||
| 165 | } | ||
| 166 | |||
| 167 | int hypfs_vm_create_files(struct super_block *sb, struct dentry *root) | ||
| 168 | { | ||
| 169 | struct dentry *dir, *file; | ||
| 170 | struct diag2fc_data *data; | ||
| 171 | int rc, i, count = 0; | ||
| 172 | |||
| 173 | data = diag2fc_store(guest_query, &count); | ||
| 174 | if (IS_ERR(data)) | ||
| 175 | return PTR_ERR(data); | ||
| 176 | |||
| 177 | /* Hpervisor Info */ | ||
| 178 | dir = hypfs_mkdir(sb, root, "hyp"); | ||
| 179 | if (IS_ERR(dir)) { | ||
| 180 | rc = PTR_ERR(dir); | ||
| 181 | goto failed; | ||
| 182 | } | ||
| 183 | file = hypfs_create_str(sb, dir, "type", "z/VM Hypervisor"); | ||
| 184 | if (IS_ERR(file)) { | ||
| 185 | rc = PTR_ERR(file); | ||
| 186 | goto failed; | ||
| 187 | } | ||
| 188 | |||
| 189 | /* physical cpus */ | ||
| 190 | dir = hypfs_mkdir(sb, root, "cpus"); | ||
| 191 | if (IS_ERR(dir)) { | ||
| 192 | rc = PTR_ERR(dir); | ||
| 193 | goto failed; | ||
| 194 | } | ||
| 195 | file = hypfs_create_u64(sb, dir, "count", data->lcpus); | ||
| 196 | if (IS_ERR(file)) { | ||
| 197 | rc = PTR_ERR(file); | ||
| 198 | goto failed; | ||
| 199 | } | ||
| 200 | |||
| 201 | /* guests */ | ||
| 202 | dir = hypfs_mkdir(sb, root, "systems"); | ||
| 203 | if (IS_ERR(dir)) { | ||
| 204 | rc = PTR_ERR(dir); | ||
| 205 | goto failed; | ||
| 206 | } | ||
| 207 | |||
| 208 | for (i = 0; i < count; i++) { | ||
| 209 | rc = hpyfs_vm_create_guest(sb, dir, &(data[i])); | ||
| 210 | if (rc) | ||
| 211 | goto failed; | ||
| 212 | } | ||
| 213 | diag2fc_free(data); | ||
| 214 | return 0; | ||
| 215 | |||
| 216 | failed: | ||
| 217 | diag2fc_free(data); | ||
| 218 | return rc; | ||
| 219 | } | ||
| 220 | |||
| 221 | int hypfs_vm_init(void) | ||
| 222 | { | ||
| 223 | if (diag2fc(0, all_guests, NULL) > 0) | ||
| 224 | guest_query = all_guests; | ||
| 225 | else if (diag2fc(0, local_guest, NULL) > 0) | ||
| 226 | guest_query = local_guest; | ||
| 227 | else | ||
| 228 | return -EACCES; | ||
| 229 | |||
| 230 | return 0; | ||
| 231 | } | ||
diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c index b6716c4b9934..a4fda7b53640 100644 --- a/arch/s390/hypfs/inode.c +++ b/arch/s390/hypfs/inode.c | |||
| @@ -19,7 +19,6 @@ | |||
| 19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
| 20 | #include <asm/ebcdic.h> | 20 | #include <asm/ebcdic.h> |
| 21 | #include "hypfs.h" | 21 | #include "hypfs.h" |
| 22 | #include "hypfs_diag.h" | ||
| 23 | 22 | ||
| 24 | #define HYPFS_MAGIC 0x687970 /* ASCII 'hyp' */ | 23 | #define HYPFS_MAGIC 0x687970 /* ASCII 'hyp' */ |
| 25 | #define TMP_SIZE 64 /* size of temporary buffers */ | 24 | #define TMP_SIZE 64 /* size of temporary buffers */ |
| @@ -192,7 +191,10 @@ static ssize_t hypfs_aio_write(struct kiocb *iocb, const struct iovec *iov, | |||
| 192 | goto out; | 191 | goto out; |
| 193 | } | 192 | } |
| 194 | hypfs_delete_tree(sb->s_root); | 193 | hypfs_delete_tree(sb->s_root); |
| 195 | rc = hypfs_diag_create_files(sb, sb->s_root); | 194 | if (MACHINE_IS_VM) |
| 195 | rc = hypfs_vm_create_files(sb, sb->s_root); | ||
| 196 | else | ||
| 197 | rc = hypfs_diag_create_files(sb, sb->s_root); | ||
| 196 | if (rc) { | 198 | if (rc) { |
| 197 | printk(KERN_ERR "hypfs: Update failed\n"); | 199 | printk(KERN_ERR "hypfs: Update failed\n"); |
| 198 | hypfs_delete_tree(sb->s_root); | 200 | hypfs_delete_tree(sb->s_root); |
| @@ -289,7 +291,10 @@ static int hypfs_fill_super(struct super_block *sb, void *data, int silent) | |||
| 289 | rc = -ENOMEM; | 291 | rc = -ENOMEM; |
| 290 | goto err_alloc; | 292 | goto err_alloc; |
| 291 | } | 293 | } |
| 292 | rc = hypfs_diag_create_files(sb, root_dentry); | 294 | if (MACHINE_IS_VM) |
| 295 | rc = hypfs_vm_create_files(sb, root_dentry); | ||
| 296 | else | ||
| 297 | rc = hypfs_diag_create_files(sb, root_dentry); | ||
| 293 | if (rc) | 298 | if (rc) |
| 294 | goto err_tree; | 299 | goto err_tree; |
| 295 | sbi->update_file = hypfs_create_update_file(sb, root_dentry); | 300 | sbi->update_file = hypfs_create_update_file(sb, root_dentry); |
| @@ -462,11 +467,15 @@ static int __init hypfs_init(void) | |||
| 462 | { | 467 | { |
| 463 | int rc; | 468 | int rc; |
| 464 | 469 | ||
| 465 | if (MACHINE_IS_VM) | 470 | if (MACHINE_IS_VM) { |
| 466 | return -ENODATA; | 471 | if (hypfs_vm_init()) |
| 467 | if (hypfs_diag_init()) { | 472 | /* no diag 2fc, just exit */ |
| 468 | rc = -ENODATA; | 473 | return -ENODATA; |
| 469 | goto fail_diag; | 474 | } else { |
| 475 | if (hypfs_diag_init()) { | ||
| 476 | rc = -ENODATA; | ||
| 477 | goto fail_diag; | ||
| 478 | } | ||
| 470 | } | 479 | } |
| 471 | kset_set_kset_s(&s390_subsys, hypervisor_subsys); | 480 | kset_set_kset_s(&s390_subsys, hypervisor_subsys); |
| 472 | rc = subsystem_register(&s390_subsys); | 481 | rc = subsystem_register(&s390_subsys); |
| @@ -480,7 +489,8 @@ static int __init hypfs_init(void) | |||
| 480 | fail_filesystem: | 489 | fail_filesystem: |
| 481 | subsystem_unregister(&s390_subsys); | 490 | subsystem_unregister(&s390_subsys); |
| 482 | fail_sysfs: | 491 | fail_sysfs: |
| 483 | hypfs_diag_exit(); | 492 | if (!MACHINE_IS_VM) |
| 493 | hypfs_diag_exit(); | ||
| 484 | fail_diag: | 494 | fail_diag: |
| 485 | printk(KERN_ERR "hypfs: Initialization failed with rc = %i.\n", rc); | 495 | printk(KERN_ERR "hypfs: Initialization failed with rc = %i.\n", rc); |
| 486 | return rc; | 496 | return rc; |
| @@ -488,7 +498,8 @@ fail_diag: | |||
| 488 | 498 | ||
| 489 | static void __exit hypfs_exit(void) | 499 | static void __exit hypfs_exit(void) |
| 490 | { | 500 | { |
| 491 | hypfs_diag_exit(); | 501 | if (!MACHINE_IS_VM) |
| 502 | hypfs_diag_exit(); | ||
| 492 | unregister_filesystem(&hypfs_type); | 503 | unregister_filesystem(&hypfs_type); |
| 493 | subsystem_unregister(&s390_subsys); | 504 | subsystem_unregister(&s390_subsys); |
| 494 | } | 505 | } |
