1 /* inode.c: /proc/openprom handling routines
3 * Copyright (C) 1996-1999 Jakub Jelinek (jakub@redhat.com)
4 * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
7 #include <linux/module.h>
8 #include <linux/types.h>
9 #include <linux/string.h>
11 #include <linux/init.h>
12 #include <linux/slab.h>
13 #include <linux/seq_file.h>
14 #include <linux/magic.h>
16 #include <asm/openprom.h>
17 #include <asm/oplib.h>
19 #include <asm/uaccess.h>
21 static DEFINE_MUTEX(op_mutex
);
23 #define OPENPROM_ROOT_INO 0
31 struct device_node
*node
;
32 struct property
*prop
;
35 struct op_inode_info
{
36 struct inode vfs_inode
;
37 enum op_inode_type type
;
38 union op_inode_data u
;
41 static struct inode
*openprom_iget(struct super_block
*sb
, ino_t ino
);
43 static inline struct op_inode_info
*OP_I(struct inode
*inode
)
45 return container_of(inode
, struct op_inode_info
, vfs_inode
);
48 static int is_string(unsigned char *p
, int len
)
52 for (i
= 0; i
< len
; i
++) {
53 unsigned char val
= p
[i
];
56 (val
>= ' ' && val
<= '~'))
65 static int property_show(struct seq_file
*f
, void *v
)
67 struct property
*prop
= f
->private;
74 if (is_string(pval
, len
)) {
78 seq_printf(f
, "%s", (char *) pval
);
80 /* Skip over the NULL byte too. */
92 seq_printf(f
, "%02x.",
93 *(unsigned char *) pval
);
96 *(unsigned char *) pval
);
104 seq_printf(f
, "%08x.",
105 *(unsigned int *) pval
);
107 seq_printf(f
, "%08x",
108 *(unsigned int *) pval
);
118 static void *property_start(struct seq_file
*f
, loff_t
*pos
)
125 static void *property_next(struct seq_file
*f
, void *v
, loff_t
*pos
)
131 static void property_stop(struct seq_file
*f
, void *v
)
136 static const struct seq_operations property_op
= {
137 .start
= property_start
,
138 .next
= property_next
,
139 .stop
= property_stop
,
140 .show
= property_show
143 static int property_open(struct inode
*inode
, struct file
*file
)
145 struct op_inode_info
*oi
= OP_I(inode
);
148 BUG_ON(oi
->type
!= op_inode_prop
);
150 ret
= seq_open(file
, &property_op
);
152 struct seq_file
*m
= file
->private_data
;
153 m
->private = oi
->u
.prop
;
158 static const struct file_operations openpromfs_prop_ops
= {
159 .open
= property_open
,
162 .release
= seq_release
,
165 static int openpromfs_readdir(struct file
*, void *, filldir_t
);
167 static const struct file_operations openprom_operations
= {
168 .read
= generic_read_dir
,
169 .readdir
= openpromfs_readdir
,
170 .llseek
= generic_file_llseek
,
173 static struct dentry
*openpromfs_lookup(struct inode
*, struct dentry
*, struct nameidata
*);
175 static const struct inode_operations openprom_inode_operations
= {
176 .lookup
= openpromfs_lookup
,
179 static struct dentry
*openpromfs_lookup(struct inode
*dir
, struct dentry
*dentry
, struct nameidata
*nd
)
181 struct op_inode_info
*ent_oi
, *oi
= OP_I(dir
);
182 struct device_node
*dp
, *child
;
183 struct property
*prop
;
184 enum op_inode_type ent_type
;
185 union op_inode_data ent_data
;
191 BUG_ON(oi
->type
!= op_inode_node
);
195 name
= dentry
->d_name
.name
;
196 len
= dentry
->d_name
.len
;
198 mutex_lock(&op_mutex
);
202 int n
= strlen(child
->path_component_name
);
205 !strncmp(child
->path_component_name
, name
, len
)) {
206 ent_type
= op_inode_node
;
207 ent_data
.node
= child
;
208 ino
= child
->unique_id
;
211 child
= child
->sibling
;
214 prop
= dp
->properties
;
216 int n
= strlen(prop
->name
);
218 if (len
== n
&& !strncmp(prop
->name
, name
, len
)) {
219 ent_type
= op_inode_prop
;
220 ent_data
.prop
= prop
;
221 ino
= prop
->unique_id
;
228 mutex_unlock(&op_mutex
);
229 return ERR_PTR(-ENOENT
);
232 inode
= openprom_iget(dir
->i_sb
, ino
);
233 mutex_unlock(&op_mutex
);
235 return ERR_CAST(inode
);
236 ent_oi
= OP_I(inode
);
237 ent_oi
->type
= ent_type
;
238 ent_oi
->u
= ent_data
;
242 inode
->i_mode
= S_IFDIR
| S_IRUGO
| S_IXUGO
;
243 inode
->i_op
= &openprom_inode_operations
;
244 inode
->i_fop
= &openprom_operations
;
248 if (!strcmp(dp
->name
, "options") && (len
== 17) &&
249 !strncmp (name
, "security-password", 17))
250 inode
->i_mode
= S_IFREG
| S_IRUSR
| S_IWUSR
;
252 inode
->i_mode
= S_IFREG
| S_IRUGO
;
253 inode
->i_fop
= &openpromfs_prop_ops
;
255 inode
->i_size
= ent_oi
->u
.prop
->length
;
259 d_add(dentry
, inode
);
263 static int openpromfs_readdir(struct file
* filp
, void * dirent
, filldir_t filldir
)
265 struct inode
*inode
= filp
->f_path
.dentry
->d_inode
;
266 struct op_inode_info
*oi
= OP_I(inode
);
267 struct device_node
*dp
= oi
->u
.node
;
268 struct device_node
*child
;
269 struct property
*prop
;
273 mutex_lock(&op_mutex
);
279 if (filldir(dirent
, ".", 1, i
, ino
, DT_DIR
) < 0)
285 if (filldir(dirent
, "..", 2, i
,
286 (dp
->parent
== NULL
?
288 dp
->parent
->unique_id
), DT_DIR
) < 0)
296 /* First, the children nodes as directories. */
299 child
= child
->sibling
;
304 child
->path_component_name
,
305 strlen(child
->path_component_name
),
306 filp
->f_pos
, child
->unique_id
, DT_DIR
) < 0)
310 child
= child
->sibling
;
313 /* Next, the properties as files. */
314 prop
= dp
->properties
;
320 if (filldir(dirent
, prop
->name
, strlen(prop
->name
),
321 filp
->f_pos
, prop
->unique_id
, DT_REG
) < 0)
329 mutex_unlock(&op_mutex
);
333 static struct kmem_cache
*op_inode_cachep
;
335 static struct inode
*openprom_alloc_inode(struct super_block
*sb
)
337 struct op_inode_info
*oi
;
339 oi
= kmem_cache_alloc(op_inode_cachep
, GFP_KERNEL
);
343 return &oi
->vfs_inode
;
346 static void openprom_i_callback(struct rcu_head
*head
)
348 struct inode
*inode
= container_of(head
, struct inode
, i_rcu
);
349 kmem_cache_free(op_inode_cachep
, OP_I(inode
));
352 static void openprom_destroy_inode(struct inode
*inode
)
354 call_rcu(&inode
->i_rcu
, openprom_i_callback
);
357 static struct inode
*openprom_iget(struct super_block
*sb
, ino_t ino
)
361 inode
= iget_locked(sb
, ino
);
363 return ERR_PTR(-ENOMEM
);
364 if (inode
->i_state
& I_NEW
) {
365 inode
->i_mtime
= inode
->i_atime
= inode
->i_ctime
= CURRENT_TIME
;
366 if (inode
->i_ino
== OPENPROM_ROOT_INO
) {
367 inode
->i_op
= &openprom_inode_operations
;
368 inode
->i_fop
= &openprom_operations
;
369 inode
->i_mode
= S_IFDIR
| S_IRUGO
| S_IXUGO
;
371 unlock_new_inode(inode
);
376 static int openprom_remount(struct super_block
*sb
, int *flags
, char *data
)
378 *flags
|= MS_NOATIME
;
382 static const struct super_operations openprom_sops
= {
383 .alloc_inode
= openprom_alloc_inode
,
384 .destroy_inode
= openprom_destroy_inode
,
385 .statfs
= simple_statfs
,
386 .remount_fs
= openprom_remount
,
389 static int openprom_fill_super(struct super_block
*s
, void *data
, int silent
)
391 struct inode
*root_inode
;
392 struct op_inode_info
*oi
;
395 s
->s_flags
|= MS_NOATIME
;
396 s
->s_blocksize
= 1024;
397 s
->s_blocksize_bits
= 10;
398 s
->s_magic
= OPENPROM_SUPER_MAGIC
;
399 s
->s_op
= &openprom_sops
;
401 root_inode
= openprom_iget(s
, OPENPROM_ROOT_INO
);
402 if (IS_ERR(root_inode
)) {
403 ret
= PTR_ERR(root_inode
);
407 oi
= OP_I(root_inode
);
408 oi
->type
= op_inode_node
;
409 oi
->u
.node
= of_find_node_by_path("/");
411 s
->s_root
= d_alloc_root(root_inode
);
413 goto out_no_root_dentry
;
420 printk("openprom_fill_super: get root inode failed\n");
424 static struct dentry
*openprom_mount(struct file_system_type
*fs_type
,
425 int flags
, const char *dev_name
, void *data
)
427 return mount_single(fs_type
, flags
, data
, openprom_fill_super
);
430 static struct file_system_type openprom_fs_type
= {
431 .owner
= THIS_MODULE
,
432 .name
= "openpromfs",
433 .mount
= openprom_mount
,
434 .kill_sb
= kill_anon_super
,
437 static void op_inode_init_once(void *data
)
439 struct op_inode_info
*oi
= (struct op_inode_info
*) data
;
441 inode_init_once(&oi
->vfs_inode
);
444 static int __init
init_openprom_fs(void)
448 op_inode_cachep
= kmem_cache_create("op_inode_cache",
449 sizeof(struct op_inode_info
),
451 (SLAB_RECLAIM_ACCOUNT
|
454 if (!op_inode_cachep
)
457 err
= register_filesystem(&openprom_fs_type
);
459 kmem_cache_destroy(op_inode_cachep
);
464 static void __exit
exit_openprom_fs(void)
466 unregister_filesystem(&openprom_fs_type
);
467 kmem_cache_destroy(op_inode_cachep
);
470 module_init(init_openprom_fs
)
471 module_exit(exit_openprom_fs
)
472 MODULE_LICENSE("GPL");