* 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/parser.h>
#include <linux/sysfs.h>
#include <linux/module.h>
+#include <linux/seq_file.h>
+#include <linux/mount.h>
#include <asm/ebcdic.h>
#include "hypfs.h"
hypfs_last_dentry = dentry;
}
+static inline int hypfs_positive(struct dentry *dentry)
+{
+ return dentry->d_inode && !d_unhashed(dentry);
+}
+
static void hypfs_remove(struct dentry *dentry)
{
struct dentry *parent;
parent = dentry->d_parent;
- if (S_ISDIR(dentry->d_inode->i_mode))
- simple_rmdir(parent->d_inode, dentry);
- else
- simple_unlink(parent->d_inode, dentry);
+ 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))
+ simple_rmdir(parent->d_inode, dentry);
+ else
+ simple_unlink(parent->d_inode, dentry);
+ }
d_delete(dentry);
dput(dentry);
+ mutex_unlock(&parent->d_inode->i_mutex);
}
static void hypfs_delete_tree(struct dentry *root)
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;
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)
else
rc = hypfs_diag_create_files(sb, 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;
}
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}
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)
+{
+ struct hypfs_sb_info *hypfs_info = mnt->mnt_sb->s_fs_info;
+
+ seq_printf(s, ",uid=%u", hypfs_info->uid);
+ seq_printf(s, ",gid=%u", hypfs_info->gid);
+ return 0;
+}
+
static int hypfs_fill_super(struct super_block *sb, void *data, int silent)
{
struct inode *root_inode;
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;
}
hypfs_update_update(sb);
sb->s_root = root_dentry;
+ pr_info("Hypervisor filesystem mounted\n");
return 0;
err_tree:
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))
- return ERR_PTR(-ENOMEM);
+ if (IS_ERR(dentry)) {
+ dentry = ERR_PTR(-ENOMEM);
+ goto fail;
+ }
inode = hypfs_make_inode(sb, mode);
if (!inode) {
dput(dentry);
- return ERR_PTR(-ENOMEM);
+ dentry = ERR_PTR(-ENOMEM);
+ goto fail;
}
if (mode & S_IFREG) {
inode->i_fop = &hypfs_file_ops;
inode->i_private = data;
d_instantiate(dentry, inode);
dget(dentry);
+fail:
+ mutex_unlock(&parent->d_inode->i_mutex);
return dentry;
}
if (IS_ERR(dentry))
return dentry;
hypfs_add_dentry(dentry);
- parent->d_inode->i_nlink++;
return dentry;
}
static struct super_operations hypfs_s_ops = {
.statfs = simple_statfs,
.drop_inode = hypfs_drop_inode,
+ .show_options = hypfs_show_options,
};
-static decl_subsys(s390, NULL, NULL);
+static struct kobject *s390_kobj;
static int __init hypfs_init(void)
{
goto fail_diag;
}
}
- kobj_set_kset_s(&s390_subsys, hypervisor_subsys);
- rc = subsystem_register(&s390_subsys);
- if (rc)
+ s390_kobj = kobject_create_and_add("s390", hypervisor_kobj);
+ if (!s390_kobj) {
+ rc = -ENOMEM;;
goto fail_sysfs;
+ }
rc = register_filesystem(&hypfs_type);
if (rc)
goto fail_filesystem;
return 0;
fail_filesystem:
- subsystem_unregister(&s390_subsys);
+ 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);
+ pr_err("Initialization of hypfs failed with rc=%i\n", rc);
return rc;
}
if (!MACHINE_IS_VM)
hypfs_diag_exit();
unregister_filesystem(&hypfs_type);
- subsystem_unregister(&s390_subsys);
+ kobject_put(s390_kobj);
}
module_init(hypfs_init)