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