[PATCH] UBI: allocate verification buffer on demand

josselin.costanzi at mobile-devices.fr josselin.costanzi at mobile-devices.fr
Wed Feb 22 10:37:05 EST 2012


From: Josselin Costanzi <josselin.costanzi at mobile-devices.fr>

Instead of using pre-allocated 'ubi->peb_buf2' buffer in
'ubi_eba_copy_leb()', dynamically allocate it when needed. The intent is
to get rid of the pre-allocated 'ubi->peb_buf2' buffer and save up to
2MiB of RAM per attached device (or more if PEB size is larger). If the
allocation fails, we fallback to a degraded mode where data integrity is
still ensured, at the cost of higher CPU usage.
---
 drivers/mtd/ubi/build.c |    6 ------
 drivers/mtd/ubi/eba.c   |   31 +++++++++++++++++++++++++++----
 drivers/mtd/ubi/ubi.h   |    4 +---
 3 files changed, 28 insertions(+), 13 deletions(-)

diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index 115749f..6e0806b 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -949,10 +949,6 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
 	if (!ubi->peb_buf1)
 		goto out_free;
 
-	ubi->peb_buf2 = vmalloc(ubi->peb_size);
-	if (!ubi->peb_buf2)
-		goto out_free;
-
 	err = ubi_debugging_init_dev(ubi);
 	if (err)
 		goto out_free;
@@ -1030,7 +1026,6 @@ out_debugging:
 	ubi_debugging_exit_dev(ubi);
 out_free:
 	vfree(ubi->peb_buf1);
-	vfree(ubi->peb_buf2);
 	if (ref)
 		put_device(&ubi->dev);
 	else
@@ -1102,7 +1097,6 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway)
 	put_mtd_device(ubi->mtd);
 	ubi_debugging_exit_dev(ubi);
 	vfree(ubi->peb_buf1);
-	vfree(ubi->peb_buf2);
 	ubi_msg("mtd%d is detached from ubi%d", ubi->mtd->index, ubi->ubi_num);
 	put_device(&ubi->dev);
 	return 0;
diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c
index cd26da8..b18ca27 100644
--- a/drivers/mtd/ubi/eba.c
+++ b/drivers/mtd/ubi/eba.c
@@ -985,9 +985,10 @@ static int is_error_sane(int err)
 int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
 		     struct ubi_vid_hdr *vid_hdr)
 {
-	int err, vol_id, lnum, data_size, aldata_size, idx;
+	int err, vol_id, lnum, data_size, aldata_size, idx, res;
 	struct ubi_volume *vol;
-	uint32_t crc;
+	uint32_t crc, crc_read;
+	void *p, *peb_buf2;
 
 	vol_id = be32_to_cpu(vid_hdr->vol_id);
 	lnum = be32_to_cpu(vid_hdr->lnum);
@@ -1121,6 +1122,19 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
 	}
 
 	if (data_size > 0) {
+		/*
+		 * We want that buffer to check we wrote the data correctly.
+		 * If we can't allocate it, we will check the data we wrote
+		 * using crc32.
+		 */
+		peb_buf2 = vmalloc(ubi->peb_size);
+		if (!peb_buf2) {
+			dbg_wl("Can't allocate verification buffer, will work "
+				"in degraded mode");
+			p = ubi->peb_buf1;
+		} else
+			p = peb_buf2;
+
 		err = ubi_io_write_data(ubi, ubi->peb_buf1, to, 0, aldata_size);
 		if (err) {
 			if (err == -EIO)
@@ -1135,7 +1149,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
 		 * sure it was written correctly.
 		 */
 
-		err = ubi_io_read_data(ubi, ubi->peb_buf2, to, 0, aldata_size);
+		err = ubi_io_read_data(ubi, p, to, 0, aldata_size);
 		if (err) {
 			if (err != UBI_IO_BITFLIPS) {
 				ubi_warn("error %d while reading data back "
@@ -1149,7 +1163,14 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
 
 		cond_resched();
 
-		if (memcmp(ubi->peb_buf1, ubi->peb_buf2, aldata_size)) {
+		if (peb_buf2) {
+			res = memcmp(ubi->peb_buf1, peb_buf2, aldata_size);
+		} else {
+			crc_read = crc32(UBI_CRC32_INIT, p, data_size);
+			res = (crc != crc_read);
+		}
+
+		if (res) {
 			ubi_warn("read data back from PEB %d and it is "
 				 "different", to);
 			err = -EINVAL;
@@ -1164,6 +1185,8 @@ out_unlock_buf:
 	mutex_unlock(&ubi->buf_mutex);
 out_unlock_leb:
 	leb_write_unlock(ubi, vol_id, lnum);
+	if (peb_buf2)
+		vfree(peb_buf2);
 	return err;
 }
 
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index d51d75d..cb93ad9 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -388,8 +388,7 @@ struct ubi_wl_entry;
  * @mtd: MTD device descriptor
  *
  * @peb_buf1: a buffer of PEB size used for different purposes
- * @peb_buf2: another buffer of PEB size used for different purposes
- * @buf_mutex: protects @peb_buf1 and @peb_buf2
+ * @buf_mutex: protects @peb_buf1
  * @ckvol_mutex: serializes static volume checking when opening
  *
  * @dbg: debugging information for this UBI device
@@ -472,7 +471,6 @@ struct ubi_device {
 	struct mtd_info *mtd;
 
 	void *peb_buf1;
-	void *peb_buf2;
 	struct mutex buf_mutex;
 	struct mutex ckvol_mutex;
 
-- 
1.7.5.4




More information about the linux-mtd mailing list