2 * JFFS2 -- Journalling Flash File System, Version 2.
4 * Copyright (C) 2001-2003 Red Hat, Inc.
6 * Created by David Woodhouse <dwmw2@infradead.org>
8 * For licensing information, see the file 'LICENCE' in this directory.
10 * $Id: read.c,v 1.42 2005/11/07 11:14:41 gleixner Exp $
14 #include <linux/kernel.h>
15 #include <linux/slab.h>
16 #include <linux/crc32.h>
17 #include <linux/pagemap.h>
18 #include <linux/mtd/mtd.h>
19 #include <linux/compiler.h>
23 int jffs2_read_dnode(struct jffs2_sb_info
*c
, struct jffs2_inode_info
*f
,
24 struct jffs2_full_dnode
*fd
, unsigned char *buf
,
27 struct jffs2_raw_inode
*ri
;
30 unsigned char *decomprbuf
= NULL
;
31 unsigned char *readbuf
= NULL
;
34 ri
= jffs2_alloc_raw_inode();
38 ret
= jffs2_flash_read(c
, ref_offset(fd
->raw
), sizeof(*ri
), &readlen
, (char *)ri
);
40 jffs2_free_raw_inode(ri
);
41 printk(KERN_WARNING
"Error reading node from 0x%08x: %d\n", ref_offset(fd
->raw
), ret
);
44 if (readlen
!= sizeof(*ri
)) {
45 jffs2_free_raw_inode(ri
);
46 printk(KERN_WARNING
"Short read from 0x%08x: wanted 0x%zx bytes, got 0x%zx\n",
47 ref_offset(fd
->raw
), sizeof(*ri
), readlen
);
50 crc
= crc32(0, ri
, sizeof(*ri
)-8);
52 D1(printk(KERN_DEBUG
"Node read from %08x: node_crc %08x, calculated CRC %08x. dsize %x, csize %x, offset %x, buf %p\n",
53 ref_offset(fd
->raw
), je32_to_cpu(ri
->node_crc
),
54 crc
, je32_to_cpu(ri
->dsize
), je32_to_cpu(ri
->csize
),
55 je32_to_cpu(ri
->offset
), buf
));
56 if (crc
!= je32_to_cpu(ri
->node_crc
)) {
57 printk(KERN_WARNING
"Node CRC %08x != calculated CRC %08x for node at %08x\n",
58 je32_to_cpu(ri
->node_crc
), crc
, ref_offset(fd
->raw
));
62 /* There was a bug where we wrote hole nodes out with csize/dsize
63 swapped. Deal with it */
64 if (ri
->compr
== JFFS2_COMPR_ZERO
&& !je32_to_cpu(ri
->dsize
) &&
65 je32_to_cpu(ri
->csize
)) {
66 ri
->dsize
= ri
->csize
;
67 ri
->csize
= cpu_to_je32(0);
70 D1(if(ofs
+ len
> je32_to_cpu(ri
->dsize
)) {
71 printk(KERN_WARNING
"jffs2_read_dnode() asked for %d bytes at %d from %d-byte node\n",
72 len
, ofs
, je32_to_cpu(ri
->dsize
));
78 if (ri
->compr
== JFFS2_COMPR_ZERO
) {
84 Reading whole node and it's uncompressed - read directly to buffer provided, check CRC.
85 Reading whole node and it's compressed - read into comprbuf, check CRC and decompress to buffer provided
86 Reading partial node and it's uncompressed - read into readbuf, check CRC, and copy
87 Reading partial node and it's compressed - read into readbuf, check checksum, decompress to decomprbuf and copy
89 if (ri
->compr
== JFFS2_COMPR_NONE
&& len
== je32_to_cpu(ri
->dsize
)) {
92 readbuf
= kmalloc(je32_to_cpu(ri
->csize
), GFP_KERNEL
);
98 if (ri
->compr
!= JFFS2_COMPR_NONE
) {
99 if (len
< je32_to_cpu(ri
->dsize
)) {
100 decomprbuf
= kmalloc(je32_to_cpu(ri
->dsize
), GFP_KERNEL
);
109 decomprbuf
= readbuf
;
112 D2(printk(KERN_DEBUG
"Read %d bytes to %p\n", je32_to_cpu(ri
->csize
),
114 ret
= jffs2_flash_read(c
, (ref_offset(fd
->raw
)) + sizeof(*ri
),
115 je32_to_cpu(ri
->csize
), &readlen
, readbuf
);
117 if (!ret
&& readlen
!= je32_to_cpu(ri
->csize
))
122 crc
= crc32(0, readbuf
, je32_to_cpu(ri
->csize
));
123 if (crc
!= je32_to_cpu(ri
->data_crc
)) {
124 printk(KERN_WARNING
"Data CRC %08x != calculated CRC %08x for node at %08x\n",
125 je32_to_cpu(ri
->data_crc
), crc
, ref_offset(fd
->raw
));
129 D2(printk(KERN_DEBUG
"Data CRC matches calculated CRC %08x\n", crc
));
130 if (ri
->compr
!= JFFS2_COMPR_NONE
) {
131 D2(printk(KERN_DEBUG
"Decompress %d bytes from %p to %d bytes at %p\n",
132 je32_to_cpu(ri
->csize
), readbuf
, je32_to_cpu(ri
->dsize
), decomprbuf
));
133 ret
= jffs2_decompress(c
, f
, ri
->compr
| (ri
->usercompr
<< 8), readbuf
, decomprbuf
, je32_to_cpu(ri
->csize
), je32_to_cpu(ri
->dsize
));
135 printk(KERN_WARNING
"Error: jffs2_decompress returned %d\n", ret
);
140 if (len
< je32_to_cpu(ri
->dsize
)) {
141 memcpy(buf
, decomprbuf
+ofs
, len
);
144 if(decomprbuf
!= buf
&& decomprbuf
!= readbuf
)
150 jffs2_free_raw_inode(ri
);
155 int jffs2_read_inode_range(struct jffs2_sb_info
*c
, struct jffs2_inode_info
*f
,
156 unsigned char *buf
, uint32_t offset
, uint32_t len
)
158 uint32_t end
= offset
+ len
;
159 struct jffs2_node_frag
*frag
;
162 D1(printk(KERN_DEBUG
"jffs2_read_inode_range: ino #%u, range 0x%08x-0x%08x\n",
163 f
->inocache
->ino
, offset
, offset
+len
));
165 frag
= jffs2_lookup_node_frag(&f
->fragtree
, offset
);
167 /* XXX FIXME: Where a single physical node actually shows up in two
168 frags, we read it twice. Don't do that. */
169 /* Now we're pointing at the first frag which overlaps our page */
170 while(offset
< end
) {
171 D2(printk(KERN_DEBUG
"jffs2_read_inode_range: offset %d, end %d\n", offset
, end
));
172 if (unlikely(!frag
|| frag
->ofs
> offset
)) {
173 uint32_t holesize
= end
- offset
;
175 D1(printk(KERN_NOTICE
"Eep. Hole in ino #%u fraglist. frag->ofs = 0x%08x, offset = 0x%08x\n", f
->inocache
->ino
, frag
->ofs
, offset
));
176 holesize
= min(holesize
, frag
->ofs
- offset
);
178 D1(printk(KERN_DEBUG
"Filling non-frag hole from %d-%d\n", offset
, offset
+holesize
));
179 memset(buf
, 0, holesize
);
183 } else if (unlikely(!frag
->node
)) {
184 uint32_t holeend
= min(end
, frag
->ofs
+ frag
->size
);
185 D1(printk(KERN_DEBUG
"Filling frag hole from %d-%d (frag 0x%x 0x%x)\n", offset
, holeend
, frag
->ofs
, frag
->ofs
+ frag
->size
));
186 memset(buf
, 0, holeend
- offset
);
187 buf
+= holeend
- offset
;
189 frag
= frag_next(frag
);
193 uint32_t fragofs
; /* offset within the frag to start reading */
195 fragofs
= offset
- frag
->ofs
;
196 readlen
= min(frag
->size
- fragofs
, end
- offset
);
197 D1(printk(KERN_DEBUG
"Reading %d-%d from node at 0x%08x (%d)\n",
198 frag
->ofs
+fragofs
, frag
->ofs
+fragofs
+readlen
,
199 ref_offset(frag
->node
->raw
), ref_flags(frag
->node
->raw
)));
200 ret
= jffs2_read_dnode(c
, f
, frag
->node
, buf
, fragofs
+ frag
->ofs
- frag
->node
->ofs
, readlen
);
201 D2(printk(KERN_DEBUG
"node read done\n"));
203 D1(printk(KERN_DEBUG
"jffs2_read_inode_range error %d\n",ret
));
204 memset(buf
, 0, readlen
);
209 frag
= frag_next(frag
);
210 D2(printk(KERN_DEBUG
"node read was OK. Looping\n"));