[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