lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <00513aa5-1cc5-bc1c-1ca7-d5cd6e3f1ed6@linux.alibaba.com>
Date:   Fri, 23 Oct 2020 10:57:33 +0800
From:   zc <zoucao@...ux.alibaba.com>
To:     viro@...iv.linux.org.uk
Cc:     linux-kernel@...r.kernel.org, linux-fsdevel@...r.kernel.org,
        zoucao <zoucao@...ux.alibaba.com>
Subject: Re: [PATCH 1/2] fs:regfs: add register easy filesystem

Hi viro:

   Through regfs is very sample and easy,  but i think it is a Interest 
,  could give  some suggestions?


Regards,

zc

在 2020/10/20 下午2:30, Zou Cao 写道:
> register filesystem is mapping the register into file dentry, it
> will use the io readio to get the register val. DBT file is use
> to decript the register tree, you can use it as follow:
>
> 	mount -t regfs -o dtb=test.dtb none /mnt
>
> 	test.dts:
> 	/ {
>
> 	compatible = "hisilicon,hi6220-hikey", "hisilicon,hi6220";
> 	#address-cells = <0x2>;
> 	#size-cells = <0x2>;
> 	model = "HiKey Development Board";
>
> 	gic-v3-dist{
> 		reg = <0x0 0x8000000 0x0 0x10000>;
> 		GIC_CTRL {
> 			offset = <0x0>;
> 		};
> 		GICD_TYPER {
> 			offset = <0x4>;
> 		};
> 	   };
> 	};
>
> it will create all regiter dentry file in /mnt
>
> Signed-off-by: Zou Cao <zoucao@...ux.alibaba.com>
> ---
>   fs/Kconfig             |   1 +
>   fs/Makefile            |   1 +
>   fs/regfs/Kconfig       |   7 +
>   fs/regfs/Makefile      |   8 ++
>   fs/regfs/file.c        | 107 +++++++++++++++
>   fs/regfs/inode.c       | 354 +++++++++++++++++++++++++++++++++++++++++++++++++
>   fs/regfs/internal.h    |  32 +++++
>   fs/regfs/regfs_inode.h |  32 +++++
>   fs/regfs/supper.c      |  71 ++++++++++
>   9 files changed, 613 insertions(+)
>   create mode 100644 fs/regfs/Kconfig
>   create mode 100644 fs/regfs/Makefile
>   create mode 100644 fs/regfs/file.c
>   create mode 100644 fs/regfs/inode.c
>   create mode 100644 fs/regfs/internal.h
>   create mode 100644 fs/regfs/regfs_inode.h
>   create mode 100644 fs/regfs/supper.c
>
> diff --git a/fs/Kconfig b/fs/Kconfig
> index a88aa3a..d95acaf 100644
> --- a/fs/Kconfig
> +++ b/fs/Kconfig
> @@ -324,6 +324,7 @@ endif # NETWORK_FILESYSTEMS
>   source "fs/nls/Kconfig"
>   source "fs/dlm/Kconfig"
>   source "fs/unicode/Kconfig"
> +source "fs/regfs/Kconfig"
>   
>   config IO_WQ
>   	bool
> diff --git a/fs/Makefile b/fs/Makefile
> index 2ce5112..24f3878 100644
> --- a/fs/Makefile
> +++ b/fs/Makefile
> @@ -136,3 +136,4 @@ obj-$(CONFIG_EFIVAR_FS)		+= efivarfs/
>   obj-$(CONFIG_EROFS_FS)		+= erofs/
>   obj-$(CONFIG_VBOXSF_FS)		+= vboxsf/
>   obj-$(CONFIG_ZONEFS_FS)		+= zonefs/
> +obj-$(CONFIG_REGFS_FS)		+= zonefs/
> diff --git a/fs/regfs/Kconfig b/fs/regfs/Kconfig
> new file mode 100644
> index 0000000..74ba85b
> --- /dev/null
> +++ b/fs/regfs/Kconfig
> @@ -0,0 +1,7 @@
> +config REGFS_FS
> +	tristate "registers filesystem support"
> +	depends on ARM64
> +	help
> +	  regfs support the read and write register of device resource by
> +	  dentry filesystem, it is more easy to support bsp debug. it also
> +	  support to printk the register val when panic
> diff --git a/fs/regfs/Makefile b/fs/regfs/Makefile
> new file mode 100644
> index 0000000..26d5eef
> --- /dev/null
> +++ b/fs/regfs/Makefile
> @@ -0,0 +1,8 @@
> +# SPDX-License-Identifier: GPL-2.0-only
> +#
> +#Makefile for the linux ramfs routines.
> +#
> +
> +obj-y += regfs.o
> +
> +regfs-objs += inode.o file.o supper.o
> diff --git a/fs/regfs/file.c b/fs/regfs/file.c
> new file mode 100644
> index 0000000..6cd9f3d
> --- /dev/null
> +++ b/fs/regfs/file.c
> @@ -0,0 +1,107 @@
> +#include <linux/fs.h>
> +#include <linux/mm.h>
> +#include <linux/mpage.h>
> +#include <linux/writeback.h>
> +#include <linux/buffer_head.h>
> +#include <linux/kernel.h>
> +#include <linux/mm.h>
> +#include <linux/memcontrol.h>
> +#include <linux/iomap.h>
> +#include <linux/pagemap.h>
> +#include <linux/uio.h>
> +#include <linux/buffer_head.h>
> +#include <linux/dax.h>
> +#include <linux/writeback.h>
> +#include <linux/swap.h>
> +#include <linux/bio.h>
> +#include <linux/sched/signal.h>
> +#include <linux/migrate.h>
> +
> +#include "regfs_inode.h"
> +#include "internal.h"
> +
> +ssize_t regfs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
> +{
> +	struct file *file = iocb->ki_filp;
> +	struct inode *inode = file->f_mapping->host;
> +	ssize_t ret;
> +
> +	inode_lock(inode);
> +	ret = generic_write_checks(iocb, from);
> +	if (ret > 0)
> +		ret = __generic_file_write_iter(iocb, from);
> +	inode_unlock(inode);
> +
> +	if (ret > 0)
> +		ret = generic_write_sync(iocb, ret);
> +	return ret;
> +}
> +
> +static ssize_t regfs_file_read(struct file *file, char __user *buf, size_t len, loff_t *ppos)
> +{
> +	struct address_space *mapping = file->f_mapping;
> +	struct regfs_inode_info  *info = REGFS_I(mapping->host);
> +	char str[64];
> +	unsigned long val;
> +
> +	val = readl_relaxed(info->base + info->offset);
> +
> +	loc_debug("name:%s base:%p val:%lx\n"
> +			, file->f_path.dentry->d_iname
> +			, info->base + info->offset
> +			, val);
> +
> +	snprintf(str, 64, "%lx", val);
> +
> +	return simple_read_from_buffer(buf, len, ppos, str, strlen(str));
> +}
> +
> +static ssize_t regfs_file_write(struct file *file, const char __user *buf, size_t len, loff_t *ppos)
> +{
> +	struct address_space *mapping = file->f_mapping;
> +	struct regfs_inode_info  *info = REGFS_I(mapping->host);
> +	char str[67];
> +	unsigned long val = 0;
> +	loff_t pos = *ppos;
> +	size_t res;
> +
> +	if (pos < 0)
> +		return -EINVAL;
> +	if (pos >= len || len > 66)
> +		return 0;
> +
> +	res = copy_from_user(str, buf, len);
> +	if (res)
> +		return -EFAULT;
> +	str[len] = 0;
> +
> +	if (kstrtoul(str, 16, &val) < 0)
> +		return -EINVAL;
> +
> +	writel_relaxed(val, info->base + info->offset);
> +
> +	loc_debug("name:%s base:%p val:%lx\n"
> +			, file->f_path.dentry->d_iname
> +			, info->base + info->offset
> +			, val);
> +
> +	return len;
> +}
> +
> +const struct file_operations regfs_file_operations = {
> +	.read = regfs_file_read,
> +	.write = regfs_file_write,
> +};
> +
> +const struct inode_operations regfs_file_inode_operations = {
> +	.setattr	= simple_setattr,
> +	.getattr	= simple_getattr,
> +};
> +
> +const struct address_space_operations regfs_aops = {
> +	.readpage   = simple_readpage,
> +	.write_begin    = simple_write_begin,
> +	.write_end  = simple_write_end,
> +	.set_page_dirty = __set_page_dirty_buffers,
> +};
> +
> diff --git a/fs/regfs/inode.c b/fs/regfs/inode.c
> new file mode 100644
> index 0000000..1643fcd
> --- /dev/null
> +++ b/fs/regfs/inode.c
> @@ -0,0 +1,354 @@
> +/*
> + * Resizable simple ram filesystem for Linux.
> + *
> + * Copyright (C) 2000 Linus Torvalds.
> + *               2000 Transmeta Corp.
> + *
> + * Usage limits added by David Gibson, Linuxcare Australia.
> + * This file is released under the GPL.
> + */
> +
> +/*
> + * NOTE! This filesystem is probably most useful
> + * not as a real filesystem, but as an example of
> + * how virtual filesystems can be written.
> + *
> + * It doesn't get much simpler than this. Consider
> + * that this file implements the full semantics of
> + * a POSIX-compliant read-write filesystem.
> + *
> + * Note in particular how the filesystem does not
> + * need to implement any data structures of its own
> + * to keep track of the virtual data: using the VFS
> + * caches is sufficient.
> + */
> +
> +#include <linux/fs.h>
> +#include <linux/pagemap.h>
> +#include <linux/highmem.h>
> +#include <linux/time.h>
> +#include <linux/init.h>
> +#include <linux/string.h>
> +#include <linux/backing-dev.h>
> +#include <linux/sched.h>
> +#include <linux/parser.h>
> +#include <linux/magic.h>
> +#include <linux/slab.h>
> +#include <linux/kernel.h>
> +#include <linux/of.h>
> +#include <linux/of_fdt.h>
> +#include <linux/libfdt.h>
> +#include <asm/uaccess.h>
> +#include <linux/module.h>
> +#include "regfs_inode.h"
> +#include "internal.h"
> +
> +static LIST_HEAD(regfs_head);
> +
> +static const struct inode_operations regfs_dir_inode_operations;
> +int regfs_debug;
> +module_param(regfs_debug, int, S_IRUGO);
> +MODULE_PARM_DESC(regfs_debug, "enable regfs debug mode");
> +
> +struct inode *regfs_get_inode(struct super_block *sb, const struct inode *dir, umode_t mode, dev_t dev)
> +{
> +	struct inode *inode = new_inode(sb);
> +
> +	if (inode) {
> +		inode->i_ino = get_next_ino();
> +		inode_init_owner(inode, dir, mode);
> +		inode->i_mapping->a_ops = &regfs_aops;
> +		//inode->i_mapping->backing_dev_info = &regfs_backing_dev_info;
> +		mapping_set_gfp_mask(inode->i_mapping, GFP_HIGHUSER);
> +		mapping_set_unevictable(inode->i_mapping);
> +		inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
> +		switch (mode & S_IFMT) {
> +		default:
> +			init_special_inode(inode, mode, dev);
> +			break;
> +		case S_IFREG:
> +			inode->i_op = &regfs_file_inode_operations;
> +			inode->i_fop = &regfs_file_operations;
> +			break;
> +		case S_IFDIR:
> +			inode->i_op = &regfs_dir_inode_operations;
> +			inode->i_fop = &simple_dir_operations;
> +
> +			/* directory inodes start off with i_nlink == 2 (for "." entry) */
> +			inc_nlink(inode);
> +			break;
> +		case S_IFLNK:
> +			inode->i_op = &page_symlink_inode_operations;
> +			break;
> +		}
> +	}
> +
> +	return inode;
> +}
> +
> +static const struct inode_operations regfs_dir_inode_operations = {
> +	.lookup		= simple_lookup,
> +};
> +
> +static struct dentry *new_dentry_create(struct super_block *sb, struct dentry *parent,
> +		 const char *name, bool is_dir, struct res_data *res)
> +{
> +	struct dentry *dentry;
> +	struct inode *inode;
> +	struct regfs_inode_info *ei;
> +	struct regfs_fs_info *fsi = sb->s_fs_info;
> +
> +	dentry = d_alloc_name(parent, name);
> +	if (!dentry)
> +		return NULL;
> +
> +	inode = new_inode(sb);
> +	if (!inode)
> +		goto out;
> +
> +	ei = REGFS_I(inode);
> +	inode->i_ino = get_next_ino();;
> +	inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
> +	inode->i_uid =  GLOBAL_ROOT_UID;
> +	inode->i_gid =  GLOBAL_ROOT_GID;
> +	if (is_dir) {
> +		inode->i_mode = S_IFDIR | S_IRUGO | S_IWUSR;
> +		inode->i_op = &regfs_dir_inode_operations;
> +		inode->i_fop = &simple_dir_operations;
> +		list_add(&ei->list, &fsi->list);
> +	} else {
> +		inode->i_mode = S_IFREG | S_IRUGO | S_IWUSR;
> +		inode->i_op = &regfs_file_inode_operations;
> +		inode->i_fop = &regfs_file_operations;
> +		inc_nlink(inode);
> +	}
> +	ei->base = (void *)res->base;
> +	ei->offset = res->offset;
> +	ei->type = res->type;
> +
> +	d_add(dentry, inode);
> +
> +	loc_debug("new dentry io base:%llx offset:%llx ei:%llx\n", (u64)ei->base, (u64)ei->offset, (u64)ei);
> +	return dentry;
> +out:
> +	dput(dentry);
> +	return NULL;
> +}
> +
> +static void node_transfer_dentry(struct super_block *sb)
> +{
> +	struct regfs_fs_info *fsi = sb->s_fs_info;
> +	void *blob = fsi->dtb_buf;
> +	const char *pathp;
> +	int node_offset, depth = -1;
> +	struct dentry *parent = NULL;
> +	u64 parent_base;
> +
> +	for (node_offset = fdt_next_node(blob, -1, &depth);
> +		node_offset >= 0 && depth >= 0;
> +		node_offset = fdt_next_node(blob, node_offset, &depth)) {
> +
> +		const struct fdt_property *prop;
> +		struct res_data res;
> +
> +		pathp = fdt_get_name(blob, node_offset, NULL);
> +		prop = (void *)fdt_getprop(blob, node_offset, "reg", NULL);
> +
> +		if (prop) {
> +			unsigned long phys;
> +
> +			phys = fdt32_to_cpu(((const __be32 *)prop)[1]);
> +			res.type = RES_TYPE_RANGE;
> +			res.offset = fdt32_to_cpu(((const __be32 *)prop)[3]);
> +			res.base = (u64)ioremap(phys, res.offset);
> +
> +			if (!res.base) {
> +				parent = NULL;
> +				parent_base = 0;
> +				continue;
> +			}
> +
> +			loc_debug("%s reg:%lx size:%lx map:%llx\n\n", pathp
> +				 , (unsigned long) fdt32_to_cpu(((const __be32 *)prop)[1])
> +				 , (unsigned long) fdt32_to_cpu(((const __be32 *)prop)[3])
> +				 , (u64)res.base);
> +
> +			parent = new_dentry_create(sb, sb->s_root, (const char *)pathp, true, &res);
> +			parent_base = res.base;
> +
> +		} else {
> +			// parent dentry is create failed, igonre all child dentry
> +			if (!parent)
> +				continue;
> +
> +			prop = (void *)fdt_getprop(blob, node_offset, "offset", NULL);
> +			if (prop) {
> +
> +				res.offset = fdt32_to_cpu(*(const __be32 *)prop);
> +				res.base = parent_base;
> +				res.type = RES_TYPE_ITEM;
> +
> +				new_dentry_create(sb, parent, (const char *) pathp, false, &res);
> +				loc_debug("%s offset:%lx\n", pathp, (unsigned long)fdt32_to_cpu(*(const __be32 *)prop));
> +			}
> +		}
> +	}
> +}
> +
> +static int parse_options(char *options, struct super_block *sb)
> +{
> +	char *p;
> +	int ret = -EINVAL;
> +	struct regfs_fs_info *fsi;
> +	size_t msize = INT_MAX;
> +
> +	fsi = sb->s_fs_info;
> +
> +	if (!options)
> +		return -EINVAL;
> +
> +	while ((p = strsep(&options, ",")) != NULL) {
> +		char *name, *name_val;
> +
> +		name = strsep(&p, "=");
> +		if (name == NULL)
> +			goto failed;
> +
> +		name_val = strsep(&p, "=");
> +		if (name_val == NULL)
> +			goto failed;
> +
> +		//get resource address
> +		if (!strcmp(name, "dtb")) {
> +			ret = kernel_read_file_from_path(name_val, &fsi->dtb_buf, &fsi->dtb_len, msize, READING_UNKNOWN);
> +			if (ret) {
> +				pr_err("load %s failed\n", name_val);
> +				goto failed;
> +			}
> +		} else
> +			goto failed;
> +	};
> +
> +	return 0;
> +
> +failed:
> +	return ret;
> +}
> +
> +int regfs_fill_super(struct super_block *sb, void *data, int silent)
> +{
> +	struct regfs_fs_info *fsi;
> +	struct inode *inode;
> +	int err;
> +
> +	fsi = kzalloc(sizeof(struct regfs_fs_info), GFP_KERNEL);
> +	if (!fsi)
> +		return -ENOMEM;
> +
> +	sb->s_fs_info = fsi;
> +	fsi->sb = sb;
> +
> +	err = parse_options((char *)data, sb);
> +	if (err)
> +		goto out;
> +
> +	sb->s_maxbytes		= MAX_LFS_FILESIZE;
> +	sb->s_blocksize		= PAGE_SIZE;
> +	sb->s_blocksize_bits	= PAGE_SHIFT;
> +	sb->s_magic		= RAMFS_MAGIC;
> +	sb->s_op		= &regfs_ops;
> +	sb->s_time_gran		= 1;
> +
> +	inode = regfs_get_inode(sb, NULL, S_IFDIR, 0);
> +	sb->s_root = d_make_root(inode);
> +	if (!sb->s_root)
> +		goto out;
> +
> +	INIT_LIST_HEAD(&fsi->list);
> +	INIT_LIST_HEAD(&fsi->regfs_head);
> +	list_add(&fsi->regfs_head, &regfs_head);
> +
> +	return 0;
> +
> +out:
> +	if (fsi)
> +		kfree(fsi);
> +
> +	return err;
> +}
> +
> +struct dentry *regfs_mount(struct file_system_type *fs_type,
> +	int flags, const char *dev_name, void *data)
> +{
> +	struct dentry *root_dentry;
> +	struct super_block *sb;
> +
> +	root_dentry = mount_nodev(fs_type, flags, data, regfs_fill_super);
> +
> +	sb = root_dentry->d_sb;
> +
> +	if (sb->s_root) {
> +		node_transfer_dentry(sb);
> +	} else
> +		return NULL;
> +
> +	return root_dentry;
> +}
> +
> +static void regfs_kill_sb(struct super_block *sb)
> +{
> +	struct regfs_fs_info *fsi = sb->s_fs_info;
> +	struct regfs_inode_info *info_res;
> +
> +	list_for_each_entry(info_res,  &fsi->list, list)
> +		iounmap(info_res->base);
> +
> +	if (fsi) {
> +		if (fsi->dtb_buf)
> +			vfree(fsi->dtb_buf);
> +		list_del(&fsi->regfs_head);
> +		kfree(sb->s_fs_info);
> +	}
> +	kill_litter_super(sb);
> +}
> +
> +static struct file_system_type regfs_fs_type = {
> +	.name		= "regfs",
> +	.mount		= regfs_mount,
> +	.kill_sb	= regfs_kill_sb,
> +	.fs_flags	= FS_USERNS_MOUNT,
> +};
> +
> +static void init_once(void *foo)
> +{
> +	struct regfs_inode_info *ei = (struct regfs_inode_info *) foo;
> +
> +	inode_init_once(&ei->vfs_inode);
> +}
> +
> +static int __init init_regfs_fs(void)
> +{
> +
> +	regfs_inode_cachep = kmem_cache_create_usercopy("regfs_inode_cache",
> +				sizeof(struct regfs_inode_info), 0,
> +				(SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD | SLAB_ACCOUNT),
> +				0, 0, init_once);
> +
> +	if (!regfs_inode_cachep)
> +		return -ENOMEM;
> +
> +	return  register_filesystem(&regfs_fs_type);
> +}
> +
> +static void __exit exit_regfs_fs(void)
> +{
> +	unregister_filesystem(&regfs_fs_type);
> +	rcu_barrier();
> +	kmem_cache_destroy(regfs_inode_cachep);
> +}
> +
> +module_init(init_regfs_fs);
> +module_exit(exit_regfs_fs);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Zou Cao<zoucaox@...ux.alibaba.com>");
> diff --git a/fs/regfs/internal.h b/fs/regfs/internal.h
> new file mode 100644
> index 0000000..61577bb
> --- /dev/null
> +++ b/fs/regfs/internal.h
> @@ -0,0 +1,32 @@
> +#ifndef __INTERNAL_H__
> +#define __INTERNAL_H__
> +
> +#define loc_debug(fmt, ...)   \
> +	do {                       \
> +		if (regfs_debug)   \
> +			printk(fmt, ##__VA_ARGS__); \
> +	} while (0)
> +
> +struct regfs_fs_info {
> +	struct super_block *sb;
> +	void   *dtb_buf;
> +	u64  	dtb_len;
> +	u64  	iomem;
> +	u64  size;
> +	// supper ifs list
> +	struct list_head regfs_head;
> +	// io map list of inode
> +	struct list_head list;
> +};
> +
> +#define RAMFS_DEFAULT_MODE	0755
> +
> +extern int regfs_debug;
> +extern const struct address_space_operations regfs_aops;
> +extern const struct inode_operations regfs_file_inode_operations;
> +extern const struct file_operations regfs_file_operations;
> +extern const struct super_operations regfs_ops;
> +extern struct kmem_cache *regfs_inode_cachep;
> +int regfs_supper_init(void);
> +
> +#endif
> diff --git a/fs/regfs/regfs_inode.h b/fs/regfs/regfs_inode.h
> new file mode 100644
> index 0000000..0883e05
> --- /dev/null
> +++ b/fs/regfs/regfs_inode.h
> @@ -0,0 +1,32 @@
> +#ifndef __REGFS_INODE_H__
> +#define __REGFS_INODE_H__
> +
> +enum res_type {
> +	RES_TYPE_NONE = 0,
> +	RES_TYPE_RANGE,
> +	RES_TYPE_ITEM,
> +};
> +
> +struct regfs_inode_info {
> +	unsigned long flag;
> +	struct inode vfs_inode;
> +	void __iomem *base;
> +	u64  offset;
> +	u64  val;  //for panic save
> +	struct list_head list;  //inode list
> +	enum res_type type;
> +};
> +
> +struct res_data {
> +	enum res_type type;
> +	u64  base;
> +	u64  offset;
> +};
> +
> +static inline struct regfs_inode_info *REGFS_I(struct inode *inode)
> +{
> +	return container_of(inode, struct regfs_inode_info, vfs_inode);
> +}
> +
> +#endif
> +
> diff --git a/fs/regfs/supper.c b/fs/regfs/supper.c
> new file mode 100644
> index 0000000..35733b6
> --- /dev/null
> +++ b/fs/regfs/supper.c
> @@ -0,0 +1,71 @@
> +#include <linux/fs.h>
> +#include <linux/pagemap.h>
> +#include <linux/highmem.h>
> +#include <linux/time.h>
> +#include <linux/init.h>
> +#include <linux/string.h>
> +#include <linux/backing-dev.h>
> +#include <linux/sched.h>
> +#include <linux/parser.h>
> +#include <linux/magic.h>
> +#include <linux/slab.h>
> +#include <linux/kernel.h>
> +#include <linux/uaccess.h>
> +#include <linux/module.h>
> +#include <linux/iversion.h>
> +#include "regfs_inode.h"
> +#include "internal.h"
> +
> +struct kmem_cache *regfs_inode_cachep;
> +
> +/*
> + * Display the mount options in /proc/mounts.
> + */
> +
> +static struct inode *regfs_alloc_inode(struct super_block *sb)
> +{
> +	struct regfs_inode_info *ei;
> +
> +	ei = kmem_cache_alloc(regfs_inode_cachep, GFP_NOFS);
> +	if (!ei)
> +		return NULL;
> +
> +	inode_set_iversion(&ei->vfs_inode, 1);
> +	ei->type = RES_TYPE_NONE;
> +
> +	return &ei->vfs_inode;
> +}
> +
> +static void regfs_i_callback(struct rcu_head *head)
> +{
> +	struct inode *inode = container_of(head, struct inode, i_rcu);
> +
> +	kmem_cache_free(regfs_inode_cachep, REGFS_I(inode));
> +}
> +
> +static void regfs_destroy_inode(struct inode *inode)
> +{
> +	call_rcu(&inode->i_rcu, regfs_i_callback);
> +}
> +
> +static int regfs_write_inode(struct inode *inode, struct writeback_control *wbc)
> +{
> +	return 0;
> +}
> +
> +static int regfs_drop_inode(struct inode *inode)
> +{
> +	return generic_drop_inode(inode);
> +}
> +
> +const struct super_operations regfs_ops = {
> +	.alloc_inode    = regfs_alloc_inode,
> +	.destroy_inode  = regfs_destroy_inode,
> +	.write_inode    = regfs_write_inode,
> +	.drop_inode = regfs_drop_inode,
> +};
> +
> +int regfs_supper_init(void)
> +{
> +	return 0;
> +}

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