aboutsummaryrefslogtreecommitdiffstats
path: root/fs/jffs2
diff options
context:
space:
mode:
Diffstat (limited to 'fs/jffs2')
-rw-r--r--fs/jffs2/nodelist.c597
1 files changed, 336 insertions, 261 deletions
diff --git a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c
index 4991c348f6ec..a04111530f4d 100644
--- a/fs/jffs2/nodelist.c
+++ b/fs/jffs2/nodelist.c
@@ -7,7 +7,7 @@
7 * 7 *
8 * For licensing information, see the file 'LICENCE' in this directory. 8 * For licensing information, see the file 'LICENCE' in this directory.
9 * 9 *
10 * $Id: nodelist.c,v 1.98 2005/07/10 15:15:32 dedekind Exp $ 10 * $Id: nodelist.c,v 1.99 2005/07/15 10:13:54 dedekind Exp $
11 * 11 *
12 */ 12 */
13 13
@@ -137,6 +137,307 @@ static struct jffs2_raw_node_ref *jffs2_first_valid_node(struct jffs2_raw_node_r
137 return NULL; 137 return NULL;
138} 138}
139 139
140/*
141 * Helper function for jffs2_get_inode_nodes().
142 * It is called every time an directory entry node is found.
143 *
144 * Returns: 0 on succes;
145 * 1 if the node should be marked obsolete;
146 * negative error code on failure.
147 */
148static inline int
149read_direntry(struct jffs2_sb_info *c,
150 struct jffs2_raw_node_ref *ref,
151 struct jffs2_raw_dirent *rd,
152 uint32_t read,
153 struct jffs2_full_dirent **fdp,
154 int32_t *latest_mctime,
155 uint32_t *mctime_ver)
156{
157 struct jffs2_full_dirent *fd;
158
159 /* The direntry nodes are checked during the flash scanning */
160 BUG_ON(ref_flags(ref) == REF_UNCHECKED);
161 /* Obsoleted. This cannot happen, surely? dwmw2 20020308 */
162 BUG_ON(ref_obsolete(ref));
163
164 /* Sanity check */
165 if (unlikely(PAD((rd->nsize + sizeof(*rd))) != PAD(je32_to_cpu(rd->totlen)))) {
166 printk(KERN_ERR "Error! Illegal nsize in node at %#08x: nsize %#02x, totlen %#04x\n",
167 ref_offset(ref), rd->nsize, je32_to_cpu(rd->totlen));
168 return 1;
169 }
170
171 fd = jffs2_alloc_full_dirent(rd->nsize + 1);
172 if (unlikely(!fd))
173 return -ENOMEM;
174
175 fd->raw = ref;
176 fd->version = je32_to_cpu(rd->version);
177 fd->ino = je32_to_cpu(rd->ino);
178 fd->type = rd->type;
179
180 /* Pick out the mctime of the latest dirent */
181 if(fd->version > *mctime_ver) {
182 *mctime_ver = fd->version;
183 *latest_mctime = je32_to_cpu(rd->mctime);
184 }
185
186 /*
187 * Copy as much of the name as possible from the raw
188 * dirent we've already read from the flash.
189 */
190 if (read > sizeof(*rd))
191 memcpy(&fd->name[0], &rd->name[0],
192 min_t(uint32_t, rd->nsize, (read - sizeof(*rd)) ));
193
194 /* Do we need to copy any more of the name directly from the flash? */
195 if (rd->nsize + sizeof(*rd) > read) {
196 /* FIXME: point() */
197 int err;
198 int already = read - sizeof(*rd);
199
200 err = jffs2_flash_read(c, (ref_offset(ref)) + read,
201 rd->nsize - already, &read, &fd->name[already]);
202 if (unlikely(read != rd->nsize - already) && likely(!err))
203 return -EIO;
204
205 if (unlikely(err)) {
206 printk(KERN_WARNING "Read remainder of name in jffs2_get_inode_nodes(): error %d\n", err);
207 jffs2_free_full_dirent(fd);
208 return -EIO;
209 }
210 }
211
212 fd->nhash = full_name_hash(fd->name, rd->nsize);
213 fd->next = NULL;
214 fd->name[rd->nsize] = '\0';
215
216 /*
217 * Wheee. We now have a complete jffs2_full_dirent structure, with
218 * the name in it and everything. Link it into the list
219 */
220 D1(printk(KERN_DEBUG "Adding fd \"%s\", ino #%u\n", fd->name, fd->ino));
221
222 jffs2_add_fd_to_list(c, fd, fdp);
223
224 return 0;
225}
226
227/*
228 * Helper function for jffs2_get_inode_nodes().
229 * It is called every time an inode node is found.
230 *
231 * Returns: 0 on succes;
232 * 1 if the node should be marked obsolete;
233 * negative error code on failure.
234 */
235static inline int
236read_dnode(struct jffs2_sb_info *c,
237 struct jffs2_raw_node_ref *ref,
238 struct jffs2_raw_inode *rd,
239 uint32_t read,
240 struct rb_root *tnp,
241 int32_t *latest_mctime,
242 uint32_t *mctime_ver)
243{
244 struct jffs2_eraseblock *jeb;
245 struct jffs2_tmp_dnode_info *tn;
246
247 /* Obsoleted. This cannot happen, surely? dwmw2 20020308 */
248 BUG_ON(ref_obsolete(ref));
249
250 /* If we've never checked the CRCs on this node, check them now */
251 if (ref_flags(ref) == REF_UNCHECKED) {
252 uint32_t crc, len;
253
254 crc = crc32(0, rd, sizeof(*rd) - 8);
255 if (unlikely(crc != je32_to_cpu(rd->node_crc))) {
256 printk(KERN_WARNING "Header CRC failed on node at %#08x: read %#08x, calculated %#08x\n",
257 ref_offset(ref), je32_to_cpu(rd->node_crc), crc);
258 return 1;
259 }
260
261 /* Sanity checks */
262 if (unlikely(je32_to_cpu(rd->offset) > je32_to_cpu(rd->isize)) ||
263 unlikely(PAD(je32_to_cpu(rd->csize) + sizeof(*rd)) != PAD(je32_to_cpu(rd->totlen)))) {
264 printk(KERN_WARNING "Inode corrupted at %#08x, totlen %d, #ino %d, version %d, "
265 "isize %d, csize %d, dsize %d \n",
266 ref_offset(ref), je32_to_cpu(rd->totlen), je32_to_cpu(rd->ino),
267 je32_to_cpu(rd->version), je32_to_cpu(rd->isize),
268 je32_to_cpu(rd->csize), je32_to_cpu(rd->dsize));
269 return 1;
270 }
271
272 if (rd->compr != JFFS2_COMPR_ZERO && je32_to_cpu(rd->csize)) {
273 unsigned char *buf = NULL;
274 uint32_t pointed = 0;
275 int err;
276#ifndef __ECOS
277 if (c->mtd->point) {
278 err = c->mtd->point (c->mtd, ref_offset(ref) + sizeof(*rd), je32_to_cpu(rd->csize),
279 &read, &buf);
280 if (unlikely(read < je32_to_cpu(rd->csize)) && likely(!err)) {
281 D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", read));
282 c->mtd->unpoint(c->mtd, buf, ref_offset(ref) + sizeof(*rd),
283 je32_to_cpu(rd->csize));
284 } else if (unlikely(err)){
285 D1(printk(KERN_DEBUG "MTD point failed %d\n", err));
286 } else
287 pointed = 1; /* succefully pointed to device */
288 }
289#endif
290 if(!pointed){
291 buf = kmalloc(je32_to_cpu(rd->csize), GFP_KERNEL);
292 if (!buf)
293 return -ENOMEM;
294
295 err = jffs2_flash_read(c, ref_offset(ref) + sizeof(*rd), je32_to_cpu(rd->csize),
296 &read, buf);
297 if (unlikely(read != je32_to_cpu(rd->csize)) && likely(!err))
298 err = -EIO;
299 if (err) {
300 kfree(buf);
301 return err;
302 }
303 }
304 crc = crc32(0, buf, je32_to_cpu(rd->csize));
305 if(!pointed)
306 kfree(buf);
307#ifndef __ECOS
308 else
309 c->mtd->unpoint(c->mtd, buf, ref_offset(ref) + sizeof(*rd), je32_to_cpu(rd->csize));
310#endif
311
312 if (crc != je32_to_cpu(rd->data_crc)) {
313 printk(KERN_NOTICE "Data CRC failed on node at %#08x: read %#08x, calculated %#08x\n",
314 ref_offset(ref), je32_to_cpu(rd->data_crc), crc);
315 return 1;
316 }
317
318 }
319
320 /* Mark the node as having been checked and fix the accounting accordingly */
321 jeb = &c->blocks[ref->flash_offset / c->sector_size];
322 len = ref_totlen(c, jeb, ref);
323
324 spin_lock(&c->erase_completion_lock);
325 jeb->used_size += len;
326 jeb->unchecked_size -= len;
327 c->used_size += len;
328 c->unchecked_size -= len;
329
330 /* If node covers at least a whole page, or if it starts at the
331 beginning of a page and runs to the end of the file, or if
332 it's a hole node, mark it REF_PRISTINE, else REF_NORMAL.
333
334 If it's actually overlapped, it'll get made NORMAL (or OBSOLETE)
335 when the overlapping node(s) get added to the tree anyway.
336 */
337 if ((je32_to_cpu(rd->dsize) >= PAGE_CACHE_SIZE) ||
338 ( ((je32_to_cpu(rd->offset) & (PAGE_CACHE_SIZE-1))==0) &&
339 (je32_to_cpu(rd->dsize) + je32_to_cpu(rd->offset) == je32_to_cpu(rd->isize)))) {
340 D1(printk(KERN_DEBUG "Marking node at %#08x REF_PRISTINE\n", ref_offset(ref)));
341 ref->flash_offset = ref_offset(ref) | REF_PRISTINE;
342 } else {
343 D1(printk(KERN_DEBUG "Marking node at %#08x REF_NORMAL\n", ref_offset(ref)));
344 ref->flash_offset = ref_offset(ref) | REF_NORMAL;
345 }
346 spin_unlock(&c->erase_completion_lock);
347 }
348
349 tn = jffs2_alloc_tmp_dnode_info();
350 if (!tn) {
351 D1(printk(KERN_DEBUG "alloc tn failed\n"));
352 return -ENOMEM;
353 }
354
355 tn->fn = jffs2_alloc_full_dnode();
356 if (!tn->fn) {
357 D1(printk(KERN_DEBUG "alloc fn failed\n"));
358 jffs2_free_tmp_dnode_info(tn);
359 return -ENOMEM;
360 }
361
362 tn->version = je32_to_cpu(rd->version);
363 tn->fn->ofs = je32_to_cpu(rd->offset);
364 tn->fn->raw = ref;
365
366 /* There was a bug where we wrote hole nodes out with
367 csize/dsize swapped. Deal with it */
368 if (rd->compr == JFFS2_COMPR_ZERO && !je32_to_cpu(rd->dsize) && je32_to_cpu(rd->csize))
369 tn->fn->size = je32_to_cpu(rd->csize);
370 else // normal case...
371 tn->fn->size = je32_to_cpu(rd->dsize);
372
373 D1(printk(KERN_DEBUG "dnode @%08x: ver %u, offset %#04x, dsize %#04x\n",
374 ref_offset(ref), je32_to_cpu(rd->version),
375 je32_to_cpu(rd->offset), je32_to_cpu(rd->dsize)));
376
377 jffs2_add_tn_to_tree(tn, tnp);
378
379 return 0;
380}
381
382/*
383 * Helper function for jffs2_get_inode_nodes().
384 * It is called every time an unknown node is found.
385 *
386 * Returns: 0 on succes;
387 * 1 if the node should be marked obsolete;
388 * negative error code on failure.
389 */
390static inline int
391read_unknown(struct jffs2_sb_info *c,
392 struct jffs2_raw_node_ref *ref,
393 struct jffs2_unknown_node *un,
394 uint32_t read)
395{
396 /* We don't mark unknown nodes as REF_UNCHECKED */
397 BUG_ON(ref_flags(ref) == REF_UNCHECKED);
398
399 un->nodetype = cpu_to_je16(JFFS2_NODE_ACCURATE | je16_to_cpu(un->nodetype));
400
401 if (crc32(0, un, sizeof(struct jffs2_unknown_node) - 4) != je32_to_cpu(un->hdr_crc)) {
402
403 /* Hmmm. This should have been caught at scan time. */
404 printk(KERN_WARNING "Warning! Node header CRC failed at %#08x. "
405 "But it must have been OK earlier.\n", ref_offset(ref));
406 D1(printk(KERN_DEBUG "Node was: { %#04x, %#04x, %#08x, %#08x }\n",
407 je16_to_cpu(un->magic), je16_to_cpu(un->nodetype),
408 je32_to_cpu(un->totlen), je32_to_cpu(un->hdr_crc)));
409 return 1;
410 } else {
411 switch(je16_to_cpu(un->nodetype) & JFFS2_COMPAT_MASK) {
412
413 case JFFS2_FEATURE_INCOMPAT:
414 printk(KERN_NOTICE "Unknown INCOMPAT nodetype %#04X at %#08x\n",
415 je16_to_cpu(un->nodetype), ref_offset(ref));
416 /* EEP */
417 BUG();
418 break;
419
420 case JFFS2_FEATURE_ROCOMPAT:
421 printk(KERN_NOTICE "Unknown ROCOMPAT nodetype %#04X at %#08x\n",
422 je16_to_cpu(un->nodetype), ref_offset(ref));
423 BUG_ON(!(c->flags & JFFS2_SB_FLAG_RO));
424 break;
425
426 case JFFS2_FEATURE_RWCOMPAT_COPY:
427 printk(KERN_NOTICE "Unknown RWCOMPAT_COPY nodetype %#04X at %#08x\n",
428 je16_to_cpu(un->nodetype), ref_offset(ref));
429 break;
430
431 case JFFS2_FEATURE_RWCOMPAT_DELETE:
432 printk(KERN_NOTICE "Unknown RWCOMPAT_DELETE nodetype %#04X at %#08x\n",
433 je16_to_cpu(un->nodetype), ref_offset(ref));
434 return 1;
435 }
436 }
437
438 return 0;
439}
440
140/* Get tmp_dnode_info and full_dirent for all non-obsolete nodes associated 441/* Get tmp_dnode_info and full_dirent for all non-obsolete nodes associated
141 with this ino, returning the former in order of version */ 442 with this ino, returning the former in order of version */
142 443
@@ -146,9 +447,8 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
146 uint32_t *mctime_ver) 447 uint32_t *mctime_ver)
147{ 448{
148 struct jffs2_raw_node_ref *ref, *valid_ref; 449 struct jffs2_raw_node_ref *ref, *valid_ref;
149 struct jffs2_tmp_dnode_info *tn;
150 struct rb_root ret_tn = RB_ROOT; 450 struct rb_root ret_tn = RB_ROOT;
151 struct jffs2_full_dirent *fd, *ret_fd = NULL; 451 struct jffs2_full_dirent *ret_fd = NULL;
152 union jffs2_node_union node; 452 union jffs2_node_union node;
153 size_t retlen; 453 size_t retlen;
154 int err; 454 int err;
@@ -186,292 +486,67 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
186 goto free_out; 486 goto free_out;
187 } 487 }
188 488
189
190 /* Check we've managed to read at least the common node header */
191 if (retlen < min_t(uint32_t, ref_totlen(c, NULL, ref), sizeof(node.u))) {
192 printk(KERN_WARNING "short read in get_inode_nodes()\n");
193 err = -EIO;
194 goto free_out;
195 }
196
197 switch (je16_to_cpu(node.u.nodetype)) { 489 switch (je16_to_cpu(node.u.nodetype)) {
490
198 case JFFS2_NODETYPE_DIRENT: 491 case JFFS2_NODETYPE_DIRENT:
199 D1(printk(KERN_DEBUG "Node at %08x (%d) is a dirent node\n", ref_offset(ref), ref_flags(ref))); 492 D1(printk(KERN_DEBUG "Node at %08x (%d) is a dirent node\n", ref_offset(ref), ref_flags(ref)));
200 if (ref_flags(ref) == REF_UNCHECKED) { 493
201 printk(KERN_WARNING "BUG: Dirent node at 0x%08x never got checked? How?\n", ref_offset(ref));
202 BUG();
203 }
204 if (retlen < sizeof(node.d)) { 494 if (retlen < sizeof(node.d)) {
205 printk(KERN_WARNING "short read in get_inode_nodes()\n"); 495 printk(KERN_WARNING "Warning! Short read dirent at %#08x\n", ref_offset(ref));
206 err = -EIO; 496 err = -EIO;
207 goto free_out; 497 goto free_out;
208 } 498 }
209 /* sanity check */ 499
210 if (PAD((node.d.nsize + sizeof (node.d))) != PAD(je32_to_cpu (node.d.totlen))) { 500 err = read_direntry(c, ref, &node.d, retlen, &ret_fd, latest_mctime, mctime_ver);
211 printk(KERN_NOTICE "jffs2_get_inode_nodes(): Illegal nsize in node at 0x%08x: nsize 0x%02x, totlen %04x\n", 501 if (err == 1) {
212 ref_offset(ref), node.d.nsize, je32_to_cpu(node.d.totlen));
213 jffs2_mark_node_obsolete(c, ref); 502 jffs2_mark_node_obsolete(c, ref);
214 spin_lock(&c->erase_completion_lock); 503 break;
215 continue; 504 } else if (unlikely(err))
216 } 505 goto free_out;
506
217 if (je32_to_cpu(node.d.version) > *highest_version) 507 if (je32_to_cpu(node.d.version) > *highest_version)
218 *highest_version = je32_to_cpu(node.d.version); 508 *highest_version = je32_to_cpu(node.d.version);
219 if (ref_obsolete(ref)) {
220 /* Obsoleted. This cannot happen, surely? dwmw2 20020308 */
221 printk(KERN_ERR "Dirent node at 0x%08x became obsolete while we weren't looking\n",
222 ref_offset(ref));
223 BUG();
224 }
225
226 fd = jffs2_alloc_full_dirent(node.d.nsize+1);
227 if (!fd) {
228 err = -ENOMEM;
229 goto free_out;
230 }
231 fd->raw = ref;
232 fd->version = je32_to_cpu(node.d.version);
233 fd->ino = je32_to_cpu(node.d.ino);
234 fd->type = node.d.type;
235
236 /* Pick out the mctime of the latest dirent */
237 if(fd->version > *mctime_ver) {
238 *mctime_ver = fd->version;
239 *latest_mctime = je32_to_cpu(node.d.mctime);
240 }
241 509
242 /* memcpy as much of the name as possible from the raw
243 dirent we've already read from the flash
244 */
245 if (retlen > sizeof(struct jffs2_raw_dirent))
246 memcpy(&fd->name[0], &node.d.name[0], min_t(uint32_t, node.d.nsize, (retlen-sizeof(struct jffs2_raw_dirent))));
247
248 /* Do we need to copy any more of the name directly
249 from the flash?
250 */
251 if (node.d.nsize + sizeof(struct jffs2_raw_dirent) > retlen) {
252 /* FIXME: point() */
253 int already = retlen - sizeof(struct jffs2_raw_dirent);
254
255 err = jffs2_flash_read(c, (ref_offset(ref)) + retlen,
256 node.d.nsize - already, &retlen, &fd->name[already]);
257 if (!err && retlen != node.d.nsize - already)
258 err = -EIO;
259
260 if (err) {
261 printk(KERN_WARNING "Read remainder of name in jffs2_get_inode_nodes(): error %d\n", err);
262 jffs2_free_full_dirent(fd);
263 goto free_out;
264 }
265 }
266 fd->nhash = full_name_hash(fd->name, node.d.nsize);
267 fd->next = NULL;
268 fd->name[node.d.nsize] = '\0';
269 /* Wheee. We now have a complete jffs2_full_dirent structure, with
270 the name in it and everything. Link it into the list
271 */
272 D1(printk(KERN_DEBUG "Adding fd \"%s\", ino #%u\n", fd->name, fd->ino));
273 jffs2_add_fd_to_list(c, fd, &ret_fd);
274 break; 510 break;
275 511
276 case JFFS2_NODETYPE_INODE: 512 case JFFS2_NODETYPE_INODE:
277 D1(printk(KERN_DEBUG "Node at %08x (%d) is a data node\n", ref_offset(ref), ref_flags(ref))); 513 D1(printk(KERN_DEBUG "Node at %08x (%d) is a data node\n", ref_offset(ref), ref_flags(ref)));
514
278 if (retlen < sizeof(node.i)) { 515 if (retlen < sizeof(node.i)) {
279 printk(KERN_WARNING "read too short for dnode\n"); 516 printk(KERN_WARNING "Warning! Short read dnode at %#08x\n", ref_offset(ref));
280 err = -EIO; 517 err = -EIO;
281 goto free_out; 518 goto free_out;
282 } 519 }
283 if (je32_to_cpu(node.i.version) > *highest_version)
284 *highest_version = je32_to_cpu(node.i.version);
285 D1(printk(KERN_DEBUG "version %d, highest_version now %d\n", je32_to_cpu(node.i.version), *highest_version));
286
287 if (ref_obsolete(ref)) {
288 /* Obsoleted. This cannot happen, surely? dwmw2 20020308 */
289 printk(KERN_ERR "Inode node at 0x%08x became obsolete while we weren't looking\n",
290 ref_offset(ref));
291 BUG();
292 }
293
294 /* If we've never checked the CRCs on this node, check them now. */
295 if (ref_flags(ref) == REF_UNCHECKED) {
296 uint32_t crc, len;
297 struct jffs2_eraseblock *jeb;
298
299 crc = crc32(0, &node, sizeof(node.i)-8);
300 if (crc != je32_to_cpu(node.i.node_crc)) {
301 printk(KERN_NOTICE "jffs2_get_inode_nodes(): CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
302 ref_offset(ref), je32_to_cpu(node.i.node_crc), crc);
303 jffs2_mark_node_obsolete(c, ref);
304 spin_lock(&c->erase_completion_lock);
305 continue;
306 }
307
308 /* sanity checks */
309 if ( je32_to_cpu(node.i.offset) > je32_to_cpu(node.i.isize) ||
310 PAD(je32_to_cpu(node.i.csize) + sizeof (node.i)) != PAD(je32_to_cpu(node.i.totlen))) {
311 printk(KERN_NOTICE "jffs2_get_inode_nodes(): Inode corrupted at 0x%08x, totlen %d, #ino %d, version %d, isize %d, csize %d, dsize %d \n",
312 ref_offset(ref), je32_to_cpu(node.i.totlen), je32_to_cpu(node.i.ino),
313 je32_to_cpu(node.i.version), je32_to_cpu(node.i.isize),
314 je32_to_cpu(node.i.csize), je32_to_cpu(node.i.dsize));
315 jffs2_mark_node_obsolete(c, ref);
316 spin_lock(&c->erase_completion_lock);
317 continue;
318 }
319 520
320 if (node.i.compr != JFFS2_COMPR_ZERO && je32_to_cpu(node.i.csize)) { 521 err = read_dnode(c, ref, &node.i, retlen, &ret_tn, latest_mctime, mctime_ver);
321 unsigned char *buf=NULL; 522 if (err == 1) {
322 uint32_t pointed = 0; 523 jffs2_mark_node_obsolete(c, ref);
323#ifndef __ECOS 524 break;
324 if (c->mtd->point) { 525 } else if (unlikely(err))
325 err = c->mtd->point (c->mtd, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize),
326 &retlen, &buf);
327 if (!err && retlen < je32_to_cpu(node.i.csize)) {
328 D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", retlen));
329 c->mtd->unpoint(c->mtd, buf, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize));
330 } else if (err){
331 D1(printk(KERN_DEBUG "MTD point failed %d\n", err));
332 } else
333 pointed = 1; /* succefully pointed to device */
334 }
335#endif
336 if(!pointed){
337 buf = kmalloc(je32_to_cpu(node.i.csize), GFP_KERNEL);
338 if (!buf)
339 return -ENOMEM;
340
341 err = jffs2_flash_read(c, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize),
342 &retlen, buf);
343 if (!err && retlen != je32_to_cpu(node.i.csize))
344 err = -EIO;
345 if (err) {
346 kfree(buf);
347 return err;
348 }
349 }
350 crc = crc32(0, buf, je32_to_cpu(node.i.csize));
351 if(!pointed)
352 kfree(buf);
353#ifndef __ECOS
354 else
355 c->mtd->unpoint(c->mtd, buf, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize));
356#endif
357
358 if (crc != je32_to_cpu(node.i.data_crc)) {
359 printk(KERN_NOTICE "jffs2_get_inode_nodes(): Data CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
360 ref_offset(ref), je32_to_cpu(node.i.data_crc), crc);
361 jffs2_mark_node_obsolete(c, ref);
362 spin_lock(&c->erase_completion_lock);
363 continue;
364 }
365
366 }
367
368 /* Mark the node as having been checked and fix the accounting accordingly */
369 spin_lock(&c->erase_completion_lock);
370 jeb = &c->blocks[ref->flash_offset / c->sector_size];
371 len = ref_totlen(c, jeb, ref);
372
373 jeb->used_size += len;
374 jeb->unchecked_size -= len;
375 c->used_size += len;
376 c->unchecked_size -= len;
377
378 /* If node covers at least a whole page, or if it starts at the
379 beginning of a page and runs to the end of the file, or if
380 it's a hole node, mark it REF_PRISTINE, else REF_NORMAL.
381
382 If it's actually overlapped, it'll get made NORMAL (or OBSOLETE)
383 when the overlapping node(s) get added to the tree anyway.
384 */
385 if ((je32_to_cpu(node.i.dsize) >= PAGE_CACHE_SIZE) ||
386 ( ((je32_to_cpu(node.i.offset)&(PAGE_CACHE_SIZE-1))==0) &&
387 (je32_to_cpu(node.i.dsize)+je32_to_cpu(node.i.offset) == je32_to_cpu(node.i.isize)))) {
388 D1(printk(KERN_DEBUG "Marking node at 0x%08x REF_PRISTINE\n", ref_offset(ref)));
389 ref->flash_offset = ref_offset(ref) | REF_PRISTINE;
390 } else {
391 D1(printk(KERN_DEBUG "Marking node at 0x%08x REF_NORMAL\n", ref_offset(ref)));
392 ref->flash_offset = ref_offset(ref) | REF_NORMAL;
393 }
394 spin_unlock(&c->erase_completion_lock);
395 }
396
397 tn = jffs2_alloc_tmp_dnode_info();
398 if (!tn) {
399 D1(printk(KERN_DEBUG "alloc tn failed\n"));
400 err = -ENOMEM;
401 goto free_out; 526 goto free_out;
402 }
403 527
404 tn->fn = jffs2_alloc_full_dnode(); 528 if (je32_to_cpu(node.i.version) > *highest_version)
405 if (!tn->fn) { 529 *highest_version = je32_to_cpu(node.i.version);
406 D1(printk(KERN_DEBUG "alloc fn failed\n")); 530
407 err = -ENOMEM; 531 D1(printk(KERN_DEBUG "version %d, highest_version now %d\n",
408 jffs2_free_tmp_dnode_info(tn); 532 je32_to_cpu(node.i.version), *highest_version));
409 goto free_out; 533
410 }
411 tn->version = je32_to_cpu(node.i.version);
412 tn->fn->ofs = je32_to_cpu(node.i.offset);
413 /* There was a bug where we wrote hole nodes out with
414 csize/dsize swapped. Deal with it */
415 if (node.i.compr == JFFS2_COMPR_ZERO && !je32_to_cpu(node.i.dsize) && je32_to_cpu(node.i.csize))
416 tn->fn->size = je32_to_cpu(node.i.csize);
417 else // normal case...
418 tn->fn->size = je32_to_cpu(node.i.dsize);
419 tn->fn->raw = ref;
420 D1(printk(KERN_DEBUG "dnode @%08x: ver %u, offset %04x, dsize %04x\n",
421 ref_offset(ref), je32_to_cpu(node.i.version),
422 je32_to_cpu(node.i.offset), je32_to_cpu(node.i.dsize)));
423 jffs2_add_tn_to_tree(tn, &ret_tn);
424 break; 534 break;
425 535
426 default: 536 default:
427 if (ref_flags(ref) == REF_UNCHECKED) { 537 /* Check we've managed to read at least the common node header */
428 struct jffs2_eraseblock *jeb; 538 if (retlen < sizeof(struct jffs2_unknown_node)) {
429 uint32_t len; 539 printk(KERN_WARNING "Warning! Short read unknown node at %#08x\n",
430 540 ref_offset(ref));
431 printk(KERN_ERR "Eep. Unknown node type %04x at %08x was marked REF_UNCHECKED\n", 541 return -EIO;
432 je16_to_cpu(node.u.nodetype), ref_offset(ref));
433
434 /* Mark the node as having been checked and fix the accounting accordingly */
435 spin_lock(&c->erase_completion_lock);
436 jeb = &c->blocks[ref->flash_offset / c->sector_size];
437 len = ref_totlen(c, jeb, ref);
438
439 jeb->used_size += len;
440 jeb->unchecked_size -= len;
441 c->used_size += len;
442 c->unchecked_size -= len;
443
444 mark_ref_normal(ref);
445 spin_unlock(&c->erase_completion_lock);
446 } 542 }
447 node.u.nodetype = cpu_to_je16(JFFS2_NODE_ACCURATE | je16_to_cpu(node.u.nodetype)); 543
448 if (crc32(0, &node, sizeof(struct jffs2_unknown_node)-4) != je32_to_cpu(node.u.hdr_crc)) { 544 err = read_unknown(c, ref, &node.u, retlen);
449 /* Hmmm. This should have been caught at scan time. */ 545 if (err == 1) {
450 printk(KERN_ERR "Node header CRC failed at %08x. But it must have been OK earlier.\n",
451 ref_offset(ref));
452 printk(KERN_ERR "Node was: { %04x, %04x, %08x, %08x }\n",
453 je16_to_cpu(node.u.magic), je16_to_cpu(node.u.nodetype), je32_to_cpu(node.u.totlen),
454 je32_to_cpu(node.u.hdr_crc));
455 jffs2_mark_node_obsolete(c, ref);
456 } else switch(je16_to_cpu(node.u.nodetype) & JFFS2_COMPAT_MASK) {
457 case JFFS2_FEATURE_INCOMPAT:
458 printk(KERN_NOTICE "Unknown INCOMPAT nodetype %04X at %08x\n", je16_to_cpu(node.u.nodetype), ref_offset(ref));
459 /* EEP */
460 BUG();
461 break;
462 case JFFS2_FEATURE_ROCOMPAT:
463 printk(KERN_NOTICE "Unknown ROCOMPAT nodetype %04X at %08x\n", je16_to_cpu(node.u.nodetype), ref_offset(ref));
464 if (!(c->flags & JFFS2_SB_FLAG_RO))
465 BUG();
466 break;
467 case JFFS2_FEATURE_RWCOMPAT_COPY:
468 printk(KERN_NOTICE "Unknown RWCOMPAT_COPY nodetype %04X at %08x\n", je16_to_cpu(node.u.nodetype), ref_offset(ref));
469 break;
470 case JFFS2_FEATURE_RWCOMPAT_DELETE:
471 printk(KERN_NOTICE "Unknown RWCOMPAT_DELETE nodetype %04X at %08x\n", je16_to_cpu(node.u.nodetype), ref_offset(ref));
472 jffs2_mark_node_obsolete(c, ref); 546 jffs2_mark_node_obsolete(c, ref);
473 break; 547 break;
474 } 548 } else if (unlikely(err))
549 goto free_out;
475 550
476 } 551 }
477 spin_lock(&c->erase_completion_lock); 552 spin_lock(&c->erase_completion_lock);