xref: /OK3568_Linux_fs/kernel/fs/openpromfs/inode.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /* inode.c: /proc/openprom handling routines
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Copyright (C) 1996-1999 Jakub Jelinek  (jakub@redhat.com)
5*4882a593Smuzhiyun  * Copyright (C) 1998      Eddie C. Dost  (ecd@skynet.be)
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include <linux/module.h>
9*4882a593Smuzhiyun #include <linux/types.h>
10*4882a593Smuzhiyun #include <linux/string.h>
11*4882a593Smuzhiyun #include <linux/fs.h>
12*4882a593Smuzhiyun #include <linux/fs_context.h>
13*4882a593Smuzhiyun #include <linux/init.h>
14*4882a593Smuzhiyun #include <linux/slab.h>
15*4882a593Smuzhiyun #include <linux/seq_file.h>
16*4882a593Smuzhiyun #include <linux/magic.h>
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun #include <asm/openprom.h>
19*4882a593Smuzhiyun #include <asm/oplib.h>
20*4882a593Smuzhiyun #include <asm/prom.h>
21*4882a593Smuzhiyun #include <linux/uaccess.h>
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun static DEFINE_MUTEX(op_mutex);
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun #define OPENPROM_ROOT_INO	0
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun enum op_inode_type {
28*4882a593Smuzhiyun 	op_inode_node,
29*4882a593Smuzhiyun 	op_inode_prop,
30*4882a593Smuzhiyun };
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun union op_inode_data {
33*4882a593Smuzhiyun 	struct device_node	*node;
34*4882a593Smuzhiyun 	struct property		*prop;
35*4882a593Smuzhiyun };
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun struct op_inode_info {
38*4882a593Smuzhiyun 	struct inode		vfs_inode;
39*4882a593Smuzhiyun 	enum op_inode_type	type;
40*4882a593Smuzhiyun 	union op_inode_data	u;
41*4882a593Smuzhiyun };
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun static struct inode *openprom_iget(struct super_block *sb, ino_t ino);
44*4882a593Smuzhiyun 
OP_I(struct inode * inode)45*4882a593Smuzhiyun static inline struct op_inode_info *OP_I(struct inode *inode)
46*4882a593Smuzhiyun {
47*4882a593Smuzhiyun 	return container_of(inode, struct op_inode_info, vfs_inode);
48*4882a593Smuzhiyun }
49*4882a593Smuzhiyun 
is_string(unsigned char * p,int len)50*4882a593Smuzhiyun static int is_string(unsigned char *p, int len)
51*4882a593Smuzhiyun {
52*4882a593Smuzhiyun 	int i;
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun 	for (i = 0; i < len; i++) {
55*4882a593Smuzhiyun 		unsigned char val = p[i];
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun 		if ((i && !val) ||
58*4882a593Smuzhiyun 		    (val >= ' ' && val <= '~'))
59*4882a593Smuzhiyun 			continue;
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun 		return 0;
62*4882a593Smuzhiyun 	}
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun 	return 1;
65*4882a593Smuzhiyun }
66*4882a593Smuzhiyun 
property_show(struct seq_file * f,void * v)67*4882a593Smuzhiyun static int property_show(struct seq_file *f, void *v)
68*4882a593Smuzhiyun {
69*4882a593Smuzhiyun 	struct property *prop = f->private;
70*4882a593Smuzhiyun 	void *pval;
71*4882a593Smuzhiyun 	int len;
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun 	len = prop->length;
74*4882a593Smuzhiyun 	pval = prop->value;
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun 	if (is_string(pval, len)) {
77*4882a593Smuzhiyun 		while (len > 0) {
78*4882a593Smuzhiyun 			int n = strlen(pval);
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun 			seq_printf(f, "%s", (char *) pval);
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun 			/* Skip over the NULL byte too.  */
83*4882a593Smuzhiyun 			pval += n + 1;
84*4882a593Smuzhiyun 			len -= n + 1;
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun 			if (len > 0)
87*4882a593Smuzhiyun 				seq_printf(f, " + ");
88*4882a593Smuzhiyun 		}
89*4882a593Smuzhiyun 	} else {
90*4882a593Smuzhiyun 		if (len & 3) {
91*4882a593Smuzhiyun 			while (len) {
92*4882a593Smuzhiyun 				len--;
93*4882a593Smuzhiyun 				if (len)
94*4882a593Smuzhiyun 					seq_printf(f, "%02x.",
95*4882a593Smuzhiyun 						   *(unsigned char *) pval);
96*4882a593Smuzhiyun 				else
97*4882a593Smuzhiyun 					seq_printf(f, "%02x",
98*4882a593Smuzhiyun 						   *(unsigned char *) pval);
99*4882a593Smuzhiyun 				pval++;
100*4882a593Smuzhiyun 			}
101*4882a593Smuzhiyun 		} else {
102*4882a593Smuzhiyun 			while (len >= 4) {
103*4882a593Smuzhiyun 				len -= 4;
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun 				if (len)
106*4882a593Smuzhiyun 					seq_printf(f, "%08x.",
107*4882a593Smuzhiyun 						   *(unsigned int *) pval);
108*4882a593Smuzhiyun 				else
109*4882a593Smuzhiyun 					seq_printf(f, "%08x",
110*4882a593Smuzhiyun 						   *(unsigned int *) pval);
111*4882a593Smuzhiyun 				pval += 4;
112*4882a593Smuzhiyun 			}
113*4882a593Smuzhiyun 		}
114*4882a593Smuzhiyun 	}
115*4882a593Smuzhiyun 	seq_printf(f, "\n");
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun 	return 0;
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun 
property_start(struct seq_file * f,loff_t * pos)120*4882a593Smuzhiyun static void *property_start(struct seq_file *f, loff_t *pos)
121*4882a593Smuzhiyun {
122*4882a593Smuzhiyun 	if (*pos == 0)
123*4882a593Smuzhiyun 		return pos;
124*4882a593Smuzhiyun 	return NULL;
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun 
property_next(struct seq_file * f,void * v,loff_t * pos)127*4882a593Smuzhiyun static void *property_next(struct seq_file *f, void *v, loff_t *pos)
128*4882a593Smuzhiyun {
129*4882a593Smuzhiyun 	(*pos)++;
130*4882a593Smuzhiyun 	return NULL;
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun 
property_stop(struct seq_file * f,void * v)133*4882a593Smuzhiyun static void property_stop(struct seq_file *f, void *v)
134*4882a593Smuzhiyun {
135*4882a593Smuzhiyun 	/* Nothing to do */
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun static const struct seq_operations property_op = {
139*4882a593Smuzhiyun 	.start		= property_start,
140*4882a593Smuzhiyun 	.next		= property_next,
141*4882a593Smuzhiyun 	.stop		= property_stop,
142*4882a593Smuzhiyun 	.show		= property_show
143*4882a593Smuzhiyun };
144*4882a593Smuzhiyun 
property_open(struct inode * inode,struct file * file)145*4882a593Smuzhiyun static int property_open(struct inode *inode, struct file *file)
146*4882a593Smuzhiyun {
147*4882a593Smuzhiyun 	struct op_inode_info *oi = OP_I(inode);
148*4882a593Smuzhiyun 	int ret;
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun 	BUG_ON(oi->type != op_inode_prop);
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 	ret = seq_open(file, &property_op);
153*4882a593Smuzhiyun 	if (!ret) {
154*4882a593Smuzhiyun 		struct seq_file *m = file->private_data;
155*4882a593Smuzhiyun 		m->private = oi->u.prop;
156*4882a593Smuzhiyun 	}
157*4882a593Smuzhiyun 	return ret;
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun static const struct file_operations openpromfs_prop_ops = {
161*4882a593Smuzhiyun 	.open		= property_open,
162*4882a593Smuzhiyun 	.read		= seq_read,
163*4882a593Smuzhiyun 	.llseek		= seq_lseek,
164*4882a593Smuzhiyun 	.release	= seq_release,
165*4882a593Smuzhiyun };
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun static int openpromfs_readdir(struct file *, struct dir_context *);
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun static const struct file_operations openprom_operations = {
170*4882a593Smuzhiyun 	.read		= generic_read_dir,
171*4882a593Smuzhiyun 	.iterate_shared	= openpromfs_readdir,
172*4882a593Smuzhiyun 	.llseek		= generic_file_llseek,
173*4882a593Smuzhiyun };
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun static struct dentry *openpromfs_lookup(struct inode *, struct dentry *, unsigned int);
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun static const struct inode_operations openprom_inode_operations = {
178*4882a593Smuzhiyun 	.lookup		= openpromfs_lookup,
179*4882a593Smuzhiyun };
180*4882a593Smuzhiyun 
openpromfs_lookup(struct inode * dir,struct dentry * dentry,unsigned int flags)181*4882a593Smuzhiyun static struct dentry *openpromfs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
182*4882a593Smuzhiyun {
183*4882a593Smuzhiyun 	struct op_inode_info *ent_oi, *oi = OP_I(dir);
184*4882a593Smuzhiyun 	struct device_node *dp, *child;
185*4882a593Smuzhiyun 	struct property *prop;
186*4882a593Smuzhiyun 	enum op_inode_type ent_type;
187*4882a593Smuzhiyun 	union op_inode_data ent_data;
188*4882a593Smuzhiyun 	const char *name;
189*4882a593Smuzhiyun 	struct inode *inode;
190*4882a593Smuzhiyun 	unsigned int ino;
191*4882a593Smuzhiyun 	int len;
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun 	BUG_ON(oi->type != op_inode_node);
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun 	dp = oi->u.node;
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun 	name = dentry->d_name.name;
198*4882a593Smuzhiyun 	len = dentry->d_name.len;
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun 	mutex_lock(&op_mutex);
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun 	child = dp->child;
203*4882a593Smuzhiyun 	while (child) {
204*4882a593Smuzhiyun 		const char *node_name = kbasename(child->full_name);
205*4882a593Smuzhiyun 		int n = strlen(node_name);
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun 		if (len == n &&
208*4882a593Smuzhiyun 		    !strncmp(node_name, name, len)) {
209*4882a593Smuzhiyun 			ent_type = op_inode_node;
210*4882a593Smuzhiyun 			ent_data.node = child;
211*4882a593Smuzhiyun 			ino = child->unique_id;
212*4882a593Smuzhiyun 			goto found;
213*4882a593Smuzhiyun 		}
214*4882a593Smuzhiyun 		child = child->sibling;
215*4882a593Smuzhiyun 	}
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun 	prop = dp->properties;
218*4882a593Smuzhiyun 	while (prop) {
219*4882a593Smuzhiyun 		int n = strlen(prop->name);
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun 		if (len == n && !strncmp(prop->name, name, len)) {
222*4882a593Smuzhiyun 			ent_type = op_inode_prop;
223*4882a593Smuzhiyun 			ent_data.prop = prop;
224*4882a593Smuzhiyun 			ino = prop->unique_id;
225*4882a593Smuzhiyun 			goto found;
226*4882a593Smuzhiyun 		}
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun 		prop = prop->next;
229*4882a593Smuzhiyun 	}
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun 	mutex_unlock(&op_mutex);
232*4882a593Smuzhiyun 	return ERR_PTR(-ENOENT);
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun found:
235*4882a593Smuzhiyun 	inode = openprom_iget(dir->i_sb, ino);
236*4882a593Smuzhiyun 	mutex_unlock(&op_mutex);
237*4882a593Smuzhiyun 	if (IS_ERR(inode))
238*4882a593Smuzhiyun 		return ERR_CAST(inode);
239*4882a593Smuzhiyun 	ent_oi = OP_I(inode);
240*4882a593Smuzhiyun 	ent_oi->type = ent_type;
241*4882a593Smuzhiyun 	ent_oi->u = ent_data;
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 	switch (ent_type) {
244*4882a593Smuzhiyun 	case op_inode_node:
245*4882a593Smuzhiyun 		inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
246*4882a593Smuzhiyun 		inode->i_op = &openprom_inode_operations;
247*4882a593Smuzhiyun 		inode->i_fop = &openprom_operations;
248*4882a593Smuzhiyun 		set_nlink(inode, 2);
249*4882a593Smuzhiyun 		break;
250*4882a593Smuzhiyun 	case op_inode_prop:
251*4882a593Smuzhiyun 		if (of_node_name_eq(dp, "options") && (len == 17) &&
252*4882a593Smuzhiyun 		    !strncmp (name, "security-password", 17))
253*4882a593Smuzhiyun 			inode->i_mode = S_IFREG | S_IRUSR | S_IWUSR;
254*4882a593Smuzhiyun 		else
255*4882a593Smuzhiyun 			inode->i_mode = S_IFREG | S_IRUGO;
256*4882a593Smuzhiyun 		inode->i_fop = &openpromfs_prop_ops;
257*4882a593Smuzhiyun 		set_nlink(inode, 1);
258*4882a593Smuzhiyun 		inode->i_size = ent_oi->u.prop->length;
259*4882a593Smuzhiyun 		break;
260*4882a593Smuzhiyun 	}
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun 	return d_splice_alias(inode, dentry);
263*4882a593Smuzhiyun }
264*4882a593Smuzhiyun 
openpromfs_readdir(struct file * file,struct dir_context * ctx)265*4882a593Smuzhiyun static int openpromfs_readdir(struct file *file, struct dir_context *ctx)
266*4882a593Smuzhiyun {
267*4882a593Smuzhiyun 	struct inode *inode = file_inode(file);
268*4882a593Smuzhiyun 	struct op_inode_info *oi = OP_I(inode);
269*4882a593Smuzhiyun 	struct device_node *dp = oi->u.node;
270*4882a593Smuzhiyun 	struct device_node *child;
271*4882a593Smuzhiyun 	struct property *prop;
272*4882a593Smuzhiyun 	int i;
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun 	mutex_lock(&op_mutex);
275*4882a593Smuzhiyun 
276*4882a593Smuzhiyun 	if (ctx->pos == 0) {
277*4882a593Smuzhiyun 		if (!dir_emit(ctx, ".", 1, inode->i_ino, DT_DIR))
278*4882a593Smuzhiyun 			goto out;
279*4882a593Smuzhiyun 		ctx->pos = 1;
280*4882a593Smuzhiyun 	}
281*4882a593Smuzhiyun 	if (ctx->pos == 1) {
282*4882a593Smuzhiyun 		if (!dir_emit(ctx, "..", 2,
283*4882a593Smuzhiyun 			    (dp->parent == NULL ?
284*4882a593Smuzhiyun 			     OPENPROM_ROOT_INO :
285*4882a593Smuzhiyun 			     dp->parent->unique_id), DT_DIR))
286*4882a593Smuzhiyun 			goto out;
287*4882a593Smuzhiyun 		ctx->pos = 2;
288*4882a593Smuzhiyun 	}
289*4882a593Smuzhiyun 	i = ctx->pos - 2;
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun 	/* First, the children nodes as directories.  */
292*4882a593Smuzhiyun 	child = dp->child;
293*4882a593Smuzhiyun 	while (i && child) {
294*4882a593Smuzhiyun 		child = child->sibling;
295*4882a593Smuzhiyun 		i--;
296*4882a593Smuzhiyun 	}
297*4882a593Smuzhiyun 	while (child) {
298*4882a593Smuzhiyun 		if (!dir_emit(ctx,
299*4882a593Smuzhiyun 			    kbasename(child->full_name),
300*4882a593Smuzhiyun 			    strlen(kbasename(child->full_name)),
301*4882a593Smuzhiyun 			    child->unique_id, DT_DIR))
302*4882a593Smuzhiyun 			goto out;
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 		ctx->pos++;
305*4882a593Smuzhiyun 		child = child->sibling;
306*4882a593Smuzhiyun 	}
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 	/* Next, the properties as files.  */
309*4882a593Smuzhiyun 	prop = dp->properties;
310*4882a593Smuzhiyun 	while (i && prop) {
311*4882a593Smuzhiyun 		prop = prop->next;
312*4882a593Smuzhiyun 		i--;
313*4882a593Smuzhiyun 	}
314*4882a593Smuzhiyun 	while (prop) {
315*4882a593Smuzhiyun 		if (!dir_emit(ctx, prop->name, strlen(prop->name),
316*4882a593Smuzhiyun 			    prop->unique_id, DT_REG))
317*4882a593Smuzhiyun 			goto out;
318*4882a593Smuzhiyun 
319*4882a593Smuzhiyun 		ctx->pos++;
320*4882a593Smuzhiyun 		prop = prop->next;
321*4882a593Smuzhiyun 	}
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun out:
324*4882a593Smuzhiyun 	mutex_unlock(&op_mutex);
325*4882a593Smuzhiyun 	return 0;
326*4882a593Smuzhiyun }
327*4882a593Smuzhiyun 
328*4882a593Smuzhiyun static struct kmem_cache *op_inode_cachep;
329*4882a593Smuzhiyun 
openprom_alloc_inode(struct super_block * sb)330*4882a593Smuzhiyun static struct inode *openprom_alloc_inode(struct super_block *sb)
331*4882a593Smuzhiyun {
332*4882a593Smuzhiyun 	struct op_inode_info *oi;
333*4882a593Smuzhiyun 
334*4882a593Smuzhiyun 	oi = kmem_cache_alloc(op_inode_cachep, GFP_KERNEL);
335*4882a593Smuzhiyun 	if (!oi)
336*4882a593Smuzhiyun 		return NULL;
337*4882a593Smuzhiyun 
338*4882a593Smuzhiyun 	return &oi->vfs_inode;
339*4882a593Smuzhiyun }
340*4882a593Smuzhiyun 
openprom_free_inode(struct inode * inode)341*4882a593Smuzhiyun static void openprom_free_inode(struct inode *inode)
342*4882a593Smuzhiyun {
343*4882a593Smuzhiyun 	kmem_cache_free(op_inode_cachep, OP_I(inode));
344*4882a593Smuzhiyun }
345*4882a593Smuzhiyun 
openprom_iget(struct super_block * sb,ino_t ino)346*4882a593Smuzhiyun static struct inode *openprom_iget(struct super_block *sb, ino_t ino)
347*4882a593Smuzhiyun {
348*4882a593Smuzhiyun 	struct inode *inode;
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun 	inode = iget_locked(sb, ino);
351*4882a593Smuzhiyun 	if (!inode)
352*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
353*4882a593Smuzhiyun 	if (inode->i_state & I_NEW) {
354*4882a593Smuzhiyun 		inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
355*4882a593Smuzhiyun 		if (inode->i_ino == OPENPROM_ROOT_INO) {
356*4882a593Smuzhiyun 			inode->i_op = &openprom_inode_operations;
357*4882a593Smuzhiyun 			inode->i_fop = &openprom_operations;
358*4882a593Smuzhiyun 			inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
359*4882a593Smuzhiyun 		}
360*4882a593Smuzhiyun 		unlock_new_inode(inode);
361*4882a593Smuzhiyun 	}
362*4882a593Smuzhiyun 	return inode;
363*4882a593Smuzhiyun }
364*4882a593Smuzhiyun 
openprom_remount(struct super_block * sb,int * flags,char * data)365*4882a593Smuzhiyun static int openprom_remount(struct super_block *sb, int *flags, char *data)
366*4882a593Smuzhiyun {
367*4882a593Smuzhiyun 	sync_filesystem(sb);
368*4882a593Smuzhiyun 	*flags |= SB_NOATIME;
369*4882a593Smuzhiyun 	return 0;
370*4882a593Smuzhiyun }
371*4882a593Smuzhiyun 
372*4882a593Smuzhiyun static const struct super_operations openprom_sops = {
373*4882a593Smuzhiyun 	.alloc_inode	= openprom_alloc_inode,
374*4882a593Smuzhiyun 	.free_inode	= openprom_free_inode,
375*4882a593Smuzhiyun 	.statfs		= simple_statfs,
376*4882a593Smuzhiyun 	.remount_fs	= openprom_remount,
377*4882a593Smuzhiyun };
378*4882a593Smuzhiyun 
openprom_fill_super(struct super_block * s,struct fs_context * fc)379*4882a593Smuzhiyun static int openprom_fill_super(struct super_block *s, struct fs_context *fc)
380*4882a593Smuzhiyun {
381*4882a593Smuzhiyun 	struct inode *root_inode;
382*4882a593Smuzhiyun 	struct op_inode_info *oi;
383*4882a593Smuzhiyun 	int ret;
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun 	s->s_flags |= SB_NOATIME;
386*4882a593Smuzhiyun 	s->s_blocksize = 1024;
387*4882a593Smuzhiyun 	s->s_blocksize_bits = 10;
388*4882a593Smuzhiyun 	s->s_magic = OPENPROM_SUPER_MAGIC;
389*4882a593Smuzhiyun 	s->s_op = &openprom_sops;
390*4882a593Smuzhiyun 	s->s_time_gran = 1;
391*4882a593Smuzhiyun 	root_inode = openprom_iget(s, OPENPROM_ROOT_INO);
392*4882a593Smuzhiyun 	if (IS_ERR(root_inode)) {
393*4882a593Smuzhiyun 		ret = PTR_ERR(root_inode);
394*4882a593Smuzhiyun 		goto out_no_root;
395*4882a593Smuzhiyun 	}
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun 	oi = OP_I(root_inode);
398*4882a593Smuzhiyun 	oi->type = op_inode_node;
399*4882a593Smuzhiyun 	oi->u.node = of_find_node_by_path("/");
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun 	s->s_root = d_make_root(root_inode);
402*4882a593Smuzhiyun 	if (!s->s_root)
403*4882a593Smuzhiyun 		goto out_no_root_dentry;
404*4882a593Smuzhiyun 	return 0;
405*4882a593Smuzhiyun 
406*4882a593Smuzhiyun out_no_root_dentry:
407*4882a593Smuzhiyun 	ret = -ENOMEM;
408*4882a593Smuzhiyun out_no_root:
409*4882a593Smuzhiyun 	printk("openprom_fill_super: get root inode failed\n");
410*4882a593Smuzhiyun 	return ret;
411*4882a593Smuzhiyun }
412*4882a593Smuzhiyun 
openpromfs_get_tree(struct fs_context * fc)413*4882a593Smuzhiyun static int openpromfs_get_tree(struct fs_context *fc)
414*4882a593Smuzhiyun {
415*4882a593Smuzhiyun 	return get_tree_single(fc, openprom_fill_super);
416*4882a593Smuzhiyun }
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun static const struct fs_context_operations openpromfs_context_ops = {
419*4882a593Smuzhiyun 	.get_tree	= openpromfs_get_tree,
420*4882a593Smuzhiyun };
421*4882a593Smuzhiyun 
openpromfs_init_fs_context(struct fs_context * fc)422*4882a593Smuzhiyun static int openpromfs_init_fs_context(struct fs_context *fc)
423*4882a593Smuzhiyun {
424*4882a593Smuzhiyun 	fc->ops = &openpromfs_context_ops;
425*4882a593Smuzhiyun 	return 0;
426*4882a593Smuzhiyun }
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun static struct file_system_type openprom_fs_type = {
429*4882a593Smuzhiyun 	.owner		= THIS_MODULE,
430*4882a593Smuzhiyun 	.name		= "openpromfs",
431*4882a593Smuzhiyun 	.init_fs_context = openpromfs_init_fs_context,
432*4882a593Smuzhiyun 	.kill_sb	= kill_anon_super,
433*4882a593Smuzhiyun };
434*4882a593Smuzhiyun MODULE_ALIAS_FS("openpromfs");
435*4882a593Smuzhiyun 
op_inode_init_once(void * data)436*4882a593Smuzhiyun static void op_inode_init_once(void *data)
437*4882a593Smuzhiyun {
438*4882a593Smuzhiyun 	struct op_inode_info *oi = (struct op_inode_info *) data;
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun 	inode_init_once(&oi->vfs_inode);
441*4882a593Smuzhiyun }
442*4882a593Smuzhiyun 
init_openprom_fs(void)443*4882a593Smuzhiyun static int __init init_openprom_fs(void)
444*4882a593Smuzhiyun {
445*4882a593Smuzhiyun 	int err;
446*4882a593Smuzhiyun 
447*4882a593Smuzhiyun 	op_inode_cachep = kmem_cache_create("op_inode_cache",
448*4882a593Smuzhiyun 					    sizeof(struct op_inode_info),
449*4882a593Smuzhiyun 					    0,
450*4882a593Smuzhiyun 					    (SLAB_RECLAIM_ACCOUNT |
451*4882a593Smuzhiyun 					     SLAB_MEM_SPREAD | SLAB_ACCOUNT),
452*4882a593Smuzhiyun 					    op_inode_init_once);
453*4882a593Smuzhiyun 	if (!op_inode_cachep)
454*4882a593Smuzhiyun 		return -ENOMEM;
455*4882a593Smuzhiyun 
456*4882a593Smuzhiyun 	err = register_filesystem(&openprom_fs_type);
457*4882a593Smuzhiyun 	if (err)
458*4882a593Smuzhiyun 		kmem_cache_destroy(op_inode_cachep);
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun 	return err;
461*4882a593Smuzhiyun }
462*4882a593Smuzhiyun 
exit_openprom_fs(void)463*4882a593Smuzhiyun static void __exit exit_openprom_fs(void)
464*4882a593Smuzhiyun {
465*4882a593Smuzhiyun 	unregister_filesystem(&openprom_fs_type);
466*4882a593Smuzhiyun 	/*
467*4882a593Smuzhiyun 	 * Make sure all delayed rcu free inodes are flushed before we
468*4882a593Smuzhiyun 	 * destroy cache.
469*4882a593Smuzhiyun 	 */
470*4882a593Smuzhiyun 	rcu_barrier();
471*4882a593Smuzhiyun 	kmem_cache_destroy(op_inode_cachep);
472*4882a593Smuzhiyun }
473*4882a593Smuzhiyun 
474*4882a593Smuzhiyun module_init(init_openprom_fs)
475*4882a593Smuzhiyun module_exit(exit_openprom_fs)
476*4882a593Smuzhiyun MODULE_LICENSE("GPL");
477