162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Hypervisor filesystem for Linux on s390 - debugfs interface 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright IBM Corp. 2010 662306a36Sopenharmony_ci * Author(s): Michael Holzheu <holzheu@linux.vnet.ibm.com> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/slab.h> 1062306a36Sopenharmony_ci#include "hypfs.h" 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_cistatic struct dentry *dbfs_dir; 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_cistatic struct hypfs_dbfs_data *hypfs_dbfs_data_alloc(struct hypfs_dbfs_file *f) 1562306a36Sopenharmony_ci{ 1662306a36Sopenharmony_ci struct hypfs_dbfs_data *data; 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci data = kmalloc(sizeof(*data), GFP_KERNEL); 1962306a36Sopenharmony_ci if (!data) 2062306a36Sopenharmony_ci return NULL; 2162306a36Sopenharmony_ci data->dbfs_file = f; 2262306a36Sopenharmony_ci return data; 2362306a36Sopenharmony_ci} 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistatic void hypfs_dbfs_data_free(struct hypfs_dbfs_data *data) 2662306a36Sopenharmony_ci{ 2762306a36Sopenharmony_ci data->dbfs_file->data_free(data->buf_free_ptr); 2862306a36Sopenharmony_ci kfree(data); 2962306a36Sopenharmony_ci} 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic ssize_t dbfs_read(struct file *file, char __user *buf, 3262306a36Sopenharmony_ci size_t size, loff_t *ppos) 3362306a36Sopenharmony_ci{ 3462306a36Sopenharmony_ci struct hypfs_dbfs_data *data; 3562306a36Sopenharmony_ci struct hypfs_dbfs_file *df; 3662306a36Sopenharmony_ci ssize_t rc; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci if (*ppos != 0) 3962306a36Sopenharmony_ci return 0; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci df = file_inode(file)->i_private; 4262306a36Sopenharmony_ci mutex_lock(&df->lock); 4362306a36Sopenharmony_ci data = hypfs_dbfs_data_alloc(df); 4462306a36Sopenharmony_ci if (!data) { 4562306a36Sopenharmony_ci mutex_unlock(&df->lock); 4662306a36Sopenharmony_ci return -ENOMEM; 4762306a36Sopenharmony_ci } 4862306a36Sopenharmony_ci rc = df->data_create(&data->buf, &data->buf_free_ptr, &data->size); 4962306a36Sopenharmony_ci if (rc) { 5062306a36Sopenharmony_ci mutex_unlock(&df->lock); 5162306a36Sopenharmony_ci kfree(data); 5262306a36Sopenharmony_ci return rc; 5362306a36Sopenharmony_ci } 5462306a36Sopenharmony_ci mutex_unlock(&df->lock); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci rc = simple_read_from_buffer(buf, size, ppos, data->buf, data->size); 5762306a36Sopenharmony_ci hypfs_dbfs_data_free(data); 5862306a36Sopenharmony_ci return rc; 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistatic long dbfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 6262306a36Sopenharmony_ci{ 6362306a36Sopenharmony_ci struct hypfs_dbfs_file *df = file_inode(file)->i_private; 6462306a36Sopenharmony_ci long rc; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci mutex_lock(&df->lock); 6762306a36Sopenharmony_ci if (df->unlocked_ioctl) 6862306a36Sopenharmony_ci rc = df->unlocked_ioctl(file, cmd, arg); 6962306a36Sopenharmony_ci else 7062306a36Sopenharmony_ci rc = -ENOTTY; 7162306a36Sopenharmony_ci mutex_unlock(&df->lock); 7262306a36Sopenharmony_ci return rc; 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic const struct file_operations dbfs_ops = { 7662306a36Sopenharmony_ci .read = dbfs_read, 7762306a36Sopenharmony_ci .llseek = no_llseek, 7862306a36Sopenharmony_ci .unlocked_ioctl = dbfs_ioctl, 7962306a36Sopenharmony_ci}; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_civoid hypfs_dbfs_create_file(struct hypfs_dbfs_file *df) 8262306a36Sopenharmony_ci{ 8362306a36Sopenharmony_ci df->dentry = debugfs_create_file(df->name, 0400, dbfs_dir, df, 8462306a36Sopenharmony_ci &dbfs_ops); 8562306a36Sopenharmony_ci mutex_init(&df->lock); 8662306a36Sopenharmony_ci} 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_civoid hypfs_dbfs_remove_file(struct hypfs_dbfs_file *df) 8962306a36Sopenharmony_ci{ 9062306a36Sopenharmony_ci debugfs_remove(df->dentry); 9162306a36Sopenharmony_ci} 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_cistatic int __init hypfs_dbfs_init(void) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci int rc = -ENODATA; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci dbfs_dir = debugfs_create_dir("s390_hypfs", NULL); 9862306a36Sopenharmony_ci if (hypfs_diag_init()) 9962306a36Sopenharmony_ci goto fail_dbfs_exit; 10062306a36Sopenharmony_ci if (hypfs_vm_init()) 10162306a36Sopenharmony_ci goto fail_hypfs_diag_exit; 10262306a36Sopenharmony_ci hypfs_sprp_init(); 10362306a36Sopenharmony_ci if (hypfs_diag0c_init()) 10462306a36Sopenharmony_ci goto fail_hypfs_sprp_exit; 10562306a36Sopenharmony_ci rc = hypfs_fs_init(); 10662306a36Sopenharmony_ci if (rc) 10762306a36Sopenharmony_ci goto fail_hypfs_diag0c_exit; 10862306a36Sopenharmony_ci return 0; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cifail_hypfs_diag0c_exit: 11162306a36Sopenharmony_ci hypfs_diag0c_exit(); 11262306a36Sopenharmony_cifail_hypfs_sprp_exit: 11362306a36Sopenharmony_ci hypfs_sprp_exit(); 11462306a36Sopenharmony_ci hypfs_vm_exit(); 11562306a36Sopenharmony_cifail_hypfs_diag_exit: 11662306a36Sopenharmony_ci hypfs_diag_exit(); 11762306a36Sopenharmony_ci pr_err("Initialization of hypfs failed with rc=%i\n", rc); 11862306a36Sopenharmony_cifail_dbfs_exit: 11962306a36Sopenharmony_ci debugfs_remove(dbfs_dir); 12062306a36Sopenharmony_ci return rc; 12162306a36Sopenharmony_ci} 12262306a36Sopenharmony_cidevice_initcall(hypfs_dbfs_init) 123