1/*
2 * Hypervisor filesystem for Linux on s390 - debugfs interface
3 *
4 * Copyright 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	data->dbfs_file = f;
21	return data;
22}
23
24static void hypfs_dbfs_data_free(struct hypfs_dbfs_data *data)
25{
26	data->dbfs_file->data_free(data->buf_free_ptr);
27	kfree(data);
28}
29
30static ssize_t dbfs_read(struct file *file, char __user *buf,
31			 size_t size, loff_t *ppos)
32{
33	struct hypfs_dbfs_data *data;
34	struct hypfs_dbfs_file *df;
35	ssize_t rc;
36
37	if (*ppos != 0)
38		return 0;
39
40	df = file_inode(file)->i_private;
41	mutex_lock(&df->lock);
42	data = hypfs_dbfs_data_alloc(df);
43	if (!data) {
44		mutex_unlock(&df->lock);
45		return -ENOMEM;
46	}
47	rc = df->data_create(&data->buf, &data->buf_free_ptr, &data->size);
48	if (rc) {
49		mutex_unlock(&df->lock);
50		kfree(data);
51		return rc;
52	}
53	mutex_unlock(&df->lock);
54
55	rc = simple_read_from_buffer(buf, size, ppos, data->buf, data->size);
56	hypfs_dbfs_data_free(data);
57	return rc;
58}
59
60static long dbfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
61{
62	struct hypfs_dbfs_file *df = file_inode(file)->i_private;
63	long rc;
64
65	mutex_lock(&df->lock);
66	if (df->unlocked_ioctl)
67		rc = df->unlocked_ioctl(file, cmd, arg);
68	else
69		rc = -ENOTTY;
70	mutex_unlock(&df->lock);
71	return rc;
72}
73
74static const struct file_operations dbfs_ops = {
75	.read		= dbfs_read,
76	.llseek		= no_llseek,
77	.unlocked_ioctl = dbfs_ioctl,
78};
79
80int hypfs_dbfs_create_file(struct hypfs_dbfs_file *df)
81{
82	df->dentry = debugfs_create_file(df->name, 0400, dbfs_dir, df,
83					 &dbfs_ops);
84	if (IS_ERR(df->dentry))
85		return PTR_ERR(df->dentry);
86	mutex_init(&df->lock);
87	return 0;
88}
89
90void hypfs_dbfs_remove_file(struct hypfs_dbfs_file *df)
91{
92	debugfs_remove(df->dentry);
93}
94
95int hypfs_dbfs_init(void)
96{
97	dbfs_dir = debugfs_create_dir("s390_hypfs", NULL);
98	return PTR_ERR_OR_ZERO(dbfs_dir);
99}
100
101void hypfs_dbfs_exit(void)
102{
103	debugfs_remove(dbfs_dir);
104}
105