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

📄 scan.c

📁 基于linux-2.6.28的mtd驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
			return -EINVAL;		}		/*		 * Now we have to drop the older one and preserve the newer		 * one.		 */		cmp_res = compare_lebs(ubi, seb, pnum, vid_hdr);		if (cmp_res < 0)			return cmp_res;		if (cmp_res & 1) {			/*			 * This logical eraseblock is newer then the one			 * found earlier.			 */			err = validate_vid_hdr(vid_hdr, sv, pnum);			if (err)				return err;			if (cmp_res & 4)				err = add_to_list(si, seb->pnum, seb->ec,						  &si->corr);			else				err = add_to_list(si, seb->pnum, seb->ec,						  &si->erase);			if (err)				return err;			seb->ec = ec;			seb->pnum = pnum;			seb->scrub = ((cmp_res & 2) || bitflips);			seb->sqnum = sqnum;			if (sv->highest_lnum == lnum)				sv->last_data_size =					be32_to_cpu(vid_hdr->data_size);			return 0;		} else {			/*			 * This logical eraseblock is older then the one found			 * previously.			 */			if (cmp_res & 4)				return add_to_list(si, pnum, ec, &si->corr);			else				return add_to_list(si, pnum, ec, &si->erase);		}	}	/*	 * We've met this logical eraseblock for the first time, add it to the	 * scanning information.	 */	err = validate_vid_hdr(vid_hdr, sv, pnum);	if (err)		return err;	seb = kmalloc(sizeof(struct ubi_scan_leb), GFP_KERNEL);	if (!seb)		return -ENOMEM;	seb->ec = ec;	seb->pnum = pnum;	seb->lnum = lnum;	seb->sqnum = sqnum;	seb->scrub = bitflips;	if (sv->highest_lnum <= lnum) {		sv->highest_lnum = lnum;		sv->last_data_size = be32_to_cpu(vid_hdr->data_size);	}	sv->leb_count += 1;	rb_link_node(&seb->u.rb, parent, p);	rb_insert_color(&seb->u.rb, &sv->root);	return 0;}/** * ubi_scan_find_sv - find volume in the scanning information. * @si: scanning information * @vol_id: the requested volume ID * * This function returns a pointer to the volume description or %NULL if there * are no data about this volume in the scanning information. */struct ubi_scan_volume *ubi_scan_find_sv(const struct ubi_scan_info *si,					 int vol_id){	struct ubi_scan_volume *sv;	struct rb_node *p = si->volumes.rb_node;	while (p) {		sv = rb_entry(p, 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;	}	return NULL;}/** * ubi_scan_find_seb - find LEB in the volume scanning information. * @sv: a pointer to the volume scanning information * @lnum: the requested logical eraseblock * * This function returns a pointer to the scanning logical eraseblock or %NULL * if there are no data about it in the scanning volume information. */struct ubi_scan_leb *ubi_scan_find_seb(const struct ubi_scan_volume *sv,				       int lnum){	struct ubi_scan_leb *seb;	struct rb_node *p = sv->root.rb_node;	while (p) {		seb = rb_entry(p, struct ubi_scan_leb, u.rb);		if (lnum == seb->lnum)			return seb;		if (lnum > seb->lnum)			p = p->rb_left;		else			p = p->rb_right;	}	return NULL;}/** * ubi_scan_rm_volume - delete scanning information about a volume. * @si: scanning information * @sv: the volume scanning information to delete */void ubi_scan_rm_volume(struct ubi_scan_info *si, struct ubi_scan_volume *sv){	struct rb_node *rb;	struct ubi_scan_leb *seb;	dbg_bld("remove scanning information about volume %d", sv->vol_id);	while ((rb = rb_first(&sv->root))) {		seb = rb_entry(rb, struct ubi_scan_leb, u.rb);		rb_erase(&seb->u.rb, &sv->root);		list_add_tail(&seb->u.list, &si->erase);	}	rb_erase(&sv->rb, &si->volumes);	kfree(sv);	si->vols_found -= 1;}/** * ubi_scan_erase_peb - erase a physical eraseblock. * @ubi: UBI device description object * @si: scanning information * @pnum: physical eraseblock number to erase; * @ec: erase counter value to write (%UBI_SCAN_UNKNOWN_EC if it is unknown) * * This function erases physical eraseblock 'pnum', and writes the erase * counter header to it. This function should only be used on UBI device * initialization stages, when the EBA sub-system had not been yet initialized. * This function returns zero in case of success and a negative error code in * case of failure. */int ubi_scan_erase_peb(struct ubi_device *ubi, const struct ubi_scan_info *si,		       int pnum, int ec){	int err;	struct ubi_ec_hdr *ec_hdr;	if ((long long)ec >= UBI_MAX_ERASECOUNTER) {		/*		 * Erase counter overflow. Upgrade UBI and use 64-bit		 * erase counters internally.		 */		ubi_err("erase counter overflow at PEB %d, EC %d", pnum, ec);		return -EINVAL;	}	ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);	if (!ec_hdr)		return -ENOMEM;	ec_hdr->ec = cpu_to_be64(ec);	err = ubi_io_sync_erase(ubi, pnum, 0);	if (err < 0)		goto out_free;	err = ubi_io_write_ec_hdr(ubi, pnum, ec_hdr);out_free:	kfree(ec_hdr);	return err;}/** * ubi_scan_get_free_peb - get a free physical eraseblock. * @ubi: UBI device description object * @si: scanning information * * This function returns a free physical eraseblock. It is supposed to be * called on the UBI initialization stages when the wear-leveling sub-system is * not initialized yet. This function picks a physical eraseblocks from one of * the lists, writes the EC header if it is needed, and removes it from the * list. * * This function returns scanning physical eraseblock information in case of * success and an error code in case of failure. */struct ubi_scan_leb *ubi_scan_get_free_peb(struct ubi_device *ubi,					   struct ubi_scan_info *si){	int err = 0, i;	struct ubi_scan_leb *seb;	if (!list_empty(&si->free)) {		seb = list_entry(si->free.next, struct ubi_scan_leb, u.list);		list_del(&seb->u.list);		dbg_bld("return free PEB %d, EC %d", seb->pnum, seb->ec);		return seb;	}	for (i = 0; i < 2; i++) {		struct list_head *head;		struct ubi_scan_leb *tmp_seb;		if (i == 0)			head = &si->erase;		else			head = &si->corr;		/*		 * We try to erase the first physical eraseblock from the @head		 * list and pick it if we succeed, or try to erase the		 * next one if not. And so forth. We don't want to take care		 * about bad eraseblocks here - they'll be handled later.		 */		list_for_each_entry_safe(seb, tmp_seb, head, u.list) {			if (seb->ec == UBI_SCAN_UNKNOWN_EC)				seb->ec = si->mean_ec;			err = ubi_scan_erase_peb(ubi, si, seb->pnum, seb->ec+1);			if (err)				continue;			seb->ec += 1;			list_del(&seb->u.list);			dbg_bld("return PEB %d, EC %d", seb->pnum, seb->ec);			return seb;		}	}	ubi_err("no eraseblocks found");	return ERR_PTR(-ENOSPC);}/** * process_eb - read, check UBI headers, and add them to scanning information. * @ubi: UBI device description object * @si: scanning information * @pnum: the physical eraseblock number * * This function returns a zero if the physical eraseblock was successfully * handled and a negative error code in case of failure. */static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,		      int pnum){	long long uninitialized_var(ec);	int err, bitflips = 0, vol_id, ec_corr = 0;	dbg_bld("scan PEB %d", pnum);	/* Skip bad physical eraseblocks */	err = ubi_io_is_bad(ubi, pnum);	if (err < 0)		return err;	else if (err) {		/*		 * FIXME: this is actually duty of the I/O sub-system to		 * initialize this, but MTD does not provide enough		 * information.		 */		si->bad_peb_count += 1;		return 0;	}	err = ubi_io_read_ec_hdr(ubi, pnum, ech, 0);	if (err < 0)		return err;	else if (err == UBI_IO_BITFLIPS)		bitflips = 1;	else if (err == UBI_IO_PEB_EMPTY)		return add_to_list(si, pnum, UBI_SCAN_UNKNOWN_EC, &si->erase);	else if (err == UBI_IO_BAD_EC_HDR) {		/*		 * We have to also look at the VID header, possibly it is not		 * corrupted. Set %bitflips flag in order to make this PEB be		 * moved and EC be re-created.		 */		ec_corr = 1;		ec = UBI_SCAN_UNKNOWN_EC;		bitflips = 1;	}	si->is_empty = 0;	if (!ec_corr) {		/* Make sure UBI version is OK */		if (ech->version != UBI_VERSION) {			ubi_err("this UBI version is %d, image version is %d",				UBI_VERSION, (int)ech->version);			return -EINVAL;		}		ec = be64_to_cpu(ech->ec);		if (ec > UBI_MAX_ERASECOUNTER) {			/*			 * Erase counter overflow. The EC headers have 64 bits			 * reserved, but we anyway make use of only 31 bit			 * values, as this seems to be enough for any existing			 * flash. Upgrade UBI and use 64-bit erase counters			 * internally.			 */			ubi_err("erase counter overflow, max is %d",				UBI_MAX_ERASECOUNTER);			ubi_dbg_dump_ec_hdr(ech);			return -EINVAL;		}	}	/* OK, we've done with the EC header, let's look at the VID header */	err = ubi_io_read_vid_hdr(ubi, pnum, vidh, 0);	if (err < 0)		return err;	else if (err == UBI_IO_BITFLIPS)		bitflips = 1;	else if (err == UBI_IO_BAD_VID_HDR ||		 (err == UBI_IO_PEB_FREE && ec_corr)) {		/* VID header is corrupted */		err = add_to_list(si, pnum, ec, &si->corr);		if (err)			return err;		goto adjust_mean_ec;	} else if (err == UBI_IO_PEB_FREE) {		/* No VID header - the physical eraseblock is free */		err = add_to_list(si, pnum, ec, &si->free);		if (err)			return err;		goto adjust_mean_ec;	}	vol_id = be32_to_cpu(vidh->vol_id);	if (vol_id > UBI_MAX_VOLUMES && vol_id != UBI_LAYOUT_VOLUME_ID) {		int lnum = be32_to_cpu(vidh->lnum);		/* Unsupported internal volume */		switch (vidh->compat) {		case UBI_COMPAT_DELETE:			ubi_msg("\"delete\" compatible internal volume %d:%d"				" found, remove it", vol_id, lnum);			err = add_to_list(si, pnum, ec, &si->corr);			if (err)				return err;			break;		case UBI_COMPAT_RO:			ubi_msg("read-only compatible internal volume %d:%d"				" found, switch to read-only mode",				vol_id, lnum);			ubi->ro_mode = 1;			break;		case UBI_COMPAT_PRESERVE:			ubi_msg("\"preserve\" compatible internal volume %d:%d"				" found", vol_id, lnum);			err = add_to_list(si, pnum, ec, &si->alien);			if (err)				return err;			si->alien_peb_count += 1;			return 0;		case UBI_COMPAT_REJECT:			ubi_err("incompatible internal volume %d:%d found",				vol_id, lnum);			return -EINVAL;		}	}	/* Both UBI headers seem to be fine */	err = ubi_scan_add_used(ubi, si, pnum, ec, vidh, bitflips);	if (err)		return err;adjust_mean_ec:	if (!ec_corr) {		si->ec_sum += ec;		si->ec_count += 1;		if (ec > si->max_ec)			si->max_ec = ec;		if (ec < si->min_ec)			si->min_ec = ec;	}	return 0;}/** * ubi_scan - scan an MTD device. * @ubi: UBI device description object * * This function does full scanning of an MTD device and returns complete * information about it. In case of failure, an error code is returned. */struct ubi_scan_info *ubi_scan(struct ubi_device *ubi){	int err, pnum;	struct rb_node *rb1, *rb2;	struct ubi_scan_volume *sv;	struct ubi_scan_leb *seb;	struct ubi_scan_info *si;	si = kzalloc(sizeof(struct ubi_scan_info), GFP_KERNEL);	if (!si)		return ERR_PTR(-ENOMEM);

⌨️ 快捷键说明

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