⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 scan.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * 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 + -