s390/hypfs: add interface for diagnose 0x304
To provide access to the set-partition-resource-parameter interface to user space add a new attribute to hypfs/debugfs: * s390_hypsfs/diag_304 The data for the query-partition-resource-parameters command can be access by a read on the attribute. All other diagnose 0x304 requests need to be submitted via ioctl with CAP_SYS_ADMIN rights. Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
Родитель
fded4329da
Коммит
07be038209
|
@ -73,6 +73,7 @@ Code Seq#(hex) Include File Comments
|
|||
0x09 all linux/raid/md_u.h
|
||||
0x10 00-0F drivers/char/s390/vmcp.h
|
||||
0x10 10-1F arch/s390/include/uapi/sclp_ctl.h
|
||||
0x10 20-2F arch/s390/include/uapi/asm/hypfs.h
|
||||
0x12 all linux/fs.h
|
||||
linux/blkpg.h
|
||||
0x1b all InfiniBand Subsystem <http://infiniband.sourceforge.net/>
|
||||
|
|
|
@ -4,4 +4,4 @@
|
|||
|
||||
obj-$(CONFIG_S390_HYPFS_FS) += s390_hypfs.o
|
||||
|
||||
s390_hypfs-objs := inode.o hypfs_diag.o hypfs_vm.o hypfs_dbfs.o
|
||||
s390_hypfs-objs := inode.o hypfs_diag.o hypfs_vm.o hypfs_dbfs.o hypfs_sprp.o
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <linux/debugfs.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/kref.h>
|
||||
#include <asm/hypfs.h>
|
||||
|
||||
#define REG_FILE_MODE 0440
|
||||
#define UPDATE_FILE_MODE 0220
|
||||
|
@ -36,6 +37,10 @@ extern int hypfs_vm_init(void);
|
|||
extern void hypfs_vm_exit(void);
|
||||
extern int hypfs_vm_create_files(struct dentry *root);
|
||||
|
||||
/* Set Partition-Resource Parameter */
|
||||
int hypfs_sprp_init(void);
|
||||
void hypfs_sprp_exit(void);
|
||||
|
||||
/* debugfs interface */
|
||||
struct hypfs_dbfs_file;
|
||||
|
||||
|
@ -52,6 +57,8 @@ struct hypfs_dbfs_file {
|
|||
int (*data_create)(void **data, void **data_free_ptr,
|
||||
size_t *size);
|
||||
void (*data_free)(const void *buf_free_ptr);
|
||||
long (*unlocked_ioctl) (struct file *, unsigned int,
|
||||
unsigned long);
|
||||
|
||||
/* Private data for hypfs_dbfs.c */
|
||||
struct hypfs_dbfs_data *data;
|
||||
|
|
|
@ -81,9 +81,25 @@ static ssize_t dbfs_read(struct file *file, char __user *buf,
|
|||
return rc;
|
||||
}
|
||||
|
||||
static long dbfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct hypfs_dbfs_file *df;
|
||||
long rc;
|
||||
|
||||
df = file->f_path.dentry->d_inode->i_private;
|
||||
mutex_lock(&df->lock);
|
||||
if (df->unlocked_ioctl)
|
||||
rc = df->unlocked_ioctl(file, cmd, arg);
|
||||
else
|
||||
rc = -ENOTTY;
|
||||
mutex_unlock(&df->lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static const struct file_operations dbfs_ops = {
|
||||
.read = dbfs_read,
|
||||
.llseek = no_llseek,
|
||||
.unlocked_ioctl = dbfs_ioctl,
|
||||
};
|
||||
|
||||
int hypfs_dbfs_create_file(struct hypfs_dbfs_file *df)
|
||||
|
|
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* Hypervisor filesystem for Linux on s390.
|
||||
* Set Partition-Resource Parameter interface.
|
||||
*
|
||||
* Copyright IBM Corp. 2013
|
||||
* Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
|
||||
*/
|
||||
|
||||
#include <linux/compat.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <asm/compat.h>
|
||||
#include <asm/sclp.h>
|
||||
#include "hypfs.h"
|
||||
|
||||
#define DIAG304_SET_WEIGHTS 0
|
||||
#define DIAG304_QUERY_PRP 1
|
||||
#define DIAG304_SET_CAPPING 2
|
||||
|
||||
#define DIAG304_CMD_MAX 2
|
||||
|
||||
static unsigned long hypfs_sprp_diag304(void *data, unsigned long cmd)
|
||||
{
|
||||
register unsigned long _data asm("2") = (unsigned long) data;
|
||||
register unsigned long _rc asm("3");
|
||||
register unsigned long _cmd asm("4") = cmd;
|
||||
|
||||
asm volatile("diag %1,%2,0x304\n"
|
||||
: "=d" (_rc) : "d" (_data), "d" (_cmd) : "memory");
|
||||
|
||||
return _rc;
|
||||
}
|
||||
|
||||
static void hypfs_sprp_free(const void *data)
|
||||
{
|
||||
free_page((unsigned long) data);
|
||||
}
|
||||
|
||||
static int hypfs_sprp_create(void **data_ptr, void **free_ptr, size_t *size)
|
||||
{
|
||||
unsigned long rc;
|
||||
void *data;
|
||||
|
||||
data = (void *) get_zeroed_page(GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
rc = hypfs_sprp_diag304(data, DIAG304_QUERY_PRP);
|
||||
if (rc != 1) {
|
||||
*data_ptr = *free_ptr = NULL;
|
||||
*size = 0;
|
||||
free_page((unsigned long) data);
|
||||
return -EIO;
|
||||
}
|
||||
*data_ptr = *free_ptr = data;
|
||||
*size = PAGE_SIZE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __hypfs_sprp_ioctl(void __user *user_area)
|
||||
{
|
||||
struct hypfs_diag304 diag304;
|
||||
unsigned long cmd;
|
||||
void __user *udata;
|
||||
void *data;
|
||||
int rc;
|
||||
|
||||
if (copy_from_user(&diag304, user_area, sizeof(diag304)))
|
||||
return -EFAULT;
|
||||
if ((diag304.args[0] >> 8) != 0 || diag304.args[1] > DIAG304_CMD_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
data = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
udata = (void __user *)(unsigned long) diag304.data;
|
||||
if (diag304.args[1] == DIAG304_SET_WEIGHTS ||
|
||||
diag304.args[1] == DIAG304_SET_CAPPING)
|
||||
if (copy_from_user(data, udata, PAGE_SIZE)) {
|
||||
rc = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
cmd = *(unsigned long *) &diag304.args[0];
|
||||
diag304.rc = hypfs_sprp_diag304(data, cmd);
|
||||
|
||||
if (diag304.args[1] == DIAG304_QUERY_PRP)
|
||||
if (copy_to_user(udata, data, PAGE_SIZE)) {
|
||||
rc = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = copy_to_user(user_area, &diag304, sizeof(diag304)) ? -EFAULT : 0;
|
||||
out:
|
||||
free_page((unsigned long) data);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static long hypfs_sprp_ioctl(struct file *file, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
void __user *argp;
|
||||
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EACCES;
|
||||
if (is_compat_task())
|
||||
argp = compat_ptr(arg);
|
||||
else
|
||||
argp = (void __user *) arg;
|
||||
switch (cmd) {
|
||||
case HYPFS_DIAG304:
|
||||
return __hypfs_sprp_ioctl(argp);
|
||||
default: /* unknown ioctl number */
|
||||
return -ENOTTY;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct hypfs_dbfs_file hypfs_sprp_file = {
|
||||
.name = "diag_304",
|
||||
.data_create = hypfs_sprp_create,
|
||||
.data_free = hypfs_sprp_free,
|
||||
.unlocked_ioctl = hypfs_sprp_ioctl,
|
||||
};
|
||||
|
||||
int hypfs_sprp_init(void)
|
||||
{
|
||||
if (!sclp_has_sprp())
|
||||
return 0;
|
||||
return hypfs_dbfs_create_file(&hypfs_sprp_file);
|
||||
}
|
||||
|
||||
void hypfs_sprp_exit(void)
|
||||
{
|
||||
if (!sclp_has_sprp())
|
||||
return;
|
||||
hypfs_dbfs_remove_file(&hypfs_sprp_file);
|
||||
}
|
|
@ -478,10 +478,14 @@ static int __init hypfs_init(void)
|
|||
rc = -ENODATA;
|
||||
goto fail_hypfs_diag_exit;
|
||||
}
|
||||
if (hypfs_sprp_init()) {
|
||||
rc = -ENODATA;
|
||||
goto fail_hypfs_vm_exit;
|
||||
}
|
||||
s390_kobj = kobject_create_and_add("s390", hypervisor_kobj);
|
||||
if (!s390_kobj) {
|
||||
rc = -ENOMEM;
|
||||
goto fail_hypfs_vm_exit;
|
||||
goto fail_hypfs_sprp_exit;
|
||||
}
|
||||
rc = register_filesystem(&hypfs_type);
|
||||
if (rc)
|
||||
|
@ -490,6 +494,8 @@ static int __init hypfs_init(void)
|
|||
|
||||
fail_filesystem:
|
||||
kobject_put(s390_kobj);
|
||||
fail_hypfs_sprp_exit:
|
||||
hypfs_sprp_exit();
|
||||
fail_hypfs_vm_exit:
|
||||
hypfs_vm_exit();
|
||||
fail_hypfs_diag_exit:
|
||||
|
@ -502,11 +508,12 @@ fail_dbfs_exit:
|
|||
|
||||
static void __exit hypfs_exit(void)
|
||||
{
|
||||
hypfs_diag_exit();
|
||||
hypfs_vm_exit();
|
||||
hypfs_dbfs_exit();
|
||||
unregister_filesystem(&hypfs_type);
|
||||
kobject_put(s390_kobj);
|
||||
hypfs_sprp_exit();
|
||||
hypfs_vm_exit();
|
||||
hypfs_diag_exit();
|
||||
hypfs_dbfs_exit();
|
||||
}
|
||||
|
||||
module_init(hypfs_init)
|
||||
|
|
|
@ -54,6 +54,7 @@ int sclp_chp_read_info(struct sclp_chp_info *info);
|
|||
void sclp_get_ipl_info(struct sclp_ipl_info *info);
|
||||
bool __init sclp_has_linemode(void);
|
||||
bool __init sclp_has_vt220(void);
|
||||
bool sclp_has_sprp(void);
|
||||
int sclp_pci_configure(u32 fid);
|
||||
int sclp_pci_deconfigure(u32 fid);
|
||||
int memcpy_hsa(void *dest, unsigned long src, size_t count, int mode);
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* IOCTL interface for hypfs
|
||||
*
|
||||
* Copyright IBM Corp. 2013
|
||||
*
|
||||
* Author: Martin Schwidefsky <schwidefsky@de.ibm.com>
|
||||
*/
|
||||
|
||||
#ifndef _ASM_HYPFS_CTL_H
|
||||
#define _ASM_HYPFS_CTL_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
struct hypfs_diag304 {
|
||||
__u32 args[2];
|
||||
__u64 data;
|
||||
__u64 rc;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define HYPFS_IOCTL_MAGIC 0x10
|
||||
|
||||
#define HYPFS_DIAG304 \
|
||||
_IOWR(HYPFS_IOCTL_MAGIC, 0x20, struct hypfs_diag304)
|
||||
|
||||
#endif
|
|
@ -700,3 +700,8 @@ out:
|
|||
free_page((unsigned long) sccb);
|
||||
return rc;
|
||||
}
|
||||
|
||||
bool sclp_has_sprp(void)
|
||||
{
|
||||
return !!(sclp_fac84 & 0x2);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче