📄 scan.c
字号:
/* * JFFS2 -- Journalling Flash File System, Version 2. * * Copyright © 2001-2007 Red Hat, Inc. * * Created by David Woodhouse <dwmw2@infradead.org> * * For licensing information, see the file 'LICENCE' in this directory. * */#include <linux/kernel.h>#include <linux/sched.h>#include <linux/slab.h>#include <linux/mtd/mtd.h>#include <linux/pagemap.h>#include <linux/crc32.h>#include <linux/compiler.h>#include "nodelist.h"#include "summary.h"#include "debug.h"#define DEFAULT_EMPTY_SCAN_SIZE 1024#define noisy_printk(noise, args...) do { \ if (*(noise)) { \ printk(KERN_NOTICE args); \ (*(noise))--; \ if (!(*(noise))) { \ printk(KERN_NOTICE "Further such events for this erase block will not be printed\n"); \ } \ } \} while(0)static uint32_t pseudo_random;static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, unsigned char *buf, uint32_t buf_size, struct jffs2_summary *s);/* These helper functions _must_ increase ofs and also do the dirty/used space accounting. * Returning an error will abort the mount - bad checksums etc. should just mark the space * as dirty. */static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, struct jffs2_raw_inode *ri, uint32_t ofs, struct jffs2_summary *s);static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, struct jffs2_raw_dirent *rd, uint32_t ofs, struct jffs2_summary *s);static inline int min_free(struct jffs2_sb_info *c){ uint32_t min = 2 * sizeof(struct jffs2_raw_inode);#ifdef CONFIG_JFFS2_FS_WRITEBUFFER if (!jffs2_can_mark_obsolete(c) && min < c->wbuf_pagesize) return c->wbuf_pagesize;#endif return min;}static inline uint32_t EMPTY_SCAN_SIZE(uint32_t sector_size) { if (sector_size < DEFAULT_EMPTY_SCAN_SIZE) return sector_size; else return DEFAULT_EMPTY_SCAN_SIZE;}static int file_dirty(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb){ int ret; if ((ret = jffs2_prealloc_raw_node_refs(c, jeb, 1))) return ret; if ((ret = jffs2_scan_dirty_space(c, jeb, jeb->free_size))) return ret; /* Turned wasted size into dirty, since we apparently think it's recoverable now. */ jeb->dirty_size += jeb->wasted_size; c->dirty_size += jeb->wasted_size; c->wasted_size -= jeb->wasted_size; jeb->wasted_size = 0; if (VERYDIRTY(c, jeb->dirty_size)) { list_add(&jeb->list, &c->very_dirty_list); } else { list_add(&jeb->list, &c->dirty_list); } return 0;}int jffs2_scan_medium(struct jffs2_sb_info *c){ int i, ret; uint32_t empty_blocks = 0, bad_blocks = 0; unsigned char *flashbuf = NULL; uint32_t buf_size = 0; struct jffs2_summary *s = NULL; /* summary info collected by the scan process */#ifndef __ECOS size_t pointlen; if (c->mtd->point) { ret = c->mtd->point (c->mtd, 0, c->mtd->size, &pointlen, &flashbuf); if (!ret && pointlen < c->mtd->size) { /* Don't muck about if it won't let us point to the whole flash */ D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", pointlen)); c->mtd->unpoint(c->mtd, flashbuf, 0, pointlen); flashbuf = NULL; } if (ret) D1(printk(KERN_DEBUG "MTD point failed %d\n", ret)); }#endif if (!flashbuf) { /* For NAND it's quicker to read a whole eraseblock at a time, apparently */ if (jffs2_cleanmarker_oob(c)) buf_size = c->sector_size; else buf_size = PAGE_SIZE; /* Respect kmalloc limitations */ if (buf_size > 128*1024) buf_size = 128*1024; D1(printk(KERN_DEBUG "Allocating readbuf of %d bytes\n", buf_size)); flashbuf = kmalloc(buf_size, GFP_KERNEL); if (!flashbuf) return -ENOMEM; } if (jffs2_sum_active()) { s = kzalloc(sizeof(struct jffs2_summary), GFP_KERNEL); if (!s) { kfree(flashbuf); JFFS2_WARNING("Can't allocate memory for summary\n"); return -ENOMEM; } } for (i=0; i<c->nr_blocks; i++) { struct jffs2_eraseblock *jeb = &c->blocks[i]; cond_resched(); /* reset summary info for next eraseblock scan */ jffs2_sum_reset_collected(s); ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset), buf_size, s); if (ret < 0) goto out; jffs2_dbg_acct_paranoia_check_nolock(c, jeb); /* Now decide which list to put it on */ switch(ret) { case BLK_STATE_ALLFF: /* * Empty block. Since we can't be sure it * was entirely erased, we just queue it for erase * again. It will be marked as such when the erase * is complete. Meanwhile we still count it as empty * for later checks. */ empty_blocks++; list_add(&jeb->list, &c->erase_pending_list); c->nr_erasing_blocks++; break; case BLK_STATE_CLEANMARKER: /* Only a CLEANMARKER node is valid */ if (!jeb->dirty_size) { /* It's actually free */ list_add(&jeb->list, &c->free_list); c->nr_free_blocks++; } else { /* Dirt */ D1(printk(KERN_DEBUG "Adding all-dirty block at 0x%08x to erase_pending_list\n", jeb->offset)); list_add(&jeb->list, &c->erase_pending_list); c->nr_erasing_blocks++; } break; case BLK_STATE_CLEAN: /* Full (or almost full) of clean data. Clean list */ list_add(&jeb->list, &c->clean_list); break; case BLK_STATE_PARTDIRTY: /* Some data, but not full. Dirty list. */ /* We want to remember the block with most free space and stick it in the 'nextblock' position to start writing to it. */ if (jeb->free_size > min_free(c) && (!c->nextblock || c->nextblock->free_size < jeb->free_size)) { /* Better candidate for the next writes to go to */ if (c->nextblock) { ret = file_dirty(c, c->nextblock); if (ret) return ret; /* deleting summary information of the old nextblock */ jffs2_sum_reset_collected(c->summary); } /* update collected summary information for the current nextblock */ jffs2_sum_move_collected(c, s); D1(printk(KERN_DEBUG "jffs2_scan_medium(): new nextblock = 0x%08x\n", jeb->offset)); c->nextblock = jeb; } else { ret = file_dirty(c, jeb); if (ret) return ret; } break; case BLK_STATE_ALLDIRTY: /* Nothing valid - not even a clean marker. Needs erasing. */ /* For now we just put it on the erasing list. We'll start the erases later */ D1(printk(KERN_NOTICE "JFFS2: Erase block at 0x%08x is not formatted. It will be erased\n", jeb->offset)); list_add(&jeb->list, &c->erase_pending_list); c->nr_erasing_blocks++; break; case BLK_STATE_BADBLOCK: D1(printk(KERN_NOTICE "JFFS2: Block at 0x%08x is bad\n", jeb->offset)); list_add(&jeb->list, &c->bad_list); c->bad_size += c->sector_size; c->free_size -= c->sector_size; bad_blocks++; break; default: printk(KERN_WARNING "jffs2_scan_medium(): unknown block state\n"); BUG(); } } /* Nextblock dirty is always seen as wasted, because we cannot recycle it now */ if (c->nextblock && (c->nextblock->dirty_size)) { c->nextblock->wasted_size += c->nextblock->dirty_size; c->wasted_size += c->nextblock->dirty_size; c->dirty_size -= c->nextblock->dirty_size; c->nextblock->dirty_size = 0; }#ifdef CONFIG_JFFS2_FS_WRITEBUFFER if (!jffs2_can_mark_obsolete(c) && c->wbuf_pagesize && c->nextblock && (c->nextblock->free_size % c->wbuf_pagesize)) { /* If we're going to start writing into a block which already contains data, and the end of the data isn't page-aligned, skip a little and align it. */ uint32_t skip = c->nextblock->free_size % c->wbuf_pagesize; D1(printk(KERN_DEBUG "jffs2_scan_medium(): Skipping %d bytes in nextblock to ensure page alignment\n", skip)); jffs2_prealloc_raw_node_refs(c, c->nextblock, 1); jffs2_scan_dirty_space(c, c->nextblock, skip); }#endif if (c->nr_erasing_blocks) { if ( !c->used_size && ((c->nr_free_blocks+empty_blocks+bad_blocks)!= c->nr_blocks || bad_blocks == c->nr_blocks) ) { printk(KERN_NOTICE "Cowardly refusing to erase blocks on filesystem with no valid JFFS2 nodes\n"); printk(KERN_NOTICE "empty_blocks %d, bad_blocks %d, c->nr_blocks %d\n",empty_blocks,bad_blocks,c->nr_blocks); ret = -EIO; goto out; } jffs2_erase_pending_trigger(c); } ret = 0; out: if (buf_size) kfree(flashbuf);#ifndef __ECOS else c->mtd->unpoint(c->mtd, flashbuf, 0, c->mtd->size);#endif if (s) kfree(s); return ret;}static int jffs2_fill_scan_buf(struct jffs2_sb_info *c, void *buf, uint32_t ofs, uint32_t len){ int ret; size_t retlen; ret = jffs2_flash_read(c, ofs, len, &retlen, buf); if (ret) { D1(printk(KERN_WARNING "mtd->read(0x%x bytes from 0x%x) returned %d\n", len, ofs, ret)); return ret; } if (retlen < len) { D1(printk(KERN_WARNING "Read at 0x%x gave only 0x%zx bytes\n", ofs, retlen)); return -EIO; } return 0;}int jffs2_scan_classify_jeb(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb){ if ((jeb->used_size + jeb->unchecked_size) == PAD(c->cleanmarker_size) && !jeb->dirty_size && (!jeb->first_node || !ref_next(jeb->first_node)) ) return BLK_STATE_CLEANMARKER; /* move blocks with max 4 byte dirty space to cleanlist */ else if (!ISDIRTY(c->sector_size - (jeb->used_size + jeb->unchecked_size))) { c->dirty_size -= jeb->dirty_size; c->wasted_size += jeb->dirty_size; jeb->wasted_size += jeb->dirty_size; jeb->dirty_size = 0; return BLK_STATE_CLEAN; } else if (jeb->used_size || jeb->unchecked_size) return BLK_STATE_PARTDIRTY; else return BLK_STATE_ALLDIRTY;}#ifdef CONFIG_JFFS2_FS_XATTRstatic int jffs2_scan_xattr_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, struct jffs2_raw_xattr *rx, uint32_t ofs, struct jffs2_summary *s){ struct jffs2_xattr_datum *xd; uint32_t xid, version, totlen, crc; int err; crc = crc32(0, rx, sizeof(struct jffs2_raw_xattr) - 4); if (crc != je32_to_cpu(rx->node_crc)) { JFFS2_WARNING("node CRC failed at %#08x, read=%#08x, calc=%#08x\n", ofs, je32_to_cpu(rx->node_crc), crc); if ((err = jffs2_scan_dirty_space(c, jeb, je32_to_cpu(rx->totlen)))) return err; return 0; } xid = je32_to_cpu(rx->xid); version = je32_to_cpu(rx->version); totlen = PAD(sizeof(struct jffs2_raw_xattr) + rx->name_len + 1 + je16_to_cpu(rx->value_len)); if (totlen != je32_to_cpu(rx->totlen)) { JFFS2_WARNING("node length mismatch at %#08x, read=%u, calc=%u\n", ofs, je32_to_cpu(rx->totlen), totlen); if ((err = jffs2_scan_dirty_space(c, jeb, je32_to_cpu(rx->totlen)))) return err; return 0; } xd = jffs2_setup_xattr_datum(c, xid, version); if (IS_ERR(xd)) return PTR_ERR(xd); if (xd->version > version) { struct jffs2_raw_node_ref *raw = jffs2_link_node_ref(c, jeb, ofs | REF_PRISTINE, totlen, NULL); raw->next_in_ino = xd->node->next_in_ino; xd->node->next_in_ino = raw; } else { xd->version = version; xd->xprefix = rx->xprefix; xd->name_len = rx->name_len; xd->value_len = je16_to_cpu(rx->value_len); xd->data_crc = je32_to_cpu(rx->data_crc); jffs2_link_node_ref(c, jeb, ofs | REF_PRISTINE, totlen, (void *)xd); } if (jffs2_sum_active()) jffs2_sum_add_xattr_mem(s, rx, ofs - jeb->offset); dbg_xattr("scaning xdatum at %#08x (xid=%u, version=%u)\n", ofs, xd->xid, xd->version); return 0;}static int jffs2_scan_xref_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, struct jffs2_raw_xref *rr, uint32_t ofs, struct jffs2_summary *s){ struct jffs2_xattr_ref *ref; uint32_t crc; int err; crc = crc32(0, rr, sizeof(*rr) - 4);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -