aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/hypfs
diff options
context:
space:
mode:
Diffstat (limited to 'arch/s390/hypfs')
-rw-r--r--arch/s390/hypfs/Makefile2
-rw-r--r--arch/s390/hypfs/hypfs.h33
-rw-r--r--arch/s390/hypfs/hypfs_dbfs.c116
-rw-r--r--arch/s390/hypfs/hypfs_diag.c82
-rw-r--r--arch/s390/hypfs/hypfs_vm.c62
-rw-r--r--arch/s390/hypfs/inode.c18
6 files changed, 195 insertions, 118 deletions
diff --git a/arch/s390/hypfs/Makefile b/arch/s390/hypfs/Makefile
index b08d2abf6178..2e671d5004ca 100644
--- a/arch/s390/hypfs/Makefile
+++ b/arch/s390/hypfs/Makefile
@@ -4,4 +4,4 @@
4 4
5obj-$(CONFIG_S390_HYPFS_FS) += s390_hypfs.o 5obj-$(CONFIG_S390_HYPFS_FS) += s390_hypfs.o
6 6
7s390_hypfs-objs := inode.o hypfs_diag.o hypfs_vm.o 7s390_hypfs-objs := inode.o hypfs_diag.o hypfs_vm.o hypfs_dbfs.o
diff --git a/arch/s390/hypfs/hypfs.h b/arch/s390/hypfs/hypfs.h
index fa487d4cc08b..80c1526f2af3 100644
--- a/arch/s390/hypfs/hypfs.h
+++ b/arch/s390/hypfs/hypfs.h
@@ -12,6 +12,8 @@
12#include <linux/fs.h> 12#include <linux/fs.h>
13#include <linux/types.h> 13#include <linux/types.h>
14#include <linux/debugfs.h> 14#include <linux/debugfs.h>
15#include <linux/workqueue.h>
16#include <linux/kref.h>
15 17
16#define REG_FILE_MODE 0440 18#define REG_FILE_MODE 0440
17#define UPDATE_FILE_MODE 0220 19#define UPDATE_FILE_MODE 0220
@@ -38,6 +40,33 @@ extern int hypfs_vm_init(void);
38extern void hypfs_vm_exit(void); 40extern void hypfs_vm_exit(void);
39extern int hypfs_vm_create_files(struct super_block *sb, struct dentry *root); 41extern int hypfs_vm_create_files(struct super_block *sb, struct dentry *root);
40 42
41/* Directory for debugfs files */ 43/* debugfs interface */
42extern struct dentry *hypfs_dbfs_dir; 44struct hypfs_dbfs_file;
45
46struct hypfs_dbfs_data {
47 void *buf;
48 void *buf_free_ptr;
49 size_t size;
50 struct hypfs_dbfs_file *dbfs_file;;
51 struct kref kref;
52};
53
54struct hypfs_dbfs_file {
55 const char *name;
56 int (*data_create)(void **data, void **data_free_ptr,
57 size_t *size);
58 void (*data_free)(const void *buf_free_ptr);
59
60 /* Private data for hypfs_dbfs.c */
61 struct hypfs_dbfs_data *data;
62 struct delayed_work data_free_work;
63 struct mutex lock;
64 struct dentry *dentry;
65};
66
67extern int hypfs_dbfs_init(void);
68extern void hypfs_dbfs_exit(void);
69extern int hypfs_dbfs_create_file(struct hypfs_dbfs_file *df);
70extern void hypfs_dbfs_remove_file(struct hypfs_dbfs_file *df);
71
43#endif /* _HYPFS_H_ */ 72#endif /* _HYPFS_H_ */
diff --git a/arch/s390/hypfs/hypfs_dbfs.c b/arch/s390/hypfs/hypfs_dbfs.c
new file mode 100644
index 000000000000..b478013b7fec
--- /dev/null
+++ b/arch/s390/hypfs/hypfs_dbfs.c
@@ -0,0 +1,116 @@
1/*
2 * Hypervisor filesystem for Linux on s390 - debugfs interface
3 *
4 * Copyright (C) IBM Corp. 2010
5 * Author(s): Michael Holzheu <holzheu@linux.vnet.ibm.com>
6 */
7
8#include <linux/slab.h>
9#include "hypfs.h"
10
11static struct dentry *dbfs_dir;
12
13static struct hypfs_dbfs_data *hypfs_dbfs_data_alloc(struct hypfs_dbfs_file *f)
14{
15 struct hypfs_dbfs_data *data;
16
17 data = kmalloc(sizeof(*data), GFP_KERNEL);
18 if (!data)
19 return NULL;
20 kref_init(&data->kref);
21 data->dbfs_file = f;
22 return data;
23}
24
25static void hypfs_dbfs_data_free(struct kref *kref)
26{
27 struct hypfs_dbfs_data *data;
28
29 data = container_of(kref, struct hypfs_dbfs_data, kref);
30 data->dbfs_file->data_free(data->buf_free_ptr);
31 kfree(data);
32}
33
34static void data_free_delayed(struct work_struct *work)
35{
36 struct hypfs_dbfs_data *data;
37 struct hypfs_dbfs_file *df;
38
39 df = container_of(work, struct hypfs_dbfs_file, data_free_work.work);
40 mutex_lock(&df->lock);
41 data = df->data;
42 df->data = NULL;
43 mutex_unlock(&df->lock);
44 kref_put(&data->kref, hypfs_dbfs_data_free);
45}
46
47static ssize_t dbfs_read(struct file *file, char __user *buf,
48 size_t size, loff_t *ppos)
49{
50 struct hypfs_dbfs_data *data;
51 struct hypfs_dbfs_file *df;
52 ssize_t rc;
53
54 if (*ppos != 0)
55 return 0;
56
57 df = file->f_path.dentry->d_inode->i_private;
58 mutex_lock(&df->lock);
59 if (!df->data) {
60 data = hypfs_dbfs_data_alloc(df);
61 if (!data) {
62 mutex_unlock(&df->lock);
63 return -ENOMEM;
64 }
65 rc = df->data_create(&data->buf, &data->buf_free_ptr,
66 &data->size);
67 if (rc) {
68 mutex_unlock(&df->lock);
69 kfree(data);
70 return rc;
71 }
72 df->data = data;
73 schedule_delayed_work(&df->data_free_work, HZ);
74 }
75 data = df->data;
76 kref_get(&data->kref);
77 mutex_unlock(&df->lock);
78
79 rc = simple_read_from_buffer(buf, size, ppos, data->buf, data->size);
80 kref_put(&data->kref, hypfs_dbfs_data_free);
81 return rc;
82}
83
84static const struct file_operations dbfs_ops = {
85 .read = dbfs_read,
86 .llseek = no_llseek,
87};
88
89int hypfs_dbfs_create_file(struct hypfs_dbfs_file *df)
90{
91 df->dentry = debugfs_create_file(df->name, 0400, dbfs_dir, df,
92 &dbfs_ops);
93 if (IS_ERR(df->dentry))
94 return PTR_ERR(df->dentry);
95 mutex_init(&df->lock);
96 INIT_DELAYED_WORK(&df->data_free_work, data_free_delayed);
97 return 0;
98}
99
100void hypfs_dbfs_remove_file(struct hypfs_dbfs_file *df)
101{
102 debugfs_remove(df->dentry);
103}
104
105int hypfs_dbfs_init(void)
106{
107 dbfs_dir = debugfs_create_dir("s390_hypfs", NULL);
108 if (IS_ERR(dbfs_dir))
109 return PTR_ERR(dbfs_dir);
110 return 0;
111}
112
113void hypfs_dbfs_exit(void)
114{
115 debugfs_remove(dbfs_dir);
116}
diff --git a/arch/s390/hypfs/hypfs_diag.c b/arch/s390/hypfs/hypfs_diag.c
index cd4a81be9cf8..6023c6dc1fb7 100644
--- a/arch/s390/hypfs/hypfs_diag.c
+++ b/arch/s390/hypfs/hypfs_diag.c
@@ -555,81 +555,38 @@ struct dbfs_d204 {
555 char buf[]; /* d204 buffer */ 555 char buf[]; /* d204 buffer */
556} __attribute__ ((packed)); 556} __attribute__ ((packed));
557 557
558struct dbfs_d204_private { 558static int dbfs_d204_create(void **data, void **data_free_ptr, size_t *size)
559 struct dbfs_d204 *d204; /* Aligned d204 data with header */
560 void *base; /* Base pointer (needed for vfree) */
561};
562
563static int dbfs_d204_open(struct inode *inode, struct file *file)
564{ 559{
565 struct dbfs_d204_private *data;
566 struct dbfs_d204 *d204; 560 struct dbfs_d204 *d204;
567 int rc, buf_size; 561 int rc, buf_size;
562 void *base;
568 563
569 data = kzalloc(sizeof(*data), GFP_KERNEL);
570 if (!data)
571 return -ENOMEM;
572 buf_size = PAGE_SIZE * (diag204_buf_pages + 1) + sizeof(d204->hdr); 564 buf_size = PAGE_SIZE * (diag204_buf_pages + 1) + sizeof(d204->hdr);
573 data->base = vmalloc(buf_size); 565 base = vmalloc(buf_size);
574 if (!data->base) { 566 if (!base)
575 rc = -ENOMEM; 567 return -ENOMEM;
576 goto fail_kfree_data; 568 memset(base, 0, buf_size);
569 d204 = page_align_ptr(base + sizeof(d204->hdr)) - sizeof(d204->hdr);
570 rc = diag204_do_store(d204->buf, diag204_buf_pages);
571 if (rc) {
572 vfree(base);
573 return rc;
577 } 574 }
578 memset(data->base, 0, buf_size);
579 d204 = page_align_ptr(data->base + sizeof(d204->hdr))
580 - sizeof(d204->hdr);
581 rc = diag204_do_store(&d204->buf, diag204_buf_pages);
582 if (rc)
583 goto fail_vfree_base;
584 d204->hdr.version = DBFS_D204_HDR_VERSION; 575 d204->hdr.version = DBFS_D204_HDR_VERSION;
585 d204->hdr.len = PAGE_SIZE * diag204_buf_pages; 576 d204->hdr.len = PAGE_SIZE * diag204_buf_pages;
586 d204->hdr.sc = diag204_store_sc; 577 d204->hdr.sc = diag204_store_sc;
587 data->d204 = d204; 578 *data = d204;
588 file->private_data = data; 579 *data_free_ptr = base;
589 return nonseekable_open(inode, file); 580 *size = d204->hdr.len + sizeof(struct dbfs_d204_hdr);
590
591fail_vfree_base:
592 vfree(data->base);
593fail_kfree_data:
594 kfree(data);
595 return rc;
596}
597
598static int dbfs_d204_release(struct inode *inode, struct file *file)
599{
600 struct dbfs_d204_private *data = file->private_data;
601
602 vfree(data->base);
603 kfree(data);
604 return 0; 581 return 0;
605} 582}
606 583
607static ssize_t dbfs_d204_read(struct file *file, char __user *buf, 584static struct hypfs_dbfs_file dbfs_file_d204 = {
608 size_t size, loff_t *ppos) 585 .name = "diag_204",
609{ 586 .data_create = dbfs_d204_create,
610 struct dbfs_d204_private *data = file->private_data; 587 .data_free = vfree,
611
612 return simple_read_from_buffer(buf, size, ppos, data->d204,
613 data->d204->hdr.len +
614 sizeof(data->d204->hdr));
615}
616
617static const struct file_operations dbfs_d204_ops = {
618 .open = dbfs_d204_open,
619 .read = dbfs_d204_read,
620 .release = dbfs_d204_release,
621 .llseek = no_llseek,
622}; 588};
623 589
624static int hypfs_dbfs_init(void)
625{
626 dbfs_d204_file = debugfs_create_file("diag_204", 0400, hypfs_dbfs_dir,
627 NULL, &dbfs_d204_ops);
628 if (IS_ERR(dbfs_d204_file))
629 return PTR_ERR(dbfs_d204_file);
630 return 0;
631}
632
633__init int hypfs_diag_init(void) 590__init int hypfs_diag_init(void)
634{ 591{
635 int rc; 592 int rc;
@@ -639,7 +596,7 @@ __init int hypfs_diag_init(void)
639 return -ENODATA; 596 return -ENODATA;
640 } 597 }
641 if (diag204_info_type == INFO_EXT) { 598 if (diag204_info_type == INFO_EXT) {
642 rc = hypfs_dbfs_init(); 599 rc = hypfs_dbfs_create_file(&dbfs_file_d204);
643 if (rc) 600 if (rc)
644 return rc; 601 return rc;
645 } 602 }
@@ -660,6 +617,7 @@ void hypfs_diag_exit(void)
660 debugfs_remove(dbfs_d204_file); 617 debugfs_remove(dbfs_d204_file);
661 diag224_delete_name_table(); 618 diag224_delete_name_table();
662 diag204_free_buffer(); 619 diag204_free_buffer();
620 hypfs_dbfs_remove_file(&dbfs_file_d204);
663} 621}
664 622
665/* 623/*
diff --git a/arch/s390/hypfs/hypfs_vm.c b/arch/s390/hypfs/hypfs_vm.c
index 26cf177f6a3a..e54796002f61 100644
--- a/arch/s390/hypfs/hypfs_vm.c
+++ b/arch/s390/hypfs/hypfs_vm.c
@@ -20,8 +20,6 @@ static char local_guest[] = " ";
20static char all_guests[] = "* "; 20static char all_guests[] = "* ";
21static char *guest_query; 21static char *guest_query;
22 22
23static struct dentry *dbfs_d2fc_file;
24
25struct diag2fc_data { 23struct diag2fc_data {
26 __u32 version; 24 __u32 version;
27 __u32 flags; 25 __u32 flags;
@@ -104,7 +102,7 @@ static void *diag2fc_store(char *query, unsigned int *count, int offset)
104 return data; 102 return data;
105} 103}
106 104
107static void diag2fc_free(void *data) 105static void diag2fc_free(const void *data)
108{ 106{
109 vfree(data); 107 vfree(data);
110} 108}
@@ -239,43 +237,29 @@ struct dbfs_d2fc {
239 char buf[]; /* d2fc buffer */ 237 char buf[]; /* d2fc buffer */
240} __attribute__ ((packed)); 238} __attribute__ ((packed));
241 239
242static int dbfs_d2fc_open(struct inode *inode, struct file *file) 240static int dbfs_diag2fc_create(void **data, void **data_free_ptr, size_t *size)
243{ 241{
244 struct dbfs_d2fc *data; 242 struct dbfs_d2fc *d2fc;
245 unsigned int count; 243 unsigned int count;
246 244
247 data = diag2fc_store(guest_query, &count, sizeof(data->hdr)); 245 d2fc = diag2fc_store(guest_query, &count, sizeof(d2fc->hdr));
248 if (IS_ERR(data)) 246 if (IS_ERR(d2fc))
249 return PTR_ERR(data); 247 return PTR_ERR(d2fc);
250 get_clock_ext(data->hdr.tod_ext); 248 get_clock_ext(d2fc->hdr.tod_ext);
251 data->hdr.len = count * sizeof(struct diag2fc_data); 249 d2fc->hdr.len = count * sizeof(struct diag2fc_data);
252 data->hdr.version = DBFS_D2FC_HDR_VERSION; 250 d2fc->hdr.version = DBFS_D2FC_HDR_VERSION;
253 data->hdr.count = count; 251 d2fc->hdr.count = count;
254 memset(&data->hdr.reserved, 0, sizeof(data->hdr.reserved)); 252 memset(&d2fc->hdr.reserved, 0, sizeof(d2fc->hdr.reserved));
255 file->private_data = data; 253 *data = d2fc;
256 return nonseekable_open(inode, file); 254 *data_free_ptr = d2fc;
257} 255 *size = d2fc->hdr.len + sizeof(struct dbfs_d2fc_hdr);
258
259static int dbfs_d2fc_release(struct inode *inode, struct file *file)
260{
261 diag2fc_free(file->private_data);
262 return 0; 256 return 0;
263} 257}
264 258
265static ssize_t dbfs_d2fc_read(struct file *file, char __user *buf, 259static struct hypfs_dbfs_file dbfs_file_2fc = {
266 size_t size, loff_t *ppos) 260 .name = "diag_2fc",
267{ 261 .data_create = dbfs_diag2fc_create,
268 struct dbfs_d2fc *data = file->private_data; 262 .data_free = diag2fc_free,
269
270 return simple_read_from_buffer(buf, size, ppos, data, data->hdr.len +
271 sizeof(struct dbfs_d2fc_hdr));
272}
273
274static const struct file_operations dbfs_d2fc_ops = {
275 .open = dbfs_d2fc_open,
276 .read = dbfs_d2fc_read,
277 .release = dbfs_d2fc_release,
278 .llseek = no_llseek,
279}; 263};
280 264
281int hypfs_vm_init(void) 265int hypfs_vm_init(void)
@@ -288,18 +272,12 @@ int hypfs_vm_init(void)
288 guest_query = local_guest; 272 guest_query = local_guest;
289 else 273 else
290 return -EACCES; 274 return -EACCES;
291 275 return hypfs_dbfs_create_file(&dbfs_file_2fc);
292 dbfs_d2fc_file = debugfs_create_file("diag_2fc", 0400, hypfs_dbfs_dir,
293 NULL, &dbfs_d2fc_ops);
294 if (IS_ERR(dbfs_d2fc_file))
295 return PTR_ERR(dbfs_d2fc_file);
296
297 return 0;
298} 276}
299 277
300void hypfs_vm_exit(void) 278void hypfs_vm_exit(void)
301{ 279{
302 if (!MACHINE_IS_VM) 280 if (!MACHINE_IS_VM)
303 return; 281 return;
304 debugfs_remove(dbfs_d2fc_file); 282 hypfs_dbfs_remove_file(&dbfs_file_2fc);
305} 283}
diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c
index 47cc446dab8f..6fe874fc5f8e 100644
--- a/arch/s390/hypfs/inode.c
+++ b/arch/s390/hypfs/inode.c
@@ -46,8 +46,6 @@ static const struct super_operations hypfs_s_ops;
46/* start of list of all dentries, which have to be deleted on update */ 46/* start of list of all dentries, which have to be deleted on update */
47static struct dentry *hypfs_last_dentry; 47static struct dentry *hypfs_last_dentry;
48 48
49struct dentry *hypfs_dbfs_dir;
50
51static void hypfs_update_update(struct super_block *sb) 49static void hypfs_update_update(struct super_block *sb)
52{ 50{
53 struct hypfs_sb_info *sb_info = sb->s_fs_info; 51 struct hypfs_sb_info *sb_info = sb->s_fs_info;
@@ -471,13 +469,12 @@ static int __init hypfs_init(void)
471{ 469{
472 int rc; 470 int rc;
473 471
474 hypfs_dbfs_dir = debugfs_create_dir("s390_hypfs", NULL); 472 rc = hypfs_dbfs_init();
475 if (IS_ERR(hypfs_dbfs_dir)) 473 if (rc)
476 return PTR_ERR(hypfs_dbfs_dir); 474 return rc;
477
478 if (hypfs_diag_init()) { 475 if (hypfs_diag_init()) {
479 rc = -ENODATA; 476 rc = -ENODATA;
480 goto fail_debugfs_remove; 477 goto fail_dbfs_exit;
481 } 478 }
482 if (hypfs_vm_init()) { 479 if (hypfs_vm_init()) {
483 rc = -ENODATA; 480 rc = -ENODATA;
@@ -499,9 +496,8 @@ fail_hypfs_vm_exit:
499 hypfs_vm_exit(); 496 hypfs_vm_exit();
500fail_hypfs_diag_exit: 497fail_hypfs_diag_exit:
501 hypfs_diag_exit(); 498 hypfs_diag_exit();
502fail_debugfs_remove: 499fail_dbfs_exit:
503 debugfs_remove(hypfs_dbfs_dir); 500 hypfs_dbfs_exit();
504
505 pr_err("Initialization of hypfs failed with rc=%i\n", rc); 501 pr_err("Initialization of hypfs failed with rc=%i\n", rc);
506 return rc; 502 return rc;
507} 503}
@@ -510,7 +506,7 @@ static void __exit hypfs_exit(void)
510{ 506{
511 hypfs_diag_exit(); 507 hypfs_diag_exit();
512 hypfs_vm_exit(); 508 hypfs_vm_exit();
513 debugfs_remove(hypfs_dbfs_dir); 509 hypfs_dbfs_exit();
514 unregister_filesystem(&hypfs_type); 510 unregister_filesystem(&hypfs_type);
515 kobject_put(s390_kobj); 511 kobject_put(s390_kobj);
516} 512}