18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Hypervisor filesystem for Linux on s390 - debugfs interface
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright IBM Corp. 2010
68c2ecf20Sopenharmony_ci * Author(s): Michael Holzheu <holzheu@linux.vnet.ibm.com>
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/slab.h>
108c2ecf20Sopenharmony_ci#include "hypfs.h"
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_cistatic struct dentry *dbfs_dir;
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_cistatic struct hypfs_dbfs_data *hypfs_dbfs_data_alloc(struct hypfs_dbfs_file *f)
158c2ecf20Sopenharmony_ci{
168c2ecf20Sopenharmony_ci	struct hypfs_dbfs_data *data;
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci	data = kmalloc(sizeof(*data), GFP_KERNEL);
198c2ecf20Sopenharmony_ci	if (!data)
208c2ecf20Sopenharmony_ci		return NULL;
218c2ecf20Sopenharmony_ci	data->dbfs_file = f;
228c2ecf20Sopenharmony_ci	return data;
238c2ecf20Sopenharmony_ci}
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_cistatic void hypfs_dbfs_data_free(struct hypfs_dbfs_data *data)
268c2ecf20Sopenharmony_ci{
278c2ecf20Sopenharmony_ci	data->dbfs_file->data_free(data->buf_free_ptr);
288c2ecf20Sopenharmony_ci	kfree(data);
298c2ecf20Sopenharmony_ci}
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_cistatic ssize_t dbfs_read(struct file *file, char __user *buf,
328c2ecf20Sopenharmony_ci			 size_t size, loff_t *ppos)
338c2ecf20Sopenharmony_ci{
348c2ecf20Sopenharmony_ci	struct hypfs_dbfs_data *data;
358c2ecf20Sopenharmony_ci	struct hypfs_dbfs_file *df;
368c2ecf20Sopenharmony_ci	ssize_t rc;
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci	if (*ppos != 0)
398c2ecf20Sopenharmony_ci		return 0;
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	df = file_inode(file)->i_private;
428c2ecf20Sopenharmony_ci	mutex_lock(&df->lock);
438c2ecf20Sopenharmony_ci	data = hypfs_dbfs_data_alloc(df);
448c2ecf20Sopenharmony_ci	if (!data) {
458c2ecf20Sopenharmony_ci		mutex_unlock(&df->lock);
468c2ecf20Sopenharmony_ci		return -ENOMEM;
478c2ecf20Sopenharmony_ci	}
488c2ecf20Sopenharmony_ci	rc = df->data_create(&data->buf, &data->buf_free_ptr, &data->size);
498c2ecf20Sopenharmony_ci	if (rc) {
508c2ecf20Sopenharmony_ci		mutex_unlock(&df->lock);
518c2ecf20Sopenharmony_ci		kfree(data);
528c2ecf20Sopenharmony_ci		return rc;
538c2ecf20Sopenharmony_ci	}
548c2ecf20Sopenharmony_ci	mutex_unlock(&df->lock);
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	rc = simple_read_from_buffer(buf, size, ppos, data->buf, data->size);
578c2ecf20Sopenharmony_ci	hypfs_dbfs_data_free(data);
588c2ecf20Sopenharmony_ci	return rc;
598c2ecf20Sopenharmony_ci}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_cistatic long dbfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
628c2ecf20Sopenharmony_ci{
638c2ecf20Sopenharmony_ci	struct hypfs_dbfs_file *df = file_inode(file)->i_private;
648c2ecf20Sopenharmony_ci	long rc;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	mutex_lock(&df->lock);
678c2ecf20Sopenharmony_ci	if (df->unlocked_ioctl)
688c2ecf20Sopenharmony_ci		rc = df->unlocked_ioctl(file, cmd, arg);
698c2ecf20Sopenharmony_ci	else
708c2ecf20Sopenharmony_ci		rc = -ENOTTY;
718c2ecf20Sopenharmony_ci	mutex_unlock(&df->lock);
728c2ecf20Sopenharmony_ci	return rc;
738c2ecf20Sopenharmony_ci}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_cistatic const struct file_operations dbfs_ops = {
768c2ecf20Sopenharmony_ci	.read		= dbfs_read,
778c2ecf20Sopenharmony_ci	.llseek		= no_llseek,
788c2ecf20Sopenharmony_ci	.unlocked_ioctl = dbfs_ioctl,
798c2ecf20Sopenharmony_ci};
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_civoid hypfs_dbfs_create_file(struct hypfs_dbfs_file *df)
828c2ecf20Sopenharmony_ci{
838c2ecf20Sopenharmony_ci	df->dentry = debugfs_create_file(df->name, 0400, dbfs_dir, df,
848c2ecf20Sopenharmony_ci					 &dbfs_ops);
858c2ecf20Sopenharmony_ci	mutex_init(&df->lock);
868c2ecf20Sopenharmony_ci}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_civoid hypfs_dbfs_remove_file(struct hypfs_dbfs_file *df)
898c2ecf20Sopenharmony_ci{
908c2ecf20Sopenharmony_ci	debugfs_remove(df->dentry);
918c2ecf20Sopenharmony_ci}
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_civoid hypfs_dbfs_init(void)
948c2ecf20Sopenharmony_ci{
958c2ecf20Sopenharmony_ci	dbfs_dir = debugfs_create_dir("s390_hypfs", NULL);
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_civoid hypfs_dbfs_exit(void)
998c2ecf20Sopenharmony_ci{
1008c2ecf20Sopenharmony_ci	debugfs_remove(dbfs_dir);
1018c2ecf20Sopenharmony_ci}
102