xref: /openbmc/linux/fs/openpromfs/inode.c (revision b181f7029bd71238ac2754ce7052dffd69432085)
109c434b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
23d824a46SDavid S. Miller /* inode.c: /proc/openprom handling routines
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  * Copyright (C) 1996-1999 Jakub Jelinek  (jakub@redhat.com)
51da177e4SLinus Torvalds  * Copyright (C) 1998      Eddie C. Dost  (ecd@skynet.be)
61da177e4SLinus Torvalds  */
71da177e4SLinus Torvalds 
81da177e4SLinus Torvalds #include <linux/module.h>
91da177e4SLinus Torvalds #include <linux/types.h>
101da177e4SLinus Torvalds #include <linux/string.h>
111da177e4SLinus Torvalds #include <linux/fs.h>
127ab2fa76SDavid Howells #include <linux/fs_context.h>
131da177e4SLinus Torvalds #include <linux/init.h>
141da177e4SLinus Torvalds #include <linux/slab.h>
153d824a46SDavid S. Miller #include <linux/seq_file.h>
16e18fa700SJeff Garzik #include <linux/magic.h>
171da177e4SLinus Torvalds 
181da177e4SLinus Torvalds #include <asm/openprom.h>
191da177e4SLinus Torvalds #include <asm/oplib.h>
203d824a46SDavid S. Miller #include <asm/prom.h>
217c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
221da177e4SLinus Torvalds 
233d824a46SDavid S. Miller static DEFINE_MUTEX(op_mutex);
241da177e4SLinus Torvalds 
253d824a46SDavid S. Miller #define OPENPROM_ROOT_INO	0
261da177e4SLinus Torvalds 
273d824a46SDavid S. Miller enum op_inode_type {
283d824a46SDavid S. Miller 	op_inode_node,
293d824a46SDavid S. Miller 	op_inode_prop,
303d824a46SDavid S. Miller };
311da177e4SLinus Torvalds 
323d824a46SDavid S. Miller union op_inode_data {
333d824a46SDavid S. Miller 	struct device_node	*node;
343d824a46SDavid S. Miller 	struct property		*prop;
353d824a46SDavid S. Miller };
361da177e4SLinus Torvalds 
373d824a46SDavid S. Miller struct op_inode_info {
383d824a46SDavid S. Miller 	struct inode		vfs_inode;
393d824a46SDavid S. Miller 	enum op_inode_type	type;
403d824a46SDavid S. Miller 	union op_inode_data	u;
413d824a46SDavid S. Miller };
421da177e4SLinus Torvalds 
43b88a27edSDavid Howells static struct inode *openprom_iget(struct super_block *sb, ino_t ino);
44b88a27edSDavid Howells 
OP_I(struct inode * inode)453d824a46SDavid S. Miller static inline struct op_inode_info *OP_I(struct inode *inode)
46a04ee146SJan Engelhardt {
473d824a46SDavid S. Miller 	return container_of(inode, struct op_inode_info, vfs_inode);
48a04ee146SJan Engelhardt }
49a04ee146SJan Engelhardt 
is_string(unsigned char * p,int len)503d824a46SDavid S. Miller static int is_string(unsigned char *p, int len)
511da177e4SLinus Torvalds {
523d824a46SDavid S. Miller 	int i;
531da177e4SLinus Torvalds 
543d824a46SDavid S. Miller 	for (i = 0; i < len; i++) {
553d824a46SDavid S. Miller 		unsigned char val = p[i];
563d824a46SDavid S. Miller 
573d824a46SDavid S. Miller 		if ((i && !val) ||
583d824a46SDavid S. Miller 		    (val >= ' ' && val <= '~'))
593d824a46SDavid S. Miller 			continue;
603d824a46SDavid S. Miller 
611da177e4SLinus Torvalds 		return 0;
621da177e4SLinus Torvalds 	}
631da177e4SLinus Torvalds 
641da177e4SLinus Torvalds 	return 1;
651da177e4SLinus Torvalds }
661da177e4SLinus Torvalds 
property_show(struct seq_file * f,void * v)673d824a46SDavid S. Miller static int property_show(struct seq_file *f, void *v)
681da177e4SLinus Torvalds {
693d824a46SDavid S. Miller 	struct property *prop = f->private;
703d824a46SDavid S. Miller 	void *pval;
713d824a46SDavid S. Miller 	int len;
721da177e4SLinus Torvalds 
733d824a46SDavid S. Miller 	len = prop->length;
743d824a46SDavid S. Miller 	pval = prop->value;
753d824a46SDavid S. Miller 
763d824a46SDavid S. Miller 	if (is_string(pval, len)) {
773d824a46SDavid S. Miller 		while (len > 0) {
783d824a46SDavid S. Miller 			int n = strlen(pval);
793d824a46SDavid S. Miller 
803d824a46SDavid S. Miller 			seq_printf(f, "%s", (char *) pval);
813d824a46SDavid S. Miller 
823d824a46SDavid S. Miller 			/* Skip over the NULL byte too.  */
833d824a46SDavid S. Miller 			pval += n + 1;
843d824a46SDavid S. Miller 			len -= n + 1;
853d824a46SDavid S. Miller 
863d824a46SDavid S. Miller 			if (len > 0)
873d824a46SDavid S. Miller 				seq_printf(f, " + ");
881da177e4SLinus Torvalds 		}
891da177e4SLinus Torvalds 	} else {
903d824a46SDavid S. Miller 		if (len & 3) {
913d824a46SDavid S. Miller 			while (len) {
923d824a46SDavid S. Miller 				len--;
933d824a46SDavid S. Miller 				if (len)
943d824a46SDavid S. Miller 					seq_printf(f, "%02x.",
953d824a46SDavid S. Miller 						   *(unsigned char *) pval);
963d824a46SDavid S. Miller 				else
973d824a46SDavid S. Miller 					seq_printf(f, "%02x",
983d824a46SDavid S. Miller 						   *(unsigned char *) pval);
993d824a46SDavid S. Miller 				pval++;
1003d824a46SDavid S. Miller 			}
1013d824a46SDavid S. Miller 		} else {
1023d824a46SDavid S. Miller 			while (len >= 4) {
1033d824a46SDavid S. Miller 				len -= 4;
1043d824a46SDavid S. Miller 
1053d824a46SDavid S. Miller 				if (len)
1063d824a46SDavid S. Miller 					seq_printf(f, "%08x.",
1073d824a46SDavid S. Miller 						   *(unsigned int *) pval);
1083d824a46SDavid S. Miller 				else
1093d824a46SDavid S. Miller 					seq_printf(f, "%08x",
1103d824a46SDavid S. Miller 						   *(unsigned int *) pval);
1113d824a46SDavid S. Miller 				pval += 4;
1121da177e4SLinus Torvalds 			}
1131da177e4SLinus Torvalds 		}
1143d824a46SDavid S. Miller 	}
1153d824a46SDavid S. Miller 	seq_printf(f, "\n");
1163d824a46SDavid S. Miller 
1171da177e4SLinus Torvalds 	return 0;
1181da177e4SLinus Torvalds }
1191da177e4SLinus Torvalds 
property_start(struct seq_file * f,loff_t * pos)1203d824a46SDavid S. Miller static void *property_start(struct seq_file *f, loff_t *pos)
1213d824a46SDavid S. Miller {
1223d824a46SDavid S. Miller 	if (*pos == 0)
1233d824a46SDavid S. Miller 		return pos;
1243d824a46SDavid S. Miller 	return NULL;
1253d824a46SDavid S. Miller }
1263d824a46SDavid S. Miller 
property_next(struct seq_file * f,void * v,loff_t * pos)1273d824a46SDavid S. Miller static void *property_next(struct seq_file *f, void *v, loff_t *pos)
1283d824a46SDavid S. Miller {
1293d824a46SDavid S. Miller 	(*pos)++;
1303d824a46SDavid S. Miller 	return NULL;
1313d824a46SDavid S. Miller }
1323d824a46SDavid S. Miller 
property_stop(struct seq_file * f,void * v)1333d824a46SDavid S. Miller static void property_stop(struct seq_file *f, void *v)
1343d824a46SDavid S. Miller {
1353d824a46SDavid S. Miller 	/* Nothing to do */
1363d824a46SDavid S. Miller }
1373d824a46SDavid S. Miller 
138872e2be7SJan Engelhardt static const struct seq_operations property_op = {
1393d824a46SDavid S. Miller 	.start		= property_start,
1403d824a46SDavid S. Miller 	.next		= property_next,
1413d824a46SDavid S. Miller 	.stop		= property_stop,
1423d824a46SDavid S. Miller 	.show		= property_show
1433d824a46SDavid S. Miller };
1443d824a46SDavid S. Miller 
property_open(struct inode * inode,struct file * file)1453d824a46SDavid S. Miller static int property_open(struct inode *inode, struct file *file)
1463d824a46SDavid S. Miller {
1473d824a46SDavid S. Miller 	struct op_inode_info *oi = OP_I(inode);
1483d824a46SDavid S. Miller 	int ret;
1493d824a46SDavid S. Miller 
1503d824a46SDavid S. Miller 	BUG_ON(oi->type != op_inode_prop);
1513d824a46SDavid S. Miller 
1523d824a46SDavid S. Miller 	ret = seq_open(file, &property_op);
1533d824a46SDavid S. Miller 	if (!ret) {
1543d824a46SDavid S. Miller 		struct seq_file *m = file->private_data;
1553d824a46SDavid S. Miller 		m->private = oi->u.prop;
1563d824a46SDavid S. Miller 	}
1573d824a46SDavid S. Miller 	return ret;
1583d824a46SDavid S. Miller }
1593d824a46SDavid S. Miller 
1604b6f5d20SArjan van de Ven static const struct file_operations openpromfs_prop_ops = {
1613d824a46SDavid S. Miller 	.open		= property_open,
1623d824a46SDavid S. Miller 	.read		= seq_read,
1633d824a46SDavid S. Miller 	.llseek		= seq_lseek,
1643d824a46SDavid S. Miller 	.release	= seq_release,
1651da177e4SLinus Torvalds };
1661da177e4SLinus Torvalds 
16768c61471SAl Viro static int openpromfs_readdir(struct file *, struct dir_context *);
1681da177e4SLinus Torvalds 
1694b6f5d20SArjan van de Ven static const struct file_operations openprom_operations = {
1701da177e4SLinus Torvalds 	.read		= generic_read_dir,
171c51da20cSAl Viro 	.iterate_shared	= openpromfs_readdir,
1723222a3e5SChristoph Hellwig 	.llseek		= generic_file_llseek,
1731da177e4SLinus Torvalds };
1741da177e4SLinus Torvalds 
17500cd8dd3SAl Viro static struct dentry *openpromfs_lookup(struct inode *, struct dentry *, unsigned int);
1761da177e4SLinus Torvalds 
17792e1d5beSArjan van de Ven static const struct inode_operations openprom_inode_operations = {
1781da177e4SLinus Torvalds 	.lookup		= openpromfs_lookup,
1791da177e4SLinus Torvalds };
1801da177e4SLinus Torvalds 
openpromfs_lookup(struct inode * dir,struct dentry * dentry,unsigned int flags)18100cd8dd3SAl Viro static struct dentry *openpromfs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
1821da177e4SLinus Torvalds {
1833d824a46SDavid S. Miller 	struct op_inode_info *ent_oi, *oi = OP_I(dir);
1843d824a46SDavid S. Miller 	struct device_node *dp, *child;
1853d824a46SDavid S. Miller 	struct property *prop;
1863d824a46SDavid S. Miller 	enum op_inode_type ent_type;
1873d824a46SDavid S. Miller 	union op_inode_data ent_data;
1881da177e4SLinus Torvalds 	const char *name;
1891da177e4SLinus Torvalds 	struct inode *inode;
1903d824a46SDavid S. Miller 	unsigned int ino;
1913d824a46SDavid S. Miller 	int len;
1921da177e4SLinus Torvalds 
1933d824a46SDavid S. Miller 	BUG_ON(oi->type != op_inode_node);
1943d824a46SDavid S. Miller 
1953d824a46SDavid S. Miller 	dp = oi->u.node;
1963d824a46SDavid S. Miller 
1971da177e4SLinus Torvalds 	name = dentry->d_name.name;
1981da177e4SLinus Torvalds 	len = dentry->d_name.len;
1993d824a46SDavid S. Miller 
2003d824a46SDavid S. Miller 	mutex_lock(&op_mutex);
2013d824a46SDavid S. Miller 
2023d824a46SDavid S. Miller 	child = dp->child;
2033d824a46SDavid S. Miller 	while (child) {
204105e996aSRob Herring 		const char *node_name = kbasename(child->full_name);
205105e996aSRob Herring 		int n = strlen(node_name);
2063d824a46SDavid S. Miller 
2073d824a46SDavid S. Miller 		if (len == n &&
208105e996aSRob Herring 		    !strncmp(node_name, name, len)) {
2093d824a46SDavid S. Miller 			ent_type = op_inode_node;
2103d824a46SDavid S. Miller 			ent_data.node = child;
2113d824a46SDavid S. Miller 			ino = child->unique_id;
2123d824a46SDavid S. Miller 			goto found;
2131da177e4SLinus Torvalds 		}
2143d824a46SDavid S. Miller 		child = child->sibling;
2151da177e4SLinus Torvalds 	}
2163d824a46SDavid S. Miller 
2173d824a46SDavid S. Miller 	prop = dp->properties;
2183d824a46SDavid S. Miller 	while (prop) {
2193d824a46SDavid S. Miller 		int n = strlen(prop->name);
2203d824a46SDavid S. Miller 
2213d824a46SDavid S. Miller 		if (len == n && !strncmp(prop->name, name, len)) {
2223d824a46SDavid S. Miller 			ent_type = op_inode_prop;
2233d824a46SDavid S. Miller 			ent_data.prop = prop;
2243d824a46SDavid S. Miller 			ino = prop->unique_id;
2253d824a46SDavid S. Miller 			goto found;
2261da177e4SLinus Torvalds 		}
2273d824a46SDavid S. Miller 
2283d824a46SDavid S. Miller 		prop = prop->next;
2291da177e4SLinus Torvalds 	}
2303d824a46SDavid S. Miller 
2313d824a46SDavid S. Miller 	mutex_unlock(&op_mutex);
2321da177e4SLinus Torvalds 	return ERR_PTR(-ENOENT);
2333d824a46SDavid S. Miller 
2343d824a46SDavid S. Miller found:
235b88a27edSDavid Howells 	inode = openprom_iget(dir->i_sb, ino);
2363d824a46SDavid S. Miller 	mutex_unlock(&op_mutex);
237b88a27edSDavid Howells 	if (IS_ERR(inode))
238b88a27edSDavid Howells 		return ERR_CAST(inode);
239e34d657fSAl Viro 	if (inode->i_state & I_NEW) {
2401520a152SJeff Layton 		inode->i_mtime = inode->i_atime = inode_set_ctime_current(inode);
2413d824a46SDavid S. Miller 		ent_oi = OP_I(inode);
2423d824a46SDavid S. Miller 		ent_oi->type = ent_type;
2433d824a46SDavid S. Miller 		ent_oi->u = ent_data;
2443d824a46SDavid S. Miller 
2453d824a46SDavid S. Miller 		switch (ent_type) {
2463d824a46SDavid S. Miller 		case op_inode_node:
2471da177e4SLinus Torvalds 			inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
2481da177e4SLinus Torvalds 			inode->i_op = &openprom_inode_operations;
2491da177e4SLinus Torvalds 			inode->i_fop = &openprom_operations;
250bfe86848SMiklos Szeredi 			set_nlink(inode, 2);
2511da177e4SLinus Torvalds 			break;
2523d824a46SDavid S. Miller 		case op_inode_prop:
253f3180e18SRob Herring 			if (of_node_name_eq(dp, "options") && (len == 17) &&
2543d824a46SDavid S. Miller 			    !strncmp (name, "security-password", 17))
2551da177e4SLinus Torvalds 				inode->i_mode = S_IFREG | S_IRUSR | S_IWUSR;
2563d824a46SDavid S. Miller 			else
2571da177e4SLinus Torvalds 				inode->i_mode = S_IFREG | S_IRUGO;
2581da177e4SLinus Torvalds 			inode->i_fop = &openpromfs_prop_ops;
259bfe86848SMiklos Szeredi 			set_nlink(inode, 1);
2603d824a46SDavid S. Miller 			inode->i_size = ent_oi->u.prop->length;
2611da177e4SLinus Torvalds 			break;
2621da177e4SLinus Torvalds 		}
263e34d657fSAl Viro 		unlock_new_inode(inode);
264e34d657fSAl Viro 	}
2651da177e4SLinus Torvalds 
2660ed883fdSAl Viro 	return d_splice_alias(inode, dentry);
2671da177e4SLinus Torvalds }
2681da177e4SLinus Torvalds 
openpromfs_readdir(struct file * file,struct dir_context * ctx)26968c61471SAl Viro static int openpromfs_readdir(struct file *file, struct dir_context *ctx)
2701da177e4SLinus Torvalds {
27168c61471SAl Viro 	struct inode *inode = file_inode(file);
2723d824a46SDavid S. Miller 	struct op_inode_info *oi = OP_I(inode);
2733d824a46SDavid S. Miller 	struct device_node *dp = oi->u.node;
2743d824a46SDavid S. Miller 	struct device_node *child;
2753d824a46SDavid S. Miller 	struct property *prop;
2763d824a46SDavid S. Miller 	int i;
2771da177e4SLinus Torvalds 
2783d824a46SDavid S. Miller 	mutex_lock(&op_mutex);
2791da177e4SLinus Torvalds 
28068c61471SAl Viro 	if (ctx->pos == 0) {
28168c61471SAl Viro 		if (!dir_emit(ctx, ".", 1, inode->i_ino, DT_DIR))
2823d824a46SDavid S. Miller 			goto out;
28368c61471SAl Viro 		ctx->pos = 1;
28468c61471SAl Viro 	}
28568c61471SAl Viro 	if (ctx->pos == 1) {
28668c61471SAl Viro 		if (!dir_emit(ctx, "..", 2,
2873d824a46SDavid S. Miller 			    (dp->parent == NULL ?
2883d824a46SDavid S. Miller 			     OPENPROM_ROOT_INO :
28968c61471SAl Viro 			     dp->parent->unique_id), DT_DIR))
2901da177e4SLinus Torvalds 			goto out;
29168c61471SAl Viro 		ctx->pos = 2;
29268c61471SAl Viro 	}
29368c61471SAl Viro 	i = ctx->pos - 2;
2943d824a46SDavid S. Miller 
2953d824a46SDavid S. Miller 	/* First, the children nodes as directories.  */
2963d824a46SDavid S. Miller 	child = dp->child;
2973d824a46SDavid S. Miller 	while (i && child) {
2983d824a46SDavid S. Miller 		child = child->sibling;
2991da177e4SLinus Torvalds 		i--;
3001da177e4SLinus Torvalds 	}
3013d824a46SDavid S. Miller 	while (child) {
30268c61471SAl Viro 		if (!dir_emit(ctx,
303105e996aSRob Herring 			    kbasename(child->full_name),
304105e996aSRob Herring 			    strlen(kbasename(child->full_name)),
30568c61471SAl Viro 			    child->unique_id, DT_DIR))
3061da177e4SLinus Torvalds 			goto out;
3073d824a46SDavid S. Miller 
30868c61471SAl Viro 		ctx->pos++;
3093d824a46SDavid S. Miller 		child = child->sibling;
3101da177e4SLinus Torvalds 	}
3113d824a46SDavid S. Miller 
3123d824a46SDavid S. Miller 	/* Next, the properties as files.  */
3133d824a46SDavid S. Miller 	prop = dp->properties;
3143d824a46SDavid S. Miller 	while (i && prop) {
3153d824a46SDavid S. Miller 		prop = prop->next;
3161da177e4SLinus Torvalds 		i--;
3171da177e4SLinus Torvalds 	}
3183d824a46SDavid S. Miller 	while (prop) {
31968c61471SAl Viro 		if (!dir_emit(ctx, prop->name, strlen(prop->name),
32068c61471SAl Viro 			    prop->unique_id, DT_REG))
3211da177e4SLinus Torvalds 			goto out;
3223d824a46SDavid S. Miller 
32368c61471SAl Viro 		ctx->pos++;
3243d824a46SDavid S. Miller 		prop = prop->next;
3251da177e4SLinus Torvalds 	}
32668c61471SAl Viro 
3271da177e4SLinus Torvalds out:
3283d824a46SDavid S. Miller 	mutex_unlock(&op_mutex);
3291da177e4SLinus Torvalds 	return 0;
3301da177e4SLinus Torvalds }
3311da177e4SLinus Torvalds 
332e18b890bSChristoph Lameter static struct kmem_cache *op_inode_cachep;
3333d824a46SDavid S. Miller 
openprom_alloc_inode(struct super_block * sb)3343d824a46SDavid S. Miller static struct inode *openprom_alloc_inode(struct super_block *sb)
3351da177e4SLinus Torvalds {
3363d824a46SDavid S. Miller 	struct op_inode_info *oi;
3371da177e4SLinus Torvalds 
338fd60b288SMuchun Song 	oi = alloc_inode_sb(sb, op_inode_cachep, GFP_KERNEL);
3393d824a46SDavid S. Miller 	if (!oi)
3403d824a46SDavid S. Miller 		return NULL;
3413d824a46SDavid S. Miller 
3423d824a46SDavid S. Miller 	return &oi->vfs_inode;
3431da177e4SLinus Torvalds }
3441da177e4SLinus Torvalds 
openprom_free_inode(struct inode * inode)345363db959SAl Viro static void openprom_free_inode(struct inode *inode)
346fa0d7e3dSNick Piggin {
347fa0d7e3dSNick Piggin 	kmem_cache_free(op_inode_cachep, OP_I(inode));
348fa0d7e3dSNick Piggin }
349fa0d7e3dSNick Piggin 
openprom_iget(struct super_block * sb,ino_t ino)350b88a27edSDavid Howells static struct inode *openprom_iget(struct super_block *sb, ino_t ino)
3511da177e4SLinus Torvalds {
352e34d657fSAl Viro 	struct inode *inode = iget_locked(sb, ino);
353b88a27edSDavid Howells 	if (!inode)
354e34d657fSAl Viro 		inode = ERR_PTR(-ENOMEM);
355b88a27edSDavid Howells 	return inode;
3561da177e4SLinus Torvalds }
3571da177e4SLinus Torvalds 
openpromfs_reconfigure(struct fs_context * fc)358*d1429573SEric Sandeen static int openpromfs_reconfigure(struct fs_context *fc)
3591da177e4SLinus Torvalds {
360*d1429573SEric Sandeen 	sync_filesystem(fc->root->d_sb);
361*d1429573SEric Sandeen 	fc->sb_flags |= SB_NOATIME;
3621da177e4SLinus Torvalds 	return 0;
3631da177e4SLinus Torvalds }
3641da177e4SLinus Torvalds 
365ee9b6d61SJosef 'Jeff' Sipek static const struct super_operations openprom_sops = {
3663d824a46SDavid S. Miller 	.alloc_inode	= openprom_alloc_inode,
367363db959SAl Viro 	.free_inode	= openprom_free_inode,
3681da177e4SLinus Torvalds 	.statfs		= simple_statfs,
3691da177e4SLinus Torvalds };
3701da177e4SLinus Torvalds 
openprom_fill_super(struct super_block * s,struct fs_context * fc)3717ab2fa76SDavid Howells static int openprom_fill_super(struct super_block *s, struct fs_context *fc)
3721da177e4SLinus Torvalds {
3731da177e4SLinus Torvalds 	struct inode *root_inode;
3743d824a46SDavid S. Miller 	struct op_inode_info *oi;
375b88a27edSDavid Howells 	int ret;
3761da177e4SLinus Torvalds 
3771751e8a6SLinus Torvalds 	s->s_flags |= SB_NOATIME;
3781da177e4SLinus Torvalds 	s->s_blocksize = 1024;
3791da177e4SLinus Torvalds 	s->s_blocksize_bits = 10;
3801da177e4SLinus Torvalds 	s->s_magic = OPENPROM_SUPER_MAGIC;
3811da177e4SLinus Torvalds 	s->s_op = &openprom_sops;
3821da177e4SLinus Torvalds 	s->s_time_gran = 1;
383b88a27edSDavid Howells 	root_inode = openprom_iget(s, OPENPROM_ROOT_INO);
384b88a27edSDavid Howells 	if (IS_ERR(root_inode)) {
385b88a27edSDavid Howells 		ret = PTR_ERR(root_inode);
3861da177e4SLinus Torvalds 		goto out_no_root;
387b88a27edSDavid Howells 	}
3883d824a46SDavid S. Miller 
3891520a152SJeff Layton 	root_inode->i_mtime = root_inode->i_atime = inode_set_ctime_current(root_inode);
390e34d657fSAl Viro 	root_inode->i_op = &openprom_inode_operations;
391e34d657fSAl Viro 	root_inode->i_fop = &openprom_operations;
392e34d657fSAl Viro 	root_inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
3933d824a46SDavid S. Miller 	oi = OP_I(root_inode);
3943d824a46SDavid S. Miller 	oi->type = op_inode_node;
3953d824a46SDavid S. Miller 	oi->u.node = of_find_node_by_path("/");
396e34d657fSAl Viro 	unlock_new_inode(root_inode);
3973d824a46SDavid S. Miller 
39848fde701SAl Viro 	s->s_root = d_make_root(root_inode);
3991da177e4SLinus Torvalds 	if (!s->s_root)
400b88a27edSDavid Howells 		goto out_no_root_dentry;
4011da177e4SLinus Torvalds 	return 0;
4021da177e4SLinus Torvalds 
403b88a27edSDavid Howells out_no_root_dentry:
404b88a27edSDavid Howells 	ret = -ENOMEM;
4051da177e4SLinus Torvalds out_no_root:
4061da177e4SLinus Torvalds 	printk("openprom_fill_super: get root inode failed\n");
407b88a27edSDavid Howells 	return ret;
4081da177e4SLinus Torvalds }
4091da177e4SLinus Torvalds 
openpromfs_get_tree(struct fs_context * fc)4107ab2fa76SDavid Howells static int openpromfs_get_tree(struct fs_context *fc)
4111da177e4SLinus Torvalds {
4127ab2fa76SDavid Howells 	return get_tree_single(fc, openprom_fill_super);
4137ab2fa76SDavid Howells }
4147ab2fa76SDavid Howells 
4157ab2fa76SDavid Howells static const struct fs_context_operations openpromfs_context_ops = {
4167ab2fa76SDavid Howells 	.get_tree	= openpromfs_get_tree,
417*d1429573SEric Sandeen 	.reconfigure	= openpromfs_reconfigure,
4187ab2fa76SDavid Howells };
4197ab2fa76SDavid Howells 
openpromfs_init_fs_context(struct fs_context * fc)4207ab2fa76SDavid Howells static int openpromfs_init_fs_context(struct fs_context *fc)
4217ab2fa76SDavid Howells {
4227ab2fa76SDavid Howells 	fc->ops = &openpromfs_context_ops;
4237ab2fa76SDavid Howells 	return 0;
4241da177e4SLinus Torvalds }
4251da177e4SLinus Torvalds 
4261da177e4SLinus Torvalds static struct file_system_type openprom_fs_type = {
4271da177e4SLinus Torvalds 	.owner		= THIS_MODULE,
4281da177e4SLinus Torvalds 	.name		= "openpromfs",
4297ab2fa76SDavid Howells 	.init_fs_context = openpromfs_init_fs_context,
4301da177e4SLinus Torvalds 	.kill_sb	= kill_anon_super,
4311da177e4SLinus Torvalds };
4327f78e035SEric W. Biederman MODULE_ALIAS_FS("openpromfs");
4331da177e4SLinus Torvalds 
op_inode_init_once(void * data)43451cc5068SAlexey Dobriyan static void op_inode_init_once(void *data)
4353d824a46SDavid S. Miller {
4363d824a46SDavid S. Miller 	struct op_inode_info *oi = (struct op_inode_info *) data;
4373d824a46SDavid S. Miller 
4383d824a46SDavid S. Miller 	inode_init_once(&oi->vfs_inode);
4393d824a46SDavid S. Miller }
4403d824a46SDavid S. Miller 
init_openprom_fs(void)4411da177e4SLinus Torvalds static int __init init_openprom_fs(void)
4421da177e4SLinus Torvalds {
4433d824a46SDavid S. Miller 	int err;
4443d824a46SDavid S. Miller 
4453d824a46SDavid S. Miller 	op_inode_cachep = kmem_cache_create("op_inode_cache",
4463d824a46SDavid S. Miller 					    sizeof(struct op_inode_info),
4473d824a46SDavid S. Miller 					    0,
4483d824a46SDavid S. Miller 					    (SLAB_RECLAIM_ACCOUNT |
4495d097056SVladimir Davydov 					     SLAB_MEM_SPREAD | SLAB_ACCOUNT),
45020c2df83SPaul Mundt 					    op_inode_init_once);
4513d824a46SDavid S. Miller 	if (!op_inode_cachep)
4523d824a46SDavid S. Miller 		return -ENOMEM;
4533d824a46SDavid S. Miller 
4543d824a46SDavid S. Miller 	err = register_filesystem(&openprom_fs_type);
4553d824a46SDavid S. Miller 	if (err)
4563d824a46SDavid S. Miller 		kmem_cache_destroy(op_inode_cachep);
4573d824a46SDavid S. Miller 
4583d824a46SDavid S. Miller 	return err;
4591da177e4SLinus Torvalds }
4601da177e4SLinus Torvalds 
exit_openprom_fs(void)4611da177e4SLinus Torvalds static void __exit exit_openprom_fs(void)
4621da177e4SLinus Torvalds {
4631da177e4SLinus Torvalds 	unregister_filesystem(&openprom_fs_type);
4648c0a8537SKirill A. Shutemov 	/*
4658c0a8537SKirill A. Shutemov 	 * Make sure all delayed rcu free inodes are flushed before we
4668c0a8537SKirill A. Shutemov 	 * destroy cache.
4678c0a8537SKirill A. Shutemov 	 */
4688c0a8537SKirill A. Shutemov 	rcu_barrier();
4693d824a46SDavid S. Miller 	kmem_cache_destroy(op_inode_cachep);
4701da177e4SLinus Torvalds }
4711da177e4SLinus Torvalds 
4721da177e4SLinus Torvalds module_init(init_openprom_fs)
4731da177e4SLinus Torvalds module_exit(exit_openprom_fs)
4741da177e4SLinus Torvalds MODULE_LICENSE("GPL");
475