12fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu/*
22fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu * Hypervisor filesystem for Linux on s390 - debugfs interface
32fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu *
4a53c8fab3f87c995c30ac226a03af95361243144Heiko Carstens * Copyright IBM Corp. 2010
52fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu * Author(s): Michael Holzheu <holzheu@linux.vnet.ibm.com>
62fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu */
72fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu
82fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu#include <linux/slab.h>
92fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu#include "hypfs.h"
102fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu
112fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheustatic struct dentry *dbfs_dir;
122fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu
132fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheustatic struct hypfs_dbfs_data *hypfs_dbfs_data_alloc(struct hypfs_dbfs_file *f)
142fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu{
152fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu	struct hypfs_dbfs_data *data;
162fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu
172fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu	data = kmalloc(sizeof(*data), GFP_KERNEL);
182fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu	if (!data)
192fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu		return NULL;
202fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu	kref_init(&data->kref);
212fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu	data->dbfs_file = f;
222fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu	return data;
232fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu}
242fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu
252fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheustatic void hypfs_dbfs_data_free(struct kref *kref)
262fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu{
272fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu	struct hypfs_dbfs_data *data;
282fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu
292fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu	data = container_of(kref, struct hypfs_dbfs_data, kref);
302fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu	data->dbfs_file->data_free(data->buf_free_ptr);
312fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu	kfree(data);
322fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu}
332fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu
342fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheustatic void data_free_delayed(struct work_struct *work)
352fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu{
362fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu	struct hypfs_dbfs_data *data;
372fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu	struct hypfs_dbfs_file *df;
382fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu
392fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu	df = container_of(work, struct hypfs_dbfs_file, data_free_work.work);
402fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu	mutex_lock(&df->lock);
412fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu	data = df->data;
422fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu	df->data = NULL;
432fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu	mutex_unlock(&df->lock);
442fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu	kref_put(&data->kref, hypfs_dbfs_data_free);
452fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu}
462fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu
472fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheustatic ssize_t dbfs_read(struct file *file, char __user *buf,
482fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu			 size_t size, loff_t *ppos)
492fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu{
502fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu	struct hypfs_dbfs_data *data;
512fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu	struct hypfs_dbfs_file *df;
522fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu	ssize_t rc;
532fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu
542fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu	if (*ppos != 0)
552fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu		return 0;
562fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu
57496ad9aa8ef448058e36ca7a787c61f2e63f0f54Al Viro	df = file_inode(file)->i_private;
582fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu	mutex_lock(&df->lock);
592fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu	if (!df->data) {
602fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu		data = hypfs_dbfs_data_alloc(df);
612fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu		if (!data) {
622fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu			mutex_unlock(&df->lock);
632fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu			return -ENOMEM;
642fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu		}
652fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu		rc = df->data_create(&data->buf, &data->buf_free_ptr,
662fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu				     &data->size);
672fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu		if (rc) {
682fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu			mutex_unlock(&df->lock);
692fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu			kfree(data);
702fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu			return rc;
712fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu		}
722fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu		df->data = data;
732fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu		schedule_delayed_work(&df->data_free_work, HZ);
742fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu	}
752fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu	data = df->data;
762fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu	kref_get(&data->kref);
772fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu	mutex_unlock(&df->lock);
782fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu
792fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu	rc = simple_read_from_buffer(buf, size, ppos, data->buf, data->size);
802fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu	kref_put(&data->kref, hypfs_dbfs_data_free);
812fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu	return rc;
822fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu}
832fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu
8407be0382097027cde68d9268cc628741069b5762Martin Schwidefskystatic long dbfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
8507be0382097027cde68d9268cc628741069b5762Martin Schwidefsky{
8607be0382097027cde68d9268cc628741069b5762Martin Schwidefsky	struct hypfs_dbfs_file *df;
8707be0382097027cde68d9268cc628741069b5762Martin Schwidefsky	long rc;
8807be0382097027cde68d9268cc628741069b5762Martin Schwidefsky
8907be0382097027cde68d9268cc628741069b5762Martin Schwidefsky	df = file->f_path.dentry->d_inode->i_private;
9007be0382097027cde68d9268cc628741069b5762Martin Schwidefsky	mutex_lock(&df->lock);
9107be0382097027cde68d9268cc628741069b5762Martin Schwidefsky	if (df->unlocked_ioctl)
9207be0382097027cde68d9268cc628741069b5762Martin Schwidefsky		rc = df->unlocked_ioctl(file, cmd, arg);
9307be0382097027cde68d9268cc628741069b5762Martin Schwidefsky	else
9407be0382097027cde68d9268cc628741069b5762Martin Schwidefsky		rc = -ENOTTY;
9507be0382097027cde68d9268cc628741069b5762Martin Schwidefsky	mutex_unlock(&df->lock);
9607be0382097027cde68d9268cc628741069b5762Martin Schwidefsky	return rc;
9707be0382097027cde68d9268cc628741069b5762Martin Schwidefsky}
9807be0382097027cde68d9268cc628741069b5762Martin Schwidefsky
992fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheustatic const struct file_operations dbfs_ops = {
1002fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu	.read		= dbfs_read,
1012fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu	.llseek		= no_llseek,
10207be0382097027cde68d9268cc628741069b5762Martin Schwidefsky	.unlocked_ioctl = dbfs_ioctl,
1032fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu};
1042fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu
1052fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheuint hypfs_dbfs_create_file(struct hypfs_dbfs_file *df)
1062fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu{
1072fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu	df->dentry = debugfs_create_file(df->name, 0400, dbfs_dir, df,
1082fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu					 &dbfs_ops);
1092fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu	if (IS_ERR(df->dentry))
1102fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu		return PTR_ERR(df->dentry);
1112fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu	mutex_init(&df->lock);
1122fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu	INIT_DELAYED_WORK(&df->data_free_work, data_free_delayed);
1132fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu	return 0;
1142fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu}
1152fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu
1162fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheuvoid hypfs_dbfs_remove_file(struct hypfs_dbfs_file *df)
1172fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu{
1182fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu	debugfs_remove(df->dentry);
1192fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu}
1202fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu
1212fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheuint hypfs_dbfs_init(void)
1222fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu{
1232fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu	dbfs_dir = debugfs_create_dir("s390_hypfs", NULL);
1248c6ffba0eddc8c110dbf444f51354ce42069abfcRusty Russell	return PTR_ERR_OR_ZERO(dbfs_dir);
1252fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu}
1262fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu
1272fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheuvoid hypfs_dbfs_exit(void)
1282fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu{
1292fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu	debugfs_remove(dbfs_dir);
1302fcb3686e1601cff992e026dceeab1b22dc81178Michael Holzheu}
131