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

Commit 4bc1dca4 authored by Artem Bityutskiy's avatar Artem Bityutskiy
Browse files

UBI: fix mean EC calculation



(a + b) / (c + d) != a / c + b / d. The old code errornously
assumed this incorrect formuld. Instead, just sum all erase
counters in a 64-bit variable and divide to the number of EBs
at the end.

Thanks to Adrian Hunter for pointing this out.

Signed-off-by: default avatarArtem Bityutskiy <Artem.Bityutskiy@nokia.com>
parent cbd8a9d2
Loading
Loading
Loading
Loading
+8 −33
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@

#include <linux/err.h>
#include <linux/crc32.h>
#include <asm/div64.h>
#include "ubi.h"

#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
@@ -91,27 +92,6 @@ static int add_to_list(struct ubi_scan_info *si, int pnum, int ec,
	return 0;
}

/**
 * commit_to_mean_value - commit intermediate results to the final mean erase
 * counter value.
 * @si: scanning information
 *
 * This is a helper function which calculates partial mean erase counter mean
 * value and adds it to the resulting mean value. As we can work only in
 * integer arithmetic and we want to calculate the mean value of erase counter
 * accurately, we first sum erase counter values in @si->ec_sum variable and
 * count these components in @si->ec_count. If this temporary @si->ec_sum is
 * going to overflow, we calculate the partial mean value
 * (@si->ec_sum/@si->ec_count) and add it to @si->mean_ec.
 */
static void commit_to_mean_value(struct ubi_scan_info *si)
{
	si->ec_sum /= si->ec_count;
	if (si->ec_sum % si->ec_count >= si->ec_count / 2)
		si->mean_ec += 1;
	si->mean_ec += si->ec_sum;
}

/**
 * validate_vid_hdr - check that volume identifier header is correct and
 * consistent.
@@ -901,15 +881,8 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum

adjust_mean_ec:
	if (!ec_corr) {
		if (si->ec_sum + ec < ec) {
			commit_to_mean_value(si);
			si->ec_sum = 0;
			si->ec_count = 0;
		} else {
		si->ec_sum += ec;
		si->ec_count += 1;
		}

		if (ec > si->max_ec)
			si->max_ec = ec;
		if (ec < si->min_ec)
@@ -965,9 +938,11 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi)

	dbg_msg("scanning is finished");

	/* Finish mean erase counter calculations */
	if (si->ec_count)
		commit_to_mean_value(si);
	/* Calculate mean erase counter */
	if (si->ec_count) {
		do_div(si->ec_sum, si->ec_count);
		si->mean_ec = si->ec_sum;
	}

	if (si->is_empty)
		ubi_msg("empty MTD device detected");
+1 −1
Original line number Diff line number Diff line
@@ -124,7 +124,7 @@ struct ubi_scan_info {
	int max_ec;
	unsigned long long max_sqnum;
	int mean_ec;
	int ec_sum;
	uint64_t ec_sum;
	int ec_count;
};