1 /* $Id: inode.c,v 1.15 2001/11/12 09:43:39 davem Exp $
2 * openpromfs.c: /proc/openprom handling routines
4 * Copyright (C) 1996-1999 Jakub Jelinek (jakub@redhat.com)
5 * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
8 #include <linux/module.h>
9 #include <linux/types.h>
10 #include <linux/string.h>
12 #include <linux/openprom_fs.h>
13 #include <linux/init.h>
14 #include <linux/slab.h>
15 #include <linux/smp_lock.h>
17 #include <asm/openprom.h>
18 #include <asm/oplib.h>
19 #include <asm/uaccess.h>
21 #define ALIASES_NNODES 64
32 #define OPP_STRING 0x10
33 #define OPP_STRINGLIST 0x20
34 #define OPP_BINARY 0x40
35 #define OPP_HEXSTRING 0x80
36 #define OPP_DIRTY 0x01
37 #define OPP_QUOTED 0x02
38 #define OPP_NOTQUOTED 0x04
39 #define OPP_ASCIIZ 0x08
47 static openpromfs_node
*nodes
;
50 static u16 first_prop
;
51 static u16 options
= 0xffff;
52 static u16 aliases
= 0xffff;
53 static int aliases_nodes
;
54 static char *alias_names
[ALIASES_NNODES
];
56 #define OPENPROM_ROOT_INO 16
57 #define OPENPROM_FIRST_INO OPENPROM_ROOT_INO
58 #define NODE(ino) nodes[ino - OPENPROM_FIRST_INO]
59 #define NODE2INO(node) (node + OPENPROM_FIRST_INO)
60 #define NODEP2INO(no) (no + OPENPROM_FIRST_INO + last_node)
62 static int openpromfs_create (struct inode
*, struct dentry
*, int, struct nameidata
*);
63 static int openpromfs_readdir(struct file
*, void *, filldir_t
);
64 static struct dentry
*openpromfs_lookup(struct inode
*, struct dentry
*dentry
, struct nameidata
*nd
);
65 static int openpromfs_unlink (struct inode
*, struct dentry
*dentry
);
67 static ssize_t
nodenum_read(struct file
*file
, char __user
*buf
,
68 size_t count
, loff_t
*ppos
)
70 struct inode
*inode
= file
->f_dentry
->d_inode
;
73 if (count
< 0 || !inode
->u
.generic_ip
)
75 sprintf (buffer
, "%8.8x\n", (u32
)(long)(inode
->u
.generic_ip
));
78 if (count
> 9 - file
->f_pos
)
79 count
= 9 - file
->f_pos
;
80 if (copy_to_user(buf
, buffer
+ file
->f_pos
, count
))
86 static ssize_t
property_read(struct file
*filp
, char __user
*buf
,
87 size_t count
, loff_t
*ppos
)
89 struct inode
*inode
= filp
->f_dentry
->d_inode
;
94 openprom_property
*op
;
97 if (!filp
->private_data
) {
98 node
= nodes
[(u16
)((long)inode
->u
.generic_ip
)].node
;
99 i
= ((u32
)(long)inode
->u
.generic_ip
) >> 16;
100 if ((u16
)((long)inode
->u
.generic_ip
) == aliases
) {
101 if (i
>= aliases_nodes
)
106 for (p
= prom_firstprop (node
, buffer
);
108 p
= prom_nextprop (node
, p
, buffer
), i
--)
112 i
= prom_getproplen (node
, p
);
114 if ((u16
)((long)inode
->u
.generic_ip
) == aliases
)
121 filp
->private_data
= kmalloc (sizeof (openprom_property
)
122 + (j
= strlen (p
)) + 2 * i
,
124 if (!filp
->private_data
)
126 op
= (openprom_property
*)filp
->private_data
;
128 op
->alloclen
= 2 * i
;
129 strcpy (op
->name
, p
);
130 op
->value
= (char *)(((unsigned long)(op
->name
+ j
+ 4)) & ~3);
132 if (k
&& prom_getproperty (node
, p
, op
->value
, i
) < 0)
136 for (s
= NULL
, p
= op
->value
; p
< op
->value
+ k
; p
++) {
137 if ((*p
>= ' ' && *p
<= '~') || *p
== '\n') {
138 op
->flag
|= OPP_STRING
;
142 if (p
> op
->value
&& !*p
&& s
== p
- 1) {
143 if (p
< op
->value
+ k
- 1)
144 op
->flag
|= OPP_STRINGLIST
;
146 op
->flag
|= OPP_ASCIIZ
;
150 op
->flag
|= (OPP_STRING
|OPP_ASCIIZ
);
153 op
->flag
&= ~(OPP_STRING
|OPP_STRINGLIST
);
155 op
->flag
|= OPP_HEXSTRING
;
157 op
->flag
|= OPP_BINARY
;
160 if (op
->flag
& OPP_STRINGLIST
)
161 op
->flag
&= ~(OPP_STRING
);
162 if (op
->flag
& OPP_ASCIIZ
)
166 op
= (openprom_property
*)filp
->private_data
;
167 if (!count
|| !(op
->len
|| (op
->flag
& OPP_ASCIIZ
)))
169 if (*ppos
>= 0xffffff || count
>= 0xffffff)
171 if (op
->flag
& OPP_STRINGLIST
) {
172 for (k
= 0, p
= op
->value
; p
< op
->value
+ op
->len
; p
++)
175 i
= op
->len
+ 4 * k
+ 3;
176 } else if (op
->flag
& OPP_STRING
) {
178 } else if (op
->flag
& OPP_BINARY
) {
179 i
= (op
->len
* 9) >> 2;
181 i
= (op
->len
<< 1) + 1;
184 if (k
>= i
) return 0;
185 if (count
> i
- k
) count
= i
- k
;
186 if (op
->flag
& OPP_STRING
) {
188 if (put_user('\'', buf
))
194 if (k
+ count
>= i
- 2)
200 if (copy_to_user(buf
+ k
- *ppos
,
201 op
->value
+ k
- 1, j
))
208 if (put_user('\'', &buf
[k
++ - *ppos
]))
212 if (put_user('\n', &buf
[k
++ - *ppos
]))
215 } else if (op
->flag
& OPP_STRINGLIST
) {
218 tmp
= kmalloc (i
, GFP_KERNEL
);
224 for (p
= op
->value
; p
< op
->value
+ op
->len
; p
++) {
234 if (copy_to_user(buf
, tmp
+ k
, count
))
240 } else if (op
->flag
& OPP_BINARY
) {
243 int first_off
, last_cnt
;
245 first
= ((u32
*)op
->value
) + k
/ 9;
247 last
= ((u32
*)op
->value
) + (k
+ count
- 1) / 9;
248 last_cnt
= (k
+ count
) % 9;
249 if (!last_cnt
) last_cnt
= 9;
252 sprintf (buffer
, "%08x.", *first
);
253 if (copy_to_user(buf
, buffer
+ first_off
,
254 last_cnt
- first_off
))
256 buf
+= last_cnt
- first_off
;
258 for (q
= first
; q
<= last
; q
++) {
259 sprintf (buffer
, "%08x.", *q
);
261 if (copy_to_user(buf
, buffer
+ first_off
,
264 buf
+= 9 - first_off
;
265 } else if (q
== last
) {
266 if (copy_to_user(buf
, buffer
, last_cnt
))
270 if (copy_to_user(buf
, buffer
, 9))
277 if (last
== (u32
*)(op
->value
+ op
->len
- 4) && last_cnt
== 9) {
278 if (put_user('\n', (buf
- 1)))
284 } else if (op
->flag
& OPP_HEXSTRING
) {
287 if ((k
< i
- 1) && (k
& 1)) {
288 sprintf (buffer
, "%02x",
289 (unsigned char) *(op
->value
+ (k
>> 1)) & 0xff);
290 if (put_user(buffer
[1], &buf
[k
++ - *ppos
]))
295 for (; (count
> 1) && (k
< i
- 1); k
+= 2) {
296 sprintf (buffer
, "%02x",
297 (unsigned char) *(op
->value
+ (k
>> 1)) & 0xff);
298 if (copy_to_user(buf
+ k
- *ppos
, buffer
, 2))
303 if (count
&& (k
< i
- 1)) {
304 sprintf (buffer
, "%02x",
305 (unsigned char) *(op
->value
+ (k
>> 1)) & 0xff);
306 if (put_user(buffer
[0], &buf
[k
++ - *ppos
]))
312 if (put_user('\n', &buf
[k
++ - *ppos
]))
321 static ssize_t
property_write(struct file
*filp
, const char __user
*buf
,
322 size_t count
, loff_t
*ppos
)
328 openprom_property
*op
;
330 if (*ppos
>= 0xffffff || count
>= 0xffffff)
332 if (!filp
->private_data
) {
333 i
= property_read (filp
, NULL
, 0, NULL
);
338 op
= (openprom_property
*)filp
->private_data
;
339 if (!(op
->flag
& OPP_STRING
)) {
341 int first_off
, last_cnt
;
347 for (i
= 0; i
< count
; i
++, j
++) {
351 if (get_user(ctmp
, &buf
[i
]))
355 if (op
->flag
& OPP_BINARY
)
358 goto write_try_string
;
367 if (get_user(ctmp
, &buf
[i
]))
370 (ctmp
> '9' && ctmp
< 'A') ||
371 (ctmp
> 'F' && ctmp
< 'a') ||
373 if (op
->flag
& OPP_BINARY
)
376 goto write_try_string
;
380 op
->flag
|= OPP_BINARY
;
382 i
= ((count
+ k
+ 8) / 9) << 2;
383 if (op
->alloclen
<= i
) {
384 b
= kmalloc (sizeof (openprom_property
) + 2 * i
,
388 memcpy (b
, filp
->private_data
,
389 sizeof (openprom_property
)
390 + strlen (op
->name
) + op
->alloclen
);
391 memset (((char *)b
) + sizeof (openprom_property
)
392 + strlen (op
->name
) + op
->alloclen
,
393 0, 2 * i
- op
->alloclen
);
394 op
= (openprom_property
*)b
;
396 b
= filp
->private_data
;
397 filp
->private_data
= (void *)op
;
400 first
= ((u32
*)op
->value
) + (k
/ 9);
402 last
= (u32
*)(op
->value
+ i
);
403 last_cnt
= (k
+ count
) % 9;
404 if (first
+ 1 == last
) {
405 memset (tmp
, '0', 8);
406 if (copy_from_user(tmp
+ first_off
, buf
,
407 (count
+ first_off
> 8) ?
408 8 - first_off
: count
))
412 for (j
= 0; j
< first_off
; j
++)
414 for (j
= 8 - count
- first_off
; j
> 0; j
--)
419 *first
|= simple_strtoul (tmp
, NULL
, 16);
420 op
->flag
|= OPP_DIRTY
;
423 op
->flag
|= OPP_DIRTY
;
424 for (q
= first
; q
< last
; q
++) {
427 memset (tmp
, '0', 8);
428 if (copy_from_user(tmp
+ first_off
,
433 for (j
= 0; j
< first_off
; j
++)
436 *q
|= simple_strtoul (tmp
,NULL
,16);
439 } else if ((q
== last
- 1) && last_cnt
441 memset (tmp
, '0', 8);
442 if (copy_from_user(tmp
, buf
, last_cnt
))
445 for (j
= 0; j
< 8 - last_cnt
; j
++)
448 *q
|= simple_strtoul (tmp
, NULL
, 16);
451 char tchars
[17]; /* XXX yuck... */
453 if (copy_from_user(tchars
, buf
, 16))
455 *q
= simple_strtoul (tchars
, NULL
, 16);
468 if (!(op
->flag
& OPP_BINARY
)) {
469 if (!(op
->flag
& (OPP_QUOTED
| OPP_NOTQUOTED
))) {
472 /* No way, if somebody starts writing from the middle,
473 * we don't know whether he uses quotes around or not
477 if (get_user(ctmp
, buf
))
480 op
->flag
|= OPP_QUOTED
;
485 op
->flag
|= OPP_STRING
;
489 op
->flag
|= OPP_NOTQUOTED
;
491 op
->flag
|= OPP_STRING
;
492 if (op
->alloclen
<= count
+ *ppos
) {
493 b
= kmalloc (sizeof (openprom_property
)
494 + 2 * (count
+ *ppos
), GFP_KERNEL
);
497 memcpy (b
, filp
->private_data
,
498 sizeof (openprom_property
)
499 + strlen (op
->name
) + op
->alloclen
);
500 memset (((char *)b
) + sizeof (openprom_property
)
501 + strlen (op
->name
) + op
->alloclen
,
502 0, 2*(count
- *ppos
) - op
->alloclen
);
503 op
= (openprom_property
*)b
;
504 op
->alloclen
= 2*(count
+ *ppos
);
505 b
= filp
->private_data
;
506 filp
->private_data
= (void *)op
;
509 p
= op
->value
+ *ppos
- ((op
->flag
& OPP_QUOTED
) ? 1 : 0);
510 if (copy_from_user(p
, buf
, count
))
512 op
->flag
|= OPP_DIRTY
;
513 for (i
= 0; i
< count
; i
++, p
++)
519 op
->len
= p
- op
->value
;
521 if ((p
> op
->value
) && (op
->flag
& OPP_QUOTED
)
522 && (*(p
- 1) == '\''))
525 if (p
- op
->value
> op
->len
)
526 op
->len
= p
- op
->value
;
533 int property_release (struct inode
*inode
, struct file
*filp
)
535 openprom_property
*op
= (openprom_property
*)filp
->private_data
;
542 node
= nodes
[(u16
)((long)inode
->u
.generic_ip
)].node
;
543 if ((u16
)((long)inode
->u
.generic_ip
) == aliases
) {
544 if ((op
->flag
& OPP_DIRTY
) && (op
->flag
& OPP_STRING
)) {
546 int i
= (op
->value
- op
->name
) - strlen (op
->name
) - 1;
547 op
->value
[op
->len
] = 0;
548 *(op
->value
- 1) = ' ';
550 for (p
= op
->value
- i
- 2; p
>= op
->name
; p
--)
554 memcpy (p
- 8, "nvalias ", 8);
557 } else if (op
->flag
& OPP_DIRTY
) {
558 if (op
->flag
& OPP_STRING
) {
559 op
->value
[op
->len
] = 0;
560 error
= prom_setprop (node
, op
->name
,
561 op
->value
, op
->len
+ 1);
563 printk (KERN_WARNING
"openpromfs: "
564 "Couldn't write property %s\n",
566 } else if ((op
->flag
& OPP_BINARY
) || !op
->len
) {
567 error
= prom_setprop (node
, op
->name
,
570 printk (KERN_WARNING
"openpromfs: "
571 "Couldn't write property %s\n",
574 printk (KERN_WARNING
"openpromfs: "
575 "Unknown property type of %s\n",
580 kfree (filp
->private_data
);
584 static struct file_operations openpromfs_prop_ops
= {
585 .read
= property_read
,
586 .write
= property_write
,
587 .release
= property_release
,
590 static struct file_operations openpromfs_nodenum_ops
= {
591 .read
= nodenum_read
,
594 static struct file_operations openprom_operations
= {
595 .read
= generic_read_dir
,
596 .readdir
= openpromfs_readdir
,
599 static struct inode_operations openprom_alias_inode_operations
= {
600 .create
= openpromfs_create
,
601 .lookup
= openpromfs_lookup
,
602 .unlink
= openpromfs_unlink
,
605 static struct inode_operations openprom_inode_operations
= {
606 .lookup
= openpromfs_lookup
,
609 static int lookup_children(u16 n
, const char * name
, int len
)
613 for (; n
!= 0xffff; n
= nodes
[n
].next
) {
614 node
= nodes
[n
].child
;
615 if (node
!= 0xffff) {
620 while (node
!= 0xffff) {
621 if (prom_getname (nodes
[node
].node
,
625 && !strncmp (buffer
, name
, len
))
626 return NODE2INO(node
);
627 p
= strchr (buffer
, '@');
628 if (p
&& (len
== p
- buffer
)
629 && !strncmp (buffer
, name
, len
))
630 return NODE2INO(node
);
632 node
= nodes
[node
].next
;
636 ret
= lookup_children (nodes
[n
].child
, name
, len
);
642 static struct dentry
*openpromfs_lookup(struct inode
* dir
, struct dentry
*dentry
, struct nameidata
*nd
)
646 #define OPFSL_PROPERTY 1
647 #define OPFSL_NODENUM 2
660 name
= dentry
->d_name
.name
;
661 len
= dentry
->d_name
.len
;
663 if (name
[0] == '.' && len
== 5 && !strncmp (name
+ 1, "node", 4)) {
664 ino
= NODEP2INO(NODE(dir
->i_ino
).first_prop
);
665 type
= OPFSL_NODENUM
;
668 u16 node
= NODE(dir
->i_ino
).child
;
669 while (node
!= 0xffff) {
670 if (prom_getname (nodes
[node
].node
, buffer
, 128) >= 0) {
672 if (len
== i
&& !strncmp (buffer
, name
, len
)) {
673 ino
= NODE2INO(node
);
677 p
= strchr (buffer
, '@');
678 if (p
&& (len
== p
- buffer
)
679 && !strncmp (buffer
, name
, len
)) {
680 ino
= NODE2INO(node
);
685 node
= nodes
[node
].next
;
688 n
= NODE(dir
->i_ino
).node
;
689 dirnode
= dir
->i_ino
- OPENPROM_FIRST_INO
;
691 int j
= NODEP2INO(NODE(dir
->i_ino
).first_prop
);
692 if (dirnode
!= aliases
) {
693 for (p
= prom_firstprop (n
, buffer2
);
695 p
= prom_nextprop (n
, p
, buffer2
)) {
697 if ((len
== strlen (p
))
698 && !strncmp (p
, name
, len
)) {
700 type
= OPFSL_PROPERTY
;
706 for (k
= 0; k
< aliases_nodes
; k
++) {
709 && (len
== strlen (alias_names
[k
]))
710 && !strncmp (alias_names
[k
], name
, len
)) {
712 type
= OPFSL_PROPERTY
;
719 ino
= lookup_children (NODE(dir
->i_ino
).child
, name
, len
);
724 return ERR_PTR(-ENOENT
);
727 inode
= iget (dir
->i_sb
, ino
);
730 return ERR_PTR(-EINVAL
);
733 inode
->i_mode
= S_IFDIR
| S_IRUGO
| S_IXUGO
;
734 if (ino
== OPENPROM_FIRST_INO
+ aliases
) {
735 inode
->i_mode
|= S_IWUSR
;
736 inode
->i_op
= &openprom_alias_inode_operations
;
738 inode
->i_op
= &openprom_inode_operations
;
739 inode
->i_fop
= &openprom_operations
;
743 inode
->i_mode
= S_IFREG
| S_IRUGO
;
744 inode
->i_fop
= &openpromfs_nodenum_ops
;
746 inode
->u
.generic_ip
= (void *)(long)(n
);
749 if ((dirnode
== options
) && (len
== 17)
750 && !strncmp (name
, "security-password", 17))
751 inode
->i_mode
= S_IFREG
| S_IRUSR
| S_IWUSR
;
753 inode
->i_mode
= S_IFREG
| S_IRUGO
;
754 if (dirnode
== options
|| dirnode
== aliases
) {
755 if (len
!= 4 || strncmp (name
, "name", 4))
756 inode
->i_mode
|= S_IWUSR
;
759 inode
->i_fop
= &openpromfs_prop_ops
;
761 if (inode
->i_size
< 0)
763 inode
->u
.generic_ip
= (void *)(long)(((u16
)dirnode
) |
764 (((u16
)(ino
- NODEP2INO(NODE(dir
->i_ino
).first_prop
) - 1)) << 16));
771 d_add(dentry
, inode
);
775 static int openpromfs_readdir(struct file
* filp
, void * dirent
, filldir_t filldir
)
777 struct inode
*inode
= filp
->f_dentry
->d_inode
;
792 if (filldir(dirent
, ".", 1, i
, ino
, DT_DIR
) < 0) goto out
;
797 if (filldir(dirent
, "..", 2, i
,
798 (NODE(ino
).parent
== 0xffff) ?
799 OPENPROM_ROOT_INO
: NODE2INO(NODE(ino
).parent
), DT_DIR
) < 0)
806 node
= NODE(ino
).child
;
807 while (i
&& node
!= 0xffff) {
808 node
= nodes
[node
].next
;
811 while (node
!= 0xffff) {
812 if (prom_getname (nodes
[node
].node
, buffer
, 128) < 0)
814 if (filldir(dirent
, buffer
, strlen(buffer
),
815 filp
->f_pos
, NODE2INO(node
), DT_DIR
) < 0)
818 node
= nodes
[node
].next
;
820 j
= NODEP2INO(NODE(ino
).first_prop
);
822 if (filldir(dirent
, ".node", 5, filp
->f_pos
, j
, DT_REG
) < 0)
828 if (ino
== OPENPROM_FIRST_INO
+ aliases
) {
829 for (j
++; i
< aliases_nodes
; i
++, j
++) {
830 if (alias_names
[i
]) {
831 if (filldir (dirent
, alias_names
[i
],
832 strlen (alias_names
[i
]),
833 filp
->f_pos
, j
, DT_REG
) < 0) goto out
;
838 for (p
= prom_firstprop (n
, buffer2
);
840 p
= prom_nextprop (n
, p
, buffer2
)) {
844 if (filldir(dirent
, p
, strlen(p
),
845 filp
->f_pos
, j
, DT_REG
) < 0)
857 static int openpromfs_create (struct inode
*dir
, struct dentry
*dentry
, int mode
,
858 struct nameidata
*nd
)
865 if (dentry
->d_name
.len
> 256)
867 p
= kmalloc (dentry
->d_name
.len
+ 1, GFP_KERNEL
);
870 strncpy (p
, dentry
->d_name
.name
, dentry
->d_name
.len
);
871 p
[dentry
->d_name
.len
] = 0;
873 if (aliases_nodes
== ALIASES_NNODES
) {
878 alias_names
[aliases_nodes
++] = p
;
879 inode
= iget (dir
->i_sb
,
880 NODEP2INO(NODE(dir
->i_ino
).first_prop
) + aliases_nodes
);
885 inode
->i_mode
= S_IFREG
| S_IRUGO
| S_IWUSR
;
886 inode
->i_fop
= &openpromfs_prop_ops
;
888 if (inode
->i_size
< 0) inode
->i_size
= 0;
889 inode
->u
.generic_ip
= (void *)(long)(((u16
)aliases
) |
890 (((u16
)(aliases_nodes
- 1)) << 16));
892 d_instantiate(dentry
, inode
);
896 static int openpromfs_unlink (struct inode
*dir
, struct dentry
*dentry
)
903 name
= dentry
->d_name
.name
;
904 len
= dentry
->d_name
.len
;
906 for (i
= 0; i
< aliases_nodes
; i
++)
907 if ((strlen (alias_names
[i
]) == len
)
908 && !strncmp (name
, alias_names
[i
], len
)) {
912 alias_names
[i
] = NULL
;
914 strcpy (buffer
, "nvunalias ");
915 memcpy (buffer
+ 10, name
, len
);
916 buffer
[10 + len
] = 0;
923 /* {{{ init section */
924 static int __init
check_space (u16 n
)
928 if ((1 << alloced
) * PAGE_SIZE
< (n
+ 2) * sizeof(openpromfs_node
)) {
929 pages
= __get_free_pages (GFP_KERNEL
, alloced
+ 1);
934 memcpy ((char *)pages
, (char *)nodes
,
935 (1 << alloced
) * PAGE_SIZE
);
936 free_pages ((unsigned long)nodes
, alloced
);
939 nodes
= (openpromfs_node
*)pages
;
944 static u16 __init
get_nodes (u16 parent
, u32 node
)
947 u16 n
= last_node
++, i
;
950 if (check_space (n
) < 0)
952 nodes
[n
].parent
= parent
;
953 nodes
[n
].node
= node
;
954 nodes
[n
].next
= 0xffff;
955 nodes
[n
].child
= 0xffff;
956 nodes
[n
].first_prop
= first_prop
++;
961 if ((j
= prom_getproperty (node
, "name", buffer
, 8)) >= 0) {
963 if (!strcmp (buffer
, "options"))
965 else if (!strcmp (buffer
, "aliases"))
970 for (p
= prom_firstprop (node
, buffer
);
971 p
&& p
!= (char *)-1 && *p
;
972 p
= prom_nextprop (node
, p
, buffer
))
976 for (p
= prom_firstprop (node
, buffer
);
977 p
&& p
!= (char *)-1 && *p
;
978 p
= prom_nextprop (node
, p
, buffer
)) {
979 if (aliases_nodes
== ALIASES_NNODES
)
981 for (i
= 0; i
< aliases_nodes
; i
++)
982 if (!strcmp (p
, alias_names
[i
]))
984 if (i
< aliases_nodes
)
986 q
= kmalloc (strlen (p
) + 1, GFP_KERNEL
);
990 alias_names
[aliases_nodes
++] = q
;
992 first_prop
+= ALIASES_NNODES
;
994 node
= prom_getchild (node
);
996 parent
= get_nodes (n
, node
);
997 if (parent
== 0xffff)
999 nodes
[n
].child
= parent
;
1000 while ((node
= prom_getsibling (node
)) != 0) {
1001 i
= get_nodes (n
, node
);
1004 nodes
[parent
].next
= i
;
1011 static void openprom_read_inode(struct inode
* inode
)
1013 inode
->i_mtime
= inode
->i_atime
= inode
->i_ctime
= CURRENT_TIME
;
1014 if (inode
->i_ino
== OPENPROM_ROOT_INO
) {
1015 inode
->i_op
= &openprom_inode_operations
;
1016 inode
->i_fop
= &openprom_operations
;
1017 inode
->i_mode
= S_IFDIR
| S_IRUGO
| S_IXUGO
;
1021 static int openprom_remount(struct super_block
*sb
, int *flags
, char *data
)
1023 *flags
|= MS_NOATIME
;
1027 static struct super_operations openprom_sops
= {
1028 .read_inode
= openprom_read_inode
,
1029 .statfs
= simple_statfs
,
1030 .remount_fs
= openprom_remount
,
1033 static int openprom_fill_super(struct super_block
*s
, void *data
, int silent
)
1035 struct inode
* root_inode
;
1037 s
->s_flags
|= MS_NOATIME
;
1038 s
->s_blocksize
= 1024;
1039 s
->s_blocksize_bits
= 10;
1040 s
->s_magic
= OPENPROM_SUPER_MAGIC
;
1041 s
->s_op
= &openprom_sops
;
1043 root_inode
= iget(s
, OPENPROM_ROOT_INO
);
1046 s
->s_root
= d_alloc_root(root_inode
);
1052 printk("openprom_fill_super: get root inode failed\n");
1057 static struct super_block
*openprom_get_sb(struct file_system_type
*fs_type
,
1058 int flags
, const char *dev_name
, void *data
)
1060 return get_sb_single(fs_type
, flags
, data
, openprom_fill_super
);
1063 static struct file_system_type openprom_fs_type
= {
1064 .owner
= THIS_MODULE
,
1065 .name
= "openpromfs",
1066 .get_sb
= openprom_get_sb
,
1067 .kill_sb
= kill_anon_super
,
1070 static int __init
init_openprom_fs(void)
1072 nodes
= (openpromfs_node
*)__get_free_pages(GFP_KERNEL
, 0);
1074 printk (KERN_WARNING
"openpromfs: can't get free page\n");
1077 if (get_nodes (0xffff, prom_root_node
) == 0xffff) {
1078 printk (KERN_WARNING
"openpromfs: couldn't setup tree\n");
1081 nodes
[last_node
].first_prop
= first_prop
;
1082 return register_filesystem(&openprom_fs_type
);
1085 static void __exit
exit_openprom_fs(void)
1088 unregister_filesystem(&openprom_fs_type
);
1089 free_pages ((unsigned long)nodes
, alloced
);
1090 for (i
= 0; i
< aliases_nodes
; i
++)
1091 kfree (alias_names
[i
]);
1095 module_init(init_openprom_fs
)
1096 module_exit(exit_openprom_fs
)
1097 MODULE_LICENSE("GPL");