12fcb3686SMichael Holzheu /* 22fcb3686SMichael Holzheu * Hypervisor filesystem for Linux on s390 - debugfs interface 32fcb3686SMichael Holzheu * 4*a53c8fabSHeiko 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 572fcb3686SMichael Holzheu df = file->f_path.dentry->d_inode->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 842fcb3686SMichael Holzheu static const struct file_operations dbfs_ops = { 852fcb3686SMichael Holzheu .read = dbfs_read, 862fcb3686SMichael Holzheu .llseek = no_llseek, 872fcb3686SMichael Holzheu }; 882fcb3686SMichael Holzheu 892fcb3686SMichael Holzheu int hypfs_dbfs_create_file(struct hypfs_dbfs_file *df) 902fcb3686SMichael Holzheu { 912fcb3686SMichael Holzheu df->dentry = debugfs_create_file(df->name, 0400, dbfs_dir, df, 922fcb3686SMichael Holzheu &dbfs_ops); 932fcb3686SMichael Holzheu if (IS_ERR(df->dentry)) 942fcb3686SMichael Holzheu return PTR_ERR(df->dentry); 952fcb3686SMichael Holzheu mutex_init(&df->lock); 962fcb3686SMichael Holzheu INIT_DELAYED_WORK(&df->data_free_work, data_free_delayed); 972fcb3686SMichael Holzheu return 0; 982fcb3686SMichael Holzheu } 992fcb3686SMichael Holzheu 1002fcb3686SMichael Holzheu void hypfs_dbfs_remove_file(struct hypfs_dbfs_file *df) 1012fcb3686SMichael Holzheu { 1022fcb3686SMichael Holzheu debugfs_remove(df->dentry); 1032fcb3686SMichael Holzheu } 1042fcb3686SMichael Holzheu 1052fcb3686SMichael Holzheu int hypfs_dbfs_init(void) 1062fcb3686SMichael Holzheu { 1072fcb3686SMichael Holzheu dbfs_dir = debugfs_create_dir("s390_hypfs", NULL); 1082fcb3686SMichael Holzheu if (IS_ERR(dbfs_dir)) 1092fcb3686SMichael Holzheu return PTR_ERR(dbfs_dir); 1102fcb3686SMichael Holzheu return 0; 1112fcb3686SMichael Holzheu } 1122fcb3686SMichael Holzheu 1132fcb3686SMichael Holzheu void hypfs_dbfs_exit(void) 1142fcb3686SMichael Holzheu { 1152fcb3686SMichael Holzheu debugfs_remove(dbfs_dir); 1162fcb3686SMichael Holzheu } 117