diff options
Diffstat (limited to 'arch/s390/hypfs')
| -rw-r--r-- | arch/s390/hypfs/Makefile | 2 | ||||
| -rw-r--r-- | arch/s390/hypfs/hypfs.h | 56 | ||||
| -rw-r--r-- | arch/s390/hypfs/hypfs_dbfs.c | 130 | ||||
| -rw-r--r-- | arch/s390/hypfs/hypfs_diag.c | 140 | ||||
| -rw-r--r-- | arch/s390/hypfs/hypfs_sprp.c | 141 | ||||
| -rw-r--r-- | arch/s390/hypfs/hypfs_vm.c | 136 | ||||
| -rw-r--r-- | arch/s390/hypfs/inode.c | 129 | 
7 files changed, 484 insertions, 250 deletions
diff --git a/arch/s390/hypfs/Makefile b/arch/s390/hypfs/Makefile index b08d2abf617..06f8d95a16c 100644 --- a/arch/s390/hypfs/Makefile +++ b/arch/s390/hypfs/Makefile @@ -4,4 +4,4 @@  obj-$(CONFIG_S390_HYPFS_FS) += s390_hypfs.o -s390_hypfs-objs := inode.o hypfs_diag.o hypfs_vm.o +s390_hypfs-objs := inode.o hypfs_diag.o hypfs_vm.o hypfs_dbfs.o hypfs_sprp.o diff --git a/arch/s390/hypfs/hypfs.h b/arch/s390/hypfs/hypfs.h index fa487d4cc08..b34b5ab90a3 100644 --- a/arch/s390/hypfs/hypfs.h +++ b/arch/s390/hypfs/hypfs.h @@ -1,8 +1,7 @@  /* - *  arch/s390/hypfs/hypfs.h   *    Hypervisor filesystem for Linux on s390.   * - *    Copyright (C) IBM Corp. 2006 + *    Copyright IBM Corp. 2006   *    Author(s): Michael Holzheu <holzheu@de.ibm.com>   */ @@ -12,32 +11,65 @@  #include <linux/fs.h>  #include <linux/types.h>  #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  #define DIR_MODE         0550 -extern struct dentry *hypfs_mkdir(struct super_block *sb, struct dentry *parent, -				  const char *name); +extern struct dentry *hypfs_mkdir(struct dentry *parent, const char *name); -extern struct dentry *hypfs_create_u64(struct super_block *sb, -				       struct dentry *dir, const char *name, +extern struct dentry *hypfs_create_u64(struct dentry *dir, const char *name,  				       __u64 value); -extern struct dentry *hypfs_create_str(struct super_block *sb, -				       struct dentry *dir, const char *name, +extern struct dentry *hypfs_create_str(struct dentry *dir, const char *name,  				       char *string);  /* LPAR Hypervisor */  extern int hypfs_diag_init(void);  extern void hypfs_diag_exit(void); -extern int hypfs_diag_create_files(struct super_block *sb, struct dentry *root); +extern int hypfs_diag_create_files(struct dentry *root);  /* VM Hypervisor */  extern int hypfs_vm_init(void);  extern void hypfs_vm_exit(void); -extern int hypfs_vm_create_files(struct super_block *sb, struct dentry *root); +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; + +struct hypfs_dbfs_data { +	void			*buf; +	void			*buf_free_ptr; +	size_t			size; +	struct hypfs_dbfs_file	*dbfs_file; +	struct kref		kref; +}; + +struct hypfs_dbfs_file { +	const char	*name; +	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; +	struct delayed_work	data_free_work; +	struct mutex		lock; +	struct dentry		*dentry; +}; + +extern int hypfs_dbfs_init(void); +extern void hypfs_dbfs_exit(void); +extern int hypfs_dbfs_create_file(struct hypfs_dbfs_file *df); +extern void hypfs_dbfs_remove_file(struct hypfs_dbfs_file *df); -/* Directory for debugfs files */ -extern struct dentry *hypfs_dbfs_dir;  #endif /* _HYPFS_H_ */ diff --git a/arch/s390/hypfs/hypfs_dbfs.c b/arch/s390/hypfs/hypfs_dbfs.c new file mode 100644 index 00000000000..2badf2bf9cd --- /dev/null +++ b/arch/s390/hypfs/hypfs_dbfs.c @@ -0,0 +1,130 @@ +/* + * Hypervisor filesystem for Linux on s390 - debugfs interface + * + * Copyright IBM Corp. 2010 + * Author(s): Michael Holzheu <holzheu@linux.vnet.ibm.com> + */ + +#include <linux/slab.h> +#include "hypfs.h" + +static struct dentry *dbfs_dir; + +static struct hypfs_dbfs_data *hypfs_dbfs_data_alloc(struct hypfs_dbfs_file *f) +{ +	struct hypfs_dbfs_data *data; + +	data = kmalloc(sizeof(*data), GFP_KERNEL); +	if (!data) +		return NULL; +	kref_init(&data->kref); +	data->dbfs_file = f; +	return data; +} + +static void hypfs_dbfs_data_free(struct kref *kref) +{ +	struct hypfs_dbfs_data *data; + +	data = container_of(kref, struct hypfs_dbfs_data, kref); +	data->dbfs_file->data_free(data->buf_free_ptr); +	kfree(data); +} + +static void data_free_delayed(struct work_struct *work) +{ +	struct hypfs_dbfs_data *data; +	struct hypfs_dbfs_file *df; + +	df = container_of(work, struct hypfs_dbfs_file, data_free_work.work); +	mutex_lock(&df->lock); +	data = df->data; +	df->data = NULL; +	mutex_unlock(&df->lock); +	kref_put(&data->kref, hypfs_dbfs_data_free); +} + +static ssize_t dbfs_read(struct file *file, char __user *buf, +			 size_t size, loff_t *ppos) +{ +	struct hypfs_dbfs_data *data; +	struct hypfs_dbfs_file *df; +	ssize_t rc; + +	if (*ppos != 0) +		return 0; + +	df = file_inode(file)->i_private; +	mutex_lock(&df->lock); +	if (!df->data) { +		data = hypfs_dbfs_data_alloc(df); +		if (!data) { +			mutex_unlock(&df->lock); +			return -ENOMEM; +		} +		rc = df->data_create(&data->buf, &data->buf_free_ptr, +				     &data->size); +		if (rc) { +			mutex_unlock(&df->lock); +			kfree(data); +			return rc; +		} +		df->data = data; +		schedule_delayed_work(&df->data_free_work, HZ); +	} +	data = df->data; +	kref_get(&data->kref); +	mutex_unlock(&df->lock); + +	rc = simple_read_from_buffer(buf, size, ppos, data->buf, data->size); +	kref_put(&data->kref, hypfs_dbfs_data_free); +	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) +{ +	df->dentry = debugfs_create_file(df->name, 0400, dbfs_dir, df, +					 &dbfs_ops); +	if (IS_ERR(df->dentry)) +		return PTR_ERR(df->dentry); +	mutex_init(&df->lock); +	INIT_DELAYED_WORK(&df->data_free_work, data_free_delayed); +	return 0; +} + +void hypfs_dbfs_remove_file(struct hypfs_dbfs_file *df) +{ +	debugfs_remove(df->dentry); +} + +int hypfs_dbfs_init(void) +{ +	dbfs_dir = debugfs_create_dir("s390_hypfs", NULL); +	return PTR_ERR_OR_ZERO(dbfs_dir); +} + +void hypfs_dbfs_exit(void) +{ +	debugfs_remove(dbfs_dir); +} diff --git a/arch/s390/hypfs/hypfs_diag.c b/arch/s390/hypfs/hypfs_diag.c index cd4a81be9cf..5eeffeefae0 100644 --- a/arch/s390/hypfs/hypfs_diag.c +++ b/arch/s390/hypfs/hypfs_diag.c @@ -1,5 +1,4 @@  /* - *  arch/s390/hypfs/hypfs_diag.c   *    Hypervisor filesystem for Linux on s390. Diag 204 and 224   *    implementation.   * @@ -555,81 +554,37 @@ struct dbfs_d204 {  	char			buf[];	/* d204 buffer */  } __attribute__ ((packed)); -struct dbfs_d204_private { -	struct dbfs_d204	*d204;	/* Aligned d204 data with header */ -	void			*base;	/* Base pointer (needed for vfree) */ -}; - -static int dbfs_d204_open(struct inode *inode, struct file *file) +static int dbfs_d204_create(void **data, void **data_free_ptr, size_t *size)  { -	struct dbfs_d204_private *data;  	struct dbfs_d204 *d204;  	int rc, buf_size; +	void *base; -	data = kzalloc(sizeof(*data), GFP_KERNEL); -	if (!data) -		return -ENOMEM;  	buf_size = PAGE_SIZE * (diag204_buf_pages + 1) + sizeof(d204->hdr); -	data->base = vmalloc(buf_size); -	if (!data->base) { -		rc = -ENOMEM; -		goto fail_kfree_data; +	base = vzalloc(buf_size); +	if (!base) +		return -ENOMEM; +	d204 = page_align_ptr(base + sizeof(d204->hdr)) - sizeof(d204->hdr); +	rc = diag204_do_store(d204->buf, diag204_buf_pages); +	if (rc) { +		vfree(base); +		return rc;  	} -	memset(data->base, 0, buf_size); -	d204 = page_align_ptr(data->base + sizeof(d204->hdr)) -		- sizeof(d204->hdr); -	rc = diag204_do_store(&d204->buf, diag204_buf_pages); -	if (rc) -		goto fail_vfree_base;  	d204->hdr.version = DBFS_D204_HDR_VERSION;  	d204->hdr.len = PAGE_SIZE * diag204_buf_pages;  	d204->hdr.sc = diag204_store_sc; -	data->d204 = d204; -	file->private_data = data; -	return nonseekable_open(inode, file); - -fail_vfree_base: -	vfree(data->base); -fail_kfree_data: -	kfree(data); -	return rc; -} - -static int dbfs_d204_release(struct inode *inode, struct file *file) -{ -	struct dbfs_d204_private *data = file->private_data; - -	vfree(data->base); -	kfree(data); +	*data = d204; +	*data_free_ptr = base; +	*size = d204->hdr.len + sizeof(struct dbfs_d204_hdr);  	return 0;  } -static ssize_t dbfs_d204_read(struct file *file, char __user *buf, -			      size_t size, loff_t *ppos) -{ -	struct dbfs_d204_private *data = file->private_data; - -	return simple_read_from_buffer(buf, size, ppos, data->d204, -				       data->d204->hdr.len + -				       sizeof(data->d204->hdr)); -} - -static const struct file_operations dbfs_d204_ops = { -	.open		= dbfs_d204_open, -	.read		= dbfs_d204_read, -	.release	= dbfs_d204_release, -	.llseek		= no_llseek, +static struct hypfs_dbfs_file dbfs_file_d204 = { +	.name		= "diag_204", +	.data_create	= dbfs_d204_create, +	.data_free	= vfree,  }; -static int hypfs_dbfs_init(void) -{ -	dbfs_d204_file = debugfs_create_file("diag_204", 0400, hypfs_dbfs_dir, -					     NULL, &dbfs_d204_ops); -	if (IS_ERR(dbfs_d204_file)) -		return PTR_ERR(dbfs_d204_file); -	return 0; -} -  __init int hypfs_diag_init(void)  {  	int rc; @@ -639,7 +594,7 @@ __init int hypfs_diag_init(void)  		return -ENODATA;  	}  	if (diag204_info_type == INFO_EXT) { -		rc = hypfs_dbfs_init(); +		rc = hypfs_dbfs_create_file(&dbfs_file_d204);  		if (rc)  			return rc;  	} @@ -660,6 +615,7 @@ void hypfs_diag_exit(void)  	debugfs_remove(dbfs_d204_file);  	diag224_delete_name_table();  	diag204_free_buffer(); +	hypfs_dbfs_remove_file(&dbfs_file_d204);  }  /* @@ -667,8 +623,7 @@ void hypfs_diag_exit(void)   * *******************************************   */ -static int hypfs_create_cpu_files(struct super_block *sb, -				  struct dentry *cpus_dir, void *cpu_info) +static int hypfs_create_cpu_files(struct dentry *cpus_dir, void *cpu_info)  {  	struct dentry *cpu_dir;  	char buffer[TMP_SIZE]; @@ -676,32 +631,29 @@ static int hypfs_create_cpu_files(struct super_block *sb,  	snprintf(buffer, TMP_SIZE, "%d", cpu_info__cpu_addr(diag204_info_type,  							    cpu_info)); -	cpu_dir = hypfs_mkdir(sb, cpus_dir, buffer); -	rc = hypfs_create_u64(sb, cpu_dir, "mgmtime", +	cpu_dir = hypfs_mkdir(cpus_dir, buffer); +	rc = hypfs_create_u64(cpu_dir, "mgmtime",  			      cpu_info__acc_time(diag204_info_type, cpu_info) -  			      cpu_info__lp_time(diag204_info_type, cpu_info));  	if (IS_ERR(rc))  		return PTR_ERR(rc); -	rc = hypfs_create_u64(sb, cpu_dir, "cputime", +	rc = hypfs_create_u64(cpu_dir, "cputime",  			      cpu_info__lp_time(diag204_info_type, cpu_info));  	if (IS_ERR(rc))  		return PTR_ERR(rc);  	if (diag204_info_type == INFO_EXT) { -		rc = hypfs_create_u64(sb, cpu_dir, "onlinetime", +		rc = hypfs_create_u64(cpu_dir, "onlinetime",  				      cpu_info__online_time(diag204_info_type,  							    cpu_info));  		if (IS_ERR(rc))  			return PTR_ERR(rc);  	}  	diag224_idx2name(cpu_info__ctidx(diag204_info_type, cpu_info), buffer); -	rc = hypfs_create_str(sb, cpu_dir, "type", buffer); -	if (IS_ERR(rc)) -		return PTR_ERR(rc); -	return 0; +	rc = hypfs_create_str(cpu_dir, "type", buffer); +	return PTR_RET(rc);  } -static void *hypfs_create_lpar_files(struct super_block *sb, -				     struct dentry *systems_dir, void *part_hdr) +static void *hypfs_create_lpar_files(struct dentry *systems_dir, void *part_hdr)  {  	struct dentry *cpus_dir;  	struct dentry *lpar_dir; @@ -711,16 +663,16 @@ static void *hypfs_create_lpar_files(struct super_block *sb,  	part_hdr__part_name(diag204_info_type, part_hdr, lpar_name);  	lpar_name[LPAR_NAME_LEN] = 0; -	lpar_dir = hypfs_mkdir(sb, systems_dir, lpar_name); +	lpar_dir = hypfs_mkdir(systems_dir, lpar_name);  	if (IS_ERR(lpar_dir))  		return lpar_dir; -	cpus_dir = hypfs_mkdir(sb, lpar_dir, "cpus"); +	cpus_dir = hypfs_mkdir(lpar_dir, "cpus");  	if (IS_ERR(cpus_dir))  		return cpus_dir;  	cpu_info = part_hdr + part_hdr__size(diag204_info_type);  	for (i = 0; i < part_hdr__rcpus(diag204_info_type, part_hdr); i++) {  		int rc; -		rc = hypfs_create_cpu_files(sb, cpus_dir, cpu_info); +		rc = hypfs_create_cpu_files(cpus_dir, cpu_info);  		if (rc)  			return ERR_PTR(rc);  		cpu_info += cpu_info__size(diag204_info_type); @@ -728,8 +680,7 @@ static void *hypfs_create_lpar_files(struct super_block *sb,  	return cpu_info;  } -static int hypfs_create_phys_cpu_files(struct super_block *sb, -				       struct dentry *cpus_dir, void *cpu_info) +static int hypfs_create_phys_cpu_files(struct dentry *cpus_dir, void *cpu_info)  {  	struct dentry *cpu_dir;  	char buffer[TMP_SIZE]; @@ -737,34 +688,31 @@ static int hypfs_create_phys_cpu_files(struct super_block *sb,  	snprintf(buffer, TMP_SIZE, "%i", phys_cpu__cpu_addr(diag204_info_type,  							    cpu_info)); -	cpu_dir = hypfs_mkdir(sb, cpus_dir, buffer); +	cpu_dir = hypfs_mkdir(cpus_dir, buffer);  	if (IS_ERR(cpu_dir))  		return PTR_ERR(cpu_dir); -	rc = hypfs_create_u64(sb, cpu_dir, "mgmtime", +	rc = hypfs_create_u64(cpu_dir, "mgmtime",  			      phys_cpu__mgm_time(diag204_info_type, cpu_info));  	if (IS_ERR(rc))  		return PTR_ERR(rc);  	diag224_idx2name(phys_cpu__ctidx(diag204_info_type, cpu_info), buffer); -	rc = hypfs_create_str(sb, cpu_dir, "type", buffer); -	if (IS_ERR(rc)) -		return PTR_ERR(rc); -	return 0; +	rc = hypfs_create_str(cpu_dir, "type", buffer); +	return PTR_RET(rc);  } -static void *hypfs_create_phys_files(struct super_block *sb, -				     struct dentry *parent_dir, void *phys_hdr) +static void *hypfs_create_phys_files(struct dentry *parent_dir, void *phys_hdr)  {  	int i;  	void *cpu_info;  	struct dentry *cpus_dir; -	cpus_dir = hypfs_mkdir(sb, parent_dir, "cpus"); +	cpus_dir = hypfs_mkdir(parent_dir, "cpus");  	if (IS_ERR(cpus_dir))  		return cpus_dir;  	cpu_info = phys_hdr + phys_hdr__size(diag204_info_type);  	for (i = 0; i < phys_hdr__cpus(diag204_info_type, phys_hdr); i++) {  		int rc; -		rc = hypfs_create_phys_cpu_files(sb, cpus_dir, cpu_info); +		rc = hypfs_create_phys_cpu_files(cpus_dir, cpu_info);  		if (rc)  			return ERR_PTR(rc);  		cpu_info += phys_cpu__size(diag204_info_type); @@ -772,7 +720,7 @@ static void *hypfs_create_phys_files(struct super_block *sb,  	return cpu_info;  } -int hypfs_diag_create_files(struct super_block *sb, struct dentry *root) +int hypfs_diag_create_files(struct dentry *root)  {  	struct dentry *systems_dir, *hyp_dir;  	void *time_hdr, *part_hdr; @@ -783,7 +731,7 @@ int hypfs_diag_create_files(struct super_block *sb, struct dentry *root)  	if (IS_ERR(buffer))  		return PTR_ERR(buffer); -	systems_dir = hypfs_mkdir(sb, root, "systems"); +	systems_dir = hypfs_mkdir(root, "systems");  	if (IS_ERR(systems_dir)) {  		rc = PTR_ERR(systems_dir);  		goto err_out; @@ -791,25 +739,25 @@ int hypfs_diag_create_files(struct super_block *sb, struct dentry *root)  	time_hdr = (struct x_info_blk_hdr *)buffer;  	part_hdr = time_hdr + info_blk_hdr__size(diag204_info_type);  	for (i = 0; i < info_blk_hdr__npar(diag204_info_type, time_hdr); i++) { -		part_hdr = hypfs_create_lpar_files(sb, systems_dir, part_hdr); +		part_hdr = hypfs_create_lpar_files(systems_dir, part_hdr);  		if (IS_ERR(part_hdr)) {  			rc = PTR_ERR(part_hdr);  			goto err_out;  		}  	}  	if (info_blk_hdr__flags(diag204_info_type, time_hdr) & LPAR_PHYS_FLG) { -		ptr = hypfs_create_phys_files(sb, root, part_hdr); +		ptr = hypfs_create_phys_files(root, part_hdr);  		if (IS_ERR(ptr)) {  			rc = PTR_ERR(ptr);  			goto err_out;  		}  	} -	hyp_dir = hypfs_mkdir(sb, root, "hyp"); +	hyp_dir = hypfs_mkdir(root, "hyp");  	if (IS_ERR(hyp_dir)) {  		rc = PTR_ERR(hyp_dir);  		goto err_out;  	} -	ptr = hypfs_create_str(sb, hyp_dir, "type", "LPAR Hypervisor"); +	ptr = hypfs_create_str(hyp_dir, "type", "LPAR Hypervisor");  	if (IS_ERR(ptr)) {  		rc = PTR_ERR(ptr);  		goto err_out; diff --git a/arch/s390/hypfs/hypfs_sprp.c b/arch/s390/hypfs/hypfs_sprp.c new file mode 100644 index 00000000000..f043c3c7e73 --- /dev/null +++ b/arch/s390/hypfs/hypfs_sprp.c @@ -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); +} diff --git a/arch/s390/hypfs/hypfs_vm.c b/arch/s390/hypfs/hypfs_vm.c index 26cf177f6a3..32040ace00e 100644 --- a/arch/s390/hypfs/hypfs_vm.c +++ b/arch/s390/hypfs/hypfs_vm.c @@ -1,7 +1,7 @@  /*   *    Hypervisor filesystem for Linux on s390. z/VM implementation.   * - *    Copyright (C) IBM Corp. 2006 + *    Copyright IBM Corp. 2006   *    Author(s): Michael Holzheu <holzheu@de.ibm.com>   */ @@ -20,8 +20,6 @@ static char local_guest[] = "        ";  static char all_guests[] = "*       ";  static char *guest_query; -static struct dentry *dbfs_d2fc_file; -  struct diag2fc_data {  	__u32 version;  	__u32 flags; @@ -34,7 +32,7 @@ struct diag2fc_data {  	__u32 pcpus;  	__u32 lcpus;  	__u32 vcpus; -	__u32 cpu_min; +	__u32 ocpus;  	__u32 cpu_max;  	__u32 cpu_shares;  	__u32 cpu_use_samp; @@ -104,21 +102,20 @@ static void *diag2fc_store(char *query, unsigned int *count, int offset)  	return data;  } -static void diag2fc_free(void *data) +static void diag2fc_free(const void *data)  {  	vfree(data);  } -#define ATTRIBUTE(sb, dir, name, member) \ +#define ATTRIBUTE(dir, name, member) \  do { \  	void *rc; \ -	rc = hypfs_create_u64(sb, dir, name, member); \ +	rc = hypfs_create_u64(dir, name, member); \  	if (IS_ERR(rc)) \  		return PTR_ERR(rc); \  } while(0) -static int hpyfs_vm_create_guest(struct super_block *sb, -				 struct dentry *systems_dir, +static int hpyfs_vm_create_guest(struct dentry *systems_dir,  				 struct diag2fc_data *data)  {  	char guest_name[NAME_LEN + 1] = {}; @@ -132,46 +129,51 @@ static int hpyfs_vm_create_guest(struct super_block *sb,  	memcpy(guest_name, data->guest_name, NAME_LEN);  	EBCASC(guest_name, NAME_LEN);  	strim(guest_name); -	guest_dir = hypfs_mkdir(sb, systems_dir, guest_name); +	guest_dir = hypfs_mkdir(systems_dir, guest_name);  	if (IS_ERR(guest_dir))  		return PTR_ERR(guest_dir); -	ATTRIBUTE(sb, guest_dir, "onlinetime_us", data->el_time); +	ATTRIBUTE(guest_dir, "onlinetime_us", data->el_time);  	/* logical cpu information */ -	cpus_dir = hypfs_mkdir(sb, guest_dir, "cpus"); +	cpus_dir = hypfs_mkdir(guest_dir, "cpus");  	if (IS_ERR(cpus_dir))  		return PTR_ERR(cpus_dir); -	ATTRIBUTE(sb, cpus_dir, "cputime_us", data->used_cpu); -	ATTRIBUTE(sb, cpus_dir, "capped", capped_value); -	ATTRIBUTE(sb, cpus_dir, "dedicated", dedicated_flag); -	ATTRIBUTE(sb, cpus_dir, "count", data->vcpus); -	ATTRIBUTE(sb, cpus_dir, "weight_min", data->cpu_min); -	ATTRIBUTE(sb, cpus_dir, "weight_max", data->cpu_max); -	ATTRIBUTE(sb, cpus_dir, "weight_cur", data->cpu_shares); +	ATTRIBUTE(cpus_dir, "cputime_us", data->used_cpu); +	ATTRIBUTE(cpus_dir, "capped", capped_value); +	ATTRIBUTE(cpus_dir, "dedicated", dedicated_flag); +	ATTRIBUTE(cpus_dir, "count", data->vcpus); +	/* +	 * Note: The "weight_min" attribute got the wrong name. +	 * The value represents the number of non-stopped (operating) +	 * CPUS. +	 */ +	ATTRIBUTE(cpus_dir, "weight_min", data->ocpus); +	ATTRIBUTE(cpus_dir, "weight_max", data->cpu_max); +	ATTRIBUTE(cpus_dir, "weight_cur", data->cpu_shares);  	/* memory information */ -	mem_dir = hypfs_mkdir(sb, guest_dir, "mem"); +	mem_dir = hypfs_mkdir(guest_dir, "mem");  	if (IS_ERR(mem_dir))  		return PTR_ERR(mem_dir); -	ATTRIBUTE(sb, mem_dir, "min_KiB", data->mem_min_kb); -	ATTRIBUTE(sb, mem_dir, "max_KiB", data->mem_max_kb); -	ATTRIBUTE(sb, mem_dir, "used_KiB", data->mem_used_kb); -	ATTRIBUTE(sb, mem_dir, "share_KiB", data->mem_share_kb); +	ATTRIBUTE(mem_dir, "min_KiB", data->mem_min_kb); +	ATTRIBUTE(mem_dir, "max_KiB", data->mem_max_kb); +	ATTRIBUTE(mem_dir, "used_KiB", data->mem_used_kb); +	ATTRIBUTE(mem_dir, "share_KiB", data->mem_share_kb);  	/* samples */ -	samples_dir = hypfs_mkdir(sb, guest_dir, "samples"); +	samples_dir = hypfs_mkdir(guest_dir, "samples");  	if (IS_ERR(samples_dir))  		return PTR_ERR(samples_dir); -	ATTRIBUTE(sb, samples_dir, "cpu_using", data->cpu_use_samp); -	ATTRIBUTE(sb, samples_dir, "cpu_delay", data->cpu_delay_samp); -	ATTRIBUTE(sb, samples_dir, "mem_delay", data->page_wait_samp); -	ATTRIBUTE(sb, samples_dir, "idle", data->idle_samp); -	ATTRIBUTE(sb, samples_dir, "other", data->other_samp); -	ATTRIBUTE(sb, samples_dir, "total", data->total_samp); +	ATTRIBUTE(samples_dir, "cpu_using", data->cpu_use_samp); +	ATTRIBUTE(samples_dir, "cpu_delay", data->cpu_delay_samp); +	ATTRIBUTE(samples_dir, "mem_delay", data->page_wait_samp); +	ATTRIBUTE(samples_dir, "idle", data->idle_samp); +	ATTRIBUTE(samples_dir, "other", data->other_samp); +	ATTRIBUTE(samples_dir, "total", data->total_samp);  	return 0;  } -int hypfs_vm_create_files(struct super_block *sb, struct dentry *root) +int hypfs_vm_create_files(struct dentry *root)  {  	struct dentry *dir, *file;  	struct diag2fc_data *data; @@ -183,38 +185,38 @@ int hypfs_vm_create_files(struct super_block *sb, struct dentry *root)  		return PTR_ERR(data);  	/* Hpervisor Info */ -	dir = hypfs_mkdir(sb, root, "hyp"); +	dir = hypfs_mkdir(root, "hyp");  	if (IS_ERR(dir)) {  		rc = PTR_ERR(dir);  		goto failed;  	} -	file = hypfs_create_str(sb, dir, "type", "z/VM Hypervisor"); +	file = hypfs_create_str(dir, "type", "z/VM Hypervisor");  	if (IS_ERR(file)) {  		rc = PTR_ERR(file);  		goto failed;  	}  	/* physical cpus */ -	dir = hypfs_mkdir(sb, root, "cpus"); +	dir = hypfs_mkdir(root, "cpus");  	if (IS_ERR(dir)) {  		rc = PTR_ERR(dir);  		goto failed;  	} -	file = hypfs_create_u64(sb, dir, "count", data->lcpus); +	file = hypfs_create_u64(dir, "count", data->lcpus);  	if (IS_ERR(file)) {  		rc = PTR_ERR(file);  		goto failed;  	}  	/* guests */ -	dir = hypfs_mkdir(sb, root, "systems"); +	dir = hypfs_mkdir(root, "systems");  	if (IS_ERR(dir)) {  		rc = PTR_ERR(dir);  		goto failed;  	}  	for (i = 0; i < count; i++) { -		rc = hpyfs_vm_create_guest(sb, dir, &(data[i])); +		rc = hpyfs_vm_create_guest(dir, &(data[i]));  		if (rc)  			goto failed;  	} @@ -239,43 +241,29 @@ struct dbfs_d2fc {  	char			buf[];	/* d2fc buffer */  } __attribute__ ((packed)); -static int dbfs_d2fc_open(struct inode *inode, struct file *file) +static int dbfs_diag2fc_create(void **data, void **data_free_ptr, size_t *size)  { -	struct dbfs_d2fc *data; +	struct dbfs_d2fc *d2fc;  	unsigned int count; -	data = diag2fc_store(guest_query, &count, sizeof(data->hdr)); -	if (IS_ERR(data)) -		return PTR_ERR(data); -	get_clock_ext(data->hdr.tod_ext); -	data->hdr.len = count * sizeof(struct diag2fc_data); -	data->hdr.version = DBFS_D2FC_HDR_VERSION; -	data->hdr.count = count; -	memset(&data->hdr.reserved, 0, sizeof(data->hdr.reserved)); -	file->private_data = data; -	return nonseekable_open(inode, file); -} - -static int dbfs_d2fc_release(struct inode *inode, struct file *file) -{ -	diag2fc_free(file->private_data); +	d2fc = diag2fc_store(guest_query, &count, sizeof(d2fc->hdr)); +	if (IS_ERR(d2fc)) +		return PTR_ERR(d2fc); +	get_tod_clock_ext(d2fc->hdr.tod_ext); +	d2fc->hdr.len = count * sizeof(struct diag2fc_data); +	d2fc->hdr.version = DBFS_D2FC_HDR_VERSION; +	d2fc->hdr.count = count; +	memset(&d2fc->hdr.reserved, 0, sizeof(d2fc->hdr.reserved)); +	*data = d2fc; +	*data_free_ptr = d2fc; +	*size = d2fc->hdr.len + sizeof(struct dbfs_d2fc_hdr);  	return 0;  } -static ssize_t dbfs_d2fc_read(struct file *file, char __user *buf, -				    size_t size, loff_t *ppos) -{ -	struct dbfs_d2fc *data = file->private_data; - -	return simple_read_from_buffer(buf, size, ppos, data, data->hdr.len + -				       sizeof(struct dbfs_d2fc_hdr)); -} - -static const struct file_operations dbfs_d2fc_ops = { -	.open		= dbfs_d2fc_open, -	.read		= dbfs_d2fc_read, -	.release	= dbfs_d2fc_release, -	.llseek		= no_llseek, +static struct hypfs_dbfs_file dbfs_file_2fc = { +	.name		= "diag_2fc", +	.data_create	= dbfs_diag2fc_create, +	.data_free	= diag2fc_free,  };  int hypfs_vm_init(void) @@ -288,18 +276,12 @@ int hypfs_vm_init(void)  		guest_query = local_guest;  	else  		return -EACCES; - -	dbfs_d2fc_file = debugfs_create_file("diag_2fc", 0400, hypfs_dbfs_dir, -					     NULL, &dbfs_d2fc_ops); -	if (IS_ERR(dbfs_d2fc_file)) -		return PTR_ERR(dbfs_d2fc_file); - -	return 0; +	return hypfs_dbfs_create_file(&dbfs_file_2fc);  }  void hypfs_vm_exit(void)  {  	if (!MACHINE_IS_VM)  		return; -	debugfs_remove(dbfs_d2fc_file); +	hypfs_dbfs_remove_file(&dbfs_file_2fc);  } diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c index 47cc446dab8..c952b981e4f 100644 --- a/arch/s390/hypfs/inode.c +++ b/arch/s390/hypfs/inode.c @@ -1,5 +1,4 @@  /* - *  arch/s390/hypfs/inode.c   *    Hypervisor filesystem for Linux on s390.   *   *    Copyright IBM Corp. 2006, 2008 @@ -22,18 +21,18 @@  #include <linux/module.h>  #include <linux/seq_file.h>  #include <linux/mount.h> +#include <linux/aio.h>  #include <asm/ebcdic.h>  #include "hypfs.h"  #define HYPFS_MAGIC 0x687970	/* ASCII 'hyp' */  #define TMP_SIZE 64		/* size of temporary buffers */ -static struct dentry *hypfs_create_update_file(struct super_block *sb, -					       struct dentry *dir); +static struct dentry *hypfs_create_update_file(struct dentry *dir);  struct hypfs_sb_info { -	uid_t uid;			/* uid used for files and dirs */ -	gid_t gid;			/* gid used for files and dirs */ +	kuid_t uid;			/* uid used for files and dirs */ +	kgid_t gid;			/* gid used for files and dirs */  	struct dentry *update_file;	/* file to trigger update */  	time_t last_update;		/* last update time in secs since 1970 */  	struct mutex lock;		/* lock to protect update process */ @@ -46,8 +45,6 @@ static const struct super_operations hypfs_s_ops;  /* start of list of all dentries, which have to be deleted on update */  static struct dentry *hypfs_last_dentry; -struct dentry *hypfs_dbfs_dir; -  static void hypfs_update_update(struct super_block *sb)  {  	struct hypfs_sb_info *sb_info = sb->s_fs_info; @@ -75,8 +72,6 @@ static void hypfs_remove(struct dentry *dentry)  	struct dentry *parent;  	parent = dentry->d_parent; -	if (!parent || !parent->d_inode) -		return;  	mutex_lock(&parent->d_inode->i_mutex);  	if (hypfs_positive(dentry)) {  		if (S_ISDIR(dentry->d_inode->i_mode)) @@ -99,33 +94,32 @@ static void hypfs_delete_tree(struct dentry *root)  	}  } -static struct inode *hypfs_make_inode(struct super_block *sb, int mode) +static struct inode *hypfs_make_inode(struct super_block *sb, umode_t mode)  {  	struct inode *ret = new_inode(sb);  	if (ret) {  		struct hypfs_sb_info *hypfs_info = sb->s_fs_info; +		ret->i_ino = get_next_ino();  		ret->i_mode = mode;  		ret->i_uid = hypfs_info->uid;  		ret->i_gid = hypfs_info->gid;  		ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME; -		if (mode & S_IFDIR) -			ret->i_nlink = 2; -		else -			ret->i_nlink = 1; +		if (S_ISDIR(mode)) +			set_nlink(ret, 2);  	}  	return ret;  }  static void hypfs_evict_inode(struct inode *inode)  { -	end_writeback(inode); +	clear_inode(inode);  	kfree(inode->i_private);  }  static int hypfs_open(struct inode *inode, struct file *filp)  { -	char *data = filp->f_path.dentry->d_inode->i_private; +	char *data = file_inode(filp)->i_private;  	struct hypfs_sb_info *fs_info;  	if (filp->f_mode & FMODE_WRITE) { @@ -177,12 +171,10 @@ static ssize_t hypfs_aio_write(struct kiocb *iocb, const struct iovec *iov,  			      unsigned long nr_segs, loff_t offset)  {  	int rc; -	struct super_block *sb; -	struct hypfs_sb_info *fs_info; +	struct super_block *sb = file_inode(iocb->ki_filp)->i_sb; +	struct hypfs_sb_info *fs_info = sb->s_fs_info;  	size_t count = iov_length(iov, nr_segs); -	sb = iocb->ki_filp->f_path.dentry->d_inode->i_sb; -	fs_info = sb->s_fs_info;  	/*  	 * Currently we only allow one update per second for two reasons:  	 * 1. diag 204 is VERY expensive @@ -200,9 +192,9 @@ static ssize_t hypfs_aio_write(struct kiocb *iocb, const struct iovec *iov,  	}  	hypfs_delete_tree(sb->s_root);  	if (MACHINE_IS_VM) -		rc = hypfs_vm_create_files(sb, sb->s_root); +		rc = hypfs_vm_create_files(sb->s_root);  	else -		rc = hypfs_diag_create_files(sb, sb->s_root); +		rc = hypfs_diag_create_files(sb->s_root);  	if (rc) {  		pr_err("Updating the hypfs tree failed\n");  		hypfs_delete_tree(sb->s_root); @@ -233,6 +225,8 @@ static int hypfs_parse_options(char *options, struct super_block *sb)  {  	char *str;  	substring_t args[MAX_OPT_ARGS]; +	kuid_t uid; +	kgid_t gid;  	if (!options)  		return 0; @@ -247,12 +241,18 @@ static int hypfs_parse_options(char *options, struct super_block *sb)  		case opt_uid:  			if (match_int(&args[0], &option))  				return -EINVAL; -			hypfs_info->uid = option; +			uid = make_kuid(current_user_ns(), option); +			if (!uid_valid(uid)) +				return -EINVAL; +			hypfs_info->uid = uid;  			break;  		case opt_gid:  			if (match_int(&args[0], &option))  				return -EINVAL; -			hypfs_info->gid = option; +			gid = make_kgid(current_user_ns(), option); +			if (!gid_valid(gid)) +				return -EINVAL; +			hypfs_info->gid = gid;  			break;  		case opt_err:  		default: @@ -263,12 +263,12 @@ static int hypfs_parse_options(char *options, struct super_block *sb)  	return 0;  } -static int hypfs_show_options(struct seq_file *s, struct vfsmount *mnt) +static int hypfs_show_options(struct seq_file *s, struct dentry *root)  { -	struct hypfs_sb_info *hypfs_info = mnt->mnt_sb->s_fs_info; +	struct hypfs_sb_info *hypfs_info = root->d_sb->s_fs_info; -	seq_printf(s, ",uid=%u", hypfs_info->uid); -	seq_printf(s, ",gid=%u", hypfs_info->gid); +	seq_printf(s, ",uid=%u", from_kuid_munged(&init_user_ns, hypfs_info->uid)); +	seq_printf(s, ",gid=%u", from_kgid_munged(&init_user_ns, hypfs_info->gid));  	return 0;  } @@ -297,18 +297,16 @@ static int hypfs_fill_super(struct super_block *sb, void *data, int silent)  		return -ENOMEM;  	root_inode->i_op = &simple_dir_inode_operations;  	root_inode->i_fop = &simple_dir_operations; -	sb->s_root = root_dentry = d_alloc_root(root_inode); -	if (!root_dentry) { -		iput(root_inode); +	sb->s_root = root_dentry = d_make_root(root_inode); +	if (!root_dentry)  		return -ENOMEM; -	}  	if (MACHINE_IS_VM) -		rc = hypfs_vm_create_files(sb, root_dentry); +		rc = hypfs_vm_create_files(root_dentry);  	else -		rc = hypfs_diag_create_files(sb, root_dentry); +		rc = hypfs_diag_create_files(root_dentry);  	if (rc)  		return rc; -	sbi->update_file = hypfs_create_update_file(sb, root_dentry); +	sbi->update_file = hypfs_create_update_file(root_dentry);  	if (IS_ERR(sbi->update_file))  		return PTR_ERR(sbi->update_file);  	hypfs_update_update(sb); @@ -335,9 +333,8 @@ static void hypfs_kill_super(struct super_block *sb)  	kill_litter_super(sb);  } -static struct dentry *hypfs_create_file(struct super_block *sb, -					struct dentry *parent, const char *name, -					char *data, mode_t mode) +static struct dentry *hypfs_create_file(struct dentry *parent, const char *name, +					char *data, umode_t mode)  {  	struct dentry *dentry;  	struct inode *inode; @@ -348,22 +345,22 @@ static struct dentry *hypfs_create_file(struct super_block *sb,  		dentry = ERR_PTR(-ENOMEM);  		goto fail;  	} -	inode = hypfs_make_inode(sb, mode); +	inode = hypfs_make_inode(parent->d_sb, mode);  	if (!inode) {  		dput(dentry);  		dentry = ERR_PTR(-ENOMEM);  		goto fail;  	} -	if (mode & S_IFREG) { +	if (S_ISREG(mode)) {  		inode->i_fop = &hypfs_file_ops;  		if (data)  			inode->i_size = strlen(data);  		else  			inode->i_size = 0; -	} else if (mode & S_IFDIR) { +	} else if (S_ISDIR(mode)) {  		inode->i_op = &simple_dir_inode_operations;  		inode->i_fop = &simple_dir_operations; -		parent->d_inode->i_nlink++; +		inc_nlink(parent->d_inode);  	} else  		BUG();  	inode->i_private = data; @@ -374,24 +371,22 @@ fail:  	return dentry;  } -struct dentry *hypfs_mkdir(struct super_block *sb, struct dentry *parent, -			   const char *name) +struct dentry *hypfs_mkdir(struct dentry *parent, const char *name)  {  	struct dentry *dentry; -	dentry = hypfs_create_file(sb, parent, name, NULL, S_IFDIR | DIR_MODE); +	dentry = hypfs_create_file(parent, name, NULL, S_IFDIR | DIR_MODE);  	if (IS_ERR(dentry))  		return dentry;  	hypfs_add_dentry(dentry);  	return dentry;  } -static struct dentry *hypfs_create_update_file(struct super_block *sb, -					       struct dentry *dir) +static struct dentry *hypfs_create_update_file(struct dentry *dir)  {  	struct dentry *dentry; -	dentry = hypfs_create_file(sb, dir, "update", NULL, +	dentry = hypfs_create_file(dir, "update", NULL,  				   S_IFREG | UPDATE_FILE_MODE);  	/*  	 * We do not put the update file on the 'delete' list with @@ -401,7 +396,7 @@ static struct dentry *hypfs_create_update_file(struct super_block *sb,  	return dentry;  } -struct dentry *hypfs_create_u64(struct super_block *sb, struct dentry *dir, +struct dentry *hypfs_create_u64(struct dentry *dir,  				const char *name, __u64 value)  {  	char *buffer; @@ -413,7 +408,7 @@ struct dentry *hypfs_create_u64(struct super_block *sb, struct dentry *dir,  	if (!buffer)  		return ERR_PTR(-ENOMEM);  	dentry = -	    hypfs_create_file(sb, dir, name, buffer, S_IFREG | REG_FILE_MODE); +	    hypfs_create_file(dir, name, buffer, S_IFREG | REG_FILE_MODE);  	if (IS_ERR(dentry)) {  		kfree(buffer);  		return ERR_PTR(-ENOMEM); @@ -422,7 +417,7 @@ struct dentry *hypfs_create_u64(struct super_block *sb, struct dentry *dir,  	return dentry;  } -struct dentry *hypfs_create_str(struct super_block *sb, struct dentry *dir, +struct dentry *hypfs_create_str(struct dentry *dir,  				const char *name, char *string)  {  	char *buffer; @@ -433,7 +428,7 @@ struct dentry *hypfs_create_str(struct super_block *sb, struct dentry *dir,  		return ERR_PTR(-ENOMEM);  	sprintf(buffer, "%s\n", string);  	dentry = -	    hypfs_create_file(sb, dir, name, buffer, S_IFREG | REG_FILE_MODE); +	    hypfs_create_file(dir, name, buffer, S_IFREG | REG_FILE_MODE);  	if (IS_ERR(dentry)) {  		kfree(buffer);  		return ERR_PTR(-ENOMEM); @@ -458,6 +453,7 @@ static struct file_system_type hypfs_type = {  	.mount		= hypfs_mount,  	.kill_sb	= hypfs_kill_super  }; +MODULE_ALIAS_FS("s390_hypfs");  static const struct super_operations hypfs_s_ops = {  	.statfs		= simple_statfs, @@ -471,22 +467,25 @@ static int __init hypfs_init(void)  {  	int rc; -	hypfs_dbfs_dir = debugfs_create_dir("s390_hypfs", NULL); -	if (IS_ERR(hypfs_dbfs_dir)) -		return PTR_ERR(hypfs_dbfs_dir); - +	rc = hypfs_dbfs_init(); +	if (rc) +		return rc;  	if (hypfs_diag_init()) {  		rc = -ENODATA; -		goto fail_debugfs_remove; +		goto fail_dbfs_exit;  	}  	if (hypfs_vm_init()) {  		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) @@ -495,24 +494,26 @@ 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:  	hypfs_diag_exit(); -fail_debugfs_remove: -	debugfs_remove(hypfs_dbfs_dir); - +fail_dbfs_exit: +	hypfs_dbfs_exit();  	pr_err("Initialization of hypfs failed with rc=%i\n", rc);  	return rc;  }  static void __exit hypfs_exit(void)  { -	hypfs_diag_exit(); -	hypfs_vm_exit(); -	debugfs_remove(hypfs_dbfs_dir);  	unregister_filesystem(&hypfs_type);  	kobject_put(s390_kobj); +	hypfs_sprp_exit(); +	hypfs_vm_exit(); +	hypfs_diag_exit(); +	hypfs_dbfs_exit();  }  module_init(hypfs_init)  | 
