1648 lines · 39.5 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-only/* * Copyright (c) 2012 Linutronix GmbH * Copyright (c) 2014 sigma star gmbh * Author: Richard Weinberger <richard@nod.at> */ #include <linux/crc32.h>#include <linux/bitmap.h>#include "ubi.h" /** * init_seen - allocate memory for used for debugging. * @ubi: UBI device description object */static inline unsigned long *init_seen(struct ubi_device *ubi){	unsigned long *ret; 	if (!ubi_dbg_chk_fastmap(ubi))		return NULL; 	ret = bitmap_zalloc(ubi->peb_count, GFP_NOFS);	if (!ret)		return ERR_PTR(-ENOMEM); 	return ret;} /** * free_seen - free the seen logic integer array. * @seen: integer array of @ubi->peb_count size */static inline void free_seen(unsigned long *seen){	bitmap_free(seen);} /** * set_seen - mark a PEB as seen. * @ubi: UBI device description object * @pnum: The PEB to be makred as seen * @seen: integer array of @ubi->peb_count size */static inline void set_seen(struct ubi_device *ubi, int pnum, unsigned long *seen){	if (!ubi_dbg_chk_fastmap(ubi) || !seen)		return; 	set_bit(pnum, seen);} /** * self_check_seen - check whether all PEB have been seen by fastmap. * @ubi: UBI device description object * @seen: integer array of @ubi->peb_count size */static int self_check_seen(struct ubi_device *ubi, unsigned long *seen){	int pnum, ret = 0; 	if (!ubi_dbg_chk_fastmap(ubi) || !seen)		return 0; 	for (pnum = 0; pnum < ubi->peb_count; pnum++) {		if (!test_bit(pnum, seen) && ubi->lookuptbl[pnum]) {			ubi_err(ubi, "self-check failed for PEB %d, fastmap didn't see it", pnum);			ret = -EINVAL;		}	} 	return ret;} /** * ubi_calc_fm_size - calculates the fastmap size in bytes for an UBI device. * @ubi: UBI device description object */size_t ubi_calc_fm_size(struct ubi_device *ubi){	size_t size; 	size = sizeof(struct ubi_fm_sb) +		sizeof(struct ubi_fm_hdr) +		sizeof(struct ubi_fm_scan_pool) +		sizeof(struct ubi_fm_scan_pool) +		(ubi->peb_count * sizeof(struct ubi_fm_ec)) +		((sizeof(struct ubi_fm_eba) +		  sizeof(struct ubi_fm_volhdr)) *		 (UBI_MAX_VOLUMES + UBI_INT_VOL_COUNT)) +		(ubi->peb_count * sizeof(__be32));	return roundup(size, ubi->leb_size);}  /** * new_fm_vbuf() - allocate a new volume header for fastmap usage. * @ubi: UBI device description object * @vol_id: the VID of the new header * * Returns a new struct ubi_vid_hdr on success. * NULL indicates out of memory. */static struct ubi_vid_io_buf *new_fm_vbuf(struct ubi_device *ubi, int vol_id){	struct ubi_vid_io_buf *new;	struct ubi_vid_hdr *vh; 	new = ubi_alloc_vid_buf(ubi, GFP_NOFS);	if (!new)		goto out; 	vh = ubi_get_vid_hdr(new);	vh->vol_type = UBI_VID_DYNAMIC;	vh->vol_id = cpu_to_be32(vol_id); 	/* UBI implementations without fastmap support have to delete the	 * fastmap.	 */	vh->compat = UBI_COMPAT_DELETE; out:	return new;} /** * add_aeb - create and add a attach erase block to a given list. * @ai: UBI attach info object * @list: the target list * @pnum: PEB number of the new attach erase block * @ec: erease counter of the new LEB * @scrub: scrub this PEB after attaching * * Returns 0 on success, < 0 indicates an internal error. */static int add_aeb(struct ubi_attach_info *ai, struct list_head *list,		   int pnum, int ec, int scrub){	struct ubi_ainf_peb *aeb; 	aeb = ubi_alloc_aeb(ai, pnum, ec);	if (!aeb)		return -ENOMEM; 	aeb->lnum = -1;	aeb->scrub = scrub;	aeb->copy_flag = aeb->sqnum = 0; 	ai->ec_sum += aeb->ec;	ai->ec_count++; 	if (ai->max_ec < aeb->ec)		ai->max_ec = aeb->ec; 	if (ai->min_ec > aeb->ec)		ai->min_ec = aeb->ec; 	list_add_tail(&aeb->u.list, list); 	return 0;} /** * add_vol - create and add a new volume to ubi_attach_info. * @ai: ubi_attach_info object * @vol_id: VID of the new volume * @used_ebs: number of used EBS * @data_pad: data padding value of the new volume * @vol_type: volume type * @last_eb_bytes: number of bytes in the last LEB * * Returns the new struct ubi_ainf_volume on success. * NULL indicates an error. */static struct ubi_ainf_volume *add_vol(struct ubi_attach_info *ai, int vol_id,				       int used_ebs, int data_pad, u8 vol_type,				       int last_eb_bytes){	struct ubi_ainf_volume *av; 	av = ubi_add_av(ai, vol_id);	if (IS_ERR(av))		return av; 	av->data_pad = data_pad;	av->last_data_size = last_eb_bytes;	av->compat = 0;	av->vol_type = vol_type;	if (av->vol_type == UBI_STATIC_VOLUME)		av->used_ebs = used_ebs; 	dbg_bld("found volume (ID %i)", vol_id);	return av;} /** * assign_aeb_to_av - assigns a SEB to a given ainf_volume and removes it * from it's original list. * @ai: ubi_attach_info object * @aeb: the to be assigned SEB * @av: target scan volume */static void assign_aeb_to_av(struct ubi_attach_info *ai,			     struct ubi_ainf_peb *aeb,			     struct ubi_ainf_volume *av){	struct ubi_ainf_peb *tmp_aeb;	struct rb_node **p = &av->root.rb_node, *parent = NULL; 	while (*p) {		parent = *p; 		tmp_aeb = rb_entry(parent, struct ubi_ainf_peb, u.rb);		if (aeb->lnum != tmp_aeb->lnum) {			if (aeb->lnum < tmp_aeb->lnum)				p = &(*p)->rb_left;			else				p = &(*p)->rb_right; 			continue;		} else			break;	} 	list_del(&aeb->u.list);	av->leb_count++; 	rb_link_node(&aeb->u.rb, parent, p);	rb_insert_color(&aeb->u.rb, &av->root);} /** * update_vol - inserts or updates a LEB which was found a pool. * @ubi: the UBI device object * @ai: attach info object * @av: the volume this LEB belongs to * @new_vh: the volume header derived from new_aeb * @new_aeb: the AEB to be examined * * Returns 0 on success, < 0 indicates an internal error. */static int update_vol(struct ubi_device *ubi, struct ubi_attach_info *ai,		      struct ubi_ainf_volume *av, struct ubi_vid_hdr *new_vh,		      struct ubi_ainf_peb *new_aeb){	struct rb_node **p = &av->root.rb_node, *parent = NULL;	struct ubi_ainf_peb *aeb, *victim;	int cmp_res; 	while (*p) {		parent = *p;		aeb = rb_entry(parent, struct ubi_ainf_peb, u.rb); 		if (be32_to_cpu(new_vh->lnum) != aeb->lnum) {			if (be32_to_cpu(new_vh->lnum) < aeb->lnum)				p = &(*p)->rb_left;			else				p = &(*p)->rb_right; 			continue;		} 		/* This case can happen if the fastmap gets written		 * because of a volume change (creation, deletion, ..).		 * Then a PEB can be within the persistent EBA and the pool.		 */		if (aeb->pnum == new_aeb->pnum) {			ubi_assert(aeb->lnum == new_aeb->lnum);			ubi_free_aeb(ai, new_aeb); 			return 0;		} 		cmp_res = ubi_compare_lebs(ubi, aeb, new_aeb->pnum, new_vh);		if (cmp_res < 0)			return cmp_res; 		/* new_aeb is newer */		if (cmp_res & 1) {			victim = ubi_alloc_aeb(ai, aeb->pnum, aeb->ec);			if (!victim)				return -ENOMEM; 			list_add_tail(&victim->u.list, &ai->erase); 			if (av->highest_lnum == be32_to_cpu(new_vh->lnum))				av->last_data_size =					be32_to_cpu(new_vh->data_size); 			dbg_bld("vol %i: AEB %i's PEB %i is the newer",				av->vol_id, aeb->lnum, new_aeb->pnum); 			aeb->ec = new_aeb->ec;			aeb->pnum = new_aeb->pnum;			aeb->copy_flag = new_vh->copy_flag;			aeb->scrub = new_aeb->scrub;			aeb->sqnum = new_aeb->sqnum;			ubi_free_aeb(ai, new_aeb); 		/* new_aeb is older */		} else {			dbg_bld("vol %i: AEB %i's PEB %i is old, dropping it",				av->vol_id, aeb->lnum, new_aeb->pnum);			list_add_tail(&new_aeb->u.list, &ai->erase);		} 		return 0;	}	/* This LEB is new, let's add it to the volume */ 	if (av->highest_lnum <= be32_to_cpu(new_vh->lnum)) {		av->highest_lnum = be32_to_cpu(new_vh->lnum);		av->last_data_size = be32_to_cpu(new_vh->data_size);	} 	if (av->vol_type == UBI_STATIC_VOLUME)		av->used_ebs = be32_to_cpu(new_vh->used_ebs); 	av->leb_count++; 	rb_link_node(&new_aeb->u.rb, parent, p);	rb_insert_color(&new_aeb->u.rb, &av->root); 	return 0;} /** * process_pool_aeb - we found a non-empty PEB in a pool. * @ubi: UBI device object * @ai: attach info object * @new_vh: the volume header derived from new_aeb * @new_aeb: the AEB to be examined * * Returns 0 on success, < 0 indicates an internal error. */static int process_pool_aeb(struct ubi_device *ubi, struct ubi_attach_info *ai,			    struct ubi_vid_hdr *new_vh,			    struct ubi_ainf_peb *new_aeb){	int vol_id = be32_to_cpu(new_vh->vol_id);	struct ubi_ainf_volume *av; 	if (vol_id == UBI_FM_SB_VOLUME_ID || vol_id == UBI_FM_DATA_VOLUME_ID) {		ubi_free_aeb(ai, new_aeb); 		return 0;	} 	/* Find the volume this SEB belongs to */	av = ubi_find_av(ai, vol_id);	if (!av) {		ubi_err(ubi, "orphaned volume in fastmap pool!");		ubi_free_aeb(ai, new_aeb);		return UBI_BAD_FASTMAP;	} 	ubi_assert(vol_id == av->vol_id); 	return update_vol(ubi, ai, av, new_vh, new_aeb);} /** * unmap_peb - unmap a PEB. * If fastmap detects a free PEB in the pool it has to check whether * this PEB has been unmapped after writing the fastmap. * * @ai: UBI attach info object * @pnum: The PEB to be unmapped */static void unmap_peb(struct ubi_attach_info *ai, int pnum){	struct ubi_ainf_volume *av;	struct rb_node *node, *node2;	struct ubi_ainf_peb *aeb; 	ubi_rb_for_each_entry(node, av, &ai->volumes, rb) {		ubi_rb_for_each_entry(node2, aeb, &av->root, u.rb) {			if (aeb->pnum == pnum) {				rb_erase(&aeb->u.rb, &av->root);				av->leb_count--;				ubi_free_aeb(ai, aeb);				return;			}		}	}} /** * scan_pool - scans a pool for changed (no longer empty PEBs). * @ubi: UBI device object * @ai: attach info object * @pebs: an array of all PEB numbers in the to be scanned pool * @pool_size: size of the pool (number of entries in @pebs) * @max_sqnum: pointer to the maximal sequence number * @free: list of PEBs which are most likely free (and go into @ai->free) * * Returns 0 on success, if the pool is unusable UBI_BAD_FASTMAP is returned. * < 0 indicates an internal error. */static int scan_pool(struct ubi_device *ubi, struct ubi_attach_info *ai,		     __be32 *pebs, int pool_size, unsigned long long *max_sqnum,		     struct list_head *free){	struct ubi_vid_io_buf *vb;	struct ubi_vid_hdr *vh;	struct ubi_ec_hdr *ech;	struct ubi_ainf_peb *new_aeb;	int i, pnum, err, ret = 0; 	ech = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);	if (!ech)		return -ENOMEM; 	vb = ubi_alloc_vid_buf(ubi, GFP_KERNEL);	if (!vb) {		kfree(ech);		return -ENOMEM;	} 	vh = ubi_get_vid_hdr(vb); 	dbg_bld("scanning fastmap pool: size = %i", pool_size); 	/*	 * Now scan all PEBs in the pool to find changes which have been made	 * after the creation of the fastmap	 */	for (i = 0; i < pool_size; i++) {		int scrub = 0;		int image_seq; 		pnum = be32_to_cpu(pebs[i]); 		if (ubi_io_is_bad(ubi, pnum)) {			ubi_err(ubi, "bad PEB in fastmap pool!");			ret = UBI_BAD_FASTMAP;			goto out;		} 		err = ubi_io_read_ec_hdr(ubi, pnum, ech, 0);		if (err && err != UBI_IO_BITFLIPS) {			ubi_err(ubi, "unable to read EC header! PEB:%i err:%i",				pnum, err);			ret = err > 0 ? UBI_BAD_FASTMAP : err;			goto out;		} else if (err == UBI_IO_BITFLIPS)			scrub = 1; 		/*		 * Older UBI implementations have image_seq set to zero, so		 * we shouldn't fail if image_seq == 0.		 */		image_seq = be32_to_cpu(ech->image_seq); 		if (image_seq && (image_seq != ubi->image_seq)) {			ubi_err(ubi, "bad image seq: 0x%x, expected: 0x%x",				be32_to_cpu(ech->image_seq), ubi->image_seq);			ret = UBI_BAD_FASTMAP;			goto out;		} 		err = ubi_io_read_vid_hdr(ubi, pnum, vb, 0);		if (err == UBI_IO_FF || err == UBI_IO_FF_BITFLIPS) {			unsigned long long ec = be64_to_cpu(ech->ec);			unmap_peb(ai, pnum);			dbg_bld("Adding PEB to free: %i", pnum); 			if (err == UBI_IO_FF_BITFLIPS)				scrub = 1; 			ret = add_aeb(ai, free, pnum, ec, scrub);			if (ret)				goto out;			continue;		} else if (err == 0 || err == UBI_IO_BITFLIPS) {			dbg_bld("Found non empty PEB:%i in pool", pnum); 			if (err == UBI_IO_BITFLIPS)				scrub = 1; 			new_aeb = ubi_alloc_aeb(ai, pnum, be64_to_cpu(ech->ec));			if (!new_aeb) {				ret = -ENOMEM;				goto out;			} 			new_aeb->lnum = be32_to_cpu(vh->lnum);			new_aeb->sqnum = be64_to_cpu(vh->sqnum);			new_aeb->copy_flag = vh->copy_flag;			new_aeb->scrub = scrub; 			if (*max_sqnum < new_aeb->sqnum)				*max_sqnum = new_aeb->sqnum; 			err = process_pool_aeb(ubi, ai, vh, new_aeb);			if (err) {				ret = err > 0 ? UBI_BAD_FASTMAP : err;				goto out;			}		} else {

Lines 1–500 of 1648.