xref: /kernel/linux/linux-5.10/fs/openpromfs/inode.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/* inode.c: /proc/openprom handling routines
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright (C) 1996-1999 Jakub Jelinek  (jakub@redhat.com)
58c2ecf20Sopenharmony_ci * Copyright (C) 1998      Eddie C. Dost  (ecd@skynet.be)
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/module.h>
98c2ecf20Sopenharmony_ci#include <linux/types.h>
108c2ecf20Sopenharmony_ci#include <linux/string.h>
118c2ecf20Sopenharmony_ci#include <linux/fs.h>
128c2ecf20Sopenharmony_ci#include <linux/fs_context.h>
138c2ecf20Sopenharmony_ci#include <linux/init.h>
148c2ecf20Sopenharmony_ci#include <linux/slab.h>
158c2ecf20Sopenharmony_ci#include <linux/seq_file.h>
168c2ecf20Sopenharmony_ci#include <linux/magic.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include <asm/openprom.h>
198c2ecf20Sopenharmony_ci#include <asm/oplib.h>
208c2ecf20Sopenharmony_ci#include <asm/prom.h>
218c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(op_mutex);
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#define OPENPROM_ROOT_INO	0
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_cienum op_inode_type {
288c2ecf20Sopenharmony_ci	op_inode_node,
298c2ecf20Sopenharmony_ci	op_inode_prop,
308c2ecf20Sopenharmony_ci};
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ciunion op_inode_data {
338c2ecf20Sopenharmony_ci	struct device_node	*node;
348c2ecf20Sopenharmony_ci	struct property		*prop;
358c2ecf20Sopenharmony_ci};
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_cistruct op_inode_info {
388c2ecf20Sopenharmony_ci	struct inode		vfs_inode;
398c2ecf20Sopenharmony_ci	enum op_inode_type	type;
408c2ecf20Sopenharmony_ci	union op_inode_data	u;
418c2ecf20Sopenharmony_ci};
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_cistatic struct inode *openprom_iget(struct super_block *sb, ino_t ino);
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_cistatic inline struct op_inode_info *OP_I(struct inode *inode)
468c2ecf20Sopenharmony_ci{
478c2ecf20Sopenharmony_ci	return container_of(inode, struct op_inode_info, vfs_inode);
488c2ecf20Sopenharmony_ci}
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_cistatic int is_string(unsigned char *p, int len)
518c2ecf20Sopenharmony_ci{
528c2ecf20Sopenharmony_ci	int i;
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	for (i = 0; i < len; i++) {
558c2ecf20Sopenharmony_ci		unsigned char val = p[i];
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci		if ((i && !val) ||
588c2ecf20Sopenharmony_ci		    (val >= ' ' && val <= '~'))
598c2ecf20Sopenharmony_ci			continue;
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci		return 0;
628c2ecf20Sopenharmony_ci	}
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	return 1;
658c2ecf20Sopenharmony_ci}
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_cistatic int property_show(struct seq_file *f, void *v)
688c2ecf20Sopenharmony_ci{
698c2ecf20Sopenharmony_ci	struct property *prop = f->private;
708c2ecf20Sopenharmony_ci	void *pval;
718c2ecf20Sopenharmony_ci	int len;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	len = prop->length;
748c2ecf20Sopenharmony_ci	pval = prop->value;
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	if (is_string(pval, len)) {
778c2ecf20Sopenharmony_ci		while (len > 0) {
788c2ecf20Sopenharmony_ci			int n = strlen(pval);
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci			seq_printf(f, "%s", (char *) pval);
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci			/* Skip over the NULL byte too.  */
838c2ecf20Sopenharmony_ci			pval += n + 1;
848c2ecf20Sopenharmony_ci			len -= n + 1;
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci			if (len > 0)
878c2ecf20Sopenharmony_ci				seq_printf(f, " + ");
888c2ecf20Sopenharmony_ci		}
898c2ecf20Sopenharmony_ci	} else {
908c2ecf20Sopenharmony_ci		if (len & 3) {
918c2ecf20Sopenharmony_ci			while (len) {
928c2ecf20Sopenharmony_ci				len--;
938c2ecf20Sopenharmony_ci				if (len)
948c2ecf20Sopenharmony_ci					seq_printf(f, "%02x.",
958c2ecf20Sopenharmony_ci						   *(unsigned char *) pval);
968c2ecf20Sopenharmony_ci				else
978c2ecf20Sopenharmony_ci					seq_printf(f, "%02x",
988c2ecf20Sopenharmony_ci						   *(unsigned char *) pval);
998c2ecf20Sopenharmony_ci				pval++;
1008c2ecf20Sopenharmony_ci			}
1018c2ecf20Sopenharmony_ci		} else {
1028c2ecf20Sopenharmony_ci			while (len >= 4) {
1038c2ecf20Sopenharmony_ci				len -= 4;
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci				if (len)
1068c2ecf20Sopenharmony_ci					seq_printf(f, "%08x.",
1078c2ecf20Sopenharmony_ci						   *(unsigned int *) pval);
1088c2ecf20Sopenharmony_ci				else
1098c2ecf20Sopenharmony_ci					seq_printf(f, "%08x",
1108c2ecf20Sopenharmony_ci						   *(unsigned int *) pval);
1118c2ecf20Sopenharmony_ci				pval += 4;
1128c2ecf20Sopenharmony_ci			}
1138c2ecf20Sopenharmony_ci		}
1148c2ecf20Sopenharmony_ci	}
1158c2ecf20Sopenharmony_ci	seq_printf(f, "\n");
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	return 0;
1188c2ecf20Sopenharmony_ci}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_cistatic void *property_start(struct seq_file *f, loff_t *pos)
1218c2ecf20Sopenharmony_ci{
1228c2ecf20Sopenharmony_ci	if (*pos == 0)
1238c2ecf20Sopenharmony_ci		return pos;
1248c2ecf20Sopenharmony_ci	return NULL;
1258c2ecf20Sopenharmony_ci}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_cistatic void *property_next(struct seq_file *f, void *v, loff_t *pos)
1288c2ecf20Sopenharmony_ci{
1298c2ecf20Sopenharmony_ci	(*pos)++;
1308c2ecf20Sopenharmony_ci	return NULL;
1318c2ecf20Sopenharmony_ci}
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_cistatic void property_stop(struct seq_file *f, void *v)
1348c2ecf20Sopenharmony_ci{
1358c2ecf20Sopenharmony_ci	/* Nothing to do */
1368c2ecf20Sopenharmony_ci}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_cistatic const struct seq_operations property_op = {
1398c2ecf20Sopenharmony_ci	.start		= property_start,
1408c2ecf20Sopenharmony_ci	.next		= property_next,
1418c2ecf20Sopenharmony_ci	.stop		= property_stop,
1428c2ecf20Sopenharmony_ci	.show		= property_show
1438c2ecf20Sopenharmony_ci};
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_cistatic int property_open(struct inode *inode, struct file *file)
1468c2ecf20Sopenharmony_ci{
1478c2ecf20Sopenharmony_ci	struct op_inode_info *oi = OP_I(inode);
1488c2ecf20Sopenharmony_ci	int ret;
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	BUG_ON(oi->type != op_inode_prop);
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	ret = seq_open(file, &property_op);
1538c2ecf20Sopenharmony_ci	if (!ret) {
1548c2ecf20Sopenharmony_ci		struct seq_file *m = file->private_data;
1558c2ecf20Sopenharmony_ci		m->private = oi->u.prop;
1568c2ecf20Sopenharmony_ci	}
1578c2ecf20Sopenharmony_ci	return ret;
1588c2ecf20Sopenharmony_ci}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_cistatic const struct file_operations openpromfs_prop_ops = {
1618c2ecf20Sopenharmony_ci	.open		= property_open,
1628c2ecf20Sopenharmony_ci	.read		= seq_read,
1638c2ecf20Sopenharmony_ci	.llseek		= seq_lseek,
1648c2ecf20Sopenharmony_ci	.release	= seq_release,
1658c2ecf20Sopenharmony_ci};
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_cistatic int openpromfs_readdir(struct file *, struct dir_context *);
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_cistatic const struct file_operations openprom_operations = {
1708c2ecf20Sopenharmony_ci	.read		= generic_read_dir,
1718c2ecf20Sopenharmony_ci	.iterate_shared	= openpromfs_readdir,
1728c2ecf20Sopenharmony_ci	.llseek		= generic_file_llseek,
1738c2ecf20Sopenharmony_ci};
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_cistatic struct dentry *openpromfs_lookup(struct inode *, struct dentry *, unsigned int);
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_cistatic const struct inode_operations openprom_inode_operations = {
1788c2ecf20Sopenharmony_ci	.lookup		= openpromfs_lookup,
1798c2ecf20Sopenharmony_ci};
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_cistatic struct dentry *openpromfs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
1828c2ecf20Sopenharmony_ci{
1838c2ecf20Sopenharmony_ci	struct op_inode_info *ent_oi, *oi = OP_I(dir);
1848c2ecf20Sopenharmony_ci	struct device_node *dp, *child;
1858c2ecf20Sopenharmony_ci	struct property *prop;
1868c2ecf20Sopenharmony_ci	enum op_inode_type ent_type;
1878c2ecf20Sopenharmony_ci	union op_inode_data ent_data;
1888c2ecf20Sopenharmony_ci	const char *name;
1898c2ecf20Sopenharmony_ci	struct inode *inode;
1908c2ecf20Sopenharmony_ci	unsigned int ino;
1918c2ecf20Sopenharmony_ci	int len;
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	BUG_ON(oi->type != op_inode_node);
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	dp = oi->u.node;
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	name = dentry->d_name.name;
1988c2ecf20Sopenharmony_ci	len = dentry->d_name.len;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	mutex_lock(&op_mutex);
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	child = dp->child;
2038c2ecf20Sopenharmony_ci	while (child) {
2048c2ecf20Sopenharmony_ci		const char *node_name = kbasename(child->full_name);
2058c2ecf20Sopenharmony_ci		int n = strlen(node_name);
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci		if (len == n &&
2088c2ecf20Sopenharmony_ci		    !strncmp(node_name, name, len)) {
2098c2ecf20Sopenharmony_ci			ent_type = op_inode_node;
2108c2ecf20Sopenharmony_ci			ent_data.node = child;
2118c2ecf20Sopenharmony_ci			ino = child->unique_id;
2128c2ecf20Sopenharmony_ci			goto found;
2138c2ecf20Sopenharmony_ci		}
2148c2ecf20Sopenharmony_ci		child = child->sibling;
2158c2ecf20Sopenharmony_ci	}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	prop = dp->properties;
2188c2ecf20Sopenharmony_ci	while (prop) {
2198c2ecf20Sopenharmony_ci		int n = strlen(prop->name);
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci		if (len == n && !strncmp(prop->name, name, len)) {
2228c2ecf20Sopenharmony_ci			ent_type = op_inode_prop;
2238c2ecf20Sopenharmony_ci			ent_data.prop = prop;
2248c2ecf20Sopenharmony_ci			ino = prop->unique_id;
2258c2ecf20Sopenharmony_ci			goto found;
2268c2ecf20Sopenharmony_ci		}
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci		prop = prop->next;
2298c2ecf20Sopenharmony_ci	}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	mutex_unlock(&op_mutex);
2328c2ecf20Sopenharmony_ci	return ERR_PTR(-ENOENT);
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_cifound:
2358c2ecf20Sopenharmony_ci	inode = openprom_iget(dir->i_sb, ino);
2368c2ecf20Sopenharmony_ci	mutex_unlock(&op_mutex);
2378c2ecf20Sopenharmony_ci	if (IS_ERR(inode))
2388c2ecf20Sopenharmony_ci		return ERR_CAST(inode);
2398c2ecf20Sopenharmony_ci	ent_oi = OP_I(inode);
2408c2ecf20Sopenharmony_ci	ent_oi->type = ent_type;
2418c2ecf20Sopenharmony_ci	ent_oi->u = ent_data;
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	switch (ent_type) {
2448c2ecf20Sopenharmony_ci	case op_inode_node:
2458c2ecf20Sopenharmony_ci		inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
2468c2ecf20Sopenharmony_ci		inode->i_op = &openprom_inode_operations;
2478c2ecf20Sopenharmony_ci		inode->i_fop = &openprom_operations;
2488c2ecf20Sopenharmony_ci		set_nlink(inode, 2);
2498c2ecf20Sopenharmony_ci		break;
2508c2ecf20Sopenharmony_ci	case op_inode_prop:
2518c2ecf20Sopenharmony_ci		if (of_node_name_eq(dp, "options") && (len == 17) &&
2528c2ecf20Sopenharmony_ci		    !strncmp (name, "security-password", 17))
2538c2ecf20Sopenharmony_ci			inode->i_mode = S_IFREG | S_IRUSR | S_IWUSR;
2548c2ecf20Sopenharmony_ci		else
2558c2ecf20Sopenharmony_ci			inode->i_mode = S_IFREG | S_IRUGO;
2568c2ecf20Sopenharmony_ci		inode->i_fop = &openpromfs_prop_ops;
2578c2ecf20Sopenharmony_ci		set_nlink(inode, 1);
2588c2ecf20Sopenharmony_ci		inode->i_size = ent_oi->u.prop->length;
2598c2ecf20Sopenharmony_ci		break;
2608c2ecf20Sopenharmony_ci	}
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	return d_splice_alias(inode, dentry);
2638c2ecf20Sopenharmony_ci}
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_cistatic int openpromfs_readdir(struct file *file, struct dir_context *ctx)
2668c2ecf20Sopenharmony_ci{
2678c2ecf20Sopenharmony_ci	struct inode *inode = file_inode(file);
2688c2ecf20Sopenharmony_ci	struct op_inode_info *oi = OP_I(inode);
2698c2ecf20Sopenharmony_ci	struct device_node *dp = oi->u.node;
2708c2ecf20Sopenharmony_ci	struct device_node *child;
2718c2ecf20Sopenharmony_ci	struct property *prop;
2728c2ecf20Sopenharmony_ci	int i;
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	mutex_lock(&op_mutex);
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	if (ctx->pos == 0) {
2778c2ecf20Sopenharmony_ci		if (!dir_emit(ctx, ".", 1, inode->i_ino, DT_DIR))
2788c2ecf20Sopenharmony_ci			goto out;
2798c2ecf20Sopenharmony_ci		ctx->pos = 1;
2808c2ecf20Sopenharmony_ci	}
2818c2ecf20Sopenharmony_ci	if (ctx->pos == 1) {
2828c2ecf20Sopenharmony_ci		if (!dir_emit(ctx, "..", 2,
2838c2ecf20Sopenharmony_ci			    (dp->parent == NULL ?
2848c2ecf20Sopenharmony_ci			     OPENPROM_ROOT_INO :
2858c2ecf20Sopenharmony_ci			     dp->parent->unique_id), DT_DIR))
2868c2ecf20Sopenharmony_ci			goto out;
2878c2ecf20Sopenharmony_ci		ctx->pos = 2;
2888c2ecf20Sopenharmony_ci	}
2898c2ecf20Sopenharmony_ci	i = ctx->pos - 2;
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	/* First, the children nodes as directories.  */
2928c2ecf20Sopenharmony_ci	child = dp->child;
2938c2ecf20Sopenharmony_ci	while (i && child) {
2948c2ecf20Sopenharmony_ci		child = child->sibling;
2958c2ecf20Sopenharmony_ci		i--;
2968c2ecf20Sopenharmony_ci	}
2978c2ecf20Sopenharmony_ci	while (child) {
2988c2ecf20Sopenharmony_ci		if (!dir_emit(ctx,
2998c2ecf20Sopenharmony_ci			    kbasename(child->full_name),
3008c2ecf20Sopenharmony_ci			    strlen(kbasename(child->full_name)),
3018c2ecf20Sopenharmony_ci			    child->unique_id, DT_DIR))
3028c2ecf20Sopenharmony_ci			goto out;
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci		ctx->pos++;
3058c2ecf20Sopenharmony_ci		child = child->sibling;
3068c2ecf20Sopenharmony_ci	}
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	/* Next, the properties as files.  */
3098c2ecf20Sopenharmony_ci	prop = dp->properties;
3108c2ecf20Sopenharmony_ci	while (i && prop) {
3118c2ecf20Sopenharmony_ci		prop = prop->next;
3128c2ecf20Sopenharmony_ci		i--;
3138c2ecf20Sopenharmony_ci	}
3148c2ecf20Sopenharmony_ci	while (prop) {
3158c2ecf20Sopenharmony_ci		if (!dir_emit(ctx, prop->name, strlen(prop->name),
3168c2ecf20Sopenharmony_ci			    prop->unique_id, DT_REG))
3178c2ecf20Sopenharmony_ci			goto out;
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci		ctx->pos++;
3208c2ecf20Sopenharmony_ci		prop = prop->next;
3218c2ecf20Sopenharmony_ci	}
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ciout:
3248c2ecf20Sopenharmony_ci	mutex_unlock(&op_mutex);
3258c2ecf20Sopenharmony_ci	return 0;
3268c2ecf20Sopenharmony_ci}
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_cistatic struct kmem_cache *op_inode_cachep;
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_cistatic struct inode *openprom_alloc_inode(struct super_block *sb)
3318c2ecf20Sopenharmony_ci{
3328c2ecf20Sopenharmony_ci	struct op_inode_info *oi;
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	oi = kmem_cache_alloc(op_inode_cachep, GFP_KERNEL);
3358c2ecf20Sopenharmony_ci	if (!oi)
3368c2ecf20Sopenharmony_ci		return NULL;
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	return &oi->vfs_inode;
3398c2ecf20Sopenharmony_ci}
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_cistatic void openprom_free_inode(struct inode *inode)
3428c2ecf20Sopenharmony_ci{
3438c2ecf20Sopenharmony_ci	kmem_cache_free(op_inode_cachep, OP_I(inode));
3448c2ecf20Sopenharmony_ci}
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_cistatic struct inode *openprom_iget(struct super_block *sb, ino_t ino)
3478c2ecf20Sopenharmony_ci{
3488c2ecf20Sopenharmony_ci	struct inode *inode;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	inode = iget_locked(sb, ino);
3518c2ecf20Sopenharmony_ci	if (!inode)
3528c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
3538c2ecf20Sopenharmony_ci	if (inode->i_state & I_NEW) {
3548c2ecf20Sopenharmony_ci		inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
3558c2ecf20Sopenharmony_ci		if (inode->i_ino == OPENPROM_ROOT_INO) {
3568c2ecf20Sopenharmony_ci			inode->i_op = &openprom_inode_operations;
3578c2ecf20Sopenharmony_ci			inode->i_fop = &openprom_operations;
3588c2ecf20Sopenharmony_ci			inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
3598c2ecf20Sopenharmony_ci		}
3608c2ecf20Sopenharmony_ci		unlock_new_inode(inode);
3618c2ecf20Sopenharmony_ci	}
3628c2ecf20Sopenharmony_ci	return inode;
3638c2ecf20Sopenharmony_ci}
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_cistatic int openprom_remount(struct super_block *sb, int *flags, char *data)
3668c2ecf20Sopenharmony_ci{
3678c2ecf20Sopenharmony_ci	sync_filesystem(sb);
3688c2ecf20Sopenharmony_ci	*flags |= SB_NOATIME;
3698c2ecf20Sopenharmony_ci	return 0;
3708c2ecf20Sopenharmony_ci}
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_cistatic const struct super_operations openprom_sops = {
3738c2ecf20Sopenharmony_ci	.alloc_inode	= openprom_alloc_inode,
3748c2ecf20Sopenharmony_ci	.free_inode	= openprom_free_inode,
3758c2ecf20Sopenharmony_ci	.statfs		= simple_statfs,
3768c2ecf20Sopenharmony_ci	.remount_fs	= openprom_remount,
3778c2ecf20Sopenharmony_ci};
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_cistatic int openprom_fill_super(struct super_block *s, struct fs_context *fc)
3808c2ecf20Sopenharmony_ci{
3818c2ecf20Sopenharmony_ci	struct inode *root_inode;
3828c2ecf20Sopenharmony_ci	struct op_inode_info *oi;
3838c2ecf20Sopenharmony_ci	int ret;
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	s->s_flags |= SB_NOATIME;
3868c2ecf20Sopenharmony_ci	s->s_blocksize = 1024;
3878c2ecf20Sopenharmony_ci	s->s_blocksize_bits = 10;
3888c2ecf20Sopenharmony_ci	s->s_magic = OPENPROM_SUPER_MAGIC;
3898c2ecf20Sopenharmony_ci	s->s_op = &openprom_sops;
3908c2ecf20Sopenharmony_ci	s->s_time_gran = 1;
3918c2ecf20Sopenharmony_ci	root_inode = openprom_iget(s, OPENPROM_ROOT_INO);
3928c2ecf20Sopenharmony_ci	if (IS_ERR(root_inode)) {
3938c2ecf20Sopenharmony_ci		ret = PTR_ERR(root_inode);
3948c2ecf20Sopenharmony_ci		goto out_no_root;
3958c2ecf20Sopenharmony_ci	}
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	oi = OP_I(root_inode);
3988c2ecf20Sopenharmony_ci	oi->type = op_inode_node;
3998c2ecf20Sopenharmony_ci	oi->u.node = of_find_node_by_path("/");
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	s->s_root = d_make_root(root_inode);
4028c2ecf20Sopenharmony_ci	if (!s->s_root)
4038c2ecf20Sopenharmony_ci		goto out_no_root_dentry;
4048c2ecf20Sopenharmony_ci	return 0;
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ciout_no_root_dentry:
4078c2ecf20Sopenharmony_ci	ret = -ENOMEM;
4088c2ecf20Sopenharmony_ciout_no_root:
4098c2ecf20Sopenharmony_ci	printk("openprom_fill_super: get root inode failed\n");
4108c2ecf20Sopenharmony_ci	return ret;
4118c2ecf20Sopenharmony_ci}
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_cistatic int openpromfs_get_tree(struct fs_context *fc)
4148c2ecf20Sopenharmony_ci{
4158c2ecf20Sopenharmony_ci	return get_tree_single(fc, openprom_fill_super);
4168c2ecf20Sopenharmony_ci}
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_cistatic const struct fs_context_operations openpromfs_context_ops = {
4198c2ecf20Sopenharmony_ci	.get_tree	= openpromfs_get_tree,
4208c2ecf20Sopenharmony_ci};
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_cistatic int openpromfs_init_fs_context(struct fs_context *fc)
4238c2ecf20Sopenharmony_ci{
4248c2ecf20Sopenharmony_ci	fc->ops = &openpromfs_context_ops;
4258c2ecf20Sopenharmony_ci	return 0;
4268c2ecf20Sopenharmony_ci}
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_cistatic struct file_system_type openprom_fs_type = {
4298c2ecf20Sopenharmony_ci	.owner		= THIS_MODULE,
4308c2ecf20Sopenharmony_ci	.name		= "openpromfs",
4318c2ecf20Sopenharmony_ci	.init_fs_context = openpromfs_init_fs_context,
4328c2ecf20Sopenharmony_ci	.kill_sb	= kill_anon_super,
4338c2ecf20Sopenharmony_ci};
4348c2ecf20Sopenharmony_ciMODULE_ALIAS_FS("openpromfs");
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_cistatic void op_inode_init_once(void *data)
4378c2ecf20Sopenharmony_ci{
4388c2ecf20Sopenharmony_ci	struct op_inode_info *oi = (struct op_inode_info *) data;
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci	inode_init_once(&oi->vfs_inode);
4418c2ecf20Sopenharmony_ci}
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_cistatic int __init init_openprom_fs(void)
4448c2ecf20Sopenharmony_ci{
4458c2ecf20Sopenharmony_ci	int err;
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	op_inode_cachep = kmem_cache_create("op_inode_cache",
4488c2ecf20Sopenharmony_ci					    sizeof(struct op_inode_info),
4498c2ecf20Sopenharmony_ci					    0,
4508c2ecf20Sopenharmony_ci					    (SLAB_RECLAIM_ACCOUNT |
4518c2ecf20Sopenharmony_ci					     SLAB_MEM_SPREAD | SLAB_ACCOUNT),
4528c2ecf20Sopenharmony_ci					    op_inode_init_once);
4538c2ecf20Sopenharmony_ci	if (!op_inode_cachep)
4548c2ecf20Sopenharmony_ci		return -ENOMEM;
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci	err = register_filesystem(&openprom_fs_type);
4578c2ecf20Sopenharmony_ci	if (err)
4588c2ecf20Sopenharmony_ci		kmem_cache_destroy(op_inode_cachep);
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	return err;
4618c2ecf20Sopenharmony_ci}
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_cistatic void __exit exit_openprom_fs(void)
4648c2ecf20Sopenharmony_ci{
4658c2ecf20Sopenharmony_ci	unregister_filesystem(&openprom_fs_type);
4668c2ecf20Sopenharmony_ci	/*
4678c2ecf20Sopenharmony_ci	 * Make sure all delayed rcu free inodes are flushed before we
4688c2ecf20Sopenharmony_ci	 * destroy cache.
4698c2ecf20Sopenharmony_ci	 */
4708c2ecf20Sopenharmony_ci	rcu_barrier();
4718c2ecf20Sopenharmony_ci	kmem_cache_destroy(op_inode_cachep);
4728c2ecf20Sopenharmony_ci}
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_cimodule_init(init_openprom_fs)
4758c2ecf20Sopenharmony_cimodule_exit(exit_openprom_fs)
4768c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
477