xref: /linux/arch/s390/hypfs/hypfs_dbfs.c (revision 2fcb3686e1601cff992e026dceeab1b22dc81178)
1*2fcb3686SMichael Holzheu /*
2*2fcb3686SMichael Holzheu  * Hypervisor filesystem for Linux on s390 - debugfs interface
3*2fcb3686SMichael Holzheu  *
4*2fcb3686SMichael Holzheu  * Copyright (C) IBM Corp. 2010
5*2fcb3686SMichael Holzheu  * Author(s): Michael Holzheu <holzheu@linux.vnet.ibm.com>
6*2fcb3686SMichael Holzheu  */
7*2fcb3686SMichael Holzheu 
8*2fcb3686SMichael Holzheu #include <linux/slab.h>
9*2fcb3686SMichael Holzheu #include "hypfs.h"
10*2fcb3686SMichael Holzheu 
11*2fcb3686SMichael Holzheu static struct dentry *dbfs_dir;
12*2fcb3686SMichael Holzheu 
13*2fcb3686SMichael Holzheu static struct hypfs_dbfs_data *hypfs_dbfs_data_alloc(struct hypfs_dbfs_file *f)
14*2fcb3686SMichael Holzheu {
15*2fcb3686SMichael Holzheu 	struct hypfs_dbfs_data *data;
16*2fcb3686SMichael Holzheu 
17*2fcb3686SMichael Holzheu 	data = kmalloc(sizeof(*data), GFP_KERNEL);
18*2fcb3686SMichael Holzheu 	if (!data)
19*2fcb3686SMichael Holzheu 		return NULL;
20*2fcb3686SMichael Holzheu 	kref_init(&data->kref);
21*2fcb3686SMichael Holzheu 	data->dbfs_file = f;
22*2fcb3686SMichael Holzheu 	return data;
23*2fcb3686SMichael Holzheu }
24*2fcb3686SMichael Holzheu 
25*2fcb3686SMichael Holzheu static void hypfs_dbfs_data_free(struct kref *kref)
26*2fcb3686SMichael Holzheu {
27*2fcb3686SMichael Holzheu 	struct hypfs_dbfs_data *data;
28*2fcb3686SMichael Holzheu 
29*2fcb3686SMichael Holzheu 	data = container_of(kref, struct hypfs_dbfs_data, kref);
30*2fcb3686SMichael Holzheu 	data->dbfs_file->data_free(data->buf_free_ptr);
31*2fcb3686SMichael Holzheu 	kfree(data);
32*2fcb3686SMichael Holzheu }
33*2fcb3686SMichael Holzheu 
34*2fcb3686SMichael Holzheu static void data_free_delayed(struct work_struct *work)
35*2fcb3686SMichael Holzheu {
36*2fcb3686SMichael Holzheu 	struct hypfs_dbfs_data *data;
37*2fcb3686SMichael Holzheu 	struct hypfs_dbfs_file *df;
38*2fcb3686SMichael Holzheu 
39*2fcb3686SMichael Holzheu 	df = container_of(work, struct hypfs_dbfs_file, data_free_work.work);
40*2fcb3686SMichael Holzheu 	mutex_lock(&df->lock);
41*2fcb3686SMichael Holzheu 	data = df->data;
42*2fcb3686SMichael Holzheu 	df->data = NULL;
43*2fcb3686SMichael Holzheu 	mutex_unlock(&df->lock);
44*2fcb3686SMichael Holzheu 	kref_put(&data->kref, hypfs_dbfs_data_free);
45*2fcb3686SMichael Holzheu }
46*2fcb3686SMichael Holzheu 
47*2fcb3686SMichael Holzheu static ssize_t dbfs_read(struct file *file, char __user *buf,
48*2fcb3686SMichael Holzheu 			 size_t size, loff_t *ppos)
49*2fcb3686SMichael Holzheu {
50*2fcb3686SMichael Holzheu 	struct hypfs_dbfs_data *data;
51*2fcb3686SMichael Holzheu 	struct hypfs_dbfs_file *df;
52*2fcb3686SMichael Holzheu 	ssize_t rc;
53*2fcb3686SMichael Holzheu 
54*2fcb3686SMichael Holzheu 	if (*ppos != 0)
55*2fcb3686SMichael Holzheu 		return 0;
56*2fcb3686SMichael Holzheu 
57*2fcb3686SMichael Holzheu 	df = file->f_path.dentry->d_inode->i_private;
58*2fcb3686SMichael Holzheu 	mutex_lock(&df->lock);
59*2fcb3686SMichael Holzheu 	if (!df->data) {
60*2fcb3686SMichael Holzheu 		data = hypfs_dbfs_data_alloc(df);
61*2fcb3686SMichael Holzheu 		if (!data) {
62*2fcb3686SMichael Holzheu 			mutex_unlock(&df->lock);
63*2fcb3686SMichael Holzheu 			return -ENOMEM;
64*2fcb3686SMichael Holzheu 		}
65*2fcb3686SMichael Holzheu 		rc = df->data_create(&data->buf, &data->buf_free_ptr,
66*2fcb3686SMichael Holzheu 				     &data->size);
67*2fcb3686SMichael Holzheu 		if (rc) {
68*2fcb3686SMichael Holzheu 			mutex_unlock(&df->lock);
69*2fcb3686SMichael Holzheu 			kfree(data);
70*2fcb3686SMichael Holzheu 			return rc;
71*2fcb3686SMichael Holzheu 		}
72*2fcb3686SMichael Holzheu 		df->data = data;
73*2fcb3686SMichael Holzheu 		schedule_delayed_work(&df->data_free_work, HZ);
74*2fcb3686SMichael Holzheu 	}
75*2fcb3686SMichael Holzheu 	data = df->data;
76*2fcb3686SMichael Holzheu 	kref_get(&data->kref);
77*2fcb3686SMichael Holzheu 	mutex_unlock(&df->lock);
78*2fcb3686SMichael Holzheu 
79*2fcb3686SMichael Holzheu 	rc = simple_read_from_buffer(buf, size, ppos, data->buf, data->size);
80*2fcb3686SMichael Holzheu 	kref_put(&data->kref, hypfs_dbfs_data_free);
81*2fcb3686SMichael Holzheu 	return rc;
82*2fcb3686SMichael Holzheu }
83*2fcb3686SMichael Holzheu 
84*2fcb3686SMichael Holzheu static const struct file_operations dbfs_ops = {
85*2fcb3686SMichael Holzheu 	.read		= dbfs_read,
86*2fcb3686SMichael Holzheu 	.llseek		= no_llseek,
87*2fcb3686SMichael Holzheu };
88*2fcb3686SMichael Holzheu 
89*2fcb3686SMichael Holzheu int hypfs_dbfs_create_file(struct hypfs_dbfs_file *df)
90*2fcb3686SMichael Holzheu {
91*2fcb3686SMichael Holzheu 	df->dentry = debugfs_create_file(df->name, 0400, dbfs_dir, df,
92*2fcb3686SMichael Holzheu 					 &dbfs_ops);
93*2fcb3686SMichael Holzheu 	if (IS_ERR(df->dentry))
94*2fcb3686SMichael Holzheu 		return PTR_ERR(df->dentry);
95*2fcb3686SMichael Holzheu 	mutex_init(&df->lock);
96*2fcb3686SMichael Holzheu 	INIT_DELAYED_WORK(&df->data_free_work, data_free_delayed);
97*2fcb3686SMichael Holzheu 	return 0;
98*2fcb3686SMichael Holzheu }
99*2fcb3686SMichael Holzheu 
100*2fcb3686SMichael Holzheu void hypfs_dbfs_remove_file(struct hypfs_dbfs_file *df)
101*2fcb3686SMichael Holzheu {
102*2fcb3686SMichael Holzheu 	debugfs_remove(df->dentry);
103*2fcb3686SMichael Holzheu }
104*2fcb3686SMichael Holzheu 
105*2fcb3686SMichael Holzheu int hypfs_dbfs_init(void)
106*2fcb3686SMichael Holzheu {
107*2fcb3686SMichael Holzheu 	dbfs_dir = debugfs_create_dir("s390_hypfs", NULL);
108*2fcb3686SMichael Holzheu 	if (IS_ERR(dbfs_dir))
109*2fcb3686SMichael Holzheu 		return PTR_ERR(dbfs_dir);
110*2fcb3686SMichael Holzheu 	return 0;
111*2fcb3686SMichael Holzheu }
112*2fcb3686SMichael Holzheu 
113*2fcb3686SMichael Holzheu void hypfs_dbfs_exit(void)
114*2fcb3686SMichael Holzheu {
115*2fcb3686SMichael Holzheu 	debugfs_remove(dbfs_dir);
116*2fcb3686SMichael Holzheu }
117