Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cd5a9795 authored by Nikhilesh Reddy's avatar Nikhilesh Reddy
Browse files

Backport UBI patches from 4.2.0-rc5



UBIFS over UBI is the default filesystem used in QCOM chipsets
that use NAND storage.

Recently a number of stability and performance fixes were
added to the kernel that address issues ranging from data loss
to bootup issues. The fastmap feature has also undergone a rewrite
to help address issues of stability and memory leaks.

Backport and bring in all the changes to ensure stability and
better performance for the NAND based devices.

* The patches included are:
  UBI: Remove unnecessary `\'
  UBI: Use static class and attribute groups
  UBI: add a helper function for updatting on-flash layout volumes
  UBI: Fastmap: Do not add vol if it already exists
  UBI: Init vol->reserved_pebs by assignment
  UBI: Fastmap: Rename variables to make them meaningful
  UBI: Fastmap: Remove unnecessary `\'
  UBI: Fastmap: Use max() to get the larger value
  UBI: block: Dynamically allocate minor numbers
  UBI: block: Add missing cache flushes
  UBI: power cut emulation for testing
  UBI: Fastmap: Fall back to scanning mode after ECC error
  UBI: Fastmap: Remove is_fm_block()
  UBI: Fastmap: Add blank line after declarations
  UBI: Fastmap: Remove else after return.
  UBI: Fastmap: Introduce may_reserve_for_fm()
  UBI: Fastmap: Introduce ubi_fastmap_init()
  UBI: Fastmap: Wire up WL accessor functions
  UBI: Add accessor functions for WL data structures
  UBI: Move fastmap specific functions out of wl.c
  UBI: Fastmap: Add new module parameter fm_debug
  UBI: Fastmap: Make self_check_eba() depend on fastmap self checking
  UBI: Fastmap: Add self check to detect absent PEBs
  UBI: Fix stale pointers in ubi->lookuptbl
  UBI: Fastmap: Enhance fastmap checking
  UBI: Add initial support for fastmap self checks
  UBI: Fastmap: Rework fastmap error paths
  UBI: Fastmap: Prepare for variable sized fastmaps
  UBI: Fastmap: Locking updates
  UBI: Fastmap: Set used_ebs only for static volumes
  UBI: Fastmap: Fix race after ubi_wl_get_peb()
  UBI: Fastmap: Fix leb_count unbalance
  UBI: Fastmap: Make WL pool size 50% of user pool size
  UBI: Fastmap: Switch to ro mode if invalidate_fastmap() fails
  UBI: Fastmap: Remove eba_orphans logic
  UBI: Fastmap: Remove bogus ubi_assert()
  UBI: Fastmap: Fix race in ubi_eba_atomic_leb_change()
  UBI: Remove alloc_ai() slab name from parameter list
  UBI: Fastmap: Fix memory leak while attaching
  UBI: Fastmap: Fix fastmap usage in ubi_volume_notify()
  UBI: Fastmap: Wrap fastmap specific function in a ifdef
  UBI: Fastmap: Notify user in case of an ubi_update_fastmap() failure
  UBI: Fastmap: Fix memory leaks while closing the WL sub-system
  UBI: Fastmap: Don't allocate new ubi_wl_entry objects
  UBI: Fastmap: Make ubi_refill_pools() fair
  UBI: Split __wl_get_peb()
  UBI: Fastmap: Fix races in ubi_wl_get_peb()
  UBI: Fastmap: Ensure that all fastmap work is done upon WL shutdown
  UBI: Fastmap: Ensure that only one fastmap work is scheduled
  UBI: align comment for readability
  UBI: fix missing brace control flow
  UBI: block: Fix checking for NULL instead of IS_ERR()
  UBI: block: Continue creating ubiblocks after an initialization error
  UBI: Block: Explain usage of blk_rq_map_sg()
  UBI: fix soft lockup in ubi_check_volume()
  UBI: Fastmap: Care about the protection queue
  UBI: do propagate positive error codes up
  UBI: clean-up printing helpers
  UBI: extend UBI layer debug/messaging capabilities - cosmetics
  UBI: Block: Add blk-mq support
  UBI: Add initial support for scatter gather
  UBI: rename_volumes: Use UBI_METAONLY
  UBI: Implement UBI_METAONLY
  UBI: vtbl: Use ubi_eba_atomic_leb_change()
  UBI: Extend UBI layer debug/messaging capabilities
  Revert "mtd: ubi: reduce messages during scrub all PEBs"
  Revert "UBI: Fastmap: Fix memory leak while attaching"

Change-Id: I1e967405f29127295d2ebc3a546eedad05de931c
Signed-off-by: default avatarNikhilesh Reddy <reddyn@codeaurora.org>
parents 77813844 fde2c92e
Loading
Loading
Loading
Loading
+74 −68
Original line number Diff line number Diff line
@@ -176,6 +176,7 @@ static int add_corrupted(struct ubi_attach_info *ai, int pnum, int ec)

