Skip to contentSkip to conversation

mtd: ubi: Fill read disturb statistics

PATCH In review Tanya Brokhman 1 participant 1 message Oct 26, 2014

Subsystems (4)
lore
Share & tools
lore
#0 lore raw

PATCH v2 2/5 mtd: ubi: Fill read disturb statistics

Fill in eraseblock statistics needed for read disturb decision making:
1. read counter: incremented at each read operation
reset at each erase operation
Saved only as part of the meta data in RAM
On attach: if fastmap data is missing a default value is assigned
2. last erase time stamp: updated at each erase operation. Saved as part of PEB OOB info on flash
On attach: if fastmap data is missing retrieved from PEB EC Header on NAND.
If fastmap data is corrupted a default value is assigned.

The above parameters are saved as part of the fastmap data.

---
 drivers/mtd/ubi/attach.c  | 137 +++++++++++++++++++++++++++++++++++-----------
 drivers/mtd/ubi/debug.c   |  11 ++++
 drivers/mtd/ubi/fastmap.c | 118 ++++++++++++++++++++++++++++++++++-----
 drivers/mtd/ubi/io.c      |  28 ++++++++++
 drivers/mtd/ubi/ubi.h     |  24 +++++++-
 drivers/mtd/ubi/vtbl.c    |   6 +-
 drivers/mtd/ubi/wl.c      |  47 ++++++++++++++++
 7 files changed, 322 insertions(+), 49 deletions(-)
drivers/mtd/ubi/attach.c +105 -32
index 6f27d9a..e102cac 100644
@@ -1,5 +1,8 @@
 /*
  * Copyright (c) International Business Machines Corp., 2006
+ * Copyright (c) 2014, Linux Foundation. All rights reserved.
+ * Linux Foundation chooses to take subject only to the GPLv2
+ * license terms, and distributes only under these terms.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -87,8 +90,21 @@
 #include <linux/crc32.h>
 #include <linux/math64.h>
 #include <linux/random.h>
+#include <linux/time.h>
 #include "ubi.h"
 
+#define set_aeb_default_values(aeb, ai)		\
+	do {					\
+		if (aeb->ec == UBI_UNKNOWN) {	\
+			aeb->ec = ai->mean_ec;	\
+			if (ai->mean_last_erase_time) \
+				aeb->last_erase_time = \
+					ai->mean_last_erase_time; \
+			else \
+				aeb->last_erase_time = UBI_DT_THRESHOLD / 2; \
+		}		\
+	} while (0)
+
 static int self_check_ai(struct ubi_device *ubi, struct ubi_attach_info *ai);
 
 /* Temporary variables used during scanning */
@@ -102,6 +118,9 @@ static struct ubi_vid_hdr *vidh;
  * @vol_id: the last used volume id for the PEB
  * @lnum: the last used LEB number for the PEB
  * @ec: erase counter of the physical eraseblock
+ * @last_erase_time: last erase time stamp (%UBI_UNKNOWN if it
+ *				is unknown)
+ * @rc: read counter (%UBI_UNKNOWN if it is unknown)
  * @to_head: if not zero, add to the head of the list
  * @list: the list to add to
  *
