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 | 172 | ||||
| -rw-r--r-- | arch/s390/hypfs/hypfs_sprp.c | 141 | ||||
| -rw-r--r-- | arch/s390/hypfs/hypfs_vm.c | 146 | ||||
| -rw-r--r-- | arch/s390/hypfs/inode.c | 260 |
7 files changed, 659 insertions, 248 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 aea572009d6..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> */ @@ -11,29 +10,66 @@ #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 int hypfs_vm_create_files(struct super_block *sb, struct dentry *root); +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; + +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); #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 b9a1ce1f28e..5eeffeefae0 100644 --- a/arch/s390/hypfs/hypfs_diag.c +++ b/arch/s390/hypfs/hypfs_diag.c @@ -1,16 +1,20 @@ /* - * arch/s390/hypfs/hypfs_diag.c * Hypervisor filesystem for Linux on s390. Diag 204 and 224 * implementation. * - * Copyright (C) IBM Corp. 2006 + * Copyright IBM Corp. 2006, 2008 * Author(s): Michael Holzheu <holzheu@de.ibm.com> */ +#define KMSG_COMPONENT "hypfs" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include <linux/types.h> #include <linux/errno.h> +#include <linux/slab.h> #include <linux/string.h> #include <linux/vmalloc.h> +#include <linux/mm.h> #include <asm/ebcdic.h> #include "hypfs.h" @@ -18,6 +22,8 @@ #define CPU_NAME_LEN 16 /* type name len of cpus in diag224 name table */ #define TMP_SIZE 64 /* size of temporary buffers */ +#define DBFS_D204_HDR_VERSION 0 + /* diag 204 subcodes */ enum diag204_sc { SUBC_STIB4 = 4, @@ -43,6 +49,8 @@ static void *diag204_buf; /* 4K aligned buffer for diag204 data */ static void *diag204_buf_vmalloc; /* vmalloc pointer for diag204 data */ static int diag204_buf_pages; /* number of pages for diag204 data */ +static struct dentry *dbfs_d204_file; + /* * DIAG 204 data structures and member access functions. * @@ -159,7 +167,7 @@ static inline void part_hdr__part_name(enum diag204_format type, void *hdr, LPAR_NAME_LEN); EBCASC(name, LPAR_NAME_LEN); name[LPAR_NAME_LEN] = 0; - strstrip(name); + strim(name); } struct cpu_info { @@ -360,18 +368,21 @@ static void diag204_free_buffer(void) } else { free_pages((unsigned long) diag204_buf, 0); } - diag204_buf_pages = 0; diag204_buf = NULL; } +static void *page_align_ptr(void *ptr) +{ + return (void *) PAGE_ALIGN((unsigned long) ptr); +} + static void *diag204_alloc_vbuf(int pages) { /* The buffer has to be page aligned! */ diag204_buf_vmalloc = vmalloc(PAGE_SIZE * (pages + 1)); if (!diag204_buf_vmalloc) return ERR_PTR(-ENOMEM); - diag204_buf = (void*)((unsigned long)diag204_buf_vmalloc - & ~0xfffUL) + 0x1000; + diag204_buf = page_align_ptr(diag204_buf_vmalloc); diag204_buf_pages = pages; return diag204_buf; } @@ -433,7 +444,7 @@ static int diag204_probe(void) } if (diag204((unsigned long)SUBC_STIB6 | (unsigned long)INFO_EXT, pages, buf) >= 0) { - diag204_store_sc = SUBC_STIB7; + diag204_store_sc = SUBC_STIB6; diag204_info_type = INFO_EXT; goto out; } @@ -464,17 +475,26 @@ fail_alloc: return rc; } +static int diag204_do_store(void *buf, int pages) +{ + int rc; + + rc = diag204((unsigned long) diag204_store_sc | + (unsigned long) diag204_info_type, pages, buf); + return rc < 0 ? -ENOSYS : 0; +} + static void *diag204_store(void) { void *buf; - int pages; + int pages, rc; buf = diag204_get_buffer(diag204_info_type, &pages); if (IS_ERR(buf)) goto out; - if (diag204((unsigned long)diag204_store_sc | - (unsigned long)diag204_info_type, pages, buf) < 0) - return ERR_PTR(-ENOSYS); + rc = diag204_do_store(buf, pages); + if (rc) + return ERR_PTR(rc); out: return buf; } @@ -483,7 +503,7 @@ out: static int diag224(void *ptr) { - int rc = -ENOTSUPP; + int rc = -EOPNOTSUPP; asm volatile( " diag %1,%2,0x224\n" @@ -502,7 +522,7 @@ static int diag224_get_name_table(void) return -ENOMEM; if (diag224(diag224_cpu_names)) { kfree(diag224_cpu_names); - return -ENOTSUPP; + return -EOPNOTSUPP; } EBCASC(diag224_cpu_names + 16, (*diag224_cpu_names + 1) * 16); return 0; @@ -518,30 +538,84 @@ static int diag224_idx2name(int index, char *name) memcpy(name, diag224_cpu_names + ((index + 1) * CPU_NAME_LEN), CPU_NAME_LEN); name[CPU_NAME_LEN] = 0; - strstrip(name); + strim(name); return 0; } +struct dbfs_d204_hdr { + u64 len; /* Length of d204 buffer without header */ + u16 version; /* Version of header */ + u8 sc; /* Used subcode */ + char reserved[53]; +} __attribute__ ((packed)); + +struct dbfs_d204 { + struct dbfs_d204_hdr hdr; /* 64 byte header */ + char buf[]; /* d204 buffer */ +} __attribute__ ((packed)); + +static int dbfs_d204_create(void **data, void **data_free_ptr, size_t *size) +{ + struct dbfs_d204 *d204; + int rc, buf_size; + void *base; + + buf_size = PAGE_SIZE * (diag204_buf_pages + 1) + sizeof(d204->hdr); + 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; + } + d204->hdr.version = DBFS_D204_HDR_VERSION; + d204->hdr.len = PAGE_SIZE * diag204_buf_pages; + d204->hdr.sc = diag204_store_sc; + *data = d204; + *data_free_ptr = base; + *size = d204->hdr.len + sizeof(struct dbfs_d204_hdr); + return 0; +} + +static struct hypfs_dbfs_file dbfs_file_d204 = { + .name = "diag_204", + .data_create = dbfs_d204_create, + .data_free = vfree, +}; + __init int hypfs_diag_init(void) { int rc; if (diag204_probe()) { - printk(KERN_ERR "hypfs: diag 204 not working."); + pr_err("The hardware system does not support hypfs\n"); return -ENODATA; } - rc = diag224_get_name_table(); - if (rc) { - diag204_free_buffer(); - printk(KERN_ERR "hypfs: could not get name table.\n"); + if (diag204_info_type == INFO_EXT) { + rc = hypfs_dbfs_create_file(&dbfs_file_d204); + if (rc) + return rc; } - return rc; + if (MACHINE_IS_LPAR) { + rc = diag224_get_name_table(); + if (rc) { + pr_err("The hardware system does not provide all " + "functions required by hypfs\n"); + debugfs_remove(dbfs_d204_file); + return rc; + } + } + return 0; } void hypfs_diag_exit(void) { + debugfs_remove(dbfs_d204_file); diag224_delete_name_table(); diag204_free_buffer(); + hypfs_dbfs_remove_file(&dbfs_file_d204); } /* @@ -549,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]; @@ -558,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; @@ -593,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); @@ -610,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]; @@ -619,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); @@ -654,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; @@ -665,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; @@ -673,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 d01fc8f799f..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> */ @@ -10,9 +10,11 @@ #include <linux/string.h> #include <linux/vmalloc.h> #include <asm/ebcdic.h> +#include <asm/timex.h> #include "hypfs.h" #define NAME_LEN 8 +#define DBFS_D2FC_HDR_VERSION 0 static char local_guest[] = " "; static char all_guests[] = "* "; @@ -30,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; @@ -76,42 +78,44 @@ static int diag2fc(int size, char* query, void *addr) return -residual_cnt; } -static struct diag2fc_data *diag2fc_store(char *query, int *count) +/* + * Allocate buffer for "query" and store diag 2fc at "offset" + */ +static void *diag2fc_store(char *query, unsigned int *count, int offset) { + void *data; int size; - struct diag2fc_data *data; do { size = diag2fc(0, query, NULL); if (size < 0) return ERR_PTR(-EACCES); - data = vmalloc(size); + data = vmalloc(size + offset); if (!data) return ERR_PTR(-ENOMEM); - if (diag2fc(size, query, data) == 0) + if (diag2fc(size, query, data + offset) == 0) break; vfree(data); } while (1); - *count = (size / sizeof(*data)); + *count = (size / sizeof(struct diag2fc_data)); 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] = {}; @@ -124,89 +128,95 @@ static int hpyfs_vm_create_guest(struct super_block *sb, /* guest dir */ memcpy(guest_name, data->guest_name, NAME_LEN); EBCASC(guest_name, NAME_LEN); - strstrip(guest_name); - guest_dir = hypfs_mkdir(sb, systems_dir, guest_name); + strim(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; - int rc, i, count = 0; + unsigned int count = 0; + int rc, i; - data = diag2fc_store(guest_query, &count); + data = diag2fc_store(guest_query, &count, 0); if (IS_ERR(data)) 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; } @@ -218,14 +228,60 @@ failed: return rc; } +struct dbfs_d2fc_hdr { + u64 len; /* Length of d2fc buffer without header */ + u16 version; /* Version of header */ + char tod_ext[16]; /* TOD clock for d2fc */ + u64 count; /* Number of VM guests in d2fc buffer */ + char reserved[30]; +} __attribute__ ((packed)); + +struct dbfs_d2fc { + struct dbfs_d2fc_hdr hdr; /* 64 byte header */ + char buf[]; /* d2fc buffer */ +} __attribute__ ((packed)); + +static int dbfs_diag2fc_create(void **data, void **data_free_ptr, size_t *size) +{ + struct dbfs_d2fc *d2fc; + unsigned int count; + + 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 struct hypfs_dbfs_file dbfs_file_2fc = { + .name = "diag_2fc", + .data_create = dbfs_diag2fc_create, + .data_free = diag2fc_free, +}; + int hypfs_vm_init(void) { + if (!MACHINE_IS_VM) + return 0; if (diag2fc(0, all_guests, NULL) > 0) guest_query = all_guests; else if (diag2fc(0, local_guest, NULL) > 0) guest_query = local_guest; else return -EACCES; + return hypfs_dbfs_create_file(&dbfs_file_2fc); +} - return 0; +void hypfs_vm_exit(void) +{ + if (!MACHINE_IS_VM) + return; + hypfs_dbfs_remove_file(&dbfs_file_2fc); } diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c index 4b010ff814c..c952b981e4f 100644 --- a/arch/s390/hypfs/inode.c +++ b/arch/s390/hypfs/inode.c @@ -1,36 +1,38 @@ /* - * arch/s390/hypfs/inode.c * Hypervisor filesystem for Linux on s390. * - * Copyright (C) IBM Corp. 2006 + * Copyright IBM Corp. 2006, 2008 * Author(s): Michael Holzheu <holzheu@de.ibm.com> */ +#define KMSG_COMPONENT "hypfs" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include <linux/types.h> #include <linux/errno.h> #include <linux/fs.h> #include <linux/namei.h> #include <linux/vfs.h> +#include <linux/slab.h> #include <linux/pagemap.h> -#include <linux/gfp.h> #include <linux/time.h> #include <linux/parser.h> #include <linux/sysfs.h> #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 */ @@ -38,7 +40,7 @@ struct hypfs_sb_info { static const struct file_operations hypfs_file_ops; static struct file_system_type hypfs_type; -static struct super_operations hypfs_s_ops; +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; @@ -70,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)) @@ -94,34 +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_blocks = 0; 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_drop_inode(struct inode *inode) +static void hypfs_evict_inode(struct inode *inode) { + clear_inode(inode); kfree(inode->i_private); - generic_delete_inode(inode); } 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) { @@ -143,51 +141,40 @@ static int hypfs_open(struct inode *inode, struct file *filp) } mutex_unlock(&fs_info->lock); } - return 0; + return nonseekable_open(inode, filp); } static ssize_t hypfs_aio_read(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t offset) { char *data; - size_t len; + ssize_t ret; struct file *filp = iocb->ki_filp; /* XXX: temporary */ char __user *buf = iov[0].iov_base; size_t count = iov[0].iov_len; - if (nr_segs != 1) { - count = -EINVAL; - goto out; - } + if (nr_segs != 1) + return -EINVAL; data = filp->private_data; - len = strlen(data); - if (offset > len) { - count = 0; - goto out; - } - if (count > len - offset) - count = len - offset; - if (copy_to_user(buf, data + offset, count)) { - count = -EFAULT; - goto out; - } - iocb->ki_pos += count; + ret = simple_read_from_buffer(buf, count, &offset, data, strlen(data)); + if (ret <= 0) + return ret; + + iocb->ki_pos += ret; file_accessed(filp); -out: - return count; + + return ret; } 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 @@ -205,11 +192,11 @@ 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) { - printk(KERN_ERR "hypfs: Update failed\n"); + pr_err("Updating the hypfs tree failed\n"); hypfs_delete_tree(sb->s_root); goto out; } @@ -228,7 +215,7 @@ static int hypfs_release(struct inode *inode, struct file *filp) enum { opt_uid, opt_gid, opt_err }; -static match_table_t hypfs_tokens = { +static const match_table_t hypfs_tokens = { {opt_uid, "uid=%u"}, {opt_gid, "gid=%u"}, {opt_err, NULL} @@ -238,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; @@ -252,29 +241,34 @@ 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: - printk(KERN_ERR "hypfs: Unrecognized mount option " - "\"%s\" or missing value\n", str); + pr_err("%s is not a valid mount option\n", str); return -EINVAL; } } 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; } @@ -289,107 +283,84 @@ static int hypfs_fill_super(struct super_block *sb, void *data, int silent) if (!sbi) return -ENOMEM; mutex_init(&sbi->lock); - sbi->uid = current->uid; - sbi->gid = current->gid; + sbi->uid = current_uid(); + sbi->gid = current_gid(); sb->s_fs_info = sbi; sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; sb->s_magic = HYPFS_MAGIC; sb->s_op = &hypfs_s_ops; - if (hypfs_parse_options(data, sb)) { - rc = -EINVAL; - goto err_alloc; - } + if (hypfs_parse_options(data, sb)) + return -EINVAL; root_inode = hypfs_make_inode(sb, S_IFDIR | 0755); - if (!root_inode) { - rc = -ENOMEM; - goto err_alloc; - } + if (!root_inode) + return -ENOMEM; root_inode->i_op = &simple_dir_inode_operations; root_inode->i_fop = &simple_dir_operations; - root_dentry = d_alloc_root(root_inode); - if (!root_dentry) { - iput(root_inode); - rc = -ENOMEM; - goto err_alloc; - } + 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) - goto err_tree; - sbi->update_file = hypfs_create_update_file(sb, root_dentry); - if (IS_ERR(sbi->update_file)) { - rc = PTR_ERR(sbi->update_file); - goto err_tree; - } + return rc; + 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); - sb->s_root = root_dentry; - printk(KERN_INFO "hypfs: Hypervisor filesystem mounted\n"); + pr_info("Hypervisor filesystem mounted\n"); return 0; - -err_tree: - hypfs_delete_tree(root_dentry); - d_genocide(root_dentry); - dput(root_dentry); -err_alloc: - kfree(sbi); - return rc; } -static int hypfs_get_super(struct file_system_type *fst, int flags, - const char *devname, void *data, struct vfsmount *mnt) +static struct dentry *hypfs_mount(struct file_system_type *fst, int flags, + const char *devname, void *data) { - return get_sb_single(fst, flags, data, hypfs_fill_super, mnt); + return mount_single(fst, flags, data, hypfs_fill_super); } static void hypfs_kill_super(struct super_block *sb) { struct hypfs_sb_info *sb_info = sb->s_fs_info; - if (sb->s_root) { + if (sb->s_root) hypfs_delete_tree(sb->s_root); + if (sb_info->update_file) hypfs_remove(sb_info->update_file); - kfree(sb->s_fs_info); - sb->s_fs_info = NULL; - } + kfree(sb->s_fs_info); + sb->s_fs_info = NULL; 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; - struct qstr qname; - qname.name = name; - qname.len = strlen(name); - qname.hash = full_name_hash(name, qname.len); mutex_lock(&parent->d_inode->i_mutex); dentry = lookup_one_len(name, parent, strlen(name)); if (IS_ERR(dentry)) { 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; @@ -400,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 @@ -427,19 +396,19 @@ 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; char tmp[TMP_SIZE]; struct dentry *dentry; - snprintf(tmp, TMP_SIZE, "%lld\n", (unsigned long long int)value); + snprintf(tmp, TMP_SIZE, "%llu\n", (unsigned long long int)value); buffer = kstrdup(tmp, GFP_KERNEL); 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); @@ -448,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; @@ -459,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); @@ -475,18 +444,20 @@ static const struct file_operations hypfs_file_ops = { .write = do_sync_write, .aio_read = hypfs_aio_read, .aio_write = hypfs_aio_write, + .llseek = no_llseek, }; static struct file_system_type hypfs_type = { .owner = THIS_MODULE, .name = "s390_hypfs", - .get_sb = hypfs_get_super, + .mount = hypfs_mount, .kill_sb = hypfs_kill_super }; +MODULE_ALIAS_FS("s390_hypfs"); -static struct super_operations hypfs_s_ops = { +static const struct super_operations hypfs_s_ops = { .statfs = simple_statfs, - .drop_inode = hypfs_drop_inode, + .evict_inode = hypfs_evict_inode, .show_options = hypfs_show_options, }; @@ -496,20 +467,25 @@ static int __init hypfs_init(void) { int rc; - if (MACHINE_IS_VM) { - if (hypfs_vm_init()) - /* no diag 2fc, just exit */ - return -ENODATA; - } else { - if (hypfs_diag_init()) { - rc = -ENODATA; - goto fail_diag; - } + rc = hypfs_dbfs_init(); + if (rc) + return rc; + if (hypfs_diag_init()) { + rc = -ENODATA; + 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_sysfs; + rc = -ENOMEM; + goto fail_hypfs_sprp_exit; } rc = register_filesystem(&hypfs_type); if (rc) @@ -518,20 +494,26 @@ static int __init hypfs_init(void) fail_filesystem: kobject_put(s390_kobj); -fail_sysfs: - if (!MACHINE_IS_VM) - hypfs_diag_exit(); -fail_diag: - printk(KERN_ERR "hypfs: Initialization failed with rc = %i.\n", rc); +fail_hypfs_sprp_exit: + hypfs_sprp_exit(); +fail_hypfs_vm_exit: + hypfs_vm_exit(); +fail_hypfs_diag_exit: + hypfs_diag_exit(); +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) { - if (!MACHINE_IS_VM) - hypfs_diag_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) |
