[PATCH 0/5] powerpc: add device tree property updates

Arnd Bergmann arnd at arndb.de
Thu Jan 12 11:34:15 EST 2006


On Wednesday 11 January 2006 22:54, Benjamin Herrenschmidt wrote:
> Yah, but I do prefer a filesystem 

Ok, if you want something to play with, try this one.
It's my two-hour, 200 line attempt to give you an idea of how
the most simple implementation could look like.

It's pretty much guaranteed not to work since I don't have any
powerpc machines around at home, but it's a start.

	Arnd <><

diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index 144e284..48285a6 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -46,6 +46,7 @@ extra-y				+= vmlinux.lds
 
 obj-y				+= process.o init_task.o time.o \
 				   prom.o traps.o setup-common.o udbg.o
+obj-y				+= prom_fs.o
 obj-$(CONFIG_PPC32)		+= entry_32.o setup_32.o misc_32.o systbl.o
 obj-$(CONFIG_PPC64)		+= misc_64.o dma_64.o iommu.o
 obj-$(CONFIG_PPC_MULTIPLATFORM)	+= prom_init.o
--- /dev/null	2006-01-11 21:47:23.852291750 +0000
+++ arch/powerpc/kernel/prom_fs.c	2006-01-12 00:23:24.000000000 +0000
@@ -0,0 +1,200 @@
+#include <linux/dcache.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/pagemap.h>
+
+#include <asm/prom.h>
+
+#define PROMFS_MAGIC 0xf0384d8c
+
+static ssize_t promfs_read(struct file *file, char __user *data,
+		size_t len, loff_t *ppos)
+{
+	struct property *prop = file->f_dentry->d_inode->u.generic_ip;
+
+	return simple_read_from_buffer(data, len, ppos,
+			prop->value, prop->length);
+}
+
+static struct file_operations promfs_property_operations = {
+	.read = promfs_read,
+};
+
+static struct inode *promfs_new_inode(struct super_block *sb,
+		int mode, void *data)
+{
+	struct inode *inode;
+
+	inode = new_inode(sb);
+	if (!inode)
+		goto out;
+
+	inode->i_mode = mode;
+	inode->i_uid = current->fsuid;
+	inode->i_gid = current->fsgid;
+	inode->i_blksize = PAGE_CACHE_SIZE;
+	inode->i_blocks = 0;
+	inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+	inode->u.generic_ip = data;
+	switch (mode & S_IFMT) {
+	case S_IFDIR:
+		inode->i_op = &simple_dir_inode_operations;
+		inode->i_fop = &simple_dir_operations;
+		break;
+	case S_IFREG:
+		inode->i_fop = &promfs_property_operations;
+		break;
+	}
+out:
+	return inode;
+}
+
+static int promfs_create_prop(struct super_block *sb, struct dentry *dir,
+				struct property *prop)
+{
+	struct dentry *dentry;
+	struct inode *inode;
+	int ret;
+
+	ret = -ENOMEM;
+	dentry = d_alloc_name(dir, prop->name);
+	if (!dentry)
+		goto out;
+	inode = promfs_new_inode(sb, S_IFREG | 0555, prop);
+	if (!inode)
+		goto out_dput;
+	d_add(dentry, inode);
+	return 0;
+
+out_dput:
+	dput(dentry);
+out:
+	return ret;
+}
+
+static int promfs_create_props(struct super_block *sb, struct dentry *dir,
+		struct device_node *node)
+{
+	struct property *prop;
+	int ret = 0;
+
+	for (prop = node->properties; prop && !ret; prop = prop->next)
+		ret = promfs_create_prop(sb, dir, prop);
+
+	if (ret) {
+		WARN_ON(1);
+/*
+		promfs_remove_props(sb, dir);
+*/
+	}
+
+	return ret;
+}
+
+static int promfs_create_dir(struct super_block *sb,
+		struct dentry *dir, struct device_node *node)
+{
+	int ret;
+	struct device_node *np;
+	struct dentry *dentry;
+	struct inode *inode;
+
+	ret = -ENOMEM;
+	dentry = d_alloc_name(dir, node->name);
+	if (!dentry)
+		goto out;
+
+	inode = promfs_new_inode(sb, S_IFREG | 0555, node);
+	if (!inode)
+		goto out_dput;
+
+	np = NULL;
+	while ((np = of_get_next_child(node, np)) != NULL) {
+		ret = promfs_create_dir(sb, dentry, np);
+		if (ret)
+			goto out;
+	}
+
+	ret = promfs_create_props(sb, dentry, node);
+	if (ret)
+		goto out_cleanup;
+
+	d_add(dentry, inode);
+	return 0;
+
+out_cleanup:
+	WARN_ON(1);
+//	promfs_remove_dirs();
+out_dput:
+	dput(dentry);
+out:
+	return ret;
+}
+
+static int promfs_create_root(struct super_block *sb, void *data)
+{
+	struct inode *inode;
+	struct device_node *node;
+	int ret;
+
+	ret = -ENOENT;
+	node = of_find_node_by_path("/");
+	if (!node)
+		goto out;
+	ret = -ENOMEM;
+	inode = promfs_new_inode(sb, S_IFDIR | 0555, node);
+	if (!inode)
+		goto out_nput;
+	sb->s_root = d_alloc_root(inode);
+	if (!sb->s_root)
+		goto out_iput;
+	return 0;
+out_iput:
+	iput(inode);
+out_nput:
+	of_node_put(node);
+out:
+	return ret;
+}
+
+static struct super_operations promfs_super_operations = {
+	.statfs = simple_statfs,
+	.drop_inode = generic_delete_inode,
+};
+
+static int promfs_fill_super(struct super_block *sb, void *data, int silent)
+{
+	sb->s_maxbytes = MAX_LFS_FILESIZE;
+	sb->s_blocksize = PAGE_CACHE_SIZE;
+	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
+	sb->s_magic = PROMFS_MAGIC;
+	sb->s_op = &promfs_super_operations;
+	return promfs_create_root(sb, data);
+}
+
+static struct super_block *promfs_get_sb(struct file_system_type *fstype,
+		int flags, const char *name, void *data)
+{
+	return get_sb_single(fstype, flags, data, promfs_fill_super);
+}
+
+static struct file_system_type promfs_type = {
+	.owner = THIS_MODULE,
+	.name = "promfs",
+	.get_sb = promfs_get_sb,
+	.kill_sb = kill_litter_super,
+};
+
+static int __init promfs_init(void)
+{
+	return register_filesystem(&promfs_type);
+}
+module_init(promfs_init);
+
+static void __exit promfs_exit(void)
+{
+	unregister_filesystem(&promfs_type);
+}
+module_exit(promfs_exit);



More information about the Linuxppc64-dev mailing list