@@ -117,7 +136,8 @@ static struct ubi_vid_hdr *vidh;
  * failure.
  */
 static int add_to_list(struct ubi_attach_info *ai, int pnum, int vol_id,
-		       int lnum, int ec, int to_head, struct list_head *list)
+		       int lnum, int ec, long last_erase_time, long rc,
+		       int to_head, struct list_head *list)
 {
 	struct ubi_ainf_peb *aeb;
 
@@ -139,6 +159,9 @@ static int add_to_list(struct ubi_attach_info *ai, int pnum, int vol_id,
 	aeb->vol_id = vol_id;
 	aeb->lnum = lnum;
 	aeb->ec = ec;
+	aeb->rc = rc;
+	aeb->last_erase_time = last_erase_time;
+
 	if (to_head)
 		list_add(&aeb->u.list, list);
 	else
@@ -151,13 +174,17 @@ static int add_to_list(struct ubi_attach_info *ai, int pnum, int vol_id,
  * @ai: attaching information
  * @pnum: physical eraseblock number to add
  * @ec: erase counter of the physical eraseblock
+ * @last_erase_time: last erase time stamp (%UBI_UNKNOWN if it
+ *			   is unknown)
+ * @rc: read counter (%UBI_UNKNOWN if it is unknown)
  *
  * This function allocates a 'struct ubi_ainf_peb' object for a corrupted
  * physical eraseblock @pnum and adds it to the 'corr' list.  The corruption
  * was presumably not caused by a power cut. Returns zero in case of success
  * and a negative error code in case of failure.
  */
-static int add_corrupted(struct ubi_attach_info *ai, int pnum, int ec)
+static int add_corrupted(struct ubi_attach_info *ai, int pnum,
+			 int ec, long rc, long last_erase_time)
 {
 	struct ubi_ainf_peb *aeb;
 
@@ -170,6 +197,8 @@ static int add_corrupted(struct ubi_attach_info *ai, int pnum, int ec)
 	ai->corr_peb_count += 1;
 	aeb->pnum = pnum;
 	aeb->ec = ec;
+	aeb->rc = rc;
+	aeb->last_erase_time = last_erase_time;
 	list_add(&aeb->u.list, &ai->corr);
 	return 0;
 }
@@ -434,6 +463,9 @@ out_free_vidh:
  * @ai: attaching information
  * @pnum: the physical eraseblock number
  * @ec: erase counter
+ * @last_erase_time: last erase time stamp (%UBI_UNKNOWN if it
+ *			   is unknown)
+ * @rc: read counter (%UBI_UNKNOWN if it is unknown)
  * @vid_hdr: the volume identifier header
  * @bitflips: if bit-flips were detected when this physical eraseblock was read
  *
@@ -445,7 +477,8 @@ out_free_vidh:
  * zero in case of success and a negative error code in case of failure.
  */
 int ubi_add_to_av(struct ubi_device *ubi, struct ubi_attach_info *ai, int pnum,
-		  int ec, const struct ubi_vid_hdr *vid_hdr, int bitflips)
+		  int ec, long last_erase_time, long rc,
+		  const struct ubi_vid_hdr *vid_hdr, int bitflips)
 {
 	int err, vol_id, lnum;
 	unsigned long long sqnum;
@@ -532,12 +565,16 @@ int ubi_add_to_av(struct ubi_device *ubi, struct ubi_attach_info *ai, int pnum,
 				return err;
 
 			err = add_to_list(ai, aeb->pnum, aeb->vol_id,
-					  aeb->lnum, aeb->ec, cmp_res & 4,
+					  aeb->lnum, aeb->ec,
+					  aeb->last_erase_time,
+					  aeb->rc, cmp_res & 4,
 					  &ai->erase);
 			if (err)
 				return err;
 
 			aeb->ec = ec;
+			aeb->last_erase_time = last_erase_time;
+			aeb->rc = rc;
 			aeb->pnum = pnum;
 			aeb->vol_id = vol_id;
 			aeb->lnum = lnum;
@@ -556,7 +593,8 @@ int ubi_add_to_av(struct ubi_device *ubi, struct ubi_attach_info *ai, int pnum,
 			 * previously.
 			 */
 			return add_to_list(ai, pnum, vol_id, lnum, ec,
-					   cmp_res & 4, &ai->erase);
+					   last_erase_time, rc, cmp_res & 4,
+					   &ai->erase);
 		}
 	}
 
@@ -574,6 +612,8 @@ int ubi_add_to_av(struct ubi_device *ubi, struct ubi_attach_info *ai, int pnum,
 		return -ENOMEM;
 
 	aeb->ec = ec;
+	aeb->last_erase_time = last_erase_time;
+	aeb->rc = rc;
 	aeb->pnum = pnum;
 	aeb->vol_id = vol_id;
 	aeb->lnum = lnum;
@@ -650,6 +690,8 @@ void ubi_remove_av(struct ubi_attach_info *ai, struct ubi_ainf_volume *av)
  * @ai: attaching information
  * @pnum: physical eraseblock number to erase;
  * @ec: erase counter value to write (%UBI_UNKNOWN if it is unknown)
+ * @last_erase_time: last erase time stamp (%UBI_UNKNOWN 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
@@ -658,7 +700,8 @@ void ubi_remove_av(struct ubi_attach_info *ai, struct ubi_ainf_volume *av)
  * case of failure.
  */
 static int early_erase_peb(struct ubi_device *ubi,
-			   const struct ubi_attach_info *ai, int pnum, int ec)
+			   const struct ubi_attach_info *ai,
+			   int pnum, int ec, long last_erase_time)
 {
 	int err;
 	struct ubi_ec_hdr *ec_hdr;
@@ -677,7 +720,7 @@ static int early_erase_peb(struct ubi_device *ubi,
 		return -ENOMEM;
 
 	ec_hdr->ec = cpu_to_be64(ec);
-
+	ec_hdr->last_erase_time = cpu_to_be64(last_erase_time);
 	err = ubi_io_sync_erase(ubi, pnum, 0);
 	if (err < 0)
 		goto out_free;
@@ -708,6 +751,7 @@ struct ubi_ainf_peb *ubi_early_get_peb(struct ubi_device *ubi,
 {
 	int err = 0;
 	struct ubi_ainf_peb *aeb, *tmp_aeb;
+	struct timeval tv;
 
 	if (!list_empty(&ai->free)) {
 		aeb = list_entry(ai->free.next, struct ubi_ainf_peb, u.list);
@@ -722,15 +766,20 @@ struct ubi_ainf_peb *ubi_early_get_peb(struct ubi_device *ubi,
 	 * so forth. We don't want to take care about bad eraseblocks here -
 	 * they'll be handled later.
 	 */
+	do_gettimeofday(&tv);
 	list_for_each_entry_safe(aeb, tmp_aeb, &ai->erase, u.list) {
 		if (aeb->ec == UBI_UNKNOWN)
 			aeb->ec = ai->mean_ec;
 
-		err = early_erase_peb(ubi, ai, aeb->pnum, aeb->ec+1);
+		/* The last erase time resolution is in days */
+		err = early_erase_peb(ubi, ai, aeb->pnum,
+				  aeb->ec+1, tv.tv_sec / NUM_SEC_IN_DAY);
 		if (err)
 			continue;
 
 		aeb->ec += 1;
+		aeb->last_erase_time = tv.tv_sec / NUM_SEC_IN_DAY;
+		aeb->rc = 0;
 		list_del(&aeb->u.list);
 		dbg_bld("return PEB %d, EC %d", aeb->pnum, aeb->ec);
 		return aeb;
@@ -817,6 +866,8 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai,
 		    int pnum, int *vid, unsigned long long *sqnum)
 {
 	long long uninitialized_var(ec);
+	long long uninitialized_var(rc);
+	long long uninitialized_var(last_erase_time);
 	int err, bitflips = 0, vol_id = -1, ec_err = 0;
 
 	dbg_bld("scan PEB %d", pnum);
@@ -842,11 +893,13 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai,
 	case UBI_IO_FF:
 		ai->empty_peb_count += 1;
 		return add_to_list(ai, pnum, UBI_UNKNOWN, UBI_UNKNOWN,
-				   UBI_UNKNOWN, 0, &ai->erase);
+				   UBI_UNKNOWN, UBI_UNKNOWN, UBI_UNKNOWN,
+				   0, &ai->erase);
 	case UBI_IO_FF_BITFLIPS:
 		ai->empty_peb_count += 1;
 		return add_to_list(ai, pnum, UBI_UNKNOWN, UBI_UNKNOWN,
-				   UBI_UNKNOWN, 1, &ai->erase);
+				   UBI_UNKNOWN, UBI_UNKNOWN, UBI_UNKNOWN,
+				   1, &ai->erase);
 	case UBI_IO_BAD_HDR_EBADMSG:
 	case UBI_IO_BAD_HDR:
 		/*
@@ -856,6 +909,8 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai,
 		 */
 		ec_err = err;
 		ec = UBI_UNKNOWN;
+		last_erase_time = UBI_UNKNOWN;
+		rc = UBI_UNKNOWN;
 		bitflips = 1;
 		break;
 	default:
@@ -874,6 +929,16 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai,
 		}
 
 		ec = be64_to_cpu(ech->ec);
+		last_erase_time = be64_to_cpu(ech->last_erase_time);
+		/*
+		 * Default value for read counter should be 0. If this is a
+		 * free or erased peb, the counter has no meaning.
+		 * If this peb is used, later code will schedule the peb for
+		 * scrubbing. We can afford erasing all used blocks in this
+		 * case as this is a rear case, and not doing so might have
+		 * destructive implication on the system.
+		 */
+		rc = 0;
 		if (ec > UBI_MAX_ERASECOUNTER) {
 			/*
 			 * Erase counter overflow. The EC headers have 64 bits
@@ -957,29 +1022,32 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai,
 		else if (!err)
 			/* This corruption is caused by a power cut */
 			err = add_to_list(ai, pnum, UBI_UNKNOWN,
-					  UBI_UNKNOWN, ec, 1, &ai->erase);
+					  UBI_UNKNOWN, ec, last_erase_time, rc,
+					  1, &ai->erase);
 		else
 			/* This is an unexpected corruption */
-			err = add_corrupted(ai, pnum, ec);
+			err = add_corrupted(ai, pnum, ec, rc, last_erase_time);
 		if (err)
 			return err;
-		goto adjust_mean_ec;
+		goto adjust_mean_av_stat;
 	case UBI_IO_FF_BITFLIPS:
 		err = add_to_list(ai, pnum, UBI_UNKNOWN, UBI_UNKNOWN,
-				  ec, 1, &ai->erase);
+				  ec, last_erase_time, rc, 1, &ai->erase);
 		if (err)
 			return err;
-		goto adjust_mean_ec;
+		goto adjust_mean_av_stat;
 	case UBI_IO_FF:
 		if (ec_err || bitflips)
 			err = add_to_list(ai, pnum, UBI_UNKNOWN,
-					  UBI_UNKNOWN, ec, 1, &ai->erase);
+					  UBI_UNKNOWN, ec, last_erase_time, rc,
+					  1, &ai->erase);
 		else
 			err = add_to_list(ai, pnum, UBI_UNKNOWN,
-					  UBI_UNKNOWN, ec, 0, &ai->free);
+					  UBI_UNKNOWN, ec, last_erase_time, 0,
+					  0, &ai->free);
 		if (err)
 			return err;
-		goto adjust_mean_ec;
+		goto adjust_mean_av_stat;
 	default:
 		ubi_err("'ubi_io_read_vid_hdr()' returned unknown code %d",
 			err);
@@ -1003,7 +1071,8 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai,
 					vol_id, lnum);
 			}
 			err = add_to_list(ai, pnum, vol_id, lnum,
-					  ec, 1, &ai->erase);
+					  ec, last_erase_time,
+					  rc, 1, &ai->erase);
 			if (err)
 				return err;
 			return 0;
@@ -1018,7 +1087,8 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai,
 			ubi_msg("\"preserve\" compatible internal volume %d:%d found",
 				vol_id, lnum);
 			err = add_to_list(ai, pnum, vol_id, lnum,
-					  ec, 0, &ai->alien);
+					  ec, last_erase_time,
+					  rc, 0, &ai->alien);
 			if (err)
 				return err;
 			return 0;
