Greg Kroah-Hartman | b244131 | 2017-11-01 15:07:57 +0100 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0 |
Michael Holzheu | 2fcb368 | 2011-01-05 12:47:43 +0100 | [diff] [blame] | 2 | /* |
| 3 | * Hypervisor filesystem for Linux on s390 - debugfs interface |
| 4 | * |
Heiko Carstens | a53c8fa | 2012-07-20 11:15:04 +0200 | [diff] [blame] | 5 | * Copyright IBM Corp. 2010 |
Michael Holzheu | 2fcb368 | 2011-01-05 12:47:43 +0100 | [diff] [blame] | 6 | * Author(s): Michael Holzheu <holzheu@linux.vnet.ibm.com> |
| 7 | */ |
| 8 | |
| 9 | #include <linux/slab.h> |
| 10 | #include "hypfs.h" |
| 11 | |
| 12 | static struct dentry *dbfs_dir; |
| 13 | |
| 14 | static struct hypfs_dbfs_data *hypfs_dbfs_data_alloc(struct hypfs_dbfs_file *f) |
| 15 | { |
| 16 | struct hypfs_dbfs_data *data; |
| 17 | |
| 18 | data = kmalloc(sizeof(*data), GFP_KERNEL); |
| 19 | if (!data) |
| 20 | return NULL; |
Michael Holzheu | 2fcb368 | 2011-01-05 12:47:43 +0100 | [diff] [blame] | 21 | data->dbfs_file = f; |
| 22 | return data; |
| 23 | } |
| 24 | |
Michael Holzheu | a178220 | 2015-02-09 14:49:32 +0100 | [diff] [blame] | 25 | static void hypfs_dbfs_data_free(struct hypfs_dbfs_data *data) |
Michael Holzheu | 2fcb368 | 2011-01-05 12:47:43 +0100 | [diff] [blame] | 26 | { |
Michael Holzheu | 2fcb368 | 2011-01-05 12:47:43 +0100 | [diff] [blame] | 27 | data->dbfs_file->data_free(data->buf_free_ptr); |
| 28 | kfree(data); |
| 29 | } |
| 30 | |
Michael Holzheu | 2fcb368 | 2011-01-05 12:47:43 +0100 | [diff] [blame] | 31 | static ssize_t dbfs_read(struct file *file, char __user *buf, |
| 32 | size_t size, loff_t *ppos) |
| 33 | { |
| 34 | struct hypfs_dbfs_data *data; |
| 35 | struct hypfs_dbfs_file *df; |
| 36 | ssize_t rc; |
| 37 | |
| 38 | if (*ppos != 0) |
| 39 | return 0; |
| 40 | |
Al Viro | 496ad9a | 2013-01-23 17:07:38 -0500 | [diff] [blame] | 41 | df = file_inode(file)->i_private; |
Michael Holzheu | 2fcb368 | 2011-01-05 12:47:43 +0100 | [diff] [blame] | 42 | mutex_lock(&df->lock); |
Michael Holzheu | a178220 | 2015-02-09 14:49:32 +0100 | [diff] [blame] | 43 | data = hypfs_dbfs_data_alloc(df); |
| 44 | if (!data) { |
| 45 | mutex_unlock(&df->lock); |
| 46 | return -ENOMEM; |
Michael Holzheu | 2fcb368 | 2011-01-05 12:47:43 +0100 | [diff] [blame] | 47 | } |
Michael Holzheu | a178220 | 2015-02-09 14:49:32 +0100 | [diff] [blame] | 48 | rc = df->data_create(&data->buf, &data->buf_free_ptr, &data->size); |
| 49 | if (rc) { |
| 50 | mutex_unlock(&df->lock); |
| 51 | kfree(data); |
| 52 | return rc; |
| 53 | } |
Michael Holzheu | 2fcb368 | 2011-01-05 12:47:43 +0100 | [diff] [blame] | 54 | mutex_unlock(&df->lock); |
| 55 | |
| 56 | rc = simple_read_from_buffer(buf, size, ppos, data->buf, data->size); |
Michael Holzheu | a178220 | 2015-02-09 14:49:32 +0100 | [diff] [blame] | 57 | hypfs_dbfs_data_free(data); |
Michael Holzheu | 2fcb368 | 2011-01-05 12:47:43 +0100 | [diff] [blame] | 58 | return rc; |
| 59 | } |
| 60 | |
Martin Schwidefsky | 07be038 | 2014-01-24 09:18:52 +0100 | [diff] [blame] | 61 | static long dbfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
| 62 | { |
Al Viro | a455589 | 2014-10-21 20:11:25 -0400 | [diff] [blame] | 63 | struct hypfs_dbfs_file *df = file_inode(file)->i_private; |
Martin Schwidefsky | 07be038 | 2014-01-24 09:18:52 +0100 | [diff] [blame] | 64 | long rc; |
| 65 | |
Martin Schwidefsky | 07be038 | 2014-01-24 09:18:52 +0100 | [diff] [blame] | 66 | mutex_lock(&df->lock); |
| 67 | if (df->unlocked_ioctl) |
| 68 | rc = df->unlocked_ioctl(file, cmd, arg); |
| 69 | else |
| 70 | rc = -ENOTTY; |
| 71 | mutex_unlock(&df->lock); |
| 72 | return rc; |
| 73 | } |
| 74 | |
Michael Holzheu | 2fcb368 | 2011-01-05 12:47:43 +0100 | [diff] [blame] | 75 | static const struct file_operations dbfs_ops = { |
| 76 | .read = dbfs_read, |
| 77 | .llseek = no_llseek, |
Martin Schwidefsky | 07be038 | 2014-01-24 09:18:52 +0100 | [diff] [blame] | 78 | .unlocked_ioctl = dbfs_ioctl, |
Michael Holzheu | 2fcb368 | 2011-01-05 12:47:43 +0100 | [diff] [blame] | 79 | }; |
| 80 | |
| 81 | int hypfs_dbfs_create_file(struct hypfs_dbfs_file *df) |
| 82 | { |
| 83 | df->dentry = debugfs_create_file(df->name, 0400, dbfs_dir, df, |
| 84 | &dbfs_ops); |
| 85 | if (IS_ERR(df->dentry)) |
| 86 | return PTR_ERR(df->dentry); |
| 87 | mutex_init(&df->lock); |
Michael Holzheu | 2fcb368 | 2011-01-05 12:47:43 +0100 | [diff] [blame] | 88 | return 0; |
| 89 | } |
| 90 | |
| 91 | void hypfs_dbfs_remove_file(struct hypfs_dbfs_file *df) |
| 92 | { |
| 93 | debugfs_remove(df->dentry); |
| 94 | } |
| 95 | |
| 96 | int hypfs_dbfs_init(void) |
| 97 | { |
| 98 | dbfs_dir = debugfs_create_dir("s390_hypfs", NULL); |
Rusty Russell | 8c6ffba | 2013-07-15 11:20:32 +0930 | [diff] [blame] | 99 | return PTR_ERR_OR_ZERO(dbfs_dir); |
Michael Holzheu | 2fcb368 | 2011-01-05 12:47:43 +0100 | [diff] [blame] | 100 | } |
| 101 | |
| 102 | void hypfs_dbfs_exit(void) |
| 103 | { |
| 104 | debugfs_remove(dbfs_dir); |
| 105 | } |