/**
 * validate_vid_hdr - check volume identifier header.
 * @ubi: UBI device description object
 * @vid_hdr: the volume identifier header to check
 * @av: information about the volume this logical eraseblock belongs to
 * @pnum: physical eraseblock number the VID header came from
@@ -188,7 +189,8 @@ static int add_corrupted(struct ubi_attach_info *ai, int pnum, int ec)
 * 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,
static int validate_vid_hdr(const struct ubi_device *ubi,
			    const struct ubi_vid_hdr *vid_hdr,
			    const struct ubi_ainf_volume *av, int pnum)
{
	int vol_type = vid_hdr->vol_type;
@@ -206,7 +208,7 @@ static int validate_vid_hdr(const struct ubi_vid_hdr *vid_hdr,
		 */

		if (vol_id != av->vol_id) {
			ubi_err("inconsistent vol_id");
			ubi_err(ubi, "inconsistent vol_id");
			goto bad;
		}

@@ -216,17 +218,17 @@ static int validate_vid_hdr(const struct ubi_vid_hdr *vid_hdr,
			av_vol_type = UBI_VID_DYNAMIC;

		if (vol_type != av_vol_type) {
			ubi_err("inconsistent vol_type");
			ubi_err(ubi, "inconsistent vol_type");
			goto bad;
		}

		if (used_ebs != av->used_ebs) {
			ubi_err("inconsistent used_ebs");
			ubi_err(ubi, "inconsistent used_ebs");
			goto bad;
		}

		if (data_pad != av->data_pad) {
			ubi_err("inconsistent data_pad");
			ubi_err(ubi, "inconsistent data_pad");
			goto bad;
		}
	}