@@ -1033,11 +1103,13 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai,
 	if (ec_err)
 		ubi_warn("valid VID header but corrupted EC header at PEB %d",
 			 pnum);
-	err = ubi_add_to_av(ubi, ai, pnum, ec, vidh, bitflips);
+
+	err = ubi_add_to_av(ubi, ai, pnum, ec, last_erase_time,
+				UBI_DEF_RD_THRESHOLD, vidh, bitflips);
 	if (err)
 		return err;
 
-adjust_mean_ec:
+adjust_mean_av_stat:
 	if (!ec_err) {
 		ai->ec_sum += ec;
 		ai->ec_count += 1;
@@ -1045,6 +1117,8 @@ adjust_mean_ec:
 			ai->max_ec = ec;
 		if (ec < ai->min_ec)
 			ai->min_ec = ec;
+		ai->last_erase_time_sum += last_erase_time;
+		ai->last_erase_time_count++;
 	}
 
 	return 0;
@@ -1254,6 +1328,10 @@ static int scan_all(struct ubi_device *ubi, struct ubi_attach_info *ai,
 	if (ai->ec_count)
 		ai->mean_ec = div_u64(ai->ec_sum, ai->ec_count);
 
+	if (ai->last_erase_time_count)
+		ai->mean_last_erase_time = div_u64(ai->last_erase_time_sum,
+						   ai->last_erase_time_count);
+
 	err = late_analysis(ubi, ai);
 	if (err)
 		goto out_vidh;
@@ -1264,22 +1342,17 @@ static int scan_all(struct ubi_device *ubi, struct ubi_attach_info *ai,
 	 */
 	ubi_rb_for_each_entry(rb1, av, &ai->volumes, rb) {
 		ubi_rb_for_each_entry(rb2, aeb, &av->root, u.rb)
-			if (aeb->ec == UBI_UNKNOWN)
-				aeb->ec = ai->mean_ec;
+			set_aeb_default_values(aeb, ai);
 	}
 
-	list_for_each_entry(aeb, &ai->free, u.list) {
-		if (aeb->ec == UBI_UNKNOWN)
-			aeb->ec = ai->mean_ec;
-	}
+	list_for_each_entry(aeb, &ai->free, u.list)
+		set_aeb_default_values(aeb, ai);
 
 	list_for_each_entry(aeb, &ai->corr, u.list)
-		if (aeb->ec == UBI_UNKNOWN)
-			aeb->ec = ai->mean_ec;
+		set_aeb_default_values(aeb, ai);
 
 	list_for_each_entry(aeb, &ai->erase, u.list)
-		if (aeb->ec == UBI_UNKNOWN)
-			aeb->ec = ai->mean_ec;
+		set_aeb_default_values(aeb, ai);
 
 	err = self_check_ai(ubi, ai);
 	if (err)
drivers/mtd/ubi/debug.c +11 -0
index 63cb1d7..d172c7c 100644
@@ -1,5 +1,8 @@
 /*
  * Copyright (c) International Business Machines Corp., 2006
+ * Copyright (c) 2014, Linux Foundation. All rights reserved.
+ * Linux Foundation chooses to take subject only to the GPLv2
+ * license terms, and distributes only under these terms.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -47,6 +50,14 @@ void ubi_dump_flash(struct ubi_device *ubi, int pnum, int offset, int len)
 			err, len, pnum, offset, read);
 		goto out;
 	}
+	if (ubi->lookuptbl) {
+		if (ubi->lookuptbl[pnum]->rc < UBI_MAX_READCOUNTER)
+			ubi->lookuptbl[pnum]->rc++;
+		else
+			ubi_err("read counter overflow at PEB %d, RC %d",
+					pnum, ubi->lookuptbl[pnum]->rc);
+	} else
+		ubi_err("Can't update RC. No lookuptbl");
 
 	ubi_msg("dumping %d bytes of data from PEB %d, offset %d",
 		len, pnum, offset);
drivers/mtd/ubi/fastmap.c +103 -15

324 lines not on this page · raw message

drivers/mtd/ubi/io.c +28 -0
index d361349..444d552 100644
@@ -1,6 +1,9 @@
 /*
  * Copyright (c) International Business Machines Corp., 2006
  * Copyright (c) Nokia Corporation, 2006, 2007
+ * Copyright (c) 2014, Linux Foundation. All rights reserved.
+ * Linux Foundation chooses to take subject only to the GPLv2
+ * license terms, and distributes only under these terms.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -204,6 +207,14 @@ retry:
 		}
 	} else {
 		ubi_assert(len == read);
+		if (ubi->lookuptbl && ubi->lookuptbl[pnum]) {
+			if (ubi->lookuptbl[pnum]->rc <
+				UBI_MAX_READCOUNTER)
+				ubi->lookuptbl[pnum]->rc++;
+			else
+				ubi_err("read counter overflow at PEB %d, RC %d",
+					pnum, ubi->lookuptbl[pnum]->rc);
+		}
 
 		if (ubi_dbg_is_bitflip(ubi)) {
 			dbg_gen("bit-flip (emulated)");
@@ -1337,6 +1348,15 @@ static int self_check_write(struct ubi_device *ubi, const void *buf, int pnum,
 	if (err && !mtd_is_bitflip(err))
 		goto out_free;
 
+	if (ubi->lookuptbl && ubi->lookuptbl[pnum]) {
+		if (ubi->lookuptbl[pnum]->rc < UBI_MAX_READCOUNTER)
+			ubi->lookuptbl[pnum]->rc++;
+		else
+			ubi_err("read counter overflow at PEB %d, RC %d",
+					pnum, ubi->lookuptbl[pnum]->rc);
+	} else
+		ubi_err("Can't update RC. No lookuptbl");
+
 	for (i = 0; i < len; i++) {
 		uint8_t c = ((uint8_t *)buf)[i];
 		uint8_t c1 = ((uint8_t *)buf1)[i];
@@ -1403,6 +1423,14 @@ int ubi_self_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len)
 			err, len, pnum, offset, read);
 		goto error;
 	}
+	if (ubi->lookuptbl && ubi->lookuptbl[pnum]) {
+		if (ubi->lookuptbl[pnum]->rc < UBI_MAX_READCOUNTER)
+			ubi->lookuptbl[pnum]->rc++;
+		else
+			ubi_err("read counter overflow at PEB %d, RC %d",
+					pnum, ubi->lookuptbl[pnum]->rc);
+	} else
+		ubi_err("Can't update RC. No lookuptbl");
 
 	err = ubi_check_pattern(buf, 0xFF, len);
 	if (err == 0) {
drivers/mtd/ubi/ubi.h +23 -1
index 6c7e53e..e4c97ad 100644
@@ -95,6 +95,16 @@
 #define UBI_RD_THRESHOLD 100000
 
 /*
+ * This is the default read counter to be assigned to blocks lacking
+ * read counter value on attach. The value was choosen as mean between
+ * just_erased_block (rc = 0) and needs_scrubbibg_block
+ * (rc = UBI_RD_THRESHOLD). On the one hand we don't want to miss
+ * blocks that needs scrubbing but on the other, we dont want to
+ * abuse scrubbing.
+ */
+#define UBI_DEF_RD_THRESHOLD (UBI_RD_THRESHOLD / 2)
+
+/*
  * This parameter defines the maximun interval (in days) between two
  * erasures of an eraseblock. When this interval is reached, UBI starts
  * performing wear leveling by means of moving data from eraseblock with
@@ -102,6 +112,9 @@
  */
 #define UBI_DT_THRESHOLD 120
 
+/* Used when calculaing the lats erase timestamp of a PEB */
+#define NUM_SEC_IN_DAY (60*60*24)
+
 /*
  * The UBI debugfs directory name pattern and maximum name length (3 for "ubi"
  * + 2 for the number plus 1 for the trailing zero byte.
@@ -709,6 +722,11 @@ struct ubi_ainf_volume {
  * @ec_sum: a temporary variable used when calculating @mean_ec
  * @ec_count: a temporary variable used when calculating @mean_ec
  * @aeb_slab_cache: slab cache for &struct ubi_ainf_peb objects
+ * @mean_last_erase_time: mean late erase timestamp value
+ * @last_erase_time_sum: temporary variable, used to calculate
+ *				@mean_last_erase_time
+ * @last_erase_time_count: temporary variable, used to calculate
+ *				@mean_last_erase_time
  *
  * This data structure contains the result of attaching an MTD device and may
  * be used by other UBI sub-systems to build final UBI data structures, further
@@ -735,6 +753,9 @@ struct ubi_attach_info {
 	uint64_t ec_sum;
 	int ec_count;
 	struct kmem_cache *aeb_slab_cache;
+	long long  mean_last_erase_time;
+	long long last_erase_time_sum;
+	int last_erase_time_count;
 };
 
 /**
@@ -775,7 +796,8 @@ extern struct blocking_notifier_head ubi_notifiers;
 
 /* attach.c */
 int ubi_add_to_av(struct ubi_device *ubi, struct ubi_attach_info *ai, int pnum,
-		  int ec, const struct ubi_vid_hdr *vid_hdr, int bitflips);
+		  int ec, long last_erase_time, long rc,
+		  const struct ubi_vid_hdr *vid_hdr, int bitflips);
 struct ubi_ainf_volume *ubi_find_av(const struct ubi_attach_info *ai,
 				    int vol_id);
 void ubi_remove_av(struct ubi_attach_info *ai, struct ubi_ainf_volume *av);
drivers/mtd/ubi/vtbl.c +5 -1
index 07cac5f..625a9b4 100644
@@ -1,6 +1,9 @@
 /*
  * Copyright (c) International Business Machines Corp., 2006
  * Copyright (c) Nokia Corporation, 2006, 2007
+ * Copyright (c) 2014, Linux Foundation. All rights reserved.
+ * Linux Foundation chooses to take subject only to the GPLv2
+ * license terms, and distributes only under these terms.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -339,7 +342,8 @@ retry:
 	 * And add it to the attaching information. Don't delete the old version
 	 * of this LEB as it will be deleted and freed in 'ubi_add_to_av()'.
 	 */
-	err = ubi_add_to_av(ubi, ai, new_aeb->pnum, new_aeb->ec, vid_hdr, 0);
+	err = ubi_add_to_av(ubi, ai, new_aeb->pnum, new_aeb->ec,
+			new_aeb->last_erase_time, new_aeb->rc, vid_hdr, 0);
 	kmem_cache_free(ai->aeb_slab_cache, new_aeb);
 	ubi_free_vid_hdr(ubi, vid_hdr);
 	return err;
drivers/mtd/ubi/wl.c +47 -0

94 lines not on this page · raw message

Signature · 3 lines
Qualcomm Israel, on behalf of Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, 
a Linux Foundation Collaborative Project