]>
Commit | Line | Data |
---|---|---|
2fcb3686 MH |
1 | /* |
2 | * Hypervisor filesystem for Linux on s390 - debugfs interface | |
3 | * | |
a53c8fab | 4 | * Copyright IBM Corp. 2010 |
2fcb3686 MH |
5 | * Author(s): Michael Holzheu <holzheu@linux.vnet.ibm.com> |
6 | */ | |
7 | ||
8 | #include <linux/slab.h> | |
9 | #include "hypfs.h" | |
10 | ||
11 | static struct dentry *dbfs_dir; | |
12 | ||
13 | static 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 | ||
25 | static 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 | ||
34 | static 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 | ||
47 | static 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 | ||
84 | static const struct file_operations dbfs_ops = { | |
85 | .read = dbfs_read, | |
86 | .llseek = no_llseek, | |
87 | }; | |
88 | ||
89 | int 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 | ||
100 | void hypfs_dbfs_remove_file(struct hypfs_dbfs_file *df) | |
101 | { | |
102 | debugfs_remove(df->dentry); | |
103 | } | |
104 | ||
105 | int 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 | ||
113 | void hypfs_dbfs_exit(void) | |
114 | { | |
115 | debugfs_remove(dbfs_dir); | |
116 | } |