@@ -234,7 +236,7 @@ static int validate_vid_hdr(const struct ubi_vid_hdr *vid_hdr,
	return 0;

bad:
	ubi_err("inconsistent VID header at PEB %d", pnum);
	ubi_err(ubi, "inconsistent VID header at PEB %d", pnum);
	ubi_dump_vid_hdr(vid_hdr);
	ubi_dump_av(av);
	return -EINVAL;
@@ -336,7 +338,7 @@ int ubi_compare_lebs(struct ubi_device *ubi, const struct ubi_ainf_peb *aeb,
		 * support these images anymore. Well, those images still work,
		 * but only if no unclean reboots happened.
		 */
		ubi_err("unsupported on-flash UBI format");
		ubi_err(ubi, "unsupported on-flash UBI format");
		return -EINVAL;
	}

@@ -377,7 +379,7 @@ int ubi_compare_lebs(struct ubi_device *ubi, const struct ubi_ainf_peb *aeb,
			if (err == UBI_IO_BITFLIPS)
				bitflips = 1;
			else {
				ubi_err("VID of PEB %d header is bad, but it was OK earlier, err %d",
				ubi_err(ubi, "VID of PEB %d header is bad, but it was OK earlier, err %d",
					pnum, err);
				if (err > 0)
					err = -EIO;
@@ -507,7 +509,7 @@ int ubi_add_to_av(struct ubi_device *ubi, struct ubi_attach_info *ai, int pnum,
		 * logical eraseblocks because there was an unclean reboot.
		 */
		if (aeb->sqnum == sqnum && sqnum != 0) {
			ubi_err("two LEBs with same sequence number %llu",
			ubi_err(ubi, "two LEBs with same sequence number %llu",
				sqnum);
			ubi_dump_aeb(aeb, 0);
			ubi_dump_vid_hdr(vid_hdr);
@@ -527,7 +529,7 @@ int ubi_add_to_av(struct ubi_device *ubi, struct ubi_attach_info *ai, int pnum,
			 * This logical eraseblock is newer than the one
			 * found earlier.
			 */
			err = validate_vid_hdr(vid_hdr, av, pnum);
			err = validate_vid_hdr(ubi, vid_hdr, av, pnum);
			if (err)
				return err;

@@ -565,7 +567,7 @@ int ubi_add_to_av(struct ubi_device *ubi, struct ubi_attach_info *ai, int pnum,
	 * attaching information.
	 */

	err = validate_vid_hdr(vid_hdr, av, pnum);
	err = validate_vid_hdr(ubi, vid_hdr, av, pnum);
	if (err)
		return err;

@@ -668,7 +670,8 @@ static int early_erase_peb(struct ubi_device *ubi,
		 * Erase counter overflow. Upgrade UBI and use 64-bit
		 * erase counters internally.
		 */
		ubi_err("erase counter overflow at PEB %d, EC %d", pnum, ec);
		ubi_err(ubi, "erase counter overflow at PEB %d, EC %d",
			pnum, ec);
		return -EINVAL;
	}

@@ -736,7 +739,7 @@ struct ubi_ainf_peb *ubi_early_get_peb(struct ubi_device *ubi,
		return aeb;
	}

	ubi_err("no free eraseblocks");
	ubi_err(ubi, "no free eraseblocks");
	return ERR_PTR(-ENOSPC);
}

@@ -785,9 +788,9 @@ static int check_corruption(struct ubi_device *ubi, struct ubi_vid_hdr *vid_hdr,
	if (ubi_check_pattern(ubi->peb_buf, 0xFF, ubi->leb_size))
		goto out_unlock;

	ubi_err("PEB %d contains corrupted VID header, and the data does not contain all 0xFF",
	ubi_err(ubi, "PEB %d contains corrupted VID header, and the data does not contain all 0xFF",
		pnum);
	ubi_err("this may be a non-UBI PEB or a severe VID header corruption which requires manual inspection");
	ubi_err(ubi, "this may be a non-UBI PEB or a severe VID header corruption which requires manual inspection");
	ubi_dump_vid_hdr(vid_hdr);
	pr_err("hexdump of PEB %d offset %d, length %d",
	       pnum, ubi->leb_start, ubi->leb_size);
@@ -859,7 +862,8 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai,
		bitflips = 1;
		break;
	default:
		ubi_err("'ubi_io_read_ec_hdr()' returned unknown code %d", err);
		ubi_err(ubi, "'ubi_io_read_ec_hdr()' returned unknown code %d",
			err);
		return -EINVAL;
	}

@@ -868,7 +872,7 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai,

		/* Make sure UBI version is OK */
		if (ech->version != UBI_VERSION) {
			ubi_err("this UBI version is %d, image version is %d",
			ubi_err(ubi, "this UBI version is %d, image version is %d",
				UBI_VERSION, (int)ech->version);
			return -EINVAL;
		}
@@ -882,7 +886,7 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai,
			 * flash. Upgrade UBI and use 64-bit erase counters
			 * internally.
			 */
			ubi_err("erase counter overflow, max is %d",
			ubi_err(ubi, "erase counter overflow, max is %d",
				UBI_MAX_ERASECOUNTER);
			ubi_dump_ec_hdr(ech);
			return -EINVAL;
@@ -903,7 +907,7 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai,
		if (!ubi->image_seq)
			ubi->image_seq = image_seq;
		if (image_seq && ubi->image_seq != image_seq) {
			ubi_err("bad image sequence number %d in PEB %d, expected %d",
			ubi_err(ubi, "bad image sequence number %d in PEB %d, expected %d",
				image_seq, pnum, ubi->image_seq);
			ubi_dump_ec_hdr(ech);
			return -EINVAL;
@@ -981,7 +985,7 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai,
			return err;
		goto adjust_mean_ec;
	default:
		ubi_err("'ubi_io_read_vid_hdr()' returned unknown code %d",
		ubi_err(ubi, "'ubi_io_read_vid_hdr()' returned unknown code %d",
			err);
		return -EINVAL;
	}
@@ -999,7 +1003,7 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai,
		case UBI_COMPAT_DELETE:
			if (vol_id != UBI_FM_SB_VOLUME_ID
			    && vol_id != UBI_FM_DATA_VOLUME_ID) {
				ubi_msg("\"delete\" compatible internal volume %d:%d found, will remove it",
				ubi_msg(ubi, "\"delete\" compatible internal volume %d:%d found, will remove it",
					vol_id, lnum);
			}
			err = add_to_list(ai, pnum, vol_id, lnum,
@@ -1009,13 +1013,13 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai,
			return 0;

		case UBI_COMPAT_RO:
			ubi_msg("read-only compatible internal volume %d:%d found, switch to read-only mode",
			ubi_msg(ubi, "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",
			ubi_msg(ubi, "\"preserve\" compatible internal volume %d:%d found",
				vol_id, lnum);
			err = add_to_list(ai, pnum, vol_id, lnum,
					  ec, 0, &ai->alien);
@@ -1024,14 +1028,14 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai,
			return 0;

		case UBI_COMPAT_REJECT:
			ubi_err("incompatible internal volume %d:%d found",
			ubi_err(ubi, "incompatible internal volume %d:%d found",
				vol_id, lnum);
			return -EINVAL;
		}
	}

	if (ec_err)
		ubi_warn("valid VID header but corrupted EC header at PEB %d",
		ubi_warn(ubi, "valid VID header but corrupted EC header at PEB %d",
			 pnum);
	err = ubi_add_to_av(ubi, ai, pnum, ec, vidh, bitflips);
	if (err)
@@ -1075,7 +1079,7 @@ static int late_analysis(struct ubi_device *ubi, struct ubi_attach_info *ai)
	 * with the flash HW or driver.
	 */
	if (ai->corr_peb_count) {
		ubi_err("%d PEBs are corrupted and preserved",
		ubi_err(ubi, "%d PEBs are corrupted and preserved",
			ai->corr_peb_count);
		pr_err("Corrupted PEBs are:");
		list_for_each_entry(aeb, &ai->corr, u.list)
@@ -1087,7 +1091,7 @@ static int late_analysis(struct ubi_device *ubi, struct ubi_attach_info *ai)
		 * otherwise, only print a warning.
		 */
		if (ai->corr_peb_count >= max_corr) {
			ubi_err("too many corrupted PEBs, refusing");
			ubi_err(ubi, "too many corrupted PEBs, refusing");
			return -EINVAL;
		}
	}
@@ -1110,11 +1114,11 @@ static int late_analysis(struct ubi_device *ubi, struct ubi_attach_info *ai)
		 */
		if (ai->maybe_bad_peb_count <= 2) {
			ai->is_empty = 1;
			ubi_msg("empty MTD device detected");
			ubi_msg(ubi, "empty MTD device detected");
			get_random_bytes(&ubi->image_seq,
					 sizeof(ubi->image_seq));
		} else {
			ubi_err("MTD device is not UBI-formatted and possibly contains non-UBI data - refusing it");
			ubi_err(ubi, "MTD device is not UBI-formatted and possibly contains non-UBI data - refusing it");
			return -EINVAL;
		}

@@ -1248,7 +1252,7 @@ static int scan_all(struct ubi_device *ubi, struct ubi_attach_info *ai,
			goto out_vidh;
	}

	ubi_msg("scanning is finished");
	ubi_msg(ubi, "scanning is finished");

	/* Calculate mean erase counter */
	if (ai->ec_count)
@@ -1297,7 +1301,7 @@ out_ech:
	return err;
}

static struct ubi_attach_info *alloc_ai(const char *slab_name)
static struct ubi_attach_info *alloc_ai(void)
{
	struct ubi_attach_info *ai;

@@ -1310,7 +1314,7 @@ static struct ubi_attach_info *alloc_ai(const char *slab_name)
	INIT_LIST_HEAD(&ai->erase);
	INIT_LIST_HEAD(&ai->alien);
	ai->volumes = RB_ROOT;
	ai->aeb_slab_cache = kmem_cache_create(slab_name,
	ai->aeb_slab_cache = kmem_cache_create("ubi_aeb_slab_cache",
					       sizeof(struct ubi_ainf_peb),
					       0, 0, NULL);
	if (!ai->aeb_slab_cache) {
@@ -1371,7 +1375,7 @@ static int scan_fast(struct ubi_device *ubi, struct ubi_attach_info **ai)
		return UBI_NO_FASTMAP;

	destroy_ai(*ai);
	*ai = alloc_ai("ubi_aeb_slab_cache");
	*ai = alloc_ai();
	if (!*ai)
		return -ENOMEM;

@@ -1400,7 +1404,7 @@ int ubi_attach(struct ubi_device *ubi, int force_scan)
	int err;
	struct ubi_attach_info *ai;

	ai = alloc_ai("ubi_aeb_slab_cache");
	ai = alloc_ai();
	if (!ai)
		return -ENOMEM;

@@ -1415,10 +1419,10 @@ int ubi_attach(struct ubi_device *ubi, int force_scan)
		err = scan_all(ubi, ai, 0);
	else {
		err = scan_fast(ubi, &ai);
		if (err > 0) {
		if (err > 0 || mtd_is_eccerr(err)) {
			if (err != UBI_NO_FASTMAP) {
				destroy_ai(ai);
				ai = alloc_ai("ubi_aeb_slab_cache2");
				ai = alloc_ai();
				if (!ai)
					return -ENOMEM;

@@ -1454,10 +1458,10 @@ int ubi_attach(struct ubi_device *ubi, int force_scan)
		goto out_wl;

#ifdef CONFIG_MTD_UBI_FASTMAP
	if (ubi->fm && ubi_dbg_chk_gen(ubi)) {
	if (ubi->fm && ubi_dbg_chk_fastmap(ubi)) {
		struct ubi_attach_info *scan_ai;

		scan_ai = alloc_ai("ubi_ckh_aeb_slab_cache");
		scan_ai = alloc_ai();
		if (!scan_ai) {
			err = -ENOMEM;
			goto out_wl;
@@ -1520,37 +1524,37 @@ static int self_check_ai(struct ubi_device *ubi, struct ubi_attach_info *ai)
		vols_found += 1;

		if (ai->is_empty) {
			ubi_err("bad is_empty flag");
			ubi_err(ubi, "bad is_empty flag");
			goto bad_av;
		}

		if (av->vol_id < 0 || av->highest_lnum < 0 ||
		    av->leb_count < 0 || av->vol_type < 0 || av->used_ebs < 0 ||
		    av->data_pad < 0 || av->last_data_size < 0) {
			ubi_err("negative values");
			ubi_err(ubi, "negative values");
			goto bad_av;
		}

		if (av->vol_id >= UBI_MAX_VOLUMES &&
		    av->vol_id < UBI_INTERNAL_VOL_START) {
			ubi_err("bad vol_id");
			ubi_err(ubi, "bad vol_id");
			goto bad_av;
		}

		if (av->vol_id > ai->highest_vol_id) {
			ubi_err("highest_vol_id is %d, but vol_id %d is there",
			ubi_err(ubi, "highest_vol_id is %d, but vol_id %d is there",
				ai->highest_vol_id, av->vol_id);
			goto out;
		}

		if (av->vol_type != UBI_DYNAMIC_VOLUME &&
		    av->vol_type != UBI_STATIC_VOLUME) {
			ubi_err("bad vol_type");
			ubi_err(ubi, "bad vol_type");
			goto bad_av;
		}

		if (av->data_pad > ubi->leb_size / 2) {
			ubi_err("bad data_pad");
			ubi_err(ubi, "bad data_pad");
			goto bad_av;
		}

@@ -1562,48 +1566,48 @@ static int self_check_ai(struct ubi_device *ubi, struct ubi_attach_info *ai)
			leb_count += 1;

			if (aeb->pnum < 0 || aeb->ec < 0) {
				ubi_err("negative values");
				ubi_err(ubi, "negative values");
				goto bad_aeb;
			}

			if (aeb->ec < ai->min_ec) {
				ubi_err("bad ai->min_ec (%d), %d found",
				ubi_err(ubi, "bad ai->min_ec (%d), %d found",
					ai->min_ec, aeb->ec);
				goto bad_aeb;
			}

			if (aeb->ec > ai->max_ec) {
				ubi_err("bad ai->max_ec (%d), %d found",
				ubi_err(ubi, "bad ai->max_ec (%d), %d found",
					ai->max_ec, aeb->ec);
				goto bad_aeb;
			}

			if (aeb->pnum >= ubi->peb_count) {
				ubi_err("too high PEB number %d, total PEBs %d",
				ubi_err(ubi, "too high PEB number %d, total PEBs %d",
					aeb->pnum, ubi->peb_count);
				goto bad_aeb;
			}

			if (av->vol_type == UBI_STATIC_VOLUME) {
				if (aeb->lnum >= av->used_ebs) {
					ubi_err("bad lnum or used_ebs");
					ubi_err(ubi, "bad lnum or used_ebs");
					goto bad_aeb;
				}
			} else {
				if (av->used_ebs != 0) {
					ubi_err("non-zero used_ebs");
					ubi_err(ubi, "non-zero used_ebs");
					goto bad_aeb;
				}
			}

			if (aeb->lnum > av->highest_lnum) {
				ubi_err("incorrect highest_lnum or lnum");
				ubi_err(ubi, "incorrect highest_lnum or lnum");
				goto bad_aeb;
			}
		}

		if (av->leb_count != leb_count) {
			ubi_err("bad leb_count, %d objects in the tree",
			ubi_err(ubi, "bad leb_count, %d objects in the tree",
				leb_count);
			goto bad_av;
		}
@@ -1614,13 +1618,13 @@ static int self_check_ai(struct ubi_device *ubi, struct ubi_attach_info *ai)
		aeb = last_aeb;

		if (aeb->lnum != av->highest_lnum) {
			ubi_err("bad highest_lnum");
			ubi_err(ubi, "bad highest_lnum");
			goto bad_aeb;
		}
	}

	if (vols_found != ai->vols_found) {
		ubi_err("bad ai->vols_found %d, should be %d",
		ubi_err(ubi, "bad ai->vols_found %d, should be %d",
			ai->vols_found, vols_found);
		goto out;
	}
@@ -1637,7 +1641,8 @@ static int self_check_ai(struct ubi_device *ubi, struct ubi_attach_info *ai)

			err = ubi_io_read_vid_hdr(ubi, aeb->pnum, vidh, 1);
			if (err && err != UBI_IO_BITFLIPS) {
				ubi_err("VID header is not OK (%d)", err);
				ubi_err(ubi, "VID header is not OK (%d)",
					err);
				if (err > 0)
					err = -EIO;
				return err;
@@ -1646,37 +1651,37 @@ static int self_check_ai(struct ubi_device *ubi, struct ubi_attach_info *ai)
			vol_type = vidh->vol_type == UBI_VID_DYNAMIC ?
				   UBI_DYNAMIC_VOLUME : UBI_STATIC_VOLUME;
			if (av->vol_type != vol_type) {
				ubi_err("bad vol_type");
				ubi_err(ubi, "bad vol_type");
				goto bad_vid_hdr;
			}

			if (aeb->sqnum != be64_to_cpu(vidh->sqnum)) {
				ubi_err("bad sqnum %llu", aeb->sqnum);
				ubi_err(ubi, "bad sqnum %llu", aeb->sqnum);
				goto bad_vid_hdr;
			}

			if (av->vol_id != be32_to_cpu(vidh->vol_id)) {
				ubi_err("bad vol_id %d", av->vol_id);
				ubi_err(ubi, "bad vol_id %d", av->vol_id);
				goto bad_vid_hdr;
			}

			if (av->compat != vidh->compat) {
				ubi_err("bad compat %d", vidh->compat);
				ubi_err(ubi, "bad compat %d", vidh->compat);
				goto bad_vid_hdr;
			}

			if (aeb->lnum != be32_to_cpu(vidh->lnum)) {
				ubi_err("bad lnum %d", aeb->lnum);
				ubi_err(ubi, "bad lnum %d", aeb->lnum);
				goto bad_vid_hdr;
			}

			if (av->used_ebs != be32_to_cpu(vidh->used_ebs)) {
				ubi_err("bad used_ebs %d", av->used_ebs);
				ubi_err(ubi, "bad used_ebs %d", av->used_ebs);
				goto bad_vid_hdr;
			}

			if (av->data_pad != be32_to_cpu(vidh->data_pad)) {
				ubi_err("bad data_pad %d", av->data_pad);
				ubi_err(ubi, "bad data_pad %d", av->data_pad);
				goto bad_vid_hdr;
			}
		}
@@ -1685,12 +1690,13 @@ static int self_check_ai(struct ubi_device *ubi, struct ubi_attach_info *ai)
			continue;

		if (av->highest_lnum != be32_to_cpu(vidh->lnum)) {
			ubi_err("bad highest_lnum %d", av->highest_lnum);
			ubi_err(ubi, "bad highest_lnum %d", av->highest_lnum);
			goto bad_vid_hdr;
		}

		if (av->last_data_size != be32_to_cpu(vidh->data_size)) {
			ubi_err("bad last_data_size %d", av->last_data_size);
			ubi_err(ubi, "bad last_data_size %d",
				av->last_data_size);
			goto bad_vid_hdr;
		}
	}
@@ -1731,7 +1737,7 @@ static int self_check_ai(struct ubi_device *ubi, struct ubi_attach_info *ai)
	err = 0;
	for (pnum = 0; pnum < ubi->peb_count; pnum++)
		if (!buf[pnum]) {
			ubi_err("PEB %d is not referred", pnum);
			ubi_err(ubi, "PEB %d is not referred", pnum);
			err = 1;
		}

@@ -1741,18 +1747,18 @@ static int self_check_ai(struct ubi_device *ubi, struct ubi_attach_info *ai)
	return 0;

bad_aeb:
	ubi_err("bad attaching information about LEB %d", aeb->lnum);
	ubi_err(ubi, "bad attaching information about LEB %d", aeb->lnum);
	ubi_dump_aeb(aeb, 0);
	ubi_dump_av(av);
	goto out;

bad_av:
	ubi_err("bad attaching information about volume %d", av->vol_id);
	ubi_err(ubi, "bad attaching information about volume %d", av->vol_id);
	ubi_dump_av(av);
	goto out;

bad_vid_hdr:
	ubi_err("bad attaching information about volume %d", av->vol_id);
	ubi_err(ubi, "bad attaching information about volume %d", av->vol_id);
	ubi_dump_av(av);
	ubi_dump_vid_hdr(vidh);

+152 −140

File changed.

Preview size limit exceeded, changes collapsed.

+119 −135

File changed.

Preview size limit exceeded, changes collapsed.

+21 −18
Original line number Diff line number Diff line
@@ -60,13 +60,13 @@ static int get_exclusive(struct ubi_volume_desc *desc)
	struct ubi_volume *vol = desc->vol;

	spin_lock(&vol->ubi->volumes_lock);
	users = vol->readers + vol->writers + vol->exclusive;
	users = vol->readers + vol->writers + vol->exclusive + vol->metaonly;
	ubi_assert(users > 0);
	if (users > 1) {
		ubi_err("%d users for volume %d", users, vol->vol_id);
		ubi_err(vol->ubi, "%d users for volume %d", users, vol->vol_id);
		err = -EBUSY;
	} else {
		vol->readers = vol->writers = 0;
		vol->readers = vol->writers = vol->metaonly = 0;
		vol->exclusive = 1;
		err = desc->mode;
		desc->mode = UBI_EXCLUSIVE;
@@ -86,13 +86,15 @@ static void revoke_exclusive(struct ubi_volume_desc *desc, int mode)
	struct ubi_volume *vol = desc->vol;

	spin_lock(&vol->ubi->volumes_lock);
	ubi_assert(vol->readers == 0 && vol->writers == 0);
	ubi_assert(vol->readers == 0 && vol->writers == 0 && vol->metaonly == 0);
	ubi_assert(vol->exclusive == 1 && desc->mode == UBI_EXCLUSIVE);
	vol->exclusive = 0;
	if (mode == UBI_READONLY)
		vol->readers = 1;
	else if (mode == UBI_READWRITE)
		vol->writers = 1;
	else if (mode == UBI_METAONLY)
		vol->metaonly = 1;
	else
		vol->exclusive = 1;
	spin_unlock(&vol->ubi->volumes_lock);
@@ -134,7 +136,7 @@ static int vol_cdev_release(struct inode *inode, struct file *file)
		vol->ubi->ubi_num, vol->vol_id, desc->mode);

	if (vol->updating) {
		ubi_warn("update of volume %d not finished, volume is damaged",
		ubi_warn(vol->ubi, "update of volume %d not finished, volume is damaged",
			 vol->vol_id);
		ubi_assert(!vol->changing_leb);
		vol->updating = 0;
@@ -158,7 +160,7 @@ static loff_t vol_cdev_llseek(struct file *file, loff_t offset, int origin)

	if (vol->updating) {
		/* Update is in progress, seeking is prohibited */
		ubi_err("updating");
		ubi_err(vol->ubi, "updating");
		return -EBUSY;
	}

@@ -193,11 +195,11 @@ static ssize_t vol_cdev_read(struct file *file, __user char *buf, size_t count,
		count, *offp, vol->vol_id);

	if (vol->updating) {
		ubi_err("updating");
		ubi_err(vol->ubi, "updating");
		return -EBUSY;
	}
	if (vol->upd_marker) {
		ubi_err("damaged volume, update marker is set");
		ubi_err(vol->ubi, "damaged volume, update marker is set");
		return -EBADF;
	}
	if (*offp == vol->used_bytes || count == 0)
@@ -277,7 +279,7 @@ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf,

	lnum = div_u64_rem(*offp, vol->usable_leb_size, &off);
	if (off & (ubi->min_io_size - 1)) {
		ubi_err("unaligned position");
		ubi_err(ubi, "unaligned position");
		return -EINVAL;
	}

@@ -286,7 +288,7 @@ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf,

	/* We can write only in fractions of the minimum I/O unit */
	if (count & (ubi->min_io_size - 1)) {
		ubi_err("unaligned write length");
		ubi_err(ubi, "unaligned write length");
		return -EINVAL;
	}

@@ -348,7 +350,7 @@ static ssize_t vol_cdev_write(struct file *file, const char __user *buf,
		err = ubi_more_leb_change_data(ubi, vol, buf, count);

	if (err < 0) {
		ubi_err("cannot accept more %zd bytes of data, error %d",
		ubi_err(ubi, "cannot accept more %zd bytes of data, error %d",
			count, err);
		return err;
	}
@@ -370,7 +372,7 @@ static ssize_t vol_cdev_write(struct file *file, const char __user *buf,
			return err;

		if (err) {
			ubi_warn("volume %d on UBI device %d is corrupted",
			ubi_warn(ubi, "volume %d on UBI device %d is corrupted",
				 vol->vol_id, ubi->ubi_num);
			vol->corrupted = 1;
		}
@@ -642,7 +644,7 @@ static int verify_mkvol_req(const struct ubi_device *ubi,
	return 0;

bad:
	ubi_err("bad volume creation request");
	ubi_err(ubi, "bad volume creation request");
	ubi_dump_mkvol_req(req);
	return err;
}
@@ -708,12 +710,12 @@ static int rename_volumes(struct ubi_device *ubi,
	for (i = 0; i < req->count - 1; i++) {
		for (n = i + 1; n < req->count; n++) {
			if (req->ents[i].vol_id == req->ents[n].vol_id) {
				ubi_err("duplicated volume id %d",
				ubi_err(ubi, "duplicated volume id %d",
					req->ents[i].vol_id);
				return -EINVAL;
			}
			if (!strcmp(req->ents[i].name, req->ents[n].name)) {
				ubi_err("duplicated volume name \"%s\"",
				ubi_err(ubi, "duplicated volume name \"%s\"",
					req->ents[i].name);
				return -EINVAL;
			}
@@ -733,10 +735,11 @@ static int rename_volumes(struct ubi_device *ubi,
			goto out_free;
		}

		re->desc = ubi_open_volume(ubi->ubi_num, vol_id, UBI_READWRITE);
		re->desc = ubi_open_volume(ubi->ubi_num, vol_id, UBI_METAONLY);
		if (IS_ERR(re->desc)) {
			err = PTR_ERR(re->desc);
			ubi_err("cannot open volume %d, error %d", vol_id, err);
			ubi_err(ubi, "cannot open volume %d, error %d",
				vol_id, err);
			kfree(re);
			goto out_free;
		}
@@ -795,7 +798,7 @@ static int rename_volumes(struct ubi_device *ubi,
				continue;

			/* The volume exists but busy, or an error occurred */
			ubi_err("cannot open volume \"%s\", error %d",
			ubi_err(ubi, "cannot open volume \"%s\", error %d",
				re->new_name, err);
			goto out_free;
		}
+103 −7
Original line number Diff line number Diff line
@@ -43,12 +43,12 @@ void ubi_dump_flash(struct ubi_device *ubi, int pnum, int offset, int len)
		return;
	err = mtd_read(ubi->mtd, addr, len, &read, buf);
	if (err && err != -EUCLEAN) {
		ubi_err("error %d while reading %d bytes from PEB %d:%d, read %zd bytes",
		ubi_err(ubi, "err %d while reading %d bytes from PEB %d:%d, read %zd bytes",
			err, len, pnum, offset, read);
		goto out;
	}

	ubi_msg("dumping %d bytes of data from PEB %d, offset %d",
	ubi_msg(ubi, "dumping %d bytes of data from PEB %d, offset %d",
		len, pnum, offset);
	print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, buf, len, 1);
out:
@@ -238,7 +238,7 @@ int ubi_debugfs_init(void)
	if (IS_ERR_OR_NULL(dfs_rootdir)) {
		int err = dfs_rootdir ? -ENODEV : PTR_ERR(dfs_rootdir);

		ubi_err("cannot create \"ubi\" debugfs directory, error %d\n",
		pr_err("UBI error: cannot create \"ubi\" debugfs directory, error %d\n",
		       err);
		return err;
	}
@@ -263,7 +263,7 @@ static ssize_t dfs_file_read(struct file *file, char __user *user_buf,
	struct dentry *dent = file->f_path.dentry;
	struct ubi_device *ubi;
	struct ubi_debug_info *d;
	char buf[3];
	char buf[8];
	int val;

	ubi = ubi_get_device(ubi_num);
@@ -275,12 +275,30 @@ static ssize_t dfs_file_read(struct file *file, char __user *user_buf,
		val = d->chk_gen;
	else if (dent == d->dfs_chk_io)
		val = d->chk_io;
	else if (dent == d->dfs_chk_fastmap)
		val = d->chk_fastmap;
	else if (dent == d->dfs_disable_bgt)
		val = d->disable_bgt;
	else if (dent == d->dfs_emulate_bitflips)
		val = d->emulate_bitflips;
	else if (dent == d->dfs_emulate_io_failures)
		val = d->emulate_io_failures;
	else if (dent == d->dfs_emulate_power_cut) {
		snprintf(buf, sizeof(buf), "%u\n", d->emulate_power_cut);
		count = simple_read_from_buffer(user_buf, count, ppos,
						buf, strlen(buf));
		goto out;
	} else if (dent == d->dfs_power_cut_min) {
		snprintf(buf, sizeof(buf), "%u\n", d->power_cut_min);
		count = simple_read_from_buffer(user_buf, count, ppos,
						buf, strlen(buf));
		goto out;
	} else if (dent == d->dfs_power_cut_max) {
		snprintf(buf, sizeof(buf), "%u\n", d->power_cut_max);
		count = simple_read_from_buffer(user_buf, count, ppos,
						buf, strlen(buf));
		goto out;
	}
	else {
		count = -EINVAL;
		goto out;
@@ -309,7 +327,7 @@ static ssize_t dfs_file_write(struct file *file, const char __user *user_buf,
	struct ubi_device *ubi;
	struct ubi_debug_info *d;
	size_t buf_size;
	char buf[8];
	char buf[8] = {0};
	int val;

	ubi = ubi_get_device(ubi_num);
@@ -323,6 +341,21 @@ static ssize_t dfs_file_write(struct file *file, const char __user *user_buf,
		goto out;
	}

	if (dent == d->dfs_power_cut_min) {
		if (kstrtouint(buf, 0, &d->power_cut_min) != 0)
			count = -EINVAL;
		goto out;
	} else if (dent == d->dfs_power_cut_max) {
		if (kstrtouint(buf, 0, &d->power_cut_max) != 0)
			count = -EINVAL;
		goto out;
	} else if (dent == d->dfs_emulate_power_cut) {
		if (kstrtoint(buf, 0, &val) != 0)
			count = -EINVAL;
		d->emulate_power_cut = val;
		goto out;
	}

	if (buf[0] == '1')
		val = 1;
	else if (buf[0] == '0')
@@ -336,6 +369,8 @@ static ssize_t dfs_file_write(struct file *file, const char __user *user_buf,
		d->chk_gen = val;
	else if (dent == d->dfs_chk_io)
		d->chk_io = val;
	else if (dent == d->dfs_chk_fastmap)
		d->chk_fastmap = val;
	else if (dent == d->dfs_disable_bgt)
		d->disable_bgt = val;
	else if (dent == d->dfs_emulate_bitflips)
@@ -406,6 +441,13 @@ int ubi_debugfs_init_dev(struct ubi_device *ubi)
		goto out_remove;
	d->dfs_chk_io = dent;

	fname = "chk_fastmap";
	dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
				   &dfs_fops);
	if (IS_ERR_OR_NULL(dent))
		goto out_remove;
	d->dfs_chk_fastmap = dent;

	fname = "tst_disable_bgt";
	dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
				   &dfs_fops);
@@ -427,13 +469,34 @@ int ubi_debugfs_init_dev(struct ubi_device *ubi)
		goto out_remove;
	d->dfs_emulate_io_failures = dent;

	fname = "tst_emulate_power_cut";
	dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
				   &dfs_fops);
	if (IS_ERR_OR_NULL(dent))
		goto out_remove;
	d->dfs_emulate_power_cut = dent;

	fname = "tst_emulate_power_cut_min";
	dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
				   &dfs_fops);
	if (IS_ERR_OR_NULL(dent))
		goto out_remove;
	d->dfs_power_cut_min = dent;

	fname = "tst_emulate_power_cut_max";
	dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num,
				   &dfs_fops);
	if (IS_ERR_OR_NULL(dent))
		goto out_remove;
	d->dfs_power_cut_max = dent;

	return 0;

out_remove:
	debugfs_remove_recursive(d->dfs_dir);
out:
	err = dent ? PTR_ERR(dent) : -ENODEV;
	ubi_err("cannot create \"%s\" debugfs file or directory, error %d\n",
	ubi_err(ubi, "cannot create \"%s\" debugfs file or directory, error %d\n",
		fname, err);
	return err;
}
@@ -447,3 +510,36 @@ void ubi_debugfs_exit_dev(struct ubi_device *ubi)
	if (IS_ENABLED(CONFIG_DEBUG_FS))
		debugfs_remove_recursive(ubi->dbg.dfs_dir);
}

/**
 * ubi_dbg_power_cut - emulate a power cut if it is time to do so
 * @ubi: UBI device description object
 * @caller: Flags set to indicate from where the function is being called
 *
 * Returns non-zero if a power cut was emulated, zero if not.
 */
int ubi_dbg_power_cut(struct ubi_device *ubi, int caller)
{
	unsigned int range;

	if ((ubi->dbg.emulate_power_cut & caller) == 0)
		return 0;

	if (ubi->dbg.power_cut_counter == 0) {
		ubi->dbg.power_cut_counter = ubi->dbg.power_cut_min;

		if (ubi->dbg.power_cut_max > ubi->dbg.power_cut_min) {
			range = ubi->dbg.power_cut_max - ubi->dbg.power_cut_min;
			ubi->dbg.power_cut_counter += prandom_u32() % range;
		}
		return 0;
	}

	ubi->dbg.power_cut_counter--;
	if (ubi->dbg.power_cut_counter)
		return 0;

	ubi_msg(ubi, "XXXXXXXXXXXXXXX emulating a power cut XXXXXXXXXXXXXXXX");
	ubi_ro_mode(ubi);
	return 1;
}
Loading