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

📄 scan.c

📁 基于linux-2.6.28的mtd驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Copyright (c) International Business Machines Corp., 2006 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Author: Artem Bityutskiy (Битюцкий Артём) *//* * UBI scanning sub-system. * * This sub-system is responsible for scanning the flash media, checking UBI * headers and providing complete information about the UBI flash image. * * The scanning information is represented by a &struct ubi_scan_info' object. * Information about found volumes is represented by &struct ubi_scan_volume * objects which are kept in volume RB-tree with root at the @volumes field. * The RB-tree is indexed by the volume ID. * * Found logical eraseblocks are represented by &struct ubi_scan_leb objects. * These objects are kept in per-volume RB-trees with the root at the * corresponding &struct ubi_scan_volume object. To put it differently, we keep * an RB-tree of per-volume objects and each of these objects is the root of * RB-tree of per-eraseblock objects. * * Corrupted physical eraseblocks are put to the @corr list, free physical * eraseblocks are put to the @free list and the physical eraseblock to be * erased are put to the @erase list. */#include <linux/err.h>#include <linux/crc32.h>#include <asm/div64.h>#include "ubi.h"#ifdef CONFIG_MTD_UBI_DEBUG_PARANOIDstatic int paranoid_check_si(struct ubi_device *ubi, struct ubi_scan_info *si);#else#define paranoid_check_si(ubi, si) 0#endif/* Temporary variables used during scanning */static struct ubi_ec_hdr *ech;static struct ubi_vid_hdr *vidh;/** * add_to_list - add physical eraseblock to a list. * @si: scanning information * @pnum: physical eraseblock number to add * @ec: erase counter of the physical eraseblock * @list: the list to add to * * This function adds physical eraseblock @pnum to free, erase, corrupted or * alien lists. Returns zero in case of success and a negative error code in * case of failure. */static int add_to_list(struct ubi_scan_info *si, int pnum, int ec,		       struct list_head *list){	struct ubi_scan_leb *seb;	if (list == &si->free)		dbg_bld("add to free: PEB %d, EC %d", pnum, ec);	else if (list == &si->erase)		dbg_bld("add to erase: PEB %d, EC %d", pnum, ec);	else if (list == &si->corr)		dbg_bld("add to corrupted: PEB %d, EC %d", pnum, ec);	else if (list == &si->alien)		dbg_bld("add to alien: PEB %d, EC %d", pnum, ec);	else		BUG();	seb = kmalloc(sizeof(struct ubi_scan_leb), GFP_KERNEL);	if (!seb)		return -ENOMEM;	seb->pnum = pnum;	seb->ec = ec;	list_add_tail(&seb->u.list, list);	return 0;}/** * validate_vid_hdr - check volume identifier header. * @vid_hdr: the volume identifier header to check * @sv: information about the volume this logical eraseblock belongs to * @pnum: physical eraseblock number the VID header came from * * This function checks that data stored in @vid_hdr is consistent. Returns * non-zero if an inconsistency was found and zero if not. * * Note, UBI does sanity check of everything it reads from the flash media. * Most of the checks are done in the I/O sub-system. Here we check that the * information in the VID header is consistent to the information in other VID * headers of the same volume. */static int validate_vid_hdr(const struct ubi_vid_hdr *vid_hdr,			    const struct ubi_scan_volume *sv, int pnum){	int vol_type = vid_hdr->vol_type;	int vol_id = be32_to_cpu(vid_hdr->vol_id);	int used_ebs = be32_to_cpu(vid_hdr->used_ebs);	int data_pad = be32_to_cpu(vid_hdr->data_pad);	if (sv->leb_count != 0) {		int sv_vol_type;		/*		 * This is not the first logical eraseblock belonging to this		 * volume. Ensure that the data in its VID header is consistent		 * to the data in previous logical eraseblock headers.		 */		if (vol_id != sv->vol_id) {			dbg_err("inconsistent vol_id");			goto bad;		}		if (sv->vol_type == UBI_STATIC_VOLUME)			sv_vol_type = UBI_VID_STATIC;		else			sv_vol_type = UBI_VID_DYNAMIC;		if (vol_type != sv_vol_type) {			dbg_err("inconsistent vol_type");			goto bad;		}		if (used_ebs != sv->used_ebs) {			dbg_err("inconsistent used_ebs");			goto bad;		}		if (data_pad != sv->data_pad) {			dbg_err("inconsistent data_pad");			goto bad;		}	}	return 0;bad:	ubi_err("inconsistent VID header at PEB %d", pnum);	ubi_dbg_dump_vid_hdr(vid_hdr);	ubi_dbg_dump_sv(sv);	return -EINVAL;}/** * add_volume - add volume to the scanning information. * @si: scanning information * @vol_id: ID of the volume to add * @pnum: physical eraseblock number * @vid_hdr: volume identifier header * * If the volume corresponding to the @vid_hdr logical eraseblock is already * present in the scanning information, this function does nothing. Otherwise * it adds corresponding volume to the scanning information. Returns a pointer * to the scanning volume object in case of success and a negative error code * in case of failure. */static struct ubi_scan_volume *add_volume(struct ubi_scan_info *si, int vol_id,					  int pnum,					  const struct ubi_vid_hdr *vid_hdr){	struct ubi_scan_volume *sv;	struct rb_node **p = &si->volumes.rb_node, *parent = NULL;	ubi_assert(vol_id == be32_to_cpu(vid_hdr->vol_id));	/* Walk the volume RB-tree to look if this volume is already present */	while (*p) {		parent = *p;		sv = rb_entry(parent, struct ubi_scan_volume, rb);		if (vol_id == sv->vol_id)			return sv;		if (vol_id > sv->vol_id)			p = &(*p)->rb_left;		else			p = &(*p)->rb_right;	}	/* The volume is absent - add it */	sv = kmalloc(sizeof(struct ubi_scan_volume), GFP_KERNEL);	if (!sv)		return ERR_PTR(-ENOMEM);	sv->highest_lnum = sv->leb_count = 0;	sv->vol_id = vol_id;	sv->root = RB_ROOT;	sv->used_ebs = be32_to_cpu(vid_hdr->used_ebs);	sv->data_pad = be32_to_cpu(vid_hdr->data_pad);	sv->compat = vid_hdr->compat;	sv->vol_type = vid_hdr->vol_type == UBI_VID_DYNAMIC ? UBI_DYNAMIC_VOLUME							    : UBI_STATIC_VOLUME;	if (vol_id > si->highest_vol_id)		si->highest_vol_id = vol_id;	rb_link_node(&sv->rb, parent, p);	rb_insert_color(&sv->rb, &si->volumes);	si->vols_found += 1;	dbg_bld("added volume %d", vol_id);	return sv;}/** * compare_lebs - find out which logical eraseblock is newer. * @ubi: UBI device description object * @seb: first logical eraseblock to compare * @pnum: physical eraseblock number of the second logical eraseblock to * compare * @vid_hdr: volume identifier header of the second logical eraseblock * * This function compares 2 copies of a LEB and informs which one is newer. In * case of success this function returns a positive value, in case of failure, a * negative error code is returned. The success return codes use the following * bits: *     o bit 0 is cleared: the first PEB (described by @seb) is newer then the *       second PEB (described by @pnum and @vid_hdr); *     o bit 0 is set: the second PEB is newer; *     o bit 1 is cleared: no bit-flips were detected in the newer LEB; *     o bit 1 is set: bit-flips were detected in the newer LEB; *     o bit 2 is cleared: the older LEB is not corrupted; *     o bit 2 is set: the older LEB is corrupted. */static int compare_lebs(struct ubi_device *ubi, const struct ubi_scan_leb *seb,			int pnum, const struct ubi_vid_hdr *vid_hdr){	void *buf;	int len, err, second_is_newer, bitflips = 0, corrupted = 0;	uint32_t data_crc, crc;	struct ubi_vid_hdr *vh = NULL;	unsigned long long sqnum2 = be64_to_cpu(vid_hdr->sqnum);	if (sqnum2 == seb->sqnum) {		/*		 * This must be a really ancient UBI image which has been		 * created before sequence numbers support has been added. At		 * that times we used 32-bit LEB versions stored in logical		 * eraseblocks. That was before UBI got into mainline. We do not		 * support these images anymore. Well, those images will work		 * still work, but only if no unclean reboots happened.		 */		ubi_err("unsupported on-flash UBI format\n");		return -EINVAL;	}	/* Obviously the LEB with lower sequence counter is older */	second_is_newer = !!(sqnum2 > seb->sqnum);	/*	 * Now we know which copy is newer. If the copy flag of the PEB with	 * newer version is not set, then we just return, otherwise we have to	 * check data CRC. For the second PEB we already have the VID header,	 * for the first one - we'll need to re-read it from flash.	 *	 * Note: this may be optimized so that we wouldn't read twice.	 */	if (second_is_newer) {		if (!vid_hdr->copy_flag) {			/* It is not a copy, so it is newer */			dbg_bld("second PEB %d is newer, copy_flag is unset",				pnum);			return 1;		}	} else {		pnum = seb->pnum;		vh = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL);		if (!vh)			return -ENOMEM;		err = ubi_io_read_vid_hdr(ubi, pnum, vh, 0);		if (err) {			if (err == UBI_IO_BITFLIPS)				bitflips = 1;			else {				dbg_err("VID of PEB %d header is bad, but it "					"was OK earlier", pnum);				if (err > 0)					err = -EIO;				goto out_free_vidh;			}		}		if (!vh->copy_flag) {			/* It is not a copy, so it is newer */			dbg_bld("first PEB %d is newer, copy_flag is unset",				pnum);			err = bitflips << 1;			goto out_free_vidh;		}		vid_hdr = vh;	}	/* Read the data of the copy and check the CRC */	len = be32_to_cpu(vid_hdr->data_size);	buf = vmalloc(len);	if (!buf) {		err = -ENOMEM;		goto out_free_vidh;	}	err = ubi_io_read_data(ubi, buf, pnum, 0, len);	if (err && err != UBI_IO_BITFLIPS && err != -EBADMSG)		goto out_free_buf;	data_crc = be32_to_cpu(vid_hdr->data_crc);	crc = crc32(UBI_CRC32_INIT, buf, len);	if (crc != data_crc) {		dbg_bld("PEB %d CRC error: calculated %#08x, must be %#08x",			pnum, crc, data_crc);		corrupted = 1;		bitflips = 0;		second_is_newer = !second_is_newer;	} else {		dbg_bld("PEB %d CRC is OK", pnum);		bitflips = !!err;	}	vfree(buf);	ubi_free_vid_hdr(ubi, vh);	if (second_is_newer)		dbg_bld("second PEB %d is newer, copy_flag is set", pnum);	else		dbg_bld("first PEB %d is newer, copy_flag is set", pnum);	return second_is_newer | (bitflips << 1) | (corrupted << 2);out_free_buf:	vfree(buf);out_free_vidh:	ubi_free_vid_hdr(ubi, vh);	return err;}/** * ubi_scan_add_used - add physical eraseblock to the scanning information. * @ubi: UBI device description object * @si: scanning information * @pnum: the physical eraseblock number * @ec: erase counter * @vid_hdr: the volume identifier header * @bitflips: if bit-flips were detected when this physical eraseblock was read * * This function adds information about a used physical eraseblock to the * 'used' tree of the corresponding volume. The function is rather complex * because it has to handle cases when this is not the first physical * eraseblock belonging to the same logical eraseblock, and the newer one has * to be picked, while the older one has to be dropped. This function returns * zero in case of success and a negative error code in case of failure. */int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si,		      int pnum, int ec, const struct ubi_vid_hdr *vid_hdr,		      int bitflips){	int err, vol_id, lnum;	unsigned long long sqnum;	struct ubi_scan_volume *sv;	struct ubi_scan_leb *seb;	struct rb_node **p, *parent = NULL;	vol_id = be32_to_cpu(vid_hdr->vol_id);	lnum = be32_to_cpu(vid_hdr->lnum);	sqnum = be64_to_cpu(vid_hdr->sqnum);	dbg_bld("PEB %d, LEB %d:%d, EC %d, sqnum %llu, bitflips %d",		pnum, vol_id, lnum, ec, sqnum, bitflips);	sv = add_volume(si, vol_id, pnum, vid_hdr);	if (IS_ERR(sv))		return PTR_ERR(sv);	if (si->max_sqnum < sqnum)		si->max_sqnum = sqnum;	/*	 * Walk the RB-tree of logical eraseblocks of volume @vol_id to look	 * if this is the first instance of this logical eraseblock or not.	 */	p = &sv->root.rb_node;	while (*p) {		int cmp_res;		parent = *p;		seb = rb_entry(parent, struct ubi_scan_leb, u.rb);		if (lnum != seb->lnum) {			if (lnum < seb->lnum)				p = &(*p)->rb_left;			else				p = &(*p)->rb_right;			continue;		}		/*		 * There is already a physical eraseblock describing the same		 * logical eraseblock present.		 */		dbg_bld("this LEB already exists: PEB %d, sqnum %llu, "			"EC %d", seb->pnum, seb->sqnum, seb->ec);		/*		 * Make sure that the logical eraseblocks have different		 * sequence numbers. Otherwise the image is bad.		 *		 * However, if the sequence number is zero, we assume it must		 * be an ancient UBI image from the era when UBI did not have		 * sequence numbers. We still can attach these images, unless		 * there is a need to distinguish between old and new		 * eraseblocks, in which case we'll refuse the image in		 * 'compare_lebs()'. In other words, we attach old clean		 * images, but refuse attaching old images with duplicated		 * logical eraseblocks because there was an unclean reboot.		 */		if (seb->sqnum == sqnum && sqnum != 0) {			ubi_err("two LEBs with same sequence number %llu",				sqnum);			ubi_dbg_dump_seb(seb, 0);			ubi_dbg_dump_vid_hdr(vid_hdr);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -