public inbox for linux-mtd@lists.infradead.org
 help / color / mirror / Atom feed
* ubi: suspicious calculation in 'ubi_wl_get_peb'
@ 2012-02-17 13:38 Shmulik Ladkani
  2012-03-07 17:20 ` Artem Bityutskiy
  0 siblings, 1 reply; 7+ messages in thread
From: Shmulik Ladkani @ 2012-02-17 13:38 UTC (permalink / raw)
  To: dedekind1; +Cc: linux-mtd

Hi,

Sorry for a long post - this issue requires some detailed background.

It looks like a calculation within 'ubi_wl_get_peb' involved in
picking a candidate PEB is incorrect.

The function 'find_wl_entry(rb_root *root, int max)' finds a
wear-leveling entry closest to a certain erase counter.

The parameter 'max' is documented as "highest possible erase counter",
however it is actually "diff from first entry" - since initially, the
funtion adds first entry's EC to the given 'max':

	e = rb_entry(rb_first(root), struct ubi_wl_entry, u.rb);
	max += e->ec;

Almost all calls to 'find_wl_entry' follow the (undocumented)
convention, providing "diff from first" argument (where the absolute
'max' value seeked is calculated *internally* by 'find_wl_entry').
E.g. 4 of 5 calls are of the pattern:

	e = find_wl_entry(&ubi->free, WL_FREE_MAX_DIFF);

However, there is one call where the caller seems to provide an actual
absolute "max" value, instead of a "diff from first".
The call is within 'ubi_wl_get_peb', quote:

	case UBI_UNKNOWN:
		/*
		 * For unknown data we pick a physical eraseblock with medium
		 * erase counter. But we by no means can pick a physical
		 * eraseblock with erase counter greater or equivalent than the
		 * lowest erase counter plus %WL_FREE_MAX_DIFF.
		 */
		first = rb_entry(rb_first(&ubi->free), struct ubi_wl_entry,
					u.rb);
		last = rb_entry(rb_last(&ubi->free), struct ubi_wl_entry, u.rb);

		if (last->ec - first->ec < WL_FREE_MAX_DIFF)
			e = rb_entry(ubi->free.rb_node,
					struct ubi_wl_entry, u.rb);
		else {
			medium_ec = (first->ec + WL_FREE_MAX_DIFF)/2;
			e = find_wl_entry(&ubi->free, medium_ec);
		}
		break;

Note calculation of 'medium_ec' - it does no seem as a "diff" value.
The *actual* resulting seeked EC is approximately 1.5*First + Diff/2.
Is it the intended behavior? it does not seem to fit the remark.

Deducting from the "last->ec - first->ec < WL_FREE_MAX_DIFF" condition,
it looks like it should have been:

-			e = find_wl_entry(&ubi->free, medium_ec);
+			e = find_wl_entry(&ubi->free, WL_FREE_MAX_DIFF/2)

Did I get something wrong?

Looking forward for any comments.

Regards,
Shmulik

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2012-03-08 10:57 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-02-17 13:38 ubi: suspicious calculation in 'ubi_wl_get_peb' Shmulik Ladkani
2012-03-07 17:20 ` Artem Bityutskiy
2012-03-07 17:31   ` Artem Bityutskiy
2012-03-07 20:08   ` Shmulik Ladkani
2012-03-08 11:00     ` Artem Bityutskiy
2012-03-07 20:26   ` Shmulik Ladkani
2012-03-07 20:43   ` Shmulik Ladkani

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox