The patch titled s390: Hypervisor File System (fixes) has been removed from the -mm tree. Its filename is s390-hypervisor-file-system-fixes.patch This patch was probably dropped from -mm because it has now been merged into a subsystem tree or into Linus's tree, or because it was folded into its parent patch in the -mm tree. From: Michael Holzheu <holzheu@xxxxxxxxxx> Here the patch with the bugfixes for your and Pekka's comments: - move some globals into the superblock - remove some inlines - fix some error handling functions - implement diag204_get_buffer() helper function - "hypfs" prefix for global functions - use uid_t and gid_t - use kstrdup() - Cosmetics Signed-off-by: Michael Holzheu <holzheu@xxxxxxxxxx> Cc: Pekka Enberg <penberg@xxxxxxxxxxxxxx> Cc: Ingo Oeser <ioe-lkml@xxxxxxxxxx> Cc: Jörn Engel <joern@xxxxxxxxxxxxxxxxxxxx> Cc: Martin Schwidefsky <schwidefsky@xxxxxxxxxx> Signed-off-by: Andrew Morton <akpm@xxxxxxxx> --- arch/s390/Kconfig | 2 arch/s390/hypfs/hypfs_diag.c | 127 ++++++++++++++++++++------------- arch/s390/hypfs/hypfs_diag.h | 6 - arch/s390/hypfs/inode.c | 107 +++++++++++++++------------ 4 files changed, 145 insertions(+), 97 deletions(-) diff -puN arch/s390/hypfs/hypfs_diag.c~s390-hypervisor-file-system-fixes arch/s390/hypfs/hypfs_diag.c --- devel/arch/s390/hypfs/hypfs_diag.c~s390-hypervisor-file-system-fixes 2006-04-28 23:40:09.000000000 -0700 +++ devel-akpm/arch/s390/hypfs/hypfs_diag.c 2006-04-28 23:40:09.000000000 -0700 @@ -322,7 +322,7 @@ static inline __u64 phys_cpu__ctidx(enum /* Diagnose 204 functions */ -static inline int diag204(unsigned long subcode, unsigned long size, void *addr) +static int diag204(unsigned long subcode, unsigned long size, void *addr) { register unsigned long _subcode asm("0") = subcode; register unsigned long _size asm("1") = size; @@ -345,6 +345,25 @@ static inline int diag204(unsigned long return _size; } +static void *diag204_get_buffer(enum diag204_format fmt, int *pages) +{ + void *buf; + + if (fmt == INFO_SIMPLE) + *pages = 1; + else + *pages = diag204(SUBC_RSI | fmt, 0, 0); + + if (*pages <= 0) + return ERR_PTR(-ENOSYS); + + buf = kmalloc(*pages * PAGE_SIZE, GFP_KERNEL); + if (!buf) + return ERR_PTR(-ENOMEM); + + return buf; +} + /* * diag204_probe() has to find out, which type of diagnose 204 implementation * we have on our machine. Currently there are three possible scanarios: @@ -364,13 +383,14 @@ static int diag204_probe(void) void *buf; int pages, rc; - pages = diag204(SUBC_RSI | INFO_EXT, 0, 0); - if (pages > 0) { - buf = kmalloc(pages * PAGE_SIZE, GFP_KERNEL); - if (!buf) { - rc = -ENOMEM; - goto err_out; - } + /* + * We first try to get the number of pages needed to store the extended + * data format. If this already fails, our machine does not support + * subcode 6 and 7. We then continue checking for subcode 4. + */ + + buf = diag204_get_buffer(INFO_EXT, &pages); + if (!IS_ERR(buf)) { if (diag204(SUBC_STIB7 | INFO_EXT, pages, buf) >= 0) { diag204_store_sc = SUBC_STIB7; diag204_info_type = INFO_EXT; @@ -382,10 +402,19 @@ static int diag204_probe(void) goto out; } kfree(buf); + } else if (PTR_ERR(buf) != -ENOSYS) { + /* other error than 'not implemented'. Give up! */ + return PTR_ERR(buf); } - buf = kmalloc(PAGE_SIZE, GFP_KERNEL); - if (!buf) { - rc = -ENOMEM; + + /* + * subcode 6 and 7 did not work. Now try subcode 4 with the simple + * data format. + */ + + buf = diag204_get_buffer(INFO_SIMPLE, &pages); + if (IS_ERR(buf)) { + rc = PTR_ERR(buf); goto err_out; } if (diag204(SUBC_STIB4 | INFO_SIMPLE, pages, buf) >= 0) { @@ -396,9 +425,9 @@ static int diag204_probe(void) rc = -ENOSYS; goto err_out; } - out: +out: rc = 0; - err_out: +err_out: kfree(buf); return rc; } @@ -408,34 +437,26 @@ static void *diag204_store(void) void *buf; int pages; - if (diag204_store_sc == SUBC_STIB4) - pages = 1; - else - pages = diag204(SUBC_RSI | diag204_info_type, 0, 0); - - if (pages < 0) - return ERR_PTR(-ENOSYS); - - buf = kmalloc(pages * PAGE_SIZE, GFP_KERNEL); - if (!buf) - return ERR_PTR(-ENOMEM); - + buf = diag204_get_buffer(diag204_info_type, &pages); + if (IS_ERR(buf)) + goto out; if (diag204(diag204_store_sc | diag204_info_type, pages, buf) < 0) { kfree(buf); return ERR_PTR(-ENOSYS); } +out: return buf; } /* Diagnose 224 functions */ -static inline void diag224(void *ptr) +static void diag224(void *ptr) { asm volatile(" diag %0,%1,0x224\n" : :"d" (0), "d"(ptr) : "memory"); } -static inline int diag224_get_name_table(void) +static int diag224_get_name_table(void) { /* memory must be below 2GB */ diag224_cpu_names = kmalloc(PAGE_SIZE, GFP_KERNEL | GFP_DMA); @@ -446,7 +467,7 @@ static inline int diag224_get_name_table return 0; } -static inline void diag224_delete_name_table(void) +static void diag224_delete_name_table(void) { kfree(diag224_cpu_names); } @@ -459,7 +480,7 @@ static int diag224_idx2name(int index, c return 0; } -int diag_init(void) +__init int hypfs_diag_init(void) { int rc; @@ -475,7 +496,7 @@ int diag_init(void) return rc; } -void diag_exit(void) +__exit void hypfs_diag_exit(void) { diag224_delete_name_table(); } @@ -590,39 +611,51 @@ static void *hypfs_create_phys_files(str return cpu_info; } -int diag_create_files(struct super_block *sb, struct dentry *root) +int hypfs_diag_create_files(struct super_block *sb, struct dentry *root) { struct dentry *systems_dir, *hyp_dir; void *time_hdr, *part_hdr; - int i; - void *buffer, *rc; + int i, rc; + void *buffer, *ptr; buffer = diag204_store(); if (IS_ERR(buffer)) return PTR_ERR(buffer); systems_dir = hypfs_mkdir(sb, root, "systems"); - if (IS_ERR(systems_dir)) - return PTR_ERR(systems_dir); + if (IS_ERR(systems_dir)) { + rc = PTR_ERR(systems_dir); + goto err_out; + } 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); - if (IS_ERR(part_hdr)) - return PTR_ERR(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) { - void *rc; - rc = hypfs_create_phys_files(sb, root, part_hdr); - if (IS_ERR(rc)) - return PTR_ERR(rc); + ptr = hypfs_create_phys_files(sb, root, part_hdr); + if (IS_ERR(ptr)) { + rc = PTR_ERR(ptr); + goto err_out; + } } hyp_dir = hypfs_mkdir(sb, root, "hyp"); - if (IS_ERR(hyp_dir)) - return PTR_ERR(hyp_dir); - rc = hypfs_create_str(sb, hyp_dir, "type", "LPAR Hypervisor"); - if (IS_ERR(rc)) - return PTR_ERR(rc); + if (IS_ERR(hyp_dir)) { + rc = PTR_ERR(hyp_dir); + goto err_out; + } + ptr = hypfs_create_str(sb, hyp_dir, "type", "LPAR Hypervisor"); + if (IS_ERR(ptr)) { + rc = PTR_ERR(ptr); + goto err_out; + } + rc = 0; + +err_out: kfree(buffer); - return 0; + return rc; } diff -puN arch/s390/hypfs/hypfs_diag.h~s390-hypervisor-file-system-fixes arch/s390/hypfs/hypfs_diag.h --- devel/arch/s390/hypfs/hypfs_diag.h~s390-hypervisor-file-system-fixes 2006-04-28 23:40:09.000000000 -0700 +++ devel-akpm/arch/s390/hypfs/hypfs_diag.h 2006-04-28 23:40:09.000000000 -0700 @@ -9,8 +9,8 @@ #ifndef _HYPFS_DIAG_H_ #define _HYPFS_DIAG_H_ -extern int diag_init(void); -extern void diag_exit(void); -extern int diag_create_files(struct super_block *sb, struct dentry *root); +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); #endif /* _HYPFS_DIAG_H_ */ diff -puN arch/s390/hypfs/inode.c~s390-hypervisor-file-system-fixes arch/s390/hypfs/inode.c --- devel/arch/s390/hypfs/inode.c~s390-hypervisor-file-system-fixes 2006-04-28 23:40:09.000000000 -0700 +++ devel-akpm/arch/s390/hypfs/inode.c 2006-04-28 23:40:09.000000000 -0700 @@ -28,25 +28,26 @@ static struct dentry *hypfs_create_updat struct dentry *dir); struct hypfs_sb_info { - int uid; /* uid used for files and dirs */ - int gid; /* gid used for files and dirs */ + uid_t uid; /* uid used for files and dirs */ + gid_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 */ }; -static struct dentry *update_file_dentry; static struct file_operations hypfs_file_ops; static struct file_system_type hypfs_type; static struct super_operations hypfs_s_ops; -static time_t last_update_time = 0; /* update time in seconds since 1970 */ -static DEFINE_MUTEX(hypfs_lock); /* start of list of all dentries, which have to be deleted on update */ static struct dentry *hypfs_last_dentry; -static void hypfs_update_update(void) +static void hypfs_update_update(struct super_block *sb) { - struct inode* inode = update_file_dentry->d_inode; + struct hypfs_sb_info *sb_info = sb->s_fs_info; + struct inode *inode = sb_info->update_file->d_inode; - last_update_time = get_seconds(); + sb_info->last_update = get_seconds(); inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; } @@ -103,7 +104,8 @@ static void hypfs_drop_inode(struct inod static int hypfs_open(struct inode *inode, struct file *filp) { - char *data = (char *)filp->f_dentry->d_inode->u.generic_ip; + char *data = filp->f_dentry->d_inode->u.generic_ip; + struct hypfs_sb_info *fs_info; if (filp->f_mode & FMODE_WRITE) { if (!(inode->i_mode & S_IWUGO)) @@ -113,14 +115,17 @@ static int hypfs_open(struct inode *inod if (!(inode->i_mode & S_IRUGO)) return -EACCES; } - mutex_lock(&hypfs_lock); - filp->private_data = kmalloc(strlen(data) + 1, GFP_KERNEL); - if (!filp->private_data) { - mutex_unlock(&hypfs_lock); - return -ENOMEM; + + fs_info = inode->i_sb->s_fs_info; + if(data) { + mutex_lock(&fs_info->lock); + filp->private_data = kstrdup(data, GFP_KERNEL); + if (!filp->private_data) { + mutex_unlock(&fs_info->lock); + return -ENOMEM; + } + mutex_unlock(&fs_info->lock); } - strcpy(filp->private_data, data); - mutex_unlock(&hypfs_lock); return 0; } @@ -131,7 +136,7 @@ static ssize_t hypfs_aio_read(struct kio size_t len; struct file *filp = iocb->ki_filp; - data = (char *)filp->private_data; + data = filp->private_data; len = strlen(data); if (offset > len) { count = 0; @@ -145,7 +150,7 @@ static ssize_t hypfs_aio_read(struct kio } iocb->ki_pos += count; file_accessed(filp); - out: +out: return count; } static ssize_t hypfs_aio_write(struct kiocb *iocb, const char __user *buf, @@ -153,24 +158,36 @@ static ssize_t hypfs_aio_write(struct ki { int rc; struct super_block *sb; + struct hypfs_sb_info *fs_info; - mutex_lock(&hypfs_lock); sb = iocb->ki_filp->f_dentry->d_inode->i_sb; - if (last_update_time == get_seconds()) { + fs_info = sb->s_fs_info; + /* + * Currently we only allow one update per second for two reasons: + * 1. diag 204 is VERY expensive + * 2. If several processes do updates in parallel and then read the + * hypfs data, the likelihood of collisions is reduced, if we restrict + * the minimum update interval. A collision occurs, if during the + * data gathering of one process another process triggers an update + * If the first process wants to ensure consistent data, it has + * to restart data collection in this case. + */ + mutex_lock(&fs_info->lock); + if (fs_info->last_update == get_seconds()) { rc = -EBUSY; goto out; } hypfs_delete_tree(sb->s_root); - rc = diag_create_files(sb, sb->s_root); + rc = hypfs_diag_create_files(sb, sb->s_root); if (rc) { printk(KERN_ERR "hypfs: Update failed\n"); hypfs_delete_tree(sb->s_root); goto out; } - hypfs_update_update(); + hypfs_update_update(sb); rc = count; - out: - mutex_unlock(&hypfs_lock); +out: + mutex_unlock(&fs_info->lock); return rc; } @@ -229,9 +246,10 @@ static int hypfs_fill_super(struct super int rc = 0; struct hypfs_sb_info *sbi; - sbi = kmalloc(sizeof(struct hypfs_sb_info), GFP_KERNEL); + sbi = kzalloc(sizeof(struct hypfs_sb_info), GFP_KERNEL); if (!sbi) return -ENOMEM; + mutex_init(&sbi->lock); sbi->uid = current->uid; sbi->gid = current->gid; sb->s_fs_info = sbi; @@ -255,23 +273,23 @@ static int hypfs_fill_super(struct super rc = -ENOMEM; goto err_inode; } - rc = diag_create_files(sb, sb->s_root); + rc = hypfs_diag_create_files(sb, sb->s_root); if (rc) goto err_tree; - update_file_dentry = hypfs_create_update_file(sb, sb->s_root); - if (IS_ERR(update_file_dentry)) { - rc = PTR_ERR(update_file_dentry); + sbi->update_file = hypfs_create_update_file(sb, sb->s_root); + if (IS_ERR(sbi->update_file)) { + rc = PTR_ERR(sbi->update_file); goto err_tree; } - hypfs_update_update(); + hypfs_update_update(sb); return 0; - err_tree: +err_tree: hypfs_delete_tree(sb->s_root); dput(sb->s_root); - err_inode: +err_inode: iput(root_inode); - err_alloc: +err_alloc: kfree(sbi); return rc; } @@ -309,7 +327,7 @@ static struct dentry *hypfs_create_file( } if (mode & S_IFREG) { inode->i_fop = &hypfs_file_ops; - if(data) + if (data) inode->i_size = strlen(data); else inode->i_size = 0; @@ -344,8 +362,6 @@ static struct dentry *hypfs_create_updat dentry = hypfs_create_file(sb, dir, "update", NULL, S_IFREG | UPDATE_FILE_MODE); - if (!dentry) - return ERR_PTR(-ENOMEM); /* * We do not put the update file on the 'delete' list with * hypfs_add_dentry(), since it should not be removed when the tree @@ -362,13 +378,12 @@ struct dentry *hypfs_create_u64(struct s struct dentry *dentry; snprintf(tmp, TMP_SIZE, "%lld\n", (unsigned long long int)value); - buffer = kmalloc(strlen(tmp) + 1, GFP_KERNEL); + buffer = kstrdup(tmp, GFP_KERNEL); if (!buffer) return ERR_PTR(-ENOMEM); - strcpy(buffer, tmp); dentry = hypfs_create_file(sb, dir, name, buffer, S_IFREG | REG_FILE_MODE); - if (!dentry) { + if (IS_ERR(dentry)) { kfree(buffer); return ERR_PTR(-ENOMEM); } @@ -388,7 +403,7 @@ struct dentry *hypfs_create_str(struct s sprintf(buffer, "%s\n", string); dentry = hypfs_create_file(sb, dir, name, buffer, S_IFREG | REG_FILE_MODE); - if (!dentry) { + if (IS_ERR(dentry)) { kfree(buffer); return ERR_PTR(-ENOMEM); } @@ -426,7 +441,7 @@ static int __init hypfs_init(void) if (MACHINE_IS_VM) return -ENODATA; - if (diag_init()) { + if (hypfs_diag_init()) { rc = -ENODATA; goto err_msg; } @@ -438,18 +453,18 @@ static int __init hypfs_init(void) goto err_sysfs; return 0; - err_sysfs: +err_sysfs: subsystem_unregister(&hypervisor_subsys); - err_diag: - diag_exit(); - err_msg: +err_diag: + hypfs_diag_exit(); +err_msg: printk(KERN_ERR "hypfs: Initialization failed with rc = %i.\n", rc); return rc; } static void __exit hypfs_exit(void) { - diag_exit(); + hypfs_diag_exit(); unregister_filesystem(&hypfs_type); subsystem_unregister(&hypervisor_subsys); } diff -puN arch/s390/Kconfig~s390-hypervisor-file-system-fixes arch/s390/Kconfig --- devel/arch/s390/Kconfig~s390-hypervisor-file-system-fixes 2006-04-28 23:40:09.000000000 -0700 +++ devel-akpm/arch/s390/Kconfig 2006-04-28 23:40:09.000000000 -0700 @@ -451,7 +451,7 @@ config HYPFS_FS default y help This is a virtual file system intended to provide accounting - information in a s390 hypervisor environment. + information in an s390 hypervisor environment. config KEXEC bool "kexec system call (EXPERIMENTAL)" _ Patches currently in -mm which might be from holzheu@xxxxxxxxxx are strstrip-api.patch - To unsubscribe from this list: send the line "unsubscribe mm-commits" